Skip to main content

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

PackageRole
@archibald/e2eFramework-agnostic core: environment merging, shared types, mock endpoint/auth constants, helpers
@archibald/cypressCypress integration (config, plugins, support)
@archibald/playwrightPlaywright integration (defineConfig, fixtures, support)
@archibald/maestroMaestro 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 by environment, tenant, platform, mode and language.
  • getRunnerOverrides(config) — derives baseUrl / viewport / userAgent from 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 tests
  • config/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:

FlagDescription
-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, --headlessRun 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:

SettingDefaultEffect
startServertrueWhether to start a server at all. Set false when you serve the app yourself or an external host serves it.
serverMode"development"developmentarchibald serve (dev server, HMR); productionarchibald build then serve the built output.

Details:

  • development starts archibald serve with the HMR/asset host pinned to localhost (ARC_HMR_HOST=localhost), so webpack chunks load from the same origin the tests navigate to. A normal archibald serve is unaffected and keeps its default dynamic host (the machine's LAN IP, useful for on-device HMR).
  • production runs archibald build -m production and 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-host archibald serve running 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 the ci environment).

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 the testUser fixture (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):

MethodPathPurpose
POST/mock/resetSeed/reset the account + cart
POST/mock/user/cartAdd a cart with given products
DELETE/mock/user/cartClear the cart
POST/mock/user/orderSeed/add an order
DELETE/mock/user/orderDelete 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.frameworkCypress specsPlaywright specs
cypress (default)src/{platform}/e2esrc/{platform}/e2e-playwright
playwrightsrc/{platform}/e2e-cypresssrc/{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 integrationintegration-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.

Coverage

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 tenant extends chains are walked most-specific first.
  • Platform — a run resolves the platform passed to archibald e2e -p …, plus the platforms it extends — 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.
  • Layoutproject.source.paths.src and project.source.paths.e2e are honoured, so renaming either folder needs no further config.
Platform inheritance differs from source shadowing

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.