# Gate Framework Patterns

> 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.

- Skill: `pramoddutta/gate-framework-patterns` (Agent Skill)
- Install (CLI): `npx skillmds@latest add pramoddutta/gate-framework-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/pramoddutta/gate-framework-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: PramodDutta (https://skillmd.com/u/pramoddutta)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/pramoddutta/gate-framework-patterns

---


# 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

1. **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.
2. **Never `new SomePage(page)` in a spec.** Take it from a fixture parameter.
3. **No locators in specs.** They live in `src/pages/*.ts` as `private readonly` fields.
4. **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

5. **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)

6. **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

7. **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.
8. **Credentials come from `@config/credentials`** or `@testdata/logintestdata.json`. Never
   hard-coded.
9. **Never commit a key.** `.env` is gitignored; new variables get a blank placeholder in
   `.env.example`, which CI copies to `.env`.

## Libraries

10. **`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.
11. **Log with `createLogger('<scope>')`** from `@utils/logger`, one scope per file.
12. **Errors carry a `[ClassName]` prefix**, as in `[BookingApi] GET /booking failed: 404`.

## Path aliases

13. `@api/*` `@config/*` `@fixtures/*` `@pages/*` `@testdata/*` `@utils/*` map to `src/*`.
    Relative imports across directories are the exception.

## The AI layer

14. **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.
15. **The suite must stay green with no API key.** That is CI's normal state. Agents return an
    unavailable result; nothing throws.
16. **A new agent is a prompt plus a schema through `createAgent`.** New transport code means the
    factory was bypassed.
17. **Self-healing suggests and verifies; it never rewrites a spec.**
18. **Demo specs that fail on purpose are gated behind `AI_DEMO`.**

## Docs

19. **No em dashes**, anywhere. Use a comma, colon, parentheses or `->`.
20. **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

21. **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.
22. **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

```bash
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.

