@swedevtools/livedoc-vitest 0.2.0 → 0.3.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/CHANGELOG.md +34 -0
- package/LICENSE +20 -20
- package/README.md +160 -95
- package/dist/{RuleContext-BZhuy-zS.d.cts → RuleContext-DQ8o_n1D.d.ts} +62 -62
- package/dist/globals.d.ts +99 -99
- package/dist/{index-Blmp569T.d.cts → index-sbV15ohX.d.ts} +21 -2
- package/dist/index.d.ts +7 -5
- package/dist/index.js +1062 -159
- package/dist/reporter/index.d.ts +2 -2
- package/dist/reporter/index.js +629 -84
- package/package.json +14 -12
- package/tools/livedoc-setup.mjs +172 -164
- package/tools/skills/SKILL.md +339 -244
- package/tools/skills/VALIDATION.md +37 -29
- package/tools/skills/examples/routing.md +75 -60
- package/tools/skills/resources/anti-patterns.md +19 -0
- package/tools/skills/resources/bdd-features.md +231 -231
- package/tools/skills/resources/partial-testing.md +77 -0
- package/tools/skills/resources/playwright.md +148 -148
- package/tools/skills/resources/reporter-config.md +213 -163
- package/tools/skills/resources/specifications.md +159 -159
- package/tools/skills/resources/test-strategy.md +103 -0
- package/tools/skills/resources/web-testing.md +62 -0
- package/dist/RuleContext-BZhuy-zS.d.ts +0 -206
- package/dist/globals.cjs +0 -2
- package/dist/globals.d.cts +0 -104
- package/dist/index-CysiWbtk.d.ts +0 -687
- package/dist/index.cjs +0 -10024
- package/dist/index.d.cts +0 -291
- package/dist/playwright/index.cjs +0 -103
- package/dist/playwright/index.d.cts +0 -129
- package/dist/reporter/index.cjs +0 -8676
- package/dist/reporter/index.d.cts +0 -7
- package/dist/setup.cjs +0 -14
- package/dist/setup.d.cts +0 -2
|
@@ -1,159 +1,159 @@
|
|
|
1
|
-
# Specifications — Full Reference
|
|
2
|
-
|
|
3
|
-
Complete reference for writing MSpec-style specification/rule tests with `@swedevtools/livedoc-vitest`.
|
|
4
|
-
|
|
5
|
-
## Keywords
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
specification → rule | ruleOutline
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Import Block
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
import { specification, rule, ruleOutline } from "@swedevtools/livedoc-vitest";
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Specification
|
|
18
|
-
|
|
19
|
-
Top-level container grouping related rules:
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
specification("Calculator Operations", (ctx) => {
|
|
23
|
-
// ctx.specification → { title, description, tags }
|
|
24
|
-
});
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Rule
|
|
28
|
-
|
|
29
|
-
Individual test cases with direct assertions:
|
|
30
|
-
|
|
31
|
-
```typescript
|
|
32
|
-
specification("Calculator Operations", () => {
|
|
33
|
-
rule("Adding '5' and '3' returns '8'", (ctx) => {
|
|
34
|
-
const [a, b, expected] = ctx.rule.values; // [5, 3, 8]
|
|
35
|
-
expect(a + b).toBe(expected);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## Value Extraction
|
|
41
|
-
|
|
42
|
-
### Quoted Values — auto-extracted, type-coerced
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
rule("Adding '5' and '3' returns '8'", (ctx) => {
|
|
46
|
-
const [a, b, expected] = ctx.rule.values;
|
|
47
|
-
// a = 5 (number), b = 3, expected = 8
|
|
48
|
-
});
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Named Parameters — `<name:value>` syntax
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
rule("Subtracting <b:3> from <a:10> returns <expected:7>", (ctx) => {
|
|
55
|
-
const a = ctx.rule.params.a; // 10
|
|
56
|
-
const b = ctx.rule.params.b; // 3
|
|
57
|
-
expect(a - b).toBe(ctx.rule.params.expected); // 7
|
|
58
|
-
});
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## RuleOutline with Examples
|
|
62
|
-
|
|
63
|
-
Data-driven rules. Each row in the Examples table creates a separate test:
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
ruleOutline(`Discount calculations
|
|
67
|
-
Examples:
|
|
68
|
-
| price | discount | expected |
|
|
69
|
-
| 100 | 10 | 90 |
|
|
70
|
-
| 200 | 25 | 150 |
|
|
71
|
-
`, (ctx) => {
|
|
72
|
-
const result = ctx.example.price - (ctx.example.price * ctx.example.discount / 100);
|
|
73
|
-
expect(result).toBe(ctx.example.expected);
|
|
74
|
-
});
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### Combining Title Values and Example Data
|
|
78
|
-
|
|
79
|
-
RuleOutline supports both title values and example table data:
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
ruleOutline(`Discount of '10' percent applies to orders over '100' dollars
|
|
83
|
-
Examples:
|
|
84
|
-
| orderTotal | expectedDiscount |
|
|
85
|
-
| 150 | 15 |
|
|
86
|
-
| 200 | 20 |
|
|
87
|
-
`, (ctx) => {
|
|
88
|
-
const [discountPct, threshold] = ctx.rule.values; // From title: [10, 100]
|
|
89
|
-
const discount = ctx.example.orderTotal * (discountPct / 100); // From table
|
|
90
|
-
expect(discount).toBe(ctx.example.expectedDiscount);
|
|
91
|
-
});
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### Named Params in RuleOutline
|
|
95
|
-
|
|
96
|
-
```typescript
|
|
97
|
-
ruleOutline(`Applying <operation:multiply> with factor <factor:3>
|
|
98
|
-
Examples:
|
|
99
|
-
| input | expected |
|
|
100
|
-
| 5 | 15 |
|
|
101
|
-
| 10 | 30 |
|
|
102
|
-
`, (ctx) => {
|
|
103
|
-
expect(ctx.rule.params.operation).toBe("multiply");
|
|
104
|
-
expect(ctx.example.input * ctx.rule.params.factor).toBe(ctx.example.expected);
|
|
105
|
-
});
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## Descriptions and Tags
|
|
109
|
-
|
|
110
|
-
```typescript
|
|
111
|
-
specification(`Email Validation
|
|
112
|
-
@validation
|
|
113
|
-
Rules for validating email addresses across formats.
|
|
114
|
-
`, (ctx) => {
|
|
115
|
-
// rules...
|
|
116
|
-
});
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
- **First line** = title
|
|
120
|
-
- **Lines starting with `@`** = tags
|
|
121
|
-
- **Remaining lines** = description
|
|
122
|
-
|
|
123
|
-
## Async Rules
|
|
124
|
-
|
|
125
|
-
`rule` callbacks support `async`. `specification` callbacks must be **synchronous**.
|
|
126
|
-
|
|
127
|
-
```typescript
|
|
128
|
-
rule("Fetching user returns valid data", async (ctx) => {
|
|
129
|
-
const user = await fetchUser(1);
|
|
130
|
-
expect(user.name).toBeTruthy(); // ✅ OK
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
specification("Test", async (ctx) => { /* ❌ NOT ALLOWED */ });
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## Context Reference
|
|
137
|
-
|
|
138
|
-
| Property | Type | Description |
|
|
139
|
-
| --- | --- | --- |
|
|
140
|
-
| `ctx.specification` | `SpecificationContext` | `{title, description, tags}` |
|
|
141
|
-
| `ctx.rule` | `RuleContext` | `{title, description, tags, specification, values, valuesRaw, params, paramsRaw}` |
|
|
142
|
-
| `ctx.example` | `object` | Current example row (ruleOutline only) |
|
|
143
|
-
|
|
144
|
-
### RuleContext Properties
|
|
145
|
-
|
|
146
|
-
| Property | Returns |
|
|
147
|
-
| --- | --- |
|
|
148
|
-
| `values` | Coerced quoted values array |
|
|
149
|
-
| `valuesRaw` | Raw string values |
|
|
150
|
-
| `params` | Coerced named values object `<n:v>` |
|
|
151
|
-
| `paramsRaw` | Raw named values string object |
|
|
152
|
-
|
|
153
|
-
## Validation Checklist
|
|
154
|
-
|
|
155
|
-
- [ ] All test data appears in rule title strings (self-documenting)
|
|
156
|
-
- [ ] Descriptions provided on `specification` blocks
|
|
157
|
-
- [ ] Values extracted via `ctx.rule.values`, `ctx.rule.params`, or `ctx.example`
|
|
158
|
-
- [ ] Async only on `rule` callbacks, not `specification`
|
|
159
|
-
- [ ] File name ends in `.Spec.ts`
|
|
1
|
+
# Specifications — Full Reference
|
|
2
|
+
|
|
3
|
+
Complete reference for writing MSpec-style specification/rule tests with `@swedevtools/livedoc-vitest`.
|
|
4
|
+
|
|
5
|
+
## Keywords
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
specification → rule | ruleOutline
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Import Block
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { specification, rule, ruleOutline } from "@swedevtools/livedoc-vitest";
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Specification
|
|
18
|
+
|
|
19
|
+
Top-level container grouping related rules:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
specification("Calculator Operations", (ctx) => {
|
|
23
|
+
// ctx.specification → { title, description, tags }
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Rule
|
|
28
|
+
|
|
29
|
+
Individual test cases with direct assertions:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
specification("Calculator Operations", () => {
|
|
33
|
+
rule("Adding '5' and '3' returns '8'", (ctx) => {
|
|
34
|
+
const [a, b, expected] = ctx.rule.values; // [5, 3, 8]
|
|
35
|
+
expect(a + b).toBe(expected);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Value Extraction
|
|
41
|
+
|
|
42
|
+
### Quoted Values — auto-extracted, type-coerced
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
rule("Adding '5' and '3' returns '8'", (ctx) => {
|
|
46
|
+
const [a, b, expected] = ctx.rule.values;
|
|
47
|
+
// a = 5 (number), b = 3, expected = 8
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Named Parameters — `<name:value>` syntax
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
rule("Subtracting <b:3> from <a:10> returns <expected:7>", (ctx) => {
|
|
55
|
+
const a = ctx.rule.params.a; // 10
|
|
56
|
+
const b = ctx.rule.params.b; // 3
|
|
57
|
+
expect(a - b).toBe(ctx.rule.params.expected); // 7
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## RuleOutline with Examples
|
|
62
|
+
|
|
63
|
+
Data-driven rules. Each row in the Examples table creates a separate test:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
ruleOutline(`Discount calculations
|
|
67
|
+
Examples:
|
|
68
|
+
| price | discount | expected |
|
|
69
|
+
| 100 | 10 | 90 |
|
|
70
|
+
| 200 | 25 | 150 |
|
|
71
|
+
`, (ctx) => {
|
|
72
|
+
const result = ctx.example.price - (ctx.example.price * ctx.example.discount / 100);
|
|
73
|
+
expect(result).toBe(ctx.example.expected);
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Combining Title Values and Example Data
|
|
78
|
+
|
|
79
|
+
RuleOutline supports both title values and example table data:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
ruleOutline(`Discount of '10' percent applies to orders over '100' dollars
|
|
83
|
+
Examples:
|
|
84
|
+
| orderTotal | expectedDiscount |
|
|
85
|
+
| 150 | 15 |
|
|
86
|
+
| 200 | 20 |
|
|
87
|
+
`, (ctx) => {
|
|
88
|
+
const [discountPct, threshold] = ctx.rule.values; // From title: [10, 100]
|
|
89
|
+
const discount = ctx.example.orderTotal * (discountPct / 100); // From table
|
|
90
|
+
expect(discount).toBe(ctx.example.expectedDiscount);
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Named Params in RuleOutline
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
ruleOutline(`Applying <operation:multiply> with factor <factor:3>
|
|
98
|
+
Examples:
|
|
99
|
+
| input | expected |
|
|
100
|
+
| 5 | 15 |
|
|
101
|
+
| 10 | 30 |
|
|
102
|
+
`, (ctx) => {
|
|
103
|
+
expect(ctx.rule.params.operation).toBe("multiply");
|
|
104
|
+
expect(ctx.example.input * ctx.rule.params.factor).toBe(ctx.example.expected);
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Descriptions and Tags
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
specification(`Email Validation
|
|
112
|
+
@validation
|
|
113
|
+
Rules for validating email addresses across formats.
|
|
114
|
+
`, (ctx) => {
|
|
115
|
+
// rules...
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- **First line** = title
|
|
120
|
+
- **Lines starting with `@`** = tags
|
|
121
|
+
- **Remaining lines** = description
|
|
122
|
+
|
|
123
|
+
## Async Rules
|
|
124
|
+
|
|
125
|
+
`rule` callbacks support `async`. `specification` callbacks must be **synchronous**.
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
rule("Fetching user returns valid data", async (ctx) => {
|
|
129
|
+
const user = await fetchUser(1);
|
|
130
|
+
expect(user.name).toBeTruthy(); // ✅ OK
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
specification("Test", async (ctx) => { /* ❌ NOT ALLOWED */ });
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Context Reference
|
|
137
|
+
|
|
138
|
+
| Property | Type | Description |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| `ctx.specification` | `SpecificationContext` | `{title, description, tags}` |
|
|
141
|
+
| `ctx.rule` | `RuleContext` | `{title, description, tags, specification, values, valuesRaw, params, paramsRaw}` |
|
|
142
|
+
| `ctx.example` | `object` | Current example row (ruleOutline only) |
|
|
143
|
+
|
|
144
|
+
### RuleContext Properties
|
|
145
|
+
|
|
146
|
+
| Property | Returns |
|
|
147
|
+
| --- | --- |
|
|
148
|
+
| `values` | Coerced quoted values array |
|
|
149
|
+
| `valuesRaw` | Raw string values |
|
|
150
|
+
| `params` | Coerced named values object `<n:v>` |
|
|
151
|
+
| `paramsRaw` | Raw named values string object |
|
|
152
|
+
|
|
153
|
+
## Validation Checklist
|
|
154
|
+
|
|
155
|
+
- [ ] All test data appears in rule title strings (self-documenting)
|
|
156
|
+
- [ ] Descriptions provided on `specification` blocks
|
|
157
|
+
- [ ] Values extracted via `ctx.rule.values`, `ctx.rule.params`, or `ctx.example`
|
|
158
|
+
- [ ] Async only on `rule` callbacks, not `specification`
|
|
159
|
+
- [ ] File name ends in `.Spec.ts`
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Test Strategy and False-Green Prevention
|
|
2
|
+
|
|
3
|
+
Use this resource before choosing LiveDoc syntax. The goal is not to convert
|
|
4
|
+
every test. The goal is to publish the smallest trustworthy test whose result
|
|
5
|
+
has lasting documentation value.
|
|
6
|
+
|
|
7
|
+
## The Two-Question Litmus
|
|
8
|
+
|
|
9
|
+
A test earns its place only when both answers are yes:
|
|
10
|
+
|
|
11
|
+
1. **Would it survive a from-scratch rewrite that kept the same promise?**
|
|
12
|
+
2. **Would it fail if that promise broke?**
|
|
13
|
+
|
|
14
|
+
If the first answer is no, the test probably asserts implementation mechanism.
|
|
15
|
+
If the second answer is no, the test is vacuous or measures the wrong thing.
|
|
16
|
+
|
|
17
|
+
## Write a Compact Test Brief
|
|
18
|
+
|
|
19
|
+
Before generating code, identify:
|
|
20
|
+
|
|
21
|
+
| Field | Question |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| Claim | What externally meaningful fact must remain true? |
|
|
24
|
+
| Boundary | What must observe that fact: pure code, component, HTTP service, browser, process, filesystem, or source tree? |
|
|
25
|
+
| Oracle | Where does the expected result come from independently of production code? |
|
|
26
|
+
| Determinism | What clock, promise, scheduler, process, port, or fixture must be controlled? |
|
|
27
|
+
| Falsification | What realistic defect must make this test fail? |
|
|
28
|
+
| Owner | Does an existing test already own this behavior? |
|
|
29
|
+
|
|
30
|
+
Do not generate a LiveDoc test when the claim or observable boundary is unclear.
|
|
31
|
+
|
|
32
|
+
## Select the Lowest Trustworthy Level
|
|
33
|
+
|
|
34
|
+
| Claim | Recommended boundary | LiveDoc pattern |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| Pure calculation, parser, formatter, or domain rule | In-process | `specification` / `rule` |
|
|
37
|
+
| Stateful component behavior | Component integration | Specification or focused Feature |
|
|
38
|
+
| Stakeholder-readable workflow | Smallest realistic workflow | `feature` / `scenario` |
|
|
39
|
+
| Serialization or public payload shape | Complete contract comparison | Rule or outline |
|
|
40
|
+
| Public HTTP behavior | Test server or real HTTP service | Feature or HTTP contract test |
|
|
41
|
+
| Browser layout, focus, scrolling, accessibility tree, or pixels | Real browser | Feature with behavioral assertion and optional evidence |
|
|
42
|
+
| Source/repository policy | AST or filesystem governance test | Rule when the result is useful documentation |
|
|
43
|
+
| Fuzz, property, load, benchmark, or soak testing | Native specialist tool | Optional summary rule, not thousands of published cases |
|
|
44
|
+
|
|
45
|
+
## Feature or Specification?
|
|
46
|
+
|
|
47
|
+
Choose in this order:
|
|
48
|
+
|
|
49
|
+
1. **Would a product stakeholder read this to understand behavior?** Use a Feature.
|
|
50
|
+
2. **Is it a multi-step user or operator journey?** Use a Feature.
|
|
51
|
+
3. **Is it one technical input/output contract or implementation-independent rule?** Use a Specification.
|
|
52
|
+
|
|
53
|
+
The runtime instrument is separate from the report pattern. A browser Feature
|
|
54
|
+
and an in-process Feature can both be valid; the claim determines the boundary.
|
|
55
|
+
|
|
56
|
+
## Phrase the Present-Day Promise
|
|
57
|
+
|
|
58
|
+
- Put values in titles, but keep implementation mechanisms out.
|
|
59
|
+
- Test the goal, not the remembered defect.
|
|
60
|
+
- Avoid team names, revision rounds, "previously", "retired", or development history.
|
|
61
|
+
- A negative assertion is valid when absence is the current promise.
|
|
62
|
+
- Ask whether the title would make sense to a reader who never saw the bug.
|
|
63
|
+
|
|
64
|
+
| Too specific | Too vague | Trustworthy claim |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| The shell uses class `h-7` | The chip is accessible | Under a coarse pointer, the chip exposes at least a `44`px target |
|
|
67
|
+
| Function calls helper `normalizeV2` | Formatting works | Input `'abc'` produces canonical output `'ABC'` |
|
|
68
|
+
|
|
69
|
+
## Make Failures Diagnosable
|
|
70
|
+
|
|
71
|
+
- One independent claim should produce one reported row.
|
|
72
|
+
- Use `scenarioOutline` or `ruleOutline` when combinations must fail independently.
|
|
73
|
+
- Avoid loops that collapse many meaningful cases into one step.
|
|
74
|
+
- A step should not hide unrelated assertions.
|
|
75
|
+
- Failure messages must name the claim and case that broke.
|
|
76
|
+
|
|
77
|
+
## False-Green Completion Gate
|
|
78
|
+
|
|
79
|
+
Before completion:
|
|
80
|
+
|
|
81
|
+
- [ ] The intended test was collected and executed.
|
|
82
|
+
- [ ] The test passes alone and in its normal suite.
|
|
83
|
+
- [ ] Expected values are independent of the production algorithm.
|
|
84
|
+
- [ ] Complete shapes are compared when shape is the contract.
|
|
85
|
+
- [ ] Missing subjects fail; helpers do not treat absence as success.
|
|
86
|
+
- [ ] No guard clause returns before the assertion.
|
|
87
|
+
- [ ] No fixed sleep is used where a deterministic seam is available.
|
|
88
|
+
- [ ] Shared state has explicit reset and ownership semantics.
|
|
89
|
+
- [ ] For critical behavior, the test has been observed failing for the intended defect.
|
|
90
|
+
- [ ] The failure was behavioral, not a syntax/import/setup failure.
|
|
91
|
+
- [ ] Existing failures are separated from failures introduced by the change.
|
|
92
|
+
|
|
93
|
+
Use Stryker or another specialist tool for automated mutation testing. LiveDoc
|
|
94
|
+
does not implement its own mutation engine.
|
|
95
|
+
|
|
96
|
+
## Curate the Living Document
|
|
97
|
+
|
|
98
|
+
Not every native Vitest test should become a LiveDoc test. Keep low-level harness
|
|
99
|
+
checks, exhaustive generated cases, performance tests, and infrastructure probes
|
|
100
|
+
in the native runner unless their result has durable reader value.
|
|
101
|
+
|
|
102
|
+
Organize LiveDoc files by product surface. The directory structure is the
|
|
103
|
+
Viewer's table of contents; keep test instrument details below that level.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Web Testing: jsdom or Real Browser
|
|
2
|
+
|
|
3
|
+
Where a test runs is decided by what it claims, not convenience.
|
|
4
|
+
|
|
5
|
+
## Use jsdom for Observable DOM Contracts
|
|
6
|
+
|
|
7
|
+
jsdom is appropriate for:
|
|
8
|
+
|
|
9
|
+
- component state transitions;
|
|
10
|
+
- roles, accessible names, labels, and descriptions;
|
|
11
|
+
- deterministic event handling;
|
|
12
|
+
- form validation and submission;
|
|
13
|
+
- loading, empty, error, and recovery states;
|
|
14
|
+
- adapter/repository calls;
|
|
15
|
+
- basic keyboard-event contracts that do not require real focus behavior.
|
|
16
|
+
|
|
17
|
+
## Use a Real Browser for Platform Behavior
|
|
18
|
+
|
|
19
|
+
Use Playwright or another real browser for:
|
|
20
|
+
|
|
21
|
+
- measured geometry and responsive breakpoints;
|
|
22
|
+
- overflow, clipping, sticky positioning, and scrolling;
|
|
23
|
+
- focus trapping and restoration;
|
|
24
|
+
- `inert`, modal isolation, and the accessibility tree;
|
|
25
|
+
- computed styles, contrast, media queries, and theme geometry;
|
|
26
|
+
- pointer hit testing and real keyboard navigation;
|
|
27
|
+
- screenshots and visual comparison.
|
|
28
|
+
|
|
29
|
+
Do not assert CSS class names as proxies for appearance. A class rename can fail
|
|
30
|
+
while the product remains correct, and a broken stylesheet can leave the proxy
|
|
31
|
+
green.
|
|
32
|
+
|
|
33
|
+
## Browser Workflow
|
|
34
|
+
|
|
35
|
+
1. Prove readiness without a fixed sleep.
|
|
36
|
+
2. Interact through user-visible controls.
|
|
37
|
+
3. Assert the semantic or geometric behavior.
|
|
38
|
+
4. Attach a screenshot when it helps a reader or reviewer understand the state.
|
|
39
|
+
5. Verify the browser, worker, server, ports, and temporary files are released.
|
|
40
|
+
|
|
41
|
+
Read `resources/playwright.md` for the LiveDoc browser and screenshot APIs.
|
|
42
|
+
|
|
43
|
+
## Screenshots Are Evidence
|
|
44
|
+
|
|
45
|
+
A screenshot supports a claim; it does not replace the assertion.
|
|
46
|
+
|
|
47
|
+
Capture states a reader needs to understand:
|
|
48
|
+
|
|
49
|
+
- meaningful starting state;
|
|
50
|
+
- important user-triggered transitions;
|
|
51
|
+
- final outcome;
|
|
52
|
+
- failure state when diagnostic evidence is useful.
|
|
53
|
+
|
|
54
|
+
Feature journeys commonly benefit from screenshots. A browser-based
|
|
55
|
+
Specification may also attach evidence when the technical contract is visual.
|
|
56
|
+
|
|
57
|
+
Never attach:
|
|
58
|
+
|
|
59
|
+
- credentials, tokens, cookies, or authorization headers;
|
|
60
|
+
- unredacted personal data;
|
|
61
|
+
- traces or screenshots captured before readiness;
|
|
62
|
+
- large artifacts without a clear documentation purpose.
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import { Attachment } from '@swedevtools/livedoc-schema';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Global type definitions for LiveDoc-Vitest
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
type DataTableRow = any[] | { [key: string]: any };
|
|
8
|
-
|
|
9
|
-
interface LiveDocMetaTable {
|
|
10
|
-
name: string;
|
|
11
|
-
description: string;
|
|
12
|
-
dataTable: DataTableRow[];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface LiveDocStepTaskMeta {
|
|
16
|
-
kind: "step";
|
|
17
|
-
step: {
|
|
18
|
-
rawTitle: string;
|
|
19
|
-
type: string;
|
|
20
|
-
};
|
|
21
|
-
scenarioOutline?: {
|
|
22
|
-
title?: string;
|
|
23
|
-
description: string;
|
|
24
|
-
tables: LiveDocMetaTable[];
|
|
25
|
-
tags: string[];
|
|
26
|
-
example: {
|
|
27
|
-
sequence: number;
|
|
28
|
-
values: Record<string, unknown>;
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
interface LiveDocRuleExampleTaskMeta {
|
|
34
|
-
kind: "ruleExample";
|
|
35
|
-
ruleOutline: {
|
|
36
|
-
title: string;
|
|
37
|
-
description: string;
|
|
38
|
-
tables: LiveDocMetaTable[];
|
|
39
|
-
tags: string[];
|
|
40
|
-
example: {
|
|
41
|
-
sequence: number;
|
|
42
|
-
values: Record<string, unknown>;
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
interface LiveDocRuleTaskMeta {
|
|
48
|
-
kind: "rule";
|
|
49
|
-
rule: {
|
|
50
|
-
title: string;
|
|
51
|
-
description: string;
|
|
52
|
-
tags: string[];
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
type LiveDocTaskMeta = LiveDocStepTaskMeta | LiveDocRuleExampleTaskMeta | LiveDocRuleTaskMeta;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Extend Vitest's TaskMeta to include LiveDoc context
|
|
60
|
-
*/
|
|
61
|
-
declare module "@vitest/runner" {
|
|
62
|
-
interface TaskMeta {
|
|
63
|
-
livedoc?: LiveDocTaskMeta;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Framework metadata about the current step
|
|
69
|
-
* READ-ONLY - contains title, parsed values, tables, docStrings
|
|
70
|
-
* Provides helpers for accessing step data in various formats
|
|
71
|
-
*/
|
|
72
|
-
declare class StepContext {
|
|
73
|
-
private _table?;
|
|
74
|
-
private _attachments;
|
|
75
|
-
title: string;
|
|
76
|
-
displayTitle: string;
|
|
77
|
-
dataTable: DataTableRow[];
|
|
78
|
-
docString: string;
|
|
79
|
-
type: string;
|
|
80
|
-
values: any[];
|
|
81
|
-
valuesRaw: string[];
|
|
82
|
-
params: Record<string, any>;
|
|
83
|
-
paramsRaw: Record<string, string>;
|
|
84
|
-
constructor(attachments?: Attachment[]);
|
|
85
|
-
/**
|
|
86
|
-
* Attach arbitrary data (base64-encoded) to this step.
|
|
87
|
-
*/
|
|
88
|
-
attach(data: string, opts?: {
|
|
89
|
-
title?: string;
|
|
90
|
-
mimeType?: string;
|
|
91
|
-
kind?: 'image' | 'screenshot' | 'file';
|
|
92
|
-
}): void;
|
|
93
|
-
/**
|
|
94
|
-
* Convenience: attach a PNG screenshot.
|
|
95
|
-
*/
|
|
96
|
-
attachScreenshot(base64: string, title?: string): void;
|
|
97
|
-
/**
|
|
98
|
-
* Convenience: attach a JSON payload (e.g., API response).
|
|
99
|
-
*/
|
|
100
|
-
attachJSON(data: unknown, title?: string): void;
|
|
101
|
-
/** Attachments collected during step execution. */
|
|
102
|
-
get attachments(): Attachment[];
|
|
103
|
-
/**
|
|
104
|
-
* Parse docString as JSON entity
|
|
105
|
-
*/
|
|
106
|
-
get docStringAsEntity(): any;
|
|
107
|
-
/**
|
|
108
|
-
* Get data table with headers as column names
|
|
109
|
-
*/
|
|
110
|
-
get table(): DataTableRow[];
|
|
111
|
-
/**
|
|
112
|
-
* Convert 2-column table to key-value entity
|
|
113
|
-
*/
|
|
114
|
-
get tableAsEntity(): DataTableRow | undefined;
|
|
115
|
-
/**
|
|
116
|
-
* Get data table as-is (raw array of arrays)
|
|
117
|
-
*/
|
|
118
|
-
tableAsList(): DataTableRow[];
|
|
119
|
-
/**
|
|
120
|
-
* Get first column as single array
|
|
121
|
-
*/
|
|
122
|
-
get tableAsSingleList(): any[];
|
|
123
|
-
private convertToTable;
|
|
124
|
-
private convertDataTableRowToEntity;
|
|
125
|
-
private coerceValue;
|
|
126
|
-
private convertToDateIfPossible;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Framework metadata about the scenario
|
|
131
|
-
* READ-ONLY - contains title/description/tags/step references
|
|
132
|
-
* NOT for user test data! Use local variables instead.
|
|
133
|
-
*/
|
|
134
|
-
declare class ScenarioContext {
|
|
135
|
-
title: string;
|
|
136
|
-
description: string;
|
|
137
|
-
given?: StepContext;
|
|
138
|
-
and: StepContext[];
|
|
139
|
-
tags: string[];
|
|
140
|
-
/** All steps in this scenario */
|
|
141
|
-
steps: StepContext[];
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Framework metadata about the feature
|
|
146
|
-
* READ-ONLY - contains file/title/description/tags
|
|
147
|
-
* NOT for user test data! Use local variables instead.
|
|
148
|
-
*/
|
|
149
|
-
declare class FeatureContext {
|
|
150
|
-
filename: string;
|
|
151
|
-
title: string;
|
|
152
|
-
description: string;
|
|
153
|
-
tags: string[];
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Framework metadata about the background
|
|
158
|
-
* READ-ONLY - extends ScenarioContext with background-specific data
|
|
159
|
-
*/
|
|
160
|
-
declare class BackgroundContext extends ScenarioContext {
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Framework metadata about the specification
|
|
165
|
-
* READ-ONLY - contains file/title/description/tags
|
|
166
|
-
* NOT for user test data! Use local variables instead.
|
|
167
|
-
*/
|
|
168
|
-
declare class SpecificationContext {
|
|
169
|
-
filename: string;
|
|
170
|
-
title: string;
|
|
171
|
-
description: string;
|
|
172
|
-
tags: string[];
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Framework metadata about the rule.
|
|
177
|
-
* Provides title, description, tags, and extracted values/params from the rule title.
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* ```typescript
|
|
181
|
-
* rule("Adding '5' and '3' returns '8'", (ctx) => {
|
|
182
|
-
* const [a, b, expected] = ctx.rule.values; // [5, 3, 8]
|
|
183
|
-
* expect(a + b).toBe(expected);
|
|
184
|
-
* });
|
|
185
|
-
*
|
|
186
|
-
* rule("Processing <action:login> for <user:alice>", (ctx) => {
|
|
187
|
-
* const action = ctx.rule.params.action; // "login"
|
|
188
|
-
* });
|
|
189
|
-
* ```
|
|
190
|
-
*/
|
|
191
|
-
declare class RuleContext {
|
|
192
|
-
title: string;
|
|
193
|
-
description: string;
|
|
194
|
-
tags: string[];
|
|
195
|
-
specification: SpecificationContext;
|
|
196
|
-
/** Extracted and type-coerced quoted values from the rule title. */
|
|
197
|
-
values: any[];
|
|
198
|
-
/** Raw string values before type coercion. */
|
|
199
|
-
valuesRaw: string[];
|
|
200
|
-
/** Extracted and type-coerced named parameters from <name:value> patterns. */
|
|
201
|
-
params: Record<string, any>;
|
|
202
|
-
/** Raw string named parameters before type coercion. */
|
|
203
|
-
paramsRaw: Record<string, string>;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
export { BackgroundContext as B, type DataTableRow as D, FeatureContext as F, RuleContext as R, ScenarioContext as S, StepContext as a, SpecificationContext as b };
|
package/dist/globals.cjs
DELETED