Gate 4: framework-patterns
Is this still part of this framework?
Code that works but ignores the repo's conventions is a slow leak: every such file makes the next
one easier to write the wrong way. These rules are specific to
AdvancePlaywrightFramework2x. Verify each against the current source before citing it.
Specs
- Import from
@fixtures/test-base, never @playwright/test. API and AI specs may use
@fixtures/booker.fixture. A spec importing @playwright/test directly has opted out of every
page-object and state fixture.
- Never
new SomePage(page) in a spec. Take it from a fixture parameter.
- No locators in specs. They live in
src/pages/*.ts as private readonly fields.
- Spec filenames need a dot:
*.spec.ts. 05_crud_spec.ts with an underscore is silently
never collected. It does not fail; it does not exist. A numeric prefix is fine because it sits
before the dot.
Page objects
- Extend
BasePage with super(page, 'ClassName'), expose a static readonly PATH, and act
through this.el.* (UtilElementLocator), never locator.click() directly. That wrapper is
what logs every action.
Project scoping (the trap that recurs)
- A new test directory needs its project decided at the same moment it is created. Three
projects exist:
| Directory |
Project |
baseURL |
Browser |
src/tests/** minus the two below |
chromium |
UI host from TTA_ENV |
Yes |
src/tests/apisTests/** |
api |
API_BASE_URL |
No |
src/tests/aiTest/** |
ai |
API_BASE_URL, 180s timeout |
Lazy, only if a test asks for page |
chromium sets testIgnore: ['**/apisTests/**', '**/aiTest/**']. Add a fourth directory
without touching this and it either runs twice, runs against the wrong host, or is invisible.
All three have happened.
Config and environment
- Read env through
@config/env (requireEnv / envOr / assertEnv). Never
dotenv.config() in a spec: Babel hoists imports above it, so modules reading process.env at
load time see nothing.
- Credentials come from
@config/credentials or @testdata/logintestdata.json. Never
hard-coded.
- Never commit a key.
.env is gitignored; new variables get a blank placeholder in
.env.example, which CI copies to .env.
Libraries
ajv + ajv-formats for schemas, jsonpath-plus for JSON queries. Zod is not a
dependency and adding it needs an argument. Schemas live in src/testdata/schemas/, draft-07,
because Ajv 8's default export only knows draft-07.
- Log with
createLogger('<scope>') from @utils/logger, one scope per file.
- Errors carry a
[ClassName] prefix, as in [BookingApi] GET /booking failed: 404.
Path aliases
@api/* @config/* @fixtures/* @pages/* @testdata/* @utils/* map to src/*.
Relative imports across directories are the exception.
The AI layer
- No test may pass or fail on model output. Assert on schema validity, HTTP status, or a
verified locator. A test whose result rides on a sampled token is not a test.
- The suite must stay green with no API key. That is CI's normal state. Agents return an
unavailable result; nothing throws.
- A new agent is a prompt plus a schema through
createAgent. New transport code means the
factory was bypassed.
- Self-healing suggests and verifies; it never rewrites a spec.
- Demo specs that fail on purpose are gated behind
AI_DEMO.
Docs
- No em dashes, anywhere. Use a comma, colon, parentheses or
->.
- Update all four sync points when adding a module: the section, the level table, the
project tree, and the env-keys table. Partial updates rot.
CI and tooling
- In CI, call the local binary, never
npx. On a checkout where a tool is not a declared
dependency, npx <tool> silently downloads an unrelated package of the same name from the
registry and runs it. This gate's own first CI run did exactly that: npx tsc fetched
tsc@2.0.4 and failed with "This is not the tsc command you are looking for". Use
./node_modules/.bin/tsc or an npm script.
- Every tool the build needs is a declared dependency.
typescript was absent from
package.json for most of this repo's life, arriving transitively, which is what made the
above possible.
Evidence required
npm run verify # typecheck, lint, suite
npx playwright test --project=<p> --list # proves a new spec is actually collected
--list is the cheapest check that a new file exists as far as the runner is concerned. If it is
absent from the listing, nothing in the file body can be at fault yet.
Verdict
FAIL on any spec importing @playwright/test directly, any locator in a spec, any new test
directory without a project decision, any hard-coded credential, any test asserting on model
output, or a suite that needs a key to pass.
1---2name: gate-framework-patterns3description: Quality gate asking "is this still part of this framework?" Enforces AdvancePlaywrightFramework2x conventions - fixture imports, page objects extending BasePage, path aliases, project scoping for src/tests vs apisTests vs aiTest, spec filenames needing a dot before spec, env access through @config/env, ajv not zod, and the AI layer's no-key and no-model-assertion rules. Use before raising a PR.4---56# Gate 4: framework-patterns78> **Is this still part of *this* framework?**910Code that works but ignores the repo's conventions is a slow leak: every such file makes the next11one easier to write the wrong way. These rules are specific to12**AdvancePlaywrightFramework2x**. Verify each against the current source before citing it.1314## Specs15161. **Import from `@fixtures/test-base`, never `@playwright/test`.** API and AI specs may use17 `@fixtures/booker.fixture`. A spec importing `@playwright/test` directly has opted out of every18 page-object and state fixture.192. **Never `new SomePage(page)` in a spec.** Take it from a fixture parameter.203. **No locators in specs.** They live in `src/pages/*.ts` as `private readonly` fields.214. **Spec filenames need a dot: `*.spec.ts`.** `05_crud_spec.ts` with an underscore is silently22 never collected. It does not fail; it does not exist. A numeric prefix is fine because it sits23 before the dot.2425## Page objects26275. **Extend `BasePage`** with `super(page, 'ClassName')`, expose a `static readonly PATH`, and act28 through `this.el.*` (`UtilElementLocator`), never `locator.click()` directly. That wrapper is29 what logs every action.3031## Project scoping (the trap that recurs)32336. **A new test directory needs its project decided at the same moment it is created.** Three34 projects exist:3536| Directory | Project | baseURL | Browser |37|:----------|:--------|:--------|:--------|38| `src/tests/**` minus the two below | `chromium` | UI host from `TTA_ENV` | Yes |39| `src/tests/apisTests/**` | `api` | `API_BASE_URL` | No |40| `src/tests/aiTest/**` | `ai` | `API_BASE_URL`, 180s timeout | Lazy, only if a test asks for `page` |4142 `chromium` sets `testIgnore: ['**/apisTests/**', '**/aiTest/**']`. Add a fourth directory43 without touching this and it either runs twice, runs against the wrong host, or is invisible.44 All three have happened.4546## Config and environment47487. **Read env through `@config/env`** (`requireEnv` / `envOr` / `assertEnv`). Never49 `dotenv.config()` in a spec: Babel hoists imports above it, so modules reading `process.env` at50 load time see nothing.518. **Credentials come from `@config/credentials`** or `@testdata/logintestdata.json`. Never52 hard-coded.539. **Never commit a key.** `.env` is gitignored; new variables get a blank placeholder in54 `.env.example`, which CI copies to `.env`.5556## Libraries575810. **`ajv` + `ajv-formats` for schemas, `jsonpath-plus` for JSON queries.** Zod is not a59 dependency and adding it needs an argument. Schemas live in `src/testdata/schemas/`, draft-07,60 because Ajv 8's default export only knows draft-07.6111. **Log with `createLogger('<scope>')`** from `@utils/logger`, one scope per file.6212. **Errors carry a `[ClassName]` prefix**, as in `[BookingApi] GET /booking failed: 404`.6364## Path aliases656613. `@api/*` `@config/*` `@fixtures/*` `@pages/*` `@testdata/*` `@utils/*` map to `src/*`.67 Relative imports across directories are the exception.6869## The AI layer707114. **No test may pass or fail on model output.** Assert on schema validity, HTTP status, or a72 verified locator. A test whose result rides on a sampled token is not a test.7315. **The suite must stay green with no API key.** That is CI's normal state. Agents return an74 unavailable result; nothing throws.7516. **A new agent is a prompt plus a schema through `createAgent`.** New transport code means the76 factory was bypassed.7717. **Self-healing suggests and verifies; it never rewrites a spec.**7818. **Demo specs that fail on purpose are gated behind `AI_DEMO`.**7980## Docs818219. **No em dashes**, anywhere. Use a comma, colon, parentheses or `->`.8320. **Update all four sync points** when adding a module: the section, the level table, the84 project tree, and the env-keys table. Partial updates rot.8586## CI and tooling878821. **In CI, call the local binary, never `npx`.** On a checkout where a tool is not a declared89 dependency, `npx <tool>` silently downloads an unrelated package of the same name from the90 registry and runs it. This gate's own first CI run did exactly that: `npx tsc` fetched91 `tsc@2.0.4` and failed with *"This is not the tsc command you are looking for"*. Use92 `./node_modules/.bin/tsc` or an npm script.9322. **Every tool the build needs is a declared dependency.** `typescript` was absent from94 `package.json` for most of this repo's life, arriving transitively, which is what made the95 above possible.9697## Evidence required9899```bash100npm run verify # typecheck, lint, suite101npx playwright test --project=<p> --list # proves a new spec is actually collected102```103104`--list` is the cheapest check that a new file exists as far as the runner is concerned. If it is105absent from the listing, nothing in the file body can be at fault yet.106107## Verdict108109`FAIL` on any spec importing `@playwright/test` directly, any locator in a spec, any new test110directory without a project decision, any hard-coded credential, any test asserting on model111output, or a suite that needs a key to pass.