The shared Playwright config passes --unsafely-treat-insecure-origin-as-secure
for every .onion origin in the environment, but Playwright's default
chrome-headless-shell ignores that switch. On the tor axis the odoo origin
therefore stayed an insecure context: navigator.clipboard was undefined and
Odoo 20's onboarding tour crashed with "Cannot read properties of undefined
(reading 'writeText')" and "Cannot destructure property 'TourInteractive'",
opening error dialogs that the addon specs read as a missing module (odoo#2,
swarm tor, main run 38038541631).
When ODOO_BASE_URL is an onion URL the odoo specs now use channel "chromium",
the full Chromium build in the Playwright image, and block service workers;
clearnet runs keep every option unchanged. The worker is blocked because a
secure context lets Odoo register /web/service-worker.js, whose fetch handler
answers a failed navigation with a cached page or /odoo/offline: gotoOnion
would get a 200 instead of the transport error it retries on. The switch stays
in the role: a use.channel in the shared config would also reach the Firefox
launch of onion-test.js, which rejects it with "Unsupported firefox channel",
and would move every other role's onion run to a browser none of them was
tested on.
Verified with Playwright 1.63 in the runner's staging layout and the real
odoo specs: an onion ODOO_BASE_URL resolves channel "chromium" and
serviceWorkers "block", also for the contexts _shared.js creates itself, and
launches chromium-<rev>/chrome-linux64/chrome; a clearnet one, and HEAD's
specs on onion, keep the headless shell and "allow". All spec files stay on
one worker, which the suite's one-worker test requires. Against Odoo 20's
service worker with a dropped connection, full Chromium returned the cached
/odoo page with status 200, while with the worker blocked page.goto threw
net::ERR_CONNECTION_FAILED as the headless shell does. In the v1.64.0 image
full Chromium made no :443 attempt to an onion host and the onion origin
reported isSecureContext with crypto.subtle, which the headless shell did not.
A local deploy of web-app-odoo variant 2 over Tor ran the odoo suite on
/ms-playwright/chromium-1248/chrome-linux64/chrome and passed all seven addon
specs, the one-worker test and the guest flow without a retry; in the variant
0 round the suites of the other roles kept chrome-headless-shell.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each of the seven addon specs opened a fresh context and ran the full SSO
round-trip. Over Tor that is roughly twelve minutes apiece, and odoo 0 of run
31340965955 died on 'Test timeout of 600000ms exceeded' inside
gotoOnion -> loginToOdoo -> contacts.spec.js:13.
authenticatedContext caches the storage state after the first login and restores
it for later callers. A restored state that no longer renders the web client is
discarded and the full login runs, so an expired session degrades to today's
behaviour rather than failing the spec.
Coverage is not reduced: the SSO flow keeps its own dedicated tests in
playwright.spec.js:98 and :160 (admin and biber, log in / verify ui / log out),
which this change does not touch. The seven addon logins were repetition of an
already-covered path, and no addon spec asserts anything about the login or
needs an anonymous session. What does change is isolation -- the specs now share
one restored session instead of each starting clean.
The TEST_E2E_PLAYWRIGHT_ONION_TEST_TIMEOUT bump belongs in this commit: four
specs lost their own test.setTimeout(resolveTimeout(180_000)), which resolved to
900s on an onion. Without the bump those four would regress from 900s to 600s.
Cause B is untouched: the global ONION_RUN_TIMEOUT of 5400s left eight tests
unstarted. The cache should relieve it, but that is arithmetic on measured
single-login times, not an observed run, and raising a timeout that spans every
onion role needs its own measurement.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add the global TIMEOUT_FACTOR and a shared timeouts.js helper: resolveTimeout(base) scales by TIMEOUT_FACTOR and, over a .onion target, an extra multiplier, so Tor's per-request latency no longer trips hard-coded timeouts. Migrate every raw timeout in the specs (timeout:/timeout=/setTimeout/waitForTimeout) to resolveTimeout, stage the helper in all three staging paths, and add test_no_raw_timeouts to forbid raw numeric timeouts. Clearnet behaviour is unchanged (factor 1: resolveTimeout(N) === N).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
odoo: sale_management.spec.js asserted `breadcrumb.or(appTitle)` without
`.first()`; when the Sales module installs correctly BOTH the menu brand
and the breadcrumb render, so `.or()` resolved to 2 elements and
`toBeVisible()` raised a strict-mode violation — failing the success case.
Add `.first()` (matching the same file's createQuotation locator).
nextcloud: the GitLab OAuth provisioning hard-`raise`d when no Organization
existed yet (default org is seeded asynchronously). Resolve/create it
defensively and add `retries/until` so a transient not-yet-seeded window no
longer fails the whole deploy.
jenkins: the deploy-lockdown service stop had no retry; under load systemd
intermittently refused with "Transaction is destructive". Add `retries/until`
so the transient contention is ridden out.
moodle: the shared `compose up` handler had no retry; a transient missing
external network (central DB stack still creating it) failed the deploy. Add
`retries/until`, matching the handler's existing compose-pull pattern.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
stock.spec.js applied .first() to each .or() operand (breadcrumb and appTitle) before combining them, so breadcrumb.or(appTitle) was a union of two locators that resolved to 2 visible elements (the stock.menu_stock_root brand link AND the 'Inventory Overview' breadcrumb) — expect().toBeVisible() requires exactly one match and threw a Playwright strict-mode violation. The two matches actually PROVE the stock module installed; the assertion message's 'module failed to install' premise was wrong. Mirror the passing account.spec.js pattern: drop the per-branch .first() and apply a single .first() after .or(). The assertion intent (Inventory identity must render) is preserved — no green-wash.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The account addon spec opened /odoo/accounting (the journal dashboard, which in Odoo 19 has no .o_account_dashboard and not the asserted invoice vocabulary) and timed out even though the account module is installed. Navigate to /odoo/invoicing — the canonical account.move customer-invoices action — and assert the invoices list/kanban plus account-specific vocabulary (customer invoice / register payment / invoice date / tax excluded). Verified green live against Odoo 19 via 'make compose-playwright role=web-app-odoo'.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The account addon spec asserted bare .o_control_panel/.o_breadcrumb, which render on every Odoo page, so it passed green even when the account module was enabled-but-not-installed. Require Accounting domain vocabulary (Customer Invoices / Vendor Bills / Chart of Accounts / Journal Entries) and text-gate the generic containers, mirroring the crm/stock specs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the generic surface check with the Inventory app identity, no invalid-action
error, the stock.picking operations dashboard, and stock-specific operation types
(Receipts/Deliveries/Internal Transfers).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the generic surface check with the Sales app identity (breadcrumb/title),
the sale.order quotations list/kanban action, and the New create button.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the generic surface check with no-error-page + the CRM control panel and a
CRM-specific surface (lead/opportunity kanban, New, Pipeline) plus CRM domain
vocabulary, proving the crm module loaded.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the generic web-client surface check with module-specific signals: no Odoo
error dialog, the Accounting/Invoicing app brand in the navbar, and an
account-specific top menu (Customers/Vendors/Chart of Accounts).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add tests/lint/ansible/services/test_addons_playwright_spec.py requiring roles/<role>/files/playwright/addons/<id>.spec.js for EVERY addon of EVERY role — no mechanism auto-exempt and no # nocheck escape. Ship the 87 per-addon specs (gated via skipUnlessAddonEnabled so they skip cleanly when the addon is disabled in the current variant), the test-e2e-playwright addon-gating harness (addon-gating.js, playwright.config.js, recursive 02_run_one.yml), the shared odoo helper, and the ADDON_<ID>_ENABLED flags in the six playwright.env.j2 templates. Relax test_env_file_schema to skip Jinja-templated keys in the ADDON loop. Doc updates (suppression.md, requirements/026) follow in a separate commit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>