Skip to content

Latest commit

 

History

History
79 lines (63 loc) · 4.66 KB

File metadata and controls

79 lines (63 loc) · 4.66 KB

web-e2e

End-to-end and integration tests for the Languages Learner web app.

Purpose

Exercises apps/web as a whole — browser-level flows and integration tests — separate from the unit tests that live inside individual packages and the Playwright component tests in uikit. In this repo "integration tests" are full-page screenshot (visual regression) tests: each spec opens a page and calls the expectScreenshot fixture, which captures the page in both light and dark themes and compares against committed -linux baselines.

Public API / exports

Not a library — it defines the test:integration target (and test:integration:update for refreshing baselines). It does not export anything for other packages to import.

Layout

  • integration/playwright.config.ts — Playwright config. testDir is integration/tests; a global_setup project logs in once and persists a storage state, on which the chromium project depends. Snapshots are stored as …-{theme}-chromium-linux.png next to each spec.
  • integration/tests/** — the specs (landing, office, dictionary) and their *-snapshots/.
  • pages/** — Page Object Models; they navigate via page.goToWithLocale(...) and reuse the web app's route constants from @/shared/routes (→ apps/web/src/ui/shared/routes).
  • core/** — shared setup (commonSetup, login) and barrels. The two barrels export different test objects on purpose: core/index.ts re-exports the plain test from app-core-tests-utils (used by global.setup for a real login, no network mocking), while integration/core/index.ts re-exports the test from app-integration-tests-utils, which adds the auto mockNetwork fixture.
  • Each spec's *-snapshots/ folder also holds committed …-chromium-linux.har (+ .dat bodies) next to the PNGs: the mockNetwork fixture records/replays backend traffic (<baseURL>/api/**) through routeFromHAR and sanitizes the HAR (har-sanitizer) in an afterAll hook, so screenshots don't depend on live backend data. Because routeFromHAR matches by exact URL and the /api origin varies between local recording and the dynamic CI stage domain, the committed HAR is host-normalized to http://mocked.local (via the fixture's urlsToReplace) and rewritten back to the live baseURL in a temp *.replay.har on replay.

Path aliases (see tsconfig.json): @/tests/app/* → package root, @/shared/* → the web app's src/ui/shared, @@/* → repo root.

Depends on

  • @languages-learner/app-core-tests-utils — the plain test fixture (expectScreenshot + goToWithLocale), used for login/global.setup.
  • @languages-learner/app-integration-tests-utils — the integration test (core + mockNetwork), used by the specs; records/replays and sanitizes the backend (/api) HAR. Committed HARs are kept secret-free by har-sanitizer, enforced in CI by pnpm har:check.
  • @languages-learner/playwright-utils — auth-storage helpers and fixture factories.
  • @playwright/test, dotenv.

Used in

  • Nothing imports it; it is a test app.
  • CI: the reusable .github/workflows/e2e-tests.yml runs test:integration on pull requests, after the staging deploy, gated on check-deploy-affected (i.e. when app-web/app-backend is affected). It receives the freshly-deployed stage URL as BASE_URL and the test account from the TEST_USER_AUTH_LOGIN / TEST_USER_AUTH_PASSWORD secrets (mapped to AUTH_LOGIN / AUTH_PASSWORD at run time).

Notes

  • global_setup performs a real UI login against the staging Supabase, so a seeded, confirmed test user must exist. Locally, provide BASE_URL, AUTH_LOGIN, AUTH_PASSWORD via integration/.env (see integration/.env.example) and point BASE_URL at a running apps/web.
  • Screenshot baselines are Linux-rendered (…-linux.png, hardcoded in the config). Regenerate them with the Docker flow test:integration:update:docker (which mirrors the uikit component-test setup: a CI-matched Ubuntu image via Dockerfile.tests.component), not a native test:integration:update on Windows/macOS, whose font rendering differs from the CI runner. The container reaches the natively-running apps/web through host.docker.internal — see the README.
  • API-dependent flows need a real Supabase project or route mocks (e.g. dictionary.spec.ts stubs rest/v1/words via page.route) — the public tree ships no turnkey backend or DB migrations.

Links