executable-stories-jest 7.0.1 → 8.0.0
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-jest",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"description": "BDD-style executable stories for Jest with documentation generation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -25,25 +25,27 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
|
-
"dist"
|
|
28
|
+
"dist",
|
|
29
|
+
"skills",
|
|
30
|
+
"bin"
|
|
29
31
|
],
|
|
30
32
|
"peerDependencies": {
|
|
31
|
-
"jest": ">=30.
|
|
32
|
-
"executable-stories-formatters": "^0.
|
|
33
|
+
"jest": ">=30.3.0",
|
|
34
|
+
"executable-stories-formatters": "^0.7.0"
|
|
33
35
|
},
|
|
34
36
|
"dependencies": {
|
|
35
37
|
"fast-glob": "^3.3.3"
|
|
36
38
|
},
|
|
37
39
|
"devDependencies": {
|
|
38
|
-
"@jest/globals": "^30.
|
|
40
|
+
"@jest/globals": "^30.3.0",
|
|
39
41
|
"@opentelemetry/api": "^1.9.0",
|
|
40
42
|
"@types/jest": "^30.0.0",
|
|
41
|
-
"@types/node": "^25.
|
|
43
|
+
"@types/node": "^25.5.0",
|
|
42
44
|
"jest": "^30.2.0",
|
|
43
45
|
"ts-jest": "^29.4.6",
|
|
44
46
|
"tsup": "^8.5.1",
|
|
45
47
|
"typescript": "~5.9.3",
|
|
46
|
-
"executable-stories-formatters": "0.
|
|
48
|
+
"executable-stories-formatters": "0.7.0"
|
|
47
49
|
},
|
|
48
50
|
"repository": {
|
|
49
51
|
"type": "git",
|
|
@@ -57,6 +59,9 @@
|
|
|
57
59
|
"documentation",
|
|
58
60
|
"executable-stories"
|
|
59
61
|
],
|
|
62
|
+
"bin": {
|
|
63
|
+
"intent": "./bin/intent.js"
|
|
64
|
+
},
|
|
60
65
|
"scripts": {
|
|
61
66
|
"build": "tsup",
|
|
62
67
|
"type-check": "tsc --noEmit",
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jest-converting-tests
|
|
3
|
+
description: >
|
|
4
|
+
Incrementally adopt executable-stories in Jest. Add story.init() and
|
|
5
|
+
top-level step imports to existing test blocks. No task argument needed.
|
|
6
|
+
File naming .story.test.ts. Progressive enhancement without rewriting.
|
|
7
|
+
type: lifecycle
|
|
8
|
+
library: executable-stories-jest
|
|
9
|
+
library_version: "7.0.1"
|
|
10
|
+
requires:
|
|
11
|
+
- jest-story-api
|
|
12
|
+
sources:
|
|
13
|
+
- "jagreehal/executable-stories:apps/docs-site/src/content/docs/guides/converting-jest.md"
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
This skill builds on jest-story-api. Read jest-story-api first.
|
|
17
|
+
|
|
18
|
+
# Converting Existing Jest Tests
|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
Install the packages and configure:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -D executable-stories-jest executable-stories-formatters
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
// jest.config.mjs
|
|
30
|
+
export default {
|
|
31
|
+
setupFilesAfterEnv: ["executable-stories-jest/setup"],
|
|
32
|
+
reporters: [
|
|
33
|
+
"default",
|
|
34
|
+
["executable-stories-jest/reporter", { formats: ["markdown"] }],
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Core Patterns
|
|
40
|
+
|
|
41
|
+
### Step 1: Rename the file
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
# Before
|
|
45
|
+
test/calculator.test.ts
|
|
46
|
+
|
|
47
|
+
# After
|
|
48
|
+
test/calculator.story.test.ts
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Step 2: Add story.init() and step markers
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// Before
|
|
55
|
+
import { describe, expect, it } from "@jest/globals";
|
|
56
|
+
|
|
57
|
+
describe("Calculator", () => {
|
|
58
|
+
it("adds two numbers", () => {
|
|
59
|
+
const result = add(2, 3);
|
|
60
|
+
expect(result).toBe(5);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// After
|
|
67
|
+
import { describe, expect, it } from "@jest/globals";
|
|
68
|
+
import { story, given, when, then } from "executable-stories-jest";
|
|
69
|
+
|
|
70
|
+
describe("Calculator", () => {
|
|
71
|
+
it("adds two numbers", () => {
|
|
72
|
+
story.init();
|
|
73
|
+
|
|
74
|
+
given("two numbers 2 and 3");
|
|
75
|
+
const a = 2, b = 3;
|
|
76
|
+
|
|
77
|
+
when("they are added");
|
|
78
|
+
const result = add(a, b);
|
|
79
|
+
|
|
80
|
+
then("the result is 5");
|
|
81
|
+
expect(result).toBe(5);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Key difference from Vitest: no `({ task })` needed. `story.init()` takes no arguments.
|
|
87
|
+
|
|
88
|
+
### Step 3: Minimal story
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
it("subtracts two numbers", () => {
|
|
92
|
+
story.init();
|
|
93
|
+
expect(subtract(10, 4)).toBe(6);
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Step 4: Add doc entries
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
it("handles division by zero", () => {
|
|
101
|
+
story.init({ tags: ["edge-case"] });
|
|
102
|
+
|
|
103
|
+
given("a divisor of zero");
|
|
104
|
+
story.note("This tests the error handling path");
|
|
105
|
+
|
|
106
|
+
when("division is attempted");
|
|
107
|
+
const fn = () => divide(10, 0);
|
|
108
|
+
|
|
109
|
+
then("an error is thrown");
|
|
110
|
+
expect(fn).toThrow("Division by zero");
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Common Mistakes
|
|
115
|
+
|
|
116
|
+
### HIGH Adding ({ task }) like Vitest
|
|
117
|
+
|
|
118
|
+
Wrong:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
it("my test", ({ task }) => {
|
|
122
|
+
story.init(task);
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Correct:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
it("my test", () => {
|
|
130
|
+
story.init();
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Jest does not provide a `task` object. `story.init()` reads the test name from `expect.getState().currentTestName`.
|
|
135
|
+
|
|
136
|
+
Source: packages/executable-stories-jest/src/story-api.ts
|
|
137
|
+
|
|
138
|
+
### HIGH Forgetting setupFilesAfterEnv
|
|
139
|
+
|
|
140
|
+
Without `setupFilesAfterEnv: ["executable-stories-jest/setup"]` in jest.config, stories are never flushed to disk and the reporter produces empty output.
|
|
141
|
+
|
|
142
|
+
Source: packages/executable-stories-jest/src/reporter.ts
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jest-reporter-setup
|
|
3
|
+
description: >
|
|
4
|
+
Configure Jest custom reporter for executable-stories-jest. jest.config
|
|
5
|
+
reporters array with options. setupFilesAfterEnv for story flushing.
|
|
6
|
+
Output formats, directory, naming. Aggregated and colocated modes.
|
|
7
|
+
type: core
|
|
8
|
+
library: executable-stories-jest
|
|
9
|
+
library_version: "7.0.1"
|
|
10
|
+
sources:
|
|
11
|
+
- "jagreehal/executable-stories:packages/executable-stories-jest/src/reporter.ts"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# executable-stories-jest — Reporter Setup
|
|
15
|
+
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
18
|
+
```javascript
|
|
19
|
+
// jest.config.mjs
|
|
20
|
+
export default {
|
|
21
|
+
setupFilesAfterEnv: ["executable-stories-jest/setup"],
|
|
22
|
+
reporters: [
|
|
23
|
+
"default",
|
|
24
|
+
[
|
|
25
|
+
"executable-stories-jest/reporter",
|
|
26
|
+
{
|
|
27
|
+
formats: ["markdown", "html"],
|
|
28
|
+
outputDir: "docs",
|
|
29
|
+
outputName: "user-stories",
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Both the `setup` file and the `reporter` entry are required. Peer dependency: `executable-stories-formatters` must be installed.
|
|
37
|
+
|
|
38
|
+
## Core Patterns
|
|
39
|
+
|
|
40
|
+
### Minimal config
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
export default {
|
|
44
|
+
setupFilesAfterEnv: ["executable-stories-jest/setup"],
|
|
45
|
+
reporters: [
|
|
46
|
+
"default",
|
|
47
|
+
["executable-stories-jest/reporter", { formats: ["markdown"] }],
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Full options
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
export default {
|
|
56
|
+
setupFilesAfterEnv: ["executable-stories-jest/setup"],
|
|
57
|
+
reporters: [
|
|
58
|
+
"default",
|
|
59
|
+
[
|
|
60
|
+
"executable-stories-jest/reporter",
|
|
61
|
+
{
|
|
62
|
+
formats: ["markdown", "html", "junit", "cucumber-json"],
|
|
63
|
+
outputDir: "reports",
|
|
64
|
+
outputName: "test-results",
|
|
65
|
+
output: {
|
|
66
|
+
mode: "aggregated",
|
|
67
|
+
// mode: "colocated",
|
|
68
|
+
// colocatedStyle: "mirrored",
|
|
69
|
+
},
|
|
70
|
+
markdown: {
|
|
71
|
+
title: "User Stories",
|
|
72
|
+
includeStatusIcons: true,
|
|
73
|
+
includeErrors: true,
|
|
74
|
+
includeMetadata: true,
|
|
75
|
+
sortScenarios: "source",
|
|
76
|
+
ticketUrlTemplate: "https://jira.example.com/browse/{ticket}",
|
|
77
|
+
},
|
|
78
|
+
html: {
|
|
79
|
+
title: "Test Report",
|
|
80
|
+
darkMode: true,
|
|
81
|
+
searchable: true,
|
|
82
|
+
},
|
|
83
|
+
rawRunPath: "reports/raw-run.json",
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### File-based communication
|
|
91
|
+
|
|
92
|
+
Jest uses worker processes. Stories are written to `.jest-executable-stories/worker-{id}/*.json` during execution. The reporter aggregates these files in `onRunComplete`. The `JEST_STORY_DOCS_DIR` env var overrides the temp directory.
|
|
93
|
+
|
|
94
|
+
## Common Mistakes
|
|
95
|
+
|
|
96
|
+
### CRITICAL Missing setupFilesAfterEnv entry
|
|
97
|
+
|
|
98
|
+
Wrong:
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
export default {
|
|
102
|
+
reporters: [
|
|
103
|
+
"default",
|
|
104
|
+
["executable-stories-jest/reporter", { formats: ["markdown"] }],
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Correct:
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
export default {
|
|
113
|
+
setupFilesAfterEnv: ["executable-stories-jest/setup"],
|
|
114
|
+
reporters: [
|
|
115
|
+
"default",
|
|
116
|
+
["executable-stories-jest/reporter", { formats: ["markdown"] }],
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The setup file registers an `afterAll` hook that flushes story metadata to disk at the end of each test file. Without it, the reporter receives no data and produces empty output.
|
|
122
|
+
|
|
123
|
+
Source: packages/executable-stories-jest/src/reporter.ts
|
|
124
|
+
|
|
125
|
+
### HIGH Using the reporter path as a string instead of tuple
|
|
126
|
+
|
|
127
|
+
Wrong:
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
reporters: ["default", "executable-stories-jest/reporter"]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Correct:
|
|
134
|
+
|
|
135
|
+
```javascript
|
|
136
|
+
reporters: [
|
|
137
|
+
"default",
|
|
138
|
+
["executable-stories-jest/reporter", { formats: ["markdown"] }],
|
|
139
|
+
]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Without options, the default format is `["cucumber-json"]`. Use the tuple form `[path, options]` to specify formats and output directory.
|
|
143
|
+
|
|
144
|
+
Source: packages/executable-stories-jest/src/reporter.ts
|
|
145
|
+
|
|
146
|
+
### MEDIUM Default format is cucumber-json, not markdown
|
|
147
|
+
|
|
148
|
+
The default `formats` is `["cucumber-json"]`. Always specify `formats: ["markdown"]` (or other desired formats) explicitly.
|
|
149
|
+
|
|
150
|
+
Source: packages/executable-stories-jest/src/reporter.ts
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jest-story-api
|
|
3
|
+
description: >
|
|
4
|
+
Write BDD stories in Jest using executable-stories-jest. Top-level exports:
|
|
5
|
+
import { given, when, then, and, but } from executable-stories-jest.
|
|
6
|
+
story.init() takes no arguments. Auto-And keyword conversion. Suite path
|
|
7
|
+
from expect.getState().currentTestName. Aliases: arrange, act, assert.
|
|
8
|
+
Doc entries: json, kv, code, table, link, section, mermaid, note, tag.
|
|
9
|
+
type: core
|
|
10
|
+
library: executable-stories-jest
|
|
11
|
+
library_version: "7.0.1"
|
|
12
|
+
sources:
|
|
13
|
+
- "jagreehal/executable-stories:packages/executable-stories-jest/src/index.ts"
|
|
14
|
+
- "jagreehal/executable-stories:packages/executable-stories-jest/src/story-api.ts"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# executable-stories-jest — Story API
|
|
18
|
+
|
|
19
|
+
## Setup
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { describe, expect, it } from "@jest/globals";
|
|
23
|
+
import { story, given, when, then } from "executable-stories-jest";
|
|
24
|
+
|
|
25
|
+
describe("Cart checkout", () => {
|
|
26
|
+
it("applies discount code", () => {
|
|
27
|
+
story.init({ tags: ["checkout"], ticket: "CART-42" });
|
|
28
|
+
|
|
29
|
+
given("a cart with items totaling $100");
|
|
30
|
+
const cart = createCart([{ name: "Shirt", price: 100 }]);
|
|
31
|
+
|
|
32
|
+
when("a 20% discount code is applied");
|
|
33
|
+
applyDiscount(cart, "SAVE20");
|
|
34
|
+
|
|
35
|
+
then("the total is $80");
|
|
36
|
+
expect(cart.total).toBe(80);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
File naming: `*.story.test.ts`.
|
|
42
|
+
|
|
43
|
+
Jest uses top-level step exports. `story.init()` takes no arguments — the test name is derived from `expect.getState().currentTestName`.
|
|
44
|
+
|
|
45
|
+
## Core Patterns
|
|
46
|
+
|
|
47
|
+
### Top-level step exports
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { story, given, when, then, and, but } from "executable-stories-jest";
|
|
51
|
+
|
|
52
|
+
it("blocks suspended user login", () => {
|
|
53
|
+
story.init();
|
|
54
|
+
|
|
55
|
+
given("the user account exists"); // renders "Given"
|
|
56
|
+
given("the account is suspended"); // renders "And" (auto-converted)
|
|
57
|
+
when("the user submits valid credentials");
|
|
58
|
+
then("the user sees an error message");
|
|
59
|
+
but("the user is not logged in"); // renders "But" (always)
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Doc entries
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { story, given, when, then } from "executable-stories-jest";
|
|
67
|
+
|
|
68
|
+
it("processes payment", () => {
|
|
69
|
+
story.init();
|
|
70
|
+
|
|
71
|
+
given("a valid payment request");
|
|
72
|
+
story.json({ label: "Payload", value: { amount: 50, currency: "USD" } });
|
|
73
|
+
|
|
74
|
+
when("the payment is submitted");
|
|
75
|
+
story.code({ label: "Response", content: '{ "status": "ok" }', lang: "json" });
|
|
76
|
+
|
|
77
|
+
then("the order is confirmed");
|
|
78
|
+
story.table({
|
|
79
|
+
label: "Order summary",
|
|
80
|
+
columns: ["Item", "Qty", "Price"],
|
|
81
|
+
rows: [["Widget", "2", "$25"]],
|
|
82
|
+
});
|
|
83
|
+
story.note("Payment processed in sandbox mode");
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Step wrappers with timing
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
const profile = await story.fn("When", "the profile is fetched", async () => {
|
|
91
|
+
return fetchProfile(userId);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
await story.expect("the profile contains the correct name", () => {
|
|
95
|
+
expect(profile.name).toBe("Alice");
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Inline docs via second argument
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
given("valid credentials", {
|
|
103
|
+
json: { label: "Credentials", value: { user: "alice", role: "admin" } },
|
|
104
|
+
note: "Password masked for security",
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Common Mistakes
|
|
109
|
+
|
|
110
|
+
### CRITICAL Calling story.init() with a task argument
|
|
111
|
+
|
|
112
|
+
Wrong:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
it("my test", ({ task }) => {
|
|
116
|
+
story.init(task); // Jest does not provide task
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Correct:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
it("my test", () => {
|
|
124
|
+
story.init(); // No arguments needed
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Jest's `story.init()` takes no arguments. It reads the test name from `expect.getState().currentTestName`. Passing an argument is a Vitest pattern that does not apply to Jest.
|
|
129
|
+
|
|
130
|
+
Source: packages/executable-stories-jest/src/story-api.ts
|
|
131
|
+
|
|
132
|
+
### HIGH Suite path not detected in docs
|
|
133
|
+
|
|
134
|
+
Wrong assumption:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
// Expecting "Calculator" to appear as a ## heading in docs
|
|
138
|
+
describe("Calculator", () => {
|
|
139
|
+
it("adds numbers", () => {
|
|
140
|
+
story.init();
|
|
141
|
+
// ...
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
// Jest's currentTestName format is "Calculator adds numbers" (space-separated)
|
|
145
|
+
// Suite path is usually undefined → docs are flat
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
This is a known limitation. Jest's `expect.getState().currentTestName` uses space-separated format (`"Describe title test name"`), not `" > "` separated. Suite path extraction only works when `" > "` is present. In the default Jest setup, docs are flat without `## Suite name` headings.
|
|
149
|
+
|
|
150
|
+
Source: CLAUDE.md — "Doc heading and describe in generated docs"
|
|
151
|
+
|
|
152
|
+
### HIGH Missing setup file in jest.config
|
|
153
|
+
|
|
154
|
+
Wrong:
|
|
155
|
+
|
|
156
|
+
```javascript
|
|
157
|
+
// jest.config.mjs
|
|
158
|
+
export default {
|
|
159
|
+
reporters: ["default", "executable-stories-jest/reporter"],
|
|
160
|
+
};
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Correct:
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
// jest.config.mjs
|
|
167
|
+
export default {
|
|
168
|
+
setupFilesAfterEnv: ["executable-stories-jest/setup"],
|
|
169
|
+
reporters: ["default", "executable-stories-jest/reporter"],
|
|
170
|
+
};
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The setup file registers an `afterAll` hook that flushes story metadata to disk. Without it, the reporter has no data to process.
|
|
174
|
+
|
|
175
|
+
Source: packages/executable-stories-jest/src/reporter.ts
|
|
176
|
+
|
|
177
|
+
### MEDIUM Calling steps before story.init()
|
|
178
|
+
|
|
179
|
+
Wrong:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
it("my test", () => {
|
|
183
|
+
given("something");
|
|
184
|
+
story.init();
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Correct:
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
it("my test", () => {
|
|
192
|
+
story.init();
|
|
193
|
+
given("something");
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Steps called before `init()` are silently dropped because no story context exists.
|
|
198
|
+
|
|
199
|
+
Source: packages/eslint-plugin-executable-stories-jest/src/rules/require-story-context-for-steps.ts
|
|
200
|
+
|
|
201
|
+
## Parameterized Scenarios (Scenario Outline equivalent)
|
|
202
|
+
|
|
203
|
+
Use Jest's `it.each` with `story()` to produce one scenario per data row — the framework-native replacement for Cucumber's Scenario Outline + Examples.
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
import { story, given, when, then } from "executable-stories-jest";
|
|
207
|
+
|
|
208
|
+
const cases = [
|
|
209
|
+
{ input: 1, expected: 2 },
|
|
210
|
+
{ input: 2, expected: 4 },
|
|
211
|
+
{ input: 3, expected: 6 },
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
describe("Doubling", () => {
|
|
215
|
+
it.each(cases)("doubles $input to $expected", ({ input, expected }) => {
|
|
216
|
+
story(`Doubles ${input} to ${expected}`);
|
|
217
|
+
given(`the input is ${input}`);
|
|
218
|
+
when("the doubler runs");
|
|
219
|
+
then(`the result is ${expected}`);
|
|
220
|
+
expect(input * 2).toBe(expected);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Each iteration produces a separate scenario in the generated report. Use interpolated titles so each scenario has a distinct, descriptive name.
|