Skip to content

Commit 837a461

Browse files
feat(learn): add section for dynamically generating test cases (#7387)
* feat(learn): add section for dynamically generating test cases * fixup!: adjust for prettier mangling * fixup!: simple & advanced examples * fixup!: re-organise examples
1 parent 317dce6 commit 837a461

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

apps/site/pages/en/learn/test-runner/using-test-runner.md

+112
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,118 @@ Then for each setup, create a dedicated `setup` file (ensuring the base `setup.m
6464

6565
Each example below was taken from real-world projects; they may not be appropriate/applicable to yours, but each demonstrate general concepts that are broadly applicable.
6666

67+
## Dynamically generating test cases
68+
69+
Some times, you may want to dynamically generate test-cases. For instance, you want to test the same thing across a bunch of files. This is possible, albeit slightly arcane. You must use `test` (you cannot use `describe`) + `testContext.test`:
70+
71+
### Simple example
72+
73+
```js displayName="23.8.0 and later"
74+
import assert from 'node:assert/strict';
75+
import { test } from 'node:test';
76+
77+
import { detectOsInUserAgent } from '';
78+
79+
const userAgents = [
80+
{ ua: /**/, os: 'WIN' },
81+
//
82+
];
83+
84+
test('Detect OS via user-agent', { concurrency: true }, t => {
85+
for (const { os, ua } from userAgents) {
86+
t.test(ua, () => assert.equal(detectOsInUserAgent(ua), os));
87+
}
88+
});
89+
```
90+
91+
```js displayName="prior to 23.8.0"
92+
import assert from 'node:assert/strict';
93+
import { test } from 'node:test';
94+
95+
import { detectOsInUserAgent } from '';
96+
97+
const userAgents = [
98+
{ ua: '', os: 'WIN' },
99+
//
100+
];
101+
102+
test('Detect OS via user-agent', { concurrency: true }, async t => {
103+
const cases = userAgents.map(({ os, ua }) => {
104+
t.test(ua, () => assert.equal(detectOsInUserAgent(ua), os));
105+
});
106+
107+
await Promise.allSettled(cases);
108+
});
109+
```
110+
111+
### Advanced example
112+
113+
```js displayName="23.8.0 and later"
114+
import assert from 'node:assert/strict';
115+
import { test } from 'node:test';
116+
117+
import { getWorkspacePJSONs } from './getWorkspacePJSONs.mjs';
118+
119+
const requiredKeywords = ['node.js', 'sliced bread'];
120+
121+
test('Check package.jsons', { concurrency: true }, async t => {
122+
const pjsons = await getWorkspacePJSONs();
123+
124+
for (const pjson of pjsons) {
125+
// ⚠️ `t.test`, NOT `test`
126+
t.test(`Ensure fields are properly set: ${pjson.name}`, () => {
127+
assert.partialDeepStrictEqual(pjson.keywords, requiredKeywords);
128+
});
129+
}
130+
});
131+
```
132+
133+
```js displayName="prior to 23.8.0"
134+
import assert from 'node:assert/strict';
135+
import { test } from 'node:test';
136+
137+
import { getWorkspacePJSONs } from './getWorkspacePJSONs.mjs';
138+
139+
const requiredKeywords = ['node.js', 'sliced bread'];
140+
141+
test('Check package.jsons', { concurrency: true }, async t => {
142+
const pjsons = await getWorkspacePJSONs();
143+
144+
const cases = pjsons.map(pjson =>
145+
// ⚠️ `t.test`, NOT `test`
146+
t.test(`Ensure fields are properly set: ${pjson.name}`, () => {
147+
assert.partialDeepStrictEqual(pjson.keywords, requiredKeywords);
148+
})
149+
);
150+
151+
// Allow the cases to run concurrently.
152+
await Promise.allSettled(cases);
153+
});
154+
```
155+
156+
```js displayName="./getWorkspacePJSONs.mjs"
157+
import { globSync } from 'node:fs';
158+
import { fileURLToPath } from 'node:url';
159+
160+
// Note: This would be better implemented as an async generator, leveraging fs.glob (instead of fs.globSync);
161+
// however, generators and especially async generators are much less understood,
162+
// so this simplified example is provided for easier understanding.
163+
164+
/**
165+
* Get all the package.json files, by default 1-level deep within ./workspaces/
166+
*/
167+
export function getWorkspacePJSONs(path = './workspaces/*/package.json') {
168+
return Promise.all(
169+
globSync(
170+
// ⚠️ Passing a file URL string, like from import.meta.resolve, causes glob* to fail silently
171+
fileURLToPath(import.meta.resolve(path))
172+
).map(path => import(path, { with: { type: 'json' } }))
173+
);
174+
}
175+
```
176+
177+
> **Note**: Prior to version 23.8.0, the setup is quite different because `testContext.test` was not automatically awaited.
178+
67179
## ServiceWorker tests
68180
69181
[`ServiceWorkerGlobalScope`](https://developer.mozilla.org/docs/Web/API/ServiceWorkerGlobalScope) contains very specific APIs that don't exist in other environments, and some of its APIs are seemingly similar to others (ex `fetch`) but have augmented behaviour. You do not want these to spill into unrelated tests.

0 commit comments

Comments
 (0)