This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Playwright + TypeScript test automation for the MEES (Minimum Energy Efficiency Standards) compliance web application. Covers functional (E2E), non-functional (accessibility + DOM/context regression), and API tests (both the app's own Page API and the backend DMS API), running against GOV.UK One Login authenticated sessions.
# Install
npm install
npx playwright install
# Authenticate test accounts (creates playwright/auth-states/user-N.json + worker-email-map.json)
# Required before functional/non-functional runs unless RUN_SETUP_AUTOMATICALLY=1
npx playwright test --project=setup
# Run by project
npx playwright test --project=functional
npx playwright test --project=non-functional
npx playwright test --project=api
npx playwright test # everything
# Single test / debugging
npx playwright test -g "test name"
npx playwright test path/to/file.spec.ts
npx playwright test --ui
npx playwright test --headed
npx playwright test --trace on
# Reports
npx playwright show-report
# non-functional coverage summary: test-results/non-functional-test-coverage.md (+ .html)There is no build/lint/typecheck npm script defined (package.json has no scripts); TypeScript is executed directly by Playwright's built-in transform. tsconfig.json only covers tests/**/* and playwright.config.ts.
Session state is stored once and reused, rather than logging in per test:
tests/test/setup/auth.setup.tsruns onesetuptest per account intests/config/test-accounts.json, logging in viaAuthUtils.performLoginand writingplaywright/auth-states/user-{workerIndex}.jsonplus a sharedworker-email-map.json(worker index → email).tests/fixtures/authFixtures.tsprovides a customtest/pagefixture (used instead of@playwright/test's in functional/non-functional specs) that creates one browser context per worker, loaded with that worker's storage state, and stashes_workerIndex/_authenticatedUserEmailon the context. Each test gets a freshpagefrom the shared worker context — this is whyworkers: 2inplaywright.config.tsmust match the number of accounts configured.- Recovery is lazy, not preemptive:
LandingPage.clickSignIn_AuthenticatedUser()detects a redirect back to GOV.UK/login and callsAuthUtils.reAuthenticate(), which looks up the worker's credentials via the stored_workerIndex, re-runs the login flow, and overwrites that worker's auth state file. No test should need to handle re-auth manually. - Credentials are never stored directly —
test-accounts.jsonholds env-var names, andAuthUtils.resolveCredentials()reads the actual values fromprocess.envat runtime.
Two account shapes matter beyond the standard parallel accounts[] list:
noAccessAccount— a valid One Login account with no MEES access, for access-denied tests.dualAccessAccount— an account with access to both MEES and PRSE (a separate app served from the same host at/PRSELocalAuthorityinstead of/compliance/); seeHomePageTests.spec.ts's "Dual Access User" describe blocks for howPRSE_BASE_URL/BASE_URLis derived.
Standard @playwright/test's test (imported as baseTest) is used instead of the custom auth fixture for tests that don't want a pre-authenticated shared context (e.g. the dual-access flows, which perform their own explicit login).
tests/pages/BasePage.tsis the abstract root: every page class implementsisDisplayed(),getPageContextLocator(),waitForPageToLoad(), and gets a shared, once-per-page-instance global console-error listener (getAllConsoleErrors()), used by functional tests to assert on known console error counts.- Pages are organized by app area:
tests/pages/Login/*(One Login flows),tests/pages/Compliance/*(the MEES app, with subfoldersGuidance/,Support/,ProfileSettings/,Cookies/), plusLandingPage.tsandPRSELandingPage.tsat the top level. - Navigation methods return the next page object (e.g.
LandingPage.clickSignIn_NotAuthenticatedUser()→SignInOrCreatePage), so tests read as a chained flow through the page graph rather than juggling locators directly. - Most pages expose a
*InNewTab()variant of their navigation methods (viaBasePage-adjacentopenLinkInNewTab) because many links in the app intentionally open new tabs — both variants are typically tested. tests/utils/ElementUtilities.tscentralizes low-level interactions (clickElement,fillText,checkElement,waitForPageToLoad) and fails loudly with descriptive errors rather than silently timing out — page objects should route through it instead of calling Playwright locator methods directly for these actions.
tests/test/non-functional/*.spec.ts are numbered by page-flow order (01-HomePage, 02-FilterProperties, … 8x for Login/edge pages) and each pairs two concerns via BaseNonFunctionalTest (tests/utils/BaseNonFunctionalTest.ts):
- Accessibility:
verifyAccessibility()runs axe-core (tests/utils/AccessibilityUtilities.ts, configured bytests/config/accessibility.config.json) and fails only oncritical/seriousimpact violations. - Context verification:
verifyContextWithLocators()assertstoMatchAriaSnapshot()against committed*.spec.ts-snapshots/*.aria.ymlfiles — these are DOM-structure/content regression snapshots, not visual screenshots. Update them via Playwright's normal--update-snapshotsflow when a page's structure intentionally changes. - Every test calls
baseTest.addTestAnnotations(PageName.X, [...])(seetests/utils/TestTypes.tsfor thePageName/TestTypeenums) — these annotations drive the customtests/utils/NonFunctionalTestReporter.tsreporter and the generatedtest-results/non-functional-test-coverage.mdsummary. New pages/test types should be added to the enums rather than passed as raw strings where possible.
tests/test/api/*.spec.ts cover two distinct boundaries — check which one a test is exercising before editing it:
- Page API — the MEES app's own backend, exercised as the authenticated user would (
PropertiesTests,PropertyTests,LocalAuthoritiesTests). - DMS API — a separate service-level export API, accessed via
tests/api/DMSExportApiClient.tsusing anx-functions-keyheader (EXPORT_KEY/DMS_BASE_URLenv vars), used byExportTests.spec.tsand by functional/non-functional tests that need to fetch real backing data (e.g. a property with multiple landlords, or one with EPC certificates) to drive test scenarios rather than hardcoding fixture data.
The api project has no auth dependency and runs fullyParallel.
Multiple .env* files exist for different targets (.env, .env.dev, .env.qa, .env.uat, etc.) — playwright.config.ts loads .env via dotenv at startup, so switching environments means swapping/pointing to the right file, not passing --env. Key variables: BASE_URL, TEST_ACCOUNT_N_{EMAIL,PASSWORD,NAME}, TEST_NO_ACCESS_*, TEST_DUAL_ACCESS_*, DMS_BASE_URL, EXPORT_KEY/PROPERTIES_KEY/PROPERTY_KEY/LOCAL_AUTHORITIES_KEY.
Test data (property IDs, addresses, expected values, etc.) is hardcoded in several spec files and must be re-verified when pointing at a new environment — see Documentation/TestDataSetup.md for the full list of what to check.
Two GitHub Actions workflows in .github/workflows/:
playwright-latest.yml— push tomain/master, nightly, or manual dispatch againstnew qa(default) ornew uat.playwright-release.yml— nightly/manual againstnew uatonly, checking out the latest git tag so tests match the deployed release. Shared job logic lives in.github/workflows/templates/. Each environment runs functional/non-functional/API jobs with their own setup + recovery steps. SeeDocumentation/CI-CD.mdfor secrets and full pipeline details.
Documentation/Test Cases/General_TestCases.csv is the git-tracked test case register and must stay in sync with the spec files. Per .github/instructions/test-cases-sync.instructions.md, whenever you create or modify a file matching tests/test/**/*.spec.ts, run the update-test-cases procedure (.github/skills/update-test-cases/SKILL.md) as a final step once the test code changes are finished — not mid-session. It upserts by test title (never duplicates), and requires a confirmed Sprint value before writing new rows; ask the user if it isn't clear from context. Field lookup rules live in .github/skills/update-test-cases/references/field-definitions.md and CSV formatting rules in .github/skills/update-test-cases/references/csv-format-guide.md.
Documentation/Authentication.md— auth setup/troubleshooting detail beyond the summary above.Documentation/Accessibility.md— WCAG 2.2 AA testing approach.Documentation/ContextVerification.md— DOM/aria snapshot verification approach.Documentation/TestDataSetup.md— hardcoded test data to check per environment.Documentation/CI-CD.md— pipeline/secrets configuration.