executable-stories-playwright 7.0.0 → 7.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "executable-stories-playwright",
3
- "version": "7.0.0",
3
+ "version": "7.0.2",
4
4
  "description": "BDD-style executable stories for Playwright Test with documentation generation",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -20,12 +20,14 @@
20
20
  },
21
21
  "files": [
22
22
  "dist",
23
- "README.md"
23
+ "skills",
24
+ "README.md",
25
+ "bin"
24
26
  ],
25
27
  "peerDependencies": {
26
28
  "@playwright/test": ">=1.58.2",
27
- "executable-stories-formatters": "^0.6.0",
28
- "autotel": ">=2.20.0"
29
+ "executable-stories-formatters": "^0.6.2",
30
+ "autotel": ">=2.21.0"
29
31
  },
30
32
  "peerDependenciesMeta": {
31
33
  "autotel": {
@@ -36,10 +38,10 @@
36
38
  "devDependencies": {
37
39
  "@opentelemetry/api": "^1.9.0",
38
40
  "@playwright/test": "^1.58.2",
39
- "@types/node": "^25.3.0",
41
+ "@types/node": "^25.3.2",
40
42
  "tsup": "^8.5.1",
41
43
  "typescript": "~5.9.3",
42
- "executable-stories-formatters": "0.6.0"
44
+ "executable-stories-formatters": "0.6.2"
43
45
  },
44
46
  "repository": {
45
47
  "type": "git",
@@ -53,6 +55,9 @@
53
55
  "documentation",
54
56
  "executable-stories"
55
57
  ],
58
+ "bin": {
59
+ "intent": "./bin/intent.js"
60
+ },
56
61
  "scripts": {
57
62
  "build": "tsup",
58
63
  "type-check": "tsc --noEmit",
@@ -0,0 +1,157 @@
1
+ ---
2
+ name: playwright-converting-tests
3
+ description: >
4
+ Incrementally adopt executable-stories in Playwright. Add story.init(testInfo)
5
+ and step markers to existing spec blocks. File naming .story.spec.ts.
6
+ TestInfo from test callback second argument. Progressive enhancement.
7
+ type: lifecycle
8
+ library: executable-stories-playwright
9
+ library_version: "7.0.1"
10
+ requires:
11
+ - playwright-story-api
12
+ sources:
13
+ - "jagreehal/executable-stories:apps/docs-site/src/content/docs/guides/converting-playwright.md"
14
+ ---
15
+
16
+ This skill builds on playwright-story-api. Read playwright-story-api first.
17
+
18
+ # Converting Existing Playwright Tests
19
+
20
+ ## Setup
21
+
22
+ Install the packages and configure the reporter:
23
+
24
+ ```bash
25
+ npm install -D executable-stories-playwright executable-stories-formatters
26
+ ```
27
+
28
+ ```typescript
29
+ // playwright.config.ts
30
+ import { defineConfig } from "@playwright/test";
31
+
32
+ export default defineConfig({
33
+ reporter: [
34
+ ["html"],
35
+ ["executable-stories-playwright/reporter", { formats: ["markdown"] }],
36
+ ],
37
+ });
38
+ ```
39
+
40
+ ## Core Patterns
41
+
42
+ ### Step 1: Rename the file
43
+
44
+ ```
45
+ # Before
46
+ tests/login.spec.ts
47
+
48
+ # After
49
+ tests/login.story.spec.ts
50
+ ```
51
+
52
+ ### Step 2: Add story.init() and step markers
53
+
54
+ ```typescript
55
+ // Before
56
+ import { test, expect } from "@playwright/test";
57
+
58
+ test("logs in successfully", async ({ page }) => {
59
+ await page.goto("/login");
60
+ await page.fill("#email", "user@example.com");
61
+ await page.fill("#password", "secret");
62
+ await page.click("#submit");
63
+ await expect(page.locator("h1")).toHaveText("Dashboard");
64
+ });
65
+ ```
66
+
67
+ ```typescript
68
+ // After
69
+ import { test, expect } from "@playwright/test";
70
+ import { story, given, when, then } from "executable-stories-playwright";
71
+
72
+ test("logs in successfully", async ({ page }, testInfo) => {
73
+ story.init(testInfo);
74
+
75
+ given("the login page is loaded");
76
+ await page.goto("/login");
77
+
78
+ when("valid credentials are entered");
79
+ await page.fill("#email", "user@example.com");
80
+ await page.fill("#password", "secret");
81
+ await page.click("#submit");
82
+
83
+ then("the dashboard is shown");
84
+ await expect(page.locator("h1")).toHaveText("Dashboard");
85
+ });
86
+ ```
87
+
88
+ Key change: add `testInfo` as the second parameter in the test callback.
89
+
90
+ ### Step 3: Minimal story
91
+
92
+ ```typescript
93
+ test("loads homepage", async ({ page }, testInfo) => {
94
+ story.init(testInfo);
95
+ await page.goto("/");
96
+ await expect(page).toHaveTitle("My App");
97
+ });
98
+ ```
99
+
100
+ ### Step 4: Add doc entries
101
+
102
+ ```typescript
103
+ test("shows product details", async ({ page }, testInfo) => {
104
+ story.init(testInfo, { tags: ["e2e", "products"] });
105
+
106
+ given("the product page is loaded");
107
+ await page.goto("/products/123");
108
+
109
+ then("the product details are shown");
110
+ story.screenshot({ path: "screenshots/product.png", alt: "Product page" });
111
+ story.json({ label: "Product", value: { id: 123, name: "Widget" } });
112
+ });
113
+ ```
114
+
115
+ ### Suite headings from test.describe
116
+
117
+ ```typescript
118
+ test.describe("Authentication", () => {
119
+ test("valid login", async ({ page }, testInfo) => {
120
+ story.init(testInfo);
121
+ // "Authentication" becomes a ## heading in docs
122
+ });
123
+ });
124
+ ```
125
+
126
+ ## Common Mistakes
127
+
128
+ ### HIGH Using .story.test.ts instead of .story.spec.ts
129
+
130
+ Wrong: `tests/login.story.test.ts`
131
+ Correct: `tests/login.story.spec.ts`
132
+
133
+ Playwright convention uses `.spec.ts`. The reporter filters accordingly.
134
+
135
+ Source: CLAUDE.md — file naming conventions
136
+
137
+ ### HIGH Forgetting testInfo parameter
138
+
139
+ Wrong:
140
+
141
+ ```typescript
142
+ test("my test", async ({ page }) => {
143
+ story.init(); // No testInfo
144
+ });
145
+ ```
146
+
147
+ Correct:
148
+
149
+ ```typescript
150
+ test("my test", async ({ page }, testInfo) => {
151
+ story.init(testInfo);
152
+ });
153
+ ```
154
+
155
+ `testInfo` is the second parameter of Playwright's test callback. Without it, story metadata is not linked to the test.
156
+
157
+ Source: packages/executable-stories-playwright/src/story-api.ts
@@ -0,0 +1,131 @@
1
+ ---
2
+ name: playwright-reporter-setup
3
+ description: >
4
+ Configure Playwright custom reporter for executable-stories-playwright.
5
+ playwright.config.ts reporter array. Default export from
6
+ executable-stories-playwright/reporter. Output formats, directory, naming.
7
+ Aggregated and colocated modes. rawRunPath for CLI.
8
+ type: core
9
+ library: executable-stories-playwright
10
+ library_version: "7.0.1"
11
+ sources:
12
+ - "jagreehal/executable-stories:packages/executable-stories-playwright/src/reporter.ts"
13
+ ---
14
+
15
+ # executable-stories-playwright — Reporter Setup
16
+
17
+ ## Setup
18
+
19
+ ```typescript
20
+ // playwright.config.ts
21
+ import { defineConfig } from "@playwright/test";
22
+
23
+ export default defineConfig({
24
+ reporter: [
25
+ ["html"],
26
+ [
27
+ "executable-stories-playwright/reporter",
28
+ {
29
+ formats: ["markdown", "html"],
30
+ outputDir: "docs",
31
+ outputName: "user-stories",
32
+ },
33
+ ],
34
+ ],
35
+ });
36
+ ```
37
+
38
+ Peer dependency: `executable-stories-formatters` must be installed.
39
+
40
+ ## Core Patterns
41
+
42
+ ### Minimal config
43
+
44
+ ```typescript
45
+ export default defineConfig({
46
+ reporter: [
47
+ ["html"],
48
+ ["executable-stories-playwright/reporter", { formats: ["markdown"] }],
49
+ ],
50
+ });
51
+ ```
52
+
53
+ ### Full options
54
+
55
+ ```typescript
56
+ export default defineConfig({
57
+ reporter: [
58
+ ["html"],
59
+ [
60
+ "executable-stories-playwright/reporter",
61
+ {
62
+ formats: ["markdown", "html", "junit", "cucumber-json"],
63
+ outputDir: "reports",
64
+ outputName: "test-results",
65
+ output: {
66
+ mode: "aggregated",
67
+ },
68
+ markdown: {
69
+ title: "User Stories",
70
+ includeStatusIcons: true,
71
+ includeErrors: true,
72
+ includeMetadata: true,
73
+ sortScenarios: "source",
74
+ },
75
+ html: {
76
+ title: "Test Report",
77
+ darkMode: true,
78
+ searchable: true,
79
+ embedScreenshots: true,
80
+ },
81
+ rawRunPath: "reports/raw-run.json",
82
+ },
83
+ ],
84
+ ],
85
+ });
86
+ ```
87
+
88
+ ### Annotation-based metadata
89
+
90
+ The reporter reads story metadata from test annotations with `type: "story-meta"`. This is handled automatically when using `story.init(testInfo)` — no manual annotation is needed.
91
+
92
+ ## Common Mistakes
93
+
94
+ ### HIGH Using default export syntax incorrectly
95
+
96
+ Wrong:
97
+
98
+ ```typescript
99
+ import StoryReporter from "executable-stories-playwright/reporter";
100
+
101
+ export default defineConfig({
102
+ reporter: [
103
+ ["html"],
104
+ [new StoryReporter({ formats: ["markdown"] })],
105
+ ],
106
+ });
107
+ ```
108
+
109
+ Correct:
110
+
111
+ ```typescript
112
+ export default defineConfig({
113
+ reporter: [
114
+ ["html"],
115
+ [
116
+ "executable-stories-playwright/reporter",
117
+ { formats: ["markdown"] },
118
+ ],
119
+ ],
120
+ });
121
+ ```
122
+
123
+ Playwright's reporter config expects a string path and options object tuple, not a class instance. Playwright instantiates the reporter itself from the path.
124
+
125
+ Source: packages/executable-stories-playwright/src/reporter.ts
126
+
127
+ ### MEDIUM Default format is cucumber-json, not markdown
128
+
129
+ The default `formats` is `["cucumber-json"]`. Always specify `formats: ["markdown"]` explicitly to get readable markdown output.
130
+
131
+ Source: packages/executable-stories-playwright/src/reporter.ts
@@ -0,0 +1,207 @@
1
+ ---
2
+ name: playwright-story-api
3
+ description: >
4
+ Write BDD stories in Playwright using executable-stories-playwright.
5
+ Top-level exports with TestInfo: story.init(testInfo). Async steps with
6
+ fixtures ({ page }). Steps: given, when, then, and, but. Doc entries:
7
+ json, kv, code, table, link, section, mermaid, screenshot, note, tag.
8
+ Auto-And keyword conversion. Aliases: arrange, act, assert.
9
+ type: core
10
+ library: executable-stories-playwright
11
+ library_version: "7.0.1"
12
+ sources:
13
+ - "jagreehal/executable-stories:packages/executable-stories-playwright/src/story-api.ts"
14
+ - "jagreehal/executable-stories:apps/docs-site/src/content/docs/playwright/playwright-story-api.md"
15
+ ---
16
+
17
+ # executable-stories-playwright — Story API
18
+
19
+ ## Setup
20
+
21
+ ```typescript
22
+ import { test, expect } from "@playwright/test";
23
+ import { story, given, when, then } from "executable-stories-playwright";
24
+
25
+ test.describe("Login page", () => {
26
+ test("authenticates with valid credentials", async ({ page }, testInfo) => {
27
+ story.init(testInfo, { tags: ["auth"], ticket: "AUTH-42" });
28
+
29
+ given("the login page is loaded");
30
+ await page.goto("/login");
31
+
32
+ when("valid credentials are entered");
33
+ await page.fill("#email", "alice@example.com");
34
+ await page.fill("#password", "secret");
35
+ await page.click('button[type="submit"]');
36
+
37
+ then("the dashboard is shown");
38
+ await expect(page.locator("h1")).toHaveText("Dashboard");
39
+ });
40
+ });
41
+ ```
42
+
43
+ File naming: `*.story.spec.ts`.
44
+
45
+ Playwright uses top-level step exports. `story.init(testInfo)` requires the `testInfo` parameter from the test callback.
46
+
47
+ ## Core Patterns
48
+
49
+ ### Top-level step exports with fixtures
50
+
51
+ ```typescript
52
+ import { story, given, when, then, and, but } from "executable-stories-playwright";
53
+
54
+ test("blocks suspended user login", async ({ page }, testInfo) => {
55
+ story.init(testInfo);
56
+
57
+ given("the user account exists"); // renders "Given"
58
+ given("the account is suspended"); // renders "And" (auto-converted)
59
+ when("the user submits valid credentials");
60
+ await page.fill("#email", "user@test.com");
61
+ await page.click("#submit");
62
+
63
+ then("the user sees an error message");
64
+ await expect(page.locator(".error")).toBeVisible();
65
+
66
+ but("the user is not logged in"); // renders "But" (always)
67
+ await expect(page).toHaveURL("/login");
68
+ });
69
+ ```
70
+
71
+ ### Doc entries with screenshots
72
+
73
+ ```typescript
74
+ test("checkout flow", async ({ page }, testInfo) => {
75
+ story.init(testInfo);
76
+
77
+ given("a cart with items");
78
+ story.json({ label: "Cart", value: { items: 3, total: 150 } });
79
+
80
+ when("the user completes checkout");
81
+ await page.click("#checkout");
82
+ await page.waitForURL("/confirmation");
83
+
84
+ then("the confirmation page is shown");
85
+ story.screenshot({ path: "screenshots/confirmation.png", alt: "Order confirmation" });
86
+ story.table({
87
+ label: "Order details",
88
+ columns: ["Item", "Qty", "Price"],
89
+ rows: [["Widget", "3", "$50"]],
90
+ });
91
+ });
92
+ ```
93
+
94
+ ### Step wrappers with timing
95
+
96
+ ```typescript
97
+ const response = await story.fn("When", "the API is called", async () => {
98
+ return page.request.get("/api/data");
99
+ });
100
+
101
+ await story.expect("the response is successful", async () => {
102
+ expect(response.status()).toBe(200);
103
+ });
104
+ ```
105
+
106
+ ### Suite headings from test.describe
107
+
108
+ ```typescript
109
+ test.describe("Authentication", () => {
110
+ test("valid login", async ({ page }, testInfo) => {
111
+ story.init(testInfo);
112
+ // Produces "## Authentication" heading in generated docs
113
+ });
114
+ });
115
+ ```
116
+
117
+ Suite path comes from `testInfo.titlePath`. Describe titles become `##` headings in generated docs.
118
+
119
+ ## Common Mistakes
120
+
121
+ ### CRITICAL Missing testInfo argument in story.init()
122
+
123
+ Wrong:
124
+
125
+ ```typescript
126
+ test("my test", async ({ page }) => {
127
+ story.init();
128
+ given("something");
129
+ });
130
+ ```
131
+
132
+ Correct:
133
+
134
+ ```typescript
135
+ test("my test", async ({ page }, testInfo) => {
136
+ story.init(testInfo);
137
+ given("something");
138
+ });
139
+ ```
140
+
141
+ Without `testInfo`, story metadata is not linked to the test. The `testInfo` parameter must be the second argument in the Playwright test callback.
142
+
143
+ Source: packages/executable-stories-playwright/src/story-api.ts
144
+
145
+ ### HIGH Using .story.test.ts file extension
146
+
147
+ Wrong:
148
+
149
+ ```
150
+ tests/login.story.test.ts
151
+ ```
152
+
153
+ Correct:
154
+
155
+ ```
156
+ tests/login.story.spec.ts
157
+ ```
158
+
159
+ Playwright uses `.spec.ts` by convention. The reporter filters for `.story.spec.ts` files. Using `.test.ts` may cause the reporter to miss story metadata.
160
+
161
+ Source: CLAUDE.md — "Story test files use .story.spec.ts (playwright)"
162
+
163
+ ### HIGH Forgetting testInfo in callback destructuring
164
+
165
+ Wrong:
166
+
167
+ ```typescript
168
+ test("my test", async ({ page }) => {
169
+ story.init(testInfo); // testInfo is undefined
170
+ });
171
+ ```
172
+
173
+ Correct:
174
+
175
+ ```typescript
176
+ test("my test", async ({ page }, testInfo) => {
177
+ story.init(testInfo);
178
+ });
179
+ ```
180
+
181
+ `testInfo` is the second parameter of the Playwright test callback, not a fixture. It must be explicitly named after the fixtures object.
182
+
183
+ Source: packages/executable-stories-playwright/src/story-api.ts
184
+
185
+ ### MEDIUM Calling steps before story.init()
186
+
187
+ Wrong:
188
+
189
+ ```typescript
190
+ test("my test", async ({ page }, testInfo) => {
191
+ given("something");
192
+ story.init(testInfo);
193
+ });
194
+ ```
195
+
196
+ Correct:
197
+
198
+ ```typescript
199
+ test("my test", async ({ page }, testInfo) => {
200
+ story.init(testInfo);
201
+ given("something");
202
+ });
203
+ ```
204
+
205
+ Steps called before `init()` are silently dropped because no story context exists.
206
+
207
+ Source: packages/eslint-plugin-executable-stories-playwright/src/rules/require-story-context-for-steps.ts