Overview
Archibald ships end-to-end testing for three runners — Cypress and Playwright for web, and Maestro for native (React Native/Expo) — all driven by the same archibald e2e command. The two web runners share configuration and a common test-user API.
Packages
| Package | Role |
|---|---|
@archibald/e2e | Framework-agnostic core: environment merging, shared types, mock endpoint/auth constants, helpers |
@archibald/cypress | Cypress integration (config, plugins, support) |
@archibald/playwright | Playwright integration (defineConfig, fixtures, support) |
@archibald/maestro | Maestro integration for native flows (see Maestro) |
@archibald/e2e is a dependency of the web integrations and keeps them in sync. It exposes, among others:
mergeEnvironment(params, cliConfig)— merges the environment/selectors/features config byenvironment,tenant,platform,modeandlanguage.getRunnerOverrides(config)— derivesbaseUrl/viewport/userAgentfrom the merged environment (applied identically in both web runners).E2E_AUTH,E2E_MOCK— shared auth cookie names and mock endpoint paths.withParallelTag(email, index)— plus-tags an email per parallel worker (see Playwright).
Choosing a runner
The active runner is stored in archibald.json under cli.e2e.framework ("cypress", "playwright", or "maestro"). It is set automatically when you add an integration:
archibald add cypress # sets cli.e2e.framework = "cypress"
archibald add playwright # sets cli.e2e.framework = "playwright"
archibald add maestro # sets cli.e2e.framework = "maestro"
archibald e2e then dispatches to the configured runner. A run can be overridden ad-hoc with -r, --runner (cypress | playwright | maestro). The legacy cli.e2e.runner key is still read as a fallback when framework is not set.
Shared configuration
Both runners read the same environment configuration from cypress/config (Playwright reuses it):
config/environment/*.json— per-environment settings (baseUrl,apiUrl, viewport, …)config/selectors.json— DOM selectors exposed to the testsconfig/features.json— feature flags
Each file is split into general plus optional tenant, platform, mode and language overrides, which mergeEnvironment layers on top of each other. See the Cypress page for an example.
Running the tests
archibald e2e
Run without flags for an interactive prompt, or pass them directly:
| Flag | Description |
|---|---|
-e, --environment <name> | Environment to use |
-t, --tenant <name> | Tenant to use |
-p, --platform <name> | Platform to use |
-l, --language <name> | Language to use |
-m, --mode <desktop|mobile> | Device/viewport mode |
-b, --browser <name> | Browser (chrome, firefox, webkit; Cypress also electron) |
-h, --headless | Run headless instead of opening the UI |
archibald e2e -e local -t netconomy-b2c -p shop -d desktop -b chrome -h
The app server is started for you
archibald e2e boots the application for the test run automatically (for both web runners). Two cli.e2e settings control this:
| Setting | Default | Effect |
|---|---|---|
startServer | true | Whether to start a server at all. Set false when you serve the app yourself or an external host serves it. |
serverMode | "development" | development → archibald serve (dev server, HMR); production → archibald build then serve the built output. |
Details:
- development starts
archibald servewith the HMR/asset host pinned tolocalhost(ARC_HMR_HOST=localhost), so webpack chunks load from the same origin the tests navigate to. A normalarchibald serveis unaffected and keeps its defaultdynamichost (the machine's LAN IP, useful for on-device HMR). - production runs
archibald build -m productionand then serves the built output (node dist/server) — the same production bundle CI tests against, without HMR (and without the LAN-IP asset-host caveat). Slower to start (it builds first) but more representative. - An already-running server (matching the merged
baseUrl) is reused — so don't keep a separate LAN-hostarchibald serverunning while you run e2e locally, or it will be reused instead. - In CI starting is always a no-op regardless of
startServer: the app is expected to be served externally (e.g. a Docker service via thecienvironment).
Test-user API
Both runners expose an isolated test account through getTestUser(), with helpers to seed/reset backend state. This replaces the old resetUserAndCart command.
// email + password identity, plus (Cypress) the operations below
const user = getTestUser();
user.reset(); // recreate a clean baseline account (call at the start of a test)
user.addCart(products?); // populate the cart (defaults to a sample set of products)
user.deleteCart(); // empty the cart
user.addOrder(order?); // add an order to the history (defaults to the sample order set)
user.deleteOrder(orderId?); // remove one order, or all when no id is given
- In Cypress the operations live directly on
getTestUser(). - In Playwright
getTestUser()returns only the identity; the operations are provided by thetestUserfixture (it needs the request context). See the Playwright page.
These call the following mock endpoints (implemented in the shop mock module and keyed per userId, so parallel workers never collide):
| Method | Path | Purpose |
|---|---|---|
POST | /mock/reset | Seed/reset the account + cart |
POST | /mock/user/cart | Add a cart with given products |
DELETE | /mock/user/cart | Clear the cart |
POST | /mock/user/order | Seed/add an order |
DELETE | /mock/user/order | Delete order(s) |
Where tests live
Web tests (Cypress/Playwright) use the page-object model and are separated per platform. The folder name depends on which runner is configured in archibald.json (cli.e2e.framework): that runner owns the base e2e folder, and every other runner uses e2e-{runner}.
cli.e2e.framework | Cypress specs | Playwright specs |
|---|---|---|
cypress (default) | src/{platform}/e2e | src/{platform}/e2e-playwright |
playwright | src/{platform}/e2e-cypress | src/{platform}/e2e |
Within each folder, specs live in specs/ and page objects in pages/. The base folder name (e2e) is configurable via project.source.paths.e2e in archibald.json; the per-runner suffix is derived from it (e.g. base integration → integration-playwright). The archibald add cypress|playwright scaffolders and the runners themselves resolve the folder the same way, so it stays consistent.
Maestro is native and keeps its flows in maestro/ instead — see the Maestro page.
Every e2e folder — the base e2e and all e2e-* variants — is excluded from Jest coverage and from SonarQube analysis and coverage, since these suites are driven by Cypress/Playwright rather than unit tests.
Spec discovery and shadowing
Both web runners resolve their spec set from archibald.json instead of taking a fixed glob, so a run collects exactly the specs of the selected platform and tenant. Cypress maps the result onto specPattern, Playwright onto testDir/testMatch; the resolution itself is shared (@archibald/e2e/specs), so the two agree on what a given run owns.
- Tenant — a spec in
src/{platform}/{e2e-folder}/tenant/{tenant}/…replaces the base spec of the same name for that tenant, exactly as a tenant override replaces a source file. Specs belonging to other tenants are left out of the run entirely, and tenantextendschains are walked most-specific first. - Platform — a run resolves the platform passed to
archibald e2e -p …, plus the platforms itextends— a platform that extends another shadows that platform's specs by name and inherits the rest. A platform that extends nothing keeps to its own specs. Running without a platform resolves every declared platform on its own. - Layout —
project.source.paths.srcandproject.source.paths.e2eare honoured, so renaming either folder needs no further config.
For source files, the first declared platform is the base of every platform, so anything not overridden falls back to it. Spec discovery follows only what extends declares: a suite is written for the app its platform actually is, and inheriting the base platform's whole suite by default would run it against apps it was never written for.
If your project declares its own shadowing rule for the e2e folder in project.shadowing.config (e.g. src/{platform}/e2e/specs(/theme/{tenant})), that rule is used; otherwise the conventional …(/tenant/{tenant}) layout is assumed. A project that keeps its specs outside src/{platform}/{e2e-folder} altogether is left to the runner's own discovery.
See the Cypress and Playwright pages for the details of each runner.