Skip to main content

Specs: the English description of a test

A spec is a plain-English markdown file that describes one test scenario. It lives in tests/specs/ and is the source of truth for everything the AI generates. If you want a test to do something different, you update the spec — not the generated TypeScript.

What a spec file looks like

Every spec has two parts: a YAML header (called frontmatter) and a body with named sections.

The frontmatter

The frontmatter sits between the --- fences at the very top of the file.

---
id: PROJECT-TEAM-ADD-KEY-MEMBER-001
feature: project
title: 'Case: Add Account Manager key member'
priority: high
tags: [happy-path, project-team]
fixture: projectTeamPage
data:
- team.account_manager_smith
---
FieldWhat it means
idUnique identifier used by the generator and CI to track this spec.
featureThe PACE feature area this spec belongs to (project, estimates, clients, …).
titleHuman-readable name shown in test reports.
priorityHow critical the scenario is — used to decide which tests run in a short smoke suite.
fixtureThe Playwright fixture that sets up the browser state (logs in, navigates to the right page).
dataOne or more dotted keys into tests/data/*.jsonc — the real values the test will use.

The body sections

After the frontmatter the spec has three sections:

  • ## Background — A sentence or two explaining what the test is proving and any setup assumptions. Written for a human reader, not the test runner.
  • ## Steps — A numbered list of actions. Each step has three parts (see below).
  • ## Expected — What the tester should observe at the end of a successful run.

Inside a step

Each numbered step has three pieces:

3. Click "Add new member" and capture the new row index
- intent: "Append a fresh row so the new key member's role + person can be set."
- method: `tp.clickAddNewMember()` then `(await grid.getRowCount()) - 1`
PartPurpose
proseThe human description — what a tester would say out loud while doing this manually.
intentThe why behind the step, written in plain English. The AI uses this to write assertions.
methodThe page-object or helper calls the Generator will translate into TypeScript.

The method: field is essentially a recipe written in pseudo-code using the page-object API. You do not need to know TypeScript to read it — it is meant to be self-explanatory.

A real excerpt

Here are steps 3–6 from tests/specs/project/team/add-key-member.md, the spec that tests adding an Account Manager to a project's Key Members grid:

3. Click "Add new member" and capture the new row index
- intent: "Append a fresh row so the new key member's role + person can be set."
- method: `tp.clickAddNewMember()` then `(await grid.getRowCount()) - 1`
4. Pick the role in the new row's role dropdown
- intent: "Assign the Account Manager role — driven by data so the spec can be
re-run for other roles by swapping data refs."
- method: `grid.selectCellDropdownOption('role_id', newRowIndex, member.role_id)`
5. Pick the person in the new row's person dropdown
- intent: "Pick the specific named person for the role."
- method: `grid.selectCellDropdownOption('person_id', newRowIndex, member.person_id)`
6. Save and wait for the success toast
- intent: "Persist the change and assert the server accepted it via the toast —
a single round-trip validation."
- method: `tp.wait.expectToastAfterAction('success', () => tp.save())`

Notice that member.role_id and member.person_id are data references — not hard-coded strings. The real values live in tests/data/team.jsonc and flow in via the data: frontmatter key. See Test data for details.

Requesting a new page-object method

Sometimes a spec needs a page-object method that does not exist yet. You signal this with a [NEW: ClassName.methodName()] annotation in the method: field:

2. Open the project settings panel
- intent: "Navigate to the settings tab so we can edit the project name."
- method: `[NEW: ProjectPage.openSettingsPanel()]`

When the Generator sees [NEW: ...] it reads the application source to learn the correct selectors, writes the method, and adds it to the page object before producing the test file.

Specs vs. generated test files

The spec (tests/specs/…/*.md) is the thing you own and maintain. The generated test file (tests/e2e/…/*.spec.ts) is produced by the Generator agent and should not be hand-edited — if you edit it directly, those changes will be lost the next time the Generator runs. When you want to change a test's behaviour, update the spec and regenerate.