| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 1 | 20 | 9 | 3% |
| Commands | 1 | 7 | 7 | 7% |
| Section tags | 3 | 3 | 1 | 43% |
What each file covers
Sections
1 shared · 20 only in A · 9 only in B- − AGENTS.md
- − Critical Rules
- − Running E2E Tests
- − Terminal 1 (or background): Start dev environment from the repo root
- − Wait for the admin dev server to be reachable (http://127.0.0.1:5174)
- − Terminal 2: Run e2e tests from the e2e/ directory
- − Naming Conventions
- − AAA Pattern
- − Page Objects
- − Structure
- − Rules
- − Locators (Strict Priority)
- − Playwright MCP Usage
- − Test Data
- − Factory Pattern (Required)
- − Best Practices
- − DO ✅
- − DON'T ❌
- − Project Structure
- − Validation Checklist
- + Koenig Lexical Test Guide
- + Test Commands
- + Unit Tests
- + Acceptance Tests (Playwright)
- + All Tests
- + AI-Friendly Testing
- + Human-Friendly Testing
- + Environment Variables
- + Development Workflow
- Test Structure
Commands
1 shared · 7 only in A · 7 only in B- − pnpm dev
- − pnpm test tests/path/to/test.ts
- − pnpm lint
- − pnpm test:types
- − pnpm build
- − pnpm test --debug
- − pnpm test path/to/test.ts
- + pnpm test:unit
- + pnpm test:unit:watch
- + pnpm test:acceptance
- + pnpm test:acceptance:quiet
- + pnpm test:acceptance:headed
- + pnpm test:acceptance:report
- + pnpm test:slowmo
- pnpm test
Section tags
3 shared · 3 only in A · 1 only in B- − code-style
- − testing-strategy
- − do-not
- + agent-behaviour
- setup
- test
- architecture
Line diff
TryGhost/Ghost · e2e/AGENTS.md
@@ −1 @@
1# AGENTS.md
2
3E2E testing guidance for AI assistants (Claude, Codex, etc.) working with Ghost tests.
4
5**IMPORTANT**: When creating or modifying E2E tests, always refer to `./.claude/E2E_TEST_WRITING_GUIDE.md` for comprehensive testing guidelines and patterns.
6
7## Critical Rules
81. **Always follow ADRs** in `../adr/` folder (ADR-0001: AAA pattern, ADR-0002: Page Objects)
92. **Always use pnpm**, never npm
103. **Always run after changes**: `pnpm lint` and `pnpm test:types`
114. **Never use CSS/XPath selectors** - only semantic locators or data-testid
125. **Prefer less comments and giving things clear names**
13
14## Running E2E Tests
15
16**`pnpm dev` must be running before you run E2E tests.** The E2E test runner auto-detects
17whether the admin dev server is reachable at `http://127.0.0.1:5174`. If it is, tests run
18in **dev mode** (fast, no pre-built Docker image required). If not, tests fall back to
19**build mode** which requires a `ghost-e2e:local` Docker image that is only built in CI.
20
21**If you see the error `Build image not found: ghost-e2e:local`, it means `pnpm dev` is
22not running.** Start it first, wait for the admin dev server to be ready, then re-run tests.
23
24```bash
25# Terminal 1 (or background): Start dev environment from the repo root
26pnpm dev
27
28# Wait for the admin dev server to be reachable (http://127.0.0.1:5174)
29
30# Terminal 2: Run e2e tests from the e2e/ directory
31pnpm test # Run all tests
32pnpm test tests/path/to/test.ts # Run specific test
33pnpm lint # Required after writing tests
34pnpm test:types # Check TypeScript errors
35pnpm build # Required after factory changes
36pnpm test --debug # See browser during execution, for debugging
37PRESERVE_ENV=true pnpm test # Debug failed tests (keeps containers)
38```
39## Test Structure
40
41### Naming Conventions
42- **Test suites**: `Ghost Admin - Feature` or `Ghost Public - Feature`
43- **Test names**: `what is tested - expected outcome` (lowercase)
44- **One test = one scenario** (never mix multiple scenarios)
45
46### AAA Pattern
47```typescript
48test('action performed - expected result', async ({page}) => {
49 const analyticsPage = new AnalyticsGrowthPage(page);
50 const postFactory = createPostFactory(page.request);
51 const post = await postFactory.create({status: 'published'});
52
53 await analyticsPage.goto();
54 await analyticsPage.topContent.postsButton.click();
55
56 await expect(analyticsPage.topContent.contentCard).toContainText('No conversions');
57});
58```
59
60## Page Objects
61
62### Structure
63```typescript
64export class AnalyticsPage extends AdminPage {
65 // Public readonly locators only
66 public readonly saveButton = this.page.getByRole('button', {name: 'Save'});
67 public readonly emailInput = this.page.getByLabel('Email');
68
69 // Semantic action methods
70 async saveSettings() {
71 await this.saveButton.click();
72 }
73}
74```
75
76### Rules
77- Page Objects are located in `helpers/pages/`
78- Expose locators as `public readonly` when used with assertions
79- Methods use semantic names (`login()` not `clickLoginButton()`)
80- Use `waitFor()` for guards, never `expect()` in page objects
81- Keep all assertions in test files
82
83## Locators (Strict Priority)
84
851. **Semantic** (always prefer):
86 - `getByRole('button', {name: 'Save'})`
87 - `getByLabel('Email')`
88 - `getByText('Success')`
89
902. **Test IDs** (when semantic unavailable):
91 - `getByTestId('analytics-card')`
92 - Suggest adding `data-testid` to Ghost codebase when needed
93
943. **Never use**: CSS selectors, XPath, nth-child, class names
95
96### Playwright MCP Usage
97- Use `mcp__playwright__browser_snapshot` to find elements
98- Use `mcp__playwright__browser_click` with semantic descriptions
99- If no good locator exists, suggest `data-testid` addition to Ghost
100
101## Test Data
102
103### Factory Pattern (Required)
104```typescript
105import {PostFactory, UserFactory} from '../data-factory';
106
107const postFactory = createPostFactory(page.request);
108const post = await postFactory.create({userId: user.id});
109```
110
111## Best Practices
112
113### DO ✅
114- Use `usePerTestIsolation()` from `@/helpers/playwright/isolation` if a file needs per-test isolation
115- Treat `config` and `labs` as environment-identity inputs: changing them should be an intentional part of test setup
116- Use `resetEnvironment()` only in `beforeEach` hooks when you need a forced recycle inside per-file mode
117- Keep `stripeEnabled` tests in per-test mode; the fixture forces this automatically
118- Use factories for all test data
119- Use Playwright's auto-waiting
120- Run tests multiple times to ensure stability
121- Use `test.only()` for debugging single tests
122
123### DON'T ❌
124- Use `test.describe.parallel(...)` or `test.describe.serial(...)` in e2e tests
125- Use nested `test.describe.configure({mode: ...})` (mode toggles are root-level only)
126- Call `resetEnvironment()` after resolving `baseURL`, `page`, `pageWithAuthenticatedUser`, or `ghostAccountOwner`
127- Hard-coded waits (`waitForTimeout`)
128- networkidle in waits (`networkidle`)
129- Test dependencies (Test B needs Test A)
130- Direct database manipulation
131- Multiple scenarios in one test
132- Assertions in page objects
133- Manual login (auto-authenticated via fixture)
134
135## Project Structure
136- `tests/admin/` - Admin area tests
137- `tests/public/` - Public site tests
138- `helpers/pages/` - Page objects
139- `helpers/environment/` - Container management
140- `data-factory/` - Test data factories
141
142## Validation Checklist
143After writing tests, verify:
1441. Test passes: `pnpm test path/to/test.ts`
1452. Linting passes: `pnpm lint`
1463. Types check: `pnpm test:types`
1474. Follows AAA pattern with clear sections
1485. Uses page objects appropriately
1496. Uses semantic locators or data-testid only
1507. No hard-coded waits or CSS selectors
151
TryGhost/Ghost · koenig/koenig-lexical/CLAUDE.md
@@ +1 @@
1# Koenig Lexical Test Guide
2
3## Test Commands
4
5### Unit Tests
6```bash
7pnpm test:unit # Run unit tests once
8pnpm test:unit:watch # Run unit tests in watch mode
9```
10
11### Acceptance Tests (Playwright)
12```bash
13pnpm test:acceptance # Run Playwright tests (headless, list reporter)
14pnpm test:acceptance:quiet # Minimal output, failures only
15pnpm test:acceptance:headed # Run with browser UI visible
16pnpm test:acceptance:report # Run with HTML report
17pnpm test:slowmo # Slow motion + UI
18```
19
20### All Tests
21```bash
22pnpm test # Run unit + acceptance tests, then lint
23```
24
25## AI-Friendly Testing
26
27The test runner has been configured to work well with AI agents:
28
29- **Default behavior**: Headless mode with list reporter (no browser UI, no web pages)
30- **Quiet mode**: Use `pnpm test:acceptance:quiet` for minimal output (only shows failures)
31- **Clean exit**: Tests complete without hanging processes or opening browsers
32- **Clear output**: List reporter provides clear pass/fail information
33
34## Human-Friendly Testing
35
36For debugging and development:
37
38- Use `pnpm test:acceptance:headed` to see the browser UI
39- Use `pnpm test:acceptance:report` to generate an HTML report
40- Use `pnpm test:slowmo` for slow-motion debugging
41
42## Environment Variables
43
44- `PLAYWRIGHT_HEADED=true` - Show browser UI
45- `PLAYWRIGHT_HTML_REPORT=true` - Generate HTML report
46- `PLAYWRIGHT_SLOWMO=100` - Slow motion delay (ms)
47
48## Test Structure
49
50- `test/unit/` - Unit tests (Vitest)
51- `test/e2e/` - Acceptance tests (Playwright, `test:acceptance` target)
52- `test/utils/` - Shared test utilities
53
54## Development Workflow
55
561. Run unit tests during development: `pnpm test:unit:watch`
572. Run acceptance tests before committing: `pnpm test:acceptance`
583. Use headed mode for debugging: `pnpm test:acceptance:headed`
59
@@ −1 +1 @@
1−# AGENTS.md
1+# Koenig Lexical Test Guide
22
3−E2E testing guidance for AI assistants (Claude, Codex, etc.) working with Ghost tests.
3+## Test Commands
44
5−**IMPORTANT**: When creating or modifying E2E tests, always refer to `./.claude/E2E_TEST_WRITING_GUIDE.md` for comprehensive testing guidelines and patterns.
6−
7−## Critical Rules
8−1. **Always follow ADRs** in `../adr/` folder (ADR-0001: AAA pattern, ADR-0002: Page Objects)
9−2. **Always use pnpm**, never npm
10−3. **Always run after changes**: `pnpm lint` and `pnpm test:types`
11−4. **Never use CSS/XPath selectors** - only semantic locators or data-testid
12−5. **Prefer less comments and giving things clear names**
13−
14−## Running E2E Tests
15−
16−**`pnpm dev` must be running before you run E2E tests.** The E2E test runner auto-detects
17−whether the admin dev server is reachable at `http://127.0.0.1:5174`. If it is, tests run
18−in **dev mode** (fast, no pre-built Docker image required). If not, tests fall back to
19−**build mode** which requires a `ghost-e2e:local` Docker image that is only built in CI.
20−
21−**If you see the error `Build image not found: ghost-e2e:local`, it means `pnpm dev` is
22−not running.** Start it first, wait for the admin dev server to be ready, then re-run tests.
23−
5+### Unit Tests
246 ```bash
25−# Terminal 1 (or background): Start dev environment from the repo root
26−pnpm dev
27−
28−# Wait for the admin dev server to be reachable (http://127.0.0.1:5174)
29−
30−# Terminal 2: Run e2e tests from the e2e/ directory
31−pnpm test # Run all tests
32−pnpm test tests/path/to/test.ts # Run specific test
33−pnpm lint # Required after writing tests
34−pnpm test:types # Check TypeScript errors
35−pnpm build # Required after factory changes
36−pnpm test --debug # See browser during execution, for debugging
37−PRESERVE_ENV=true pnpm test # Debug failed tests (keeps containers)
7+pnpm test:unit # Run unit tests once
8+pnpm test:unit:watch # Run unit tests in watch mode
389 ```
39−## Test Structure
4010
41−### Naming Conventions
42−- **Test suites**: `Ghost Admin - Feature` or `Ghost Public - Feature`
43−- **Test names**: `what is tested - expected outcome` (lowercase)
44−- **One test = one scenario** (never mix multiple scenarios)
45−
46−### AAA Pattern
47−```typescript
48−test('action performed - expected result', async ({page}) => {
49− const analyticsPage = new AnalyticsGrowthPage(page);
50− const postFactory = createPostFactory(page.request);
51− const post = await postFactory.create({status: 'published'});
52−
53− await analyticsPage.goto();
54− await analyticsPage.topContent.postsButton.click();
55−
56− await expect(analyticsPage.topContent.contentCard).toContainText('No conversions');
57−});
11+### Acceptance Tests (Playwright)
12+```bash
13+pnpm test:acceptance # Run Playwright tests (headless, list reporter)
14+pnpm test:acceptance:quiet # Minimal output, failures only
15+pnpm test:acceptance:headed # Run with browser UI visible
16+pnpm test:acceptance:report # Run with HTML report
17+pnpm test:slowmo # Slow motion + UI
5818 ```
5919
60−## Page Objects
61−
62−### Structure
63−```typescript
64−export class AnalyticsPage extends AdminPage {
65− // Public readonly locators only
66− public readonly saveButton = this.page.getByRole('button', {name: 'Save'});
67− public readonly emailInput = this.page.getByLabel('Email');
68−
69− // Semantic action methods
70− async saveSettings() {
71− await this.saveButton.click();
72− }
73−}
20+### All Tests
21+```bash
22+pnpm test # Run unit + acceptance tests, then lint
7423 ```
7524
76−### Rules
77−- Page Objects are located in `helpers/pages/`
78−- Expose locators as `public readonly` when used with assertions
79−- Methods use semantic names (`login()` not `clickLoginButton()`)
80−- Use `waitFor()` for guards, never `expect()` in page objects
81−- Keep all assertions in test files
25+## AI-Friendly Testing
8226
83−## Locators (Strict Priority)
27+The test runner has been configured to work well with AI agents:
8428
85−1. **Semantic** (always prefer):
86− - `getByRole('button', {name: 'Save'})`
87− - `getByLabel('Email')`
88− - `getByText('Success')`
29+- **Default behavior**: Headless mode with list reporter (no browser UI, no web pages)
30+- **Quiet mode**: Use `pnpm test:acceptance:quiet` for minimal output (only shows failures)
31+- **Clean exit**: Tests complete without hanging processes or opening browsers
32+- **Clear output**: List reporter provides clear pass/fail information
8933
90−2. **Test IDs** (when semantic unavailable):
91− - `getByTestId('analytics-card')`
92− - Suggest adding `data-testid` to Ghost codebase when needed
34+## Human-Friendly Testing
9335
94−3. **Never use**: CSS selectors, XPath, nth-child, class names
36+For debugging and development:
9537
96−### Playwright MCP Usage
97−- Use `mcp__playwright__browser_snapshot` to find elements
98−- Use `mcp__playwright__browser_click` with semantic descriptions
99−- If no good locator exists, suggest `data-testid` addition to Ghost
38+- Use `pnpm test:acceptance:headed` to see the browser UI
39+- Use `pnpm test:acceptance:report` to generate an HTML report
40+- Use `pnpm test:slowmo` for slow-motion debugging
10041
101−## Test Data
42+## Environment Variables
10243
103−### Factory Pattern (Required)
104−```typescript
105−import {PostFactory, UserFactory} from '../data-factory';
44+- `PLAYWRIGHT_HEADED=true` - Show browser UI
45+- `PLAYWRIGHT_HTML_REPORT=true` - Generate HTML report
46+- `PLAYWRIGHT_SLOWMO=100` - Slow motion delay (ms)
10647
107−const postFactory = createPostFactory(page.request);
108−const post = await postFactory.create({userId: user.id});
109−```
48+## Test Structure
11049
111−## Best Practices
50+- `test/unit/` - Unit tests (Vitest)
51+- `test/e2e/` - Acceptance tests (Playwright, `test:acceptance` target)
52+- `test/utils/` - Shared test utilities
11253
113−### DO ✅
114−- Use `usePerTestIsolation()` from `@/helpers/playwright/isolation` if a file needs per-test isolation
115−- Treat `config` and `labs` as environment-identity inputs: changing them should be an intentional part of test setup
116−- Use `resetEnvironment()` only in `beforeEach` hooks when you need a forced recycle inside per-file mode
117−- Keep `stripeEnabled` tests in per-test mode; the fixture forces this automatically
118−- Use factories for all test data
119−- Use Playwright's auto-waiting
120−- Run tests multiple times to ensure stability
121−- Use `test.only()` for debugging single tests
54+## Development Workflow
12255
123−### DON'T ❌
124−- Use `test.describe.parallel(...)` or `test.describe.serial(...)` in e2e tests
125−- Use nested `test.describe.configure({mode: ...})` (mode toggles are root-level only)
126−- Call `resetEnvironment()` after resolving `baseURL`, `page`, `pageWithAuthenticatedUser`, or `ghostAccountOwner`
127−- Hard-coded waits (`waitForTimeout`)
128−- networkidle in waits (`networkidle`)
129−- Test dependencies (Test B needs Test A)
130−- Direct database manipulation
131−- Multiple scenarios in one test
132−- Assertions in page objects
133−- Manual login (auto-authenticated via fixture)
134−
135−## Project Structure
136−- `tests/admin/` - Admin area tests
137−- `tests/public/` - Public site tests
138−- `helpers/pages/` - Page objects
139−- `helpers/environment/` - Container management
140−- `data-factory/` - Test data factories
141−
142−## Validation Checklist
143−After writing tests, verify:
144−1. Test passes: `pnpm test path/to/test.ts`
145−2. Linting passes: `pnpm lint`
146−3. Types check: `pnpm test:types`
147−4. Follows AAA pattern with clear sections
148−5. Uses page objects appropriately
149−6. Uses semantic locators or data-testid only
150−7. No hard-coded waits or CSS selectors
56+1. Run unit tests during development: `pnpm test:unit:watch`
57+2. Run acceptance tests before committing: `pnpm test:acceptance`
58+3. Use headed mode for debugging: `pnpm test:acceptance:headed`
15159
