<!--
SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project

SPDX-License-Identifier: Apache-2.0
-->

# Playwright E2E

End-to-end tests for `citrineos-operator-ui` against a real Hasura + CitrineOS Core stack.

## Prerequisites

1. Backend stack running. From the `citrineos-core` repository root (full stack incl. UI), or from
   `citrineos-core/apps/Server` (backend only):
   ```bash
   docker compose up -d
   ```
   Healthchecks: Hasura `:8090/healthz`, Citrine `:8080/health`, UI `:3000/login`.
2. UI server running. From `apps/operator-ui`:
   ```bash
   pnpm run dev
   ```
   If nothing is listening on `:3000`, `globalSetup` will build a production
   bundle and start `next start` for the lifetime of the suite (see
   `tests/e2e/utils/managed-server.ts`).
3. `.env.test` exists. Copy from `.env.test.example` and fill in admin credentials.

## Run

```bash
# Full suite
pnpm run test:e2e

# A single spec
npx playwright test specs/auth/login.spec.ts

# UI mode
pnpm run test:e2e:ui

# Step through with the inspector
pnpm run test:e2e:debug

# Open the HTML report from the last run
pnpm run test:e2e:report
```

## What's covered

| Area              | Specs                                                                                                                                                                  |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Auth              | `specs/auth/login.spec.ts`, `specs/auth/logout.spec.ts`                                                                                                                |
| Overview          | `specs/overview/dashboard.spec.ts`, `welcome-modal.spec.ts`, `theme.spec.ts`                                                                                           |
| Locations         | `specs/locations/crud.spec.ts`, `map.spec.ts`, `form-conditional.spec.ts`                                                                                              |
| Charging stations | `specs/charging-stations/list.spec.ts`, `crud.spec.ts`, `detail-tabs.spec.ts`, `realtime.spec.ts`, `onboarding.spec.ts`, `admin-toggles.spec.ts`, `commands-*.spec.ts` |
| Transactions      | `specs/transactions/list.spec.ts`, `detail-charts.spec.ts`                                                                                                             |
| Authorizations    | `specs/authorizations/crud.spec.ts`                                                                                                                                    |
| Tariffs           | `specs/tariffs/crud.spec.ts`                                                                                                                                           |
| Partners          | `specs/partners/register.spec.ts`                                                                                                                                      |
| Schema guard      | `specs/schema/schema-drift.spec.ts`                                                                                                                                    |

The schema-drift guard also runs as part of `globalSetup` — any spec run fails
fast if the live Hasura schema has drifted from
`tests/e2e/data/schema-snapshot.json`. When an upstream schema change is
intentional (renamed operation, dropped column, new tracked table), regenerate
the baseline with:

```bash
npx tsx tests/e2e/scripts/capture-schema.ts
```

Review the diff before committing — the script overwrites the JSON in place.

`@everest` tagged tests need the EVerest manager image
(`citrineos-core/apps/Server/everest`) and run on the `everest-serial` project.
They are skipped automatically when the image is not running.

## Folder layout

```
tests/e2e/
├── auth/           global-setup, global-teardown, admin.setup
├── pages/          Page Object Models
├── fixtures/       apiClient, seeded-data, everest, index (test.extend barrel)
├── specs/          Test specs mirroring the app routes
├── utils/          env, wait, random, route-overrides, storage, schema-drift, managed-server
├── scripts/        capture-schema.ts (regenerates the schema-drift baseline)
├── data/           schema-snapshot.json
├── TESTIDS.md      data-testid registry (reserved for future src-side additions)
└── README.md       this file
```

## Coding principles

- TypeScript strict, no `any`.
- Selector hierarchy: `getByRole` > `getByLabel` > `getByText` > `getByPlaceholder` > `getByTestId`. The suite currently uses no `data-testid` at all (project constraint: no `src/` modifications).
- No `waitForTimeout`. Use `expect.poll`, `expect(locator).toBeVisible()`, or `locator.waitFor`.
- POMs hold locators and small actions. Specs hold assertions.
- Storage state is generated by `auth/admin.setup.ts`, never hand-written.
- Seeding mutations always have typed responses. Fixture teardown deletes seeded rows; `globalTeardown` performs a best-effort sweep.
