@hyperfixi/testing-framework 3.1.1 → 3.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +186 -1
  2. package/dist/index.js +5 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +5 -1
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/runner.js +5 -1
  7. package/dist/runner.js.map +1 -1
  8. package/dist/runner.mjs +5 -1
  9. package/dist/runner.mjs.map +1 -1
  10. package/package.json +21 -19
  11. package/src/multilingual/README.md +39 -0
  12. package/src/multilingual/en-reference-equivalences.test.ts +321 -0
  13. package/src/multilingual/en-reference-preservation.test.ts +124 -0
  14. package/src/multilingual/en-reference-preservation.ts +495 -0
  15. package/src/multilingual/engine-parser-parity.test.ts +67 -0
  16. package/src/multilingual/pattern-loader.test.ts +43 -0
  17. package/src/multilingual/pattern-loader.ts +7 -2
  18. package/src/multilingual/shipped-examples-execution.test.ts +76 -1
  19. package/src/multilingual/shipped-examples-execution.ts +73 -3
  20. package/src/multilingual/shipped-sources-engine.test.ts +106 -0
  21. package/src/multilingual/shipped-sources-validity.ts +65 -0
  22. package/src/multilingual/validators/execution-validator.test.ts +32 -3
  23. package/src/multilingual/validators/execution-validator.ts +22 -5
  24. package/src/multilingual/value-matrix-gate.ts +118 -0
  25. package/src/multilingual/value-matrix.accepted.test.ts +65 -0
  26. package/src/multilingual/value-matrix.assign.test.ts +13 -0
  27. package/src/multilingual/value-matrix.chain-phrases.test.ts +13 -0
  28. package/src/multilingual/value-matrix.chain.test.ts +13 -0
  29. package/src/multilingual/value-matrix.count.test.ts +13 -0
  30. package/src/multilingual/value-matrix.get-phrases.test.ts +13 -0
  31. package/src/multilingual/value-matrix.get.test.ts +13 -0
  32. package/src/multilingual/value-matrix.if-phrases.test.ts +13 -0
  33. package/src/multilingual/value-matrix.if.test.ts +13 -0
  34. package/src/multilingual/value-matrix.increment.test.ts +13 -0
  35. package/src/multilingual/value-matrix.isolation.test.ts +57 -0
  36. package/src/multilingual/value-matrix.names.test.ts +62 -0
  37. package/src/multilingual/value-matrix.put-phrases.test.ts +13 -0
  38. package/src/multilingual/value-matrix.put.test.ts +13 -0
  39. package/src/multilingual/value-matrix.set-phrases.test.ts +13 -0
  40. package/src/multilingual/value-matrix.set.test.ts +13 -0
  41. package/src/multilingual/value-matrix.times.test.ts +13 -0
  42. package/src/multilingual/value-matrix.ts +1208 -0
  43. package/src/multilingual/value-matrix.while.test.ts +13 -0
  44. package/src/runner.ts +7 -1
@@ -0,0 +1,118 @@
1
+ /**
2
+ * The value matrix gate (see value-matrix.ts), one position per test file —
3
+ * `value-matrix.<position>.test.ts`, and a position's operator-phrase cells in
4
+ * `value-matrix.<position>-phrases.test.ts` — so vitest runs the shards in
5
+ * parallel. Each shard judges only its own cells against the shared baseline.
6
+ *
7
+ * Assertions:
8
+ * 1. every cell has an oracle: upstream runs its English source (the
9
+ * generator only produces upstream-valid cells);
10
+ * 2. no failing (cell, lane) pair is missing from the baseline;
11
+ * 3. no listed pair passes now — prune it, so the list only shrinks;
12
+ * 4. no listed cell is gone from the generator.
13
+ *
14
+ * After an intentional change: `npx tsx tools/regen-value-matrix-baseline.ts`
15
+ * (shrink-only; `--allow-new` to accept new failures, with a reason in the PR).
16
+ */
17
+
18
+ import { existsSync, readFileSync } from 'node:fs';
19
+ import path from 'node:path';
20
+ import { fileURLToPath } from 'node:url';
21
+ import { describe, it, expect, beforeAll } from 'vitest';
22
+ import {
23
+ diffBaseline,
24
+ failingLanes,
25
+ generateCells,
26
+ isPhraseCell,
27
+ orphanedEntries,
28
+ runValueMatrix,
29
+ type CellResult,
30
+ type Position,
31
+ type ValueMatrixBaseline,
32
+ } from './value-matrix';
33
+
34
+ export const BASELINE_PATH = path.resolve(
35
+ path.dirname(fileURLToPath(import.meta.url)),
36
+ '../../baselines/value-matrix.json'
37
+ );
38
+
39
+ export function loadBaseline(): ValueMatrixBaseline {
40
+ return JSON.parse(readFileSync(BASELINE_PATH, 'utf8')) as ValueMatrixBaseline;
41
+ }
42
+
43
+ /** At most `max` lines, then a count: a broad regression must not print thousands. */
44
+ function capped(lines: string[], max = 40): string[] {
45
+ return lines.length <= max ? lines : [...lines.slice(0, max), `… and ${lines.length - max} more`];
46
+ }
47
+
48
+ /**
49
+ * One shard: a position's cells without the operator phrases (`values`), or
50
+ * its phrase cells (`phrases`), which add half again to the matrix and would
51
+ * double a position's shard.
52
+ */
53
+ export function describeValueMatrixShard(
54
+ position: Position,
55
+ part: 'values' | 'phrases' = 'values'
56
+ ): void {
57
+ const all = generateCells();
58
+ const cells = all.filter(
59
+ cell => cell.position === position && isPhraseCell(cell) === (part === 'phrases')
60
+ );
61
+ const shard = part === 'phrases' ? `${position}-phrases` : position;
62
+ const baseline = loadBaseline();
63
+
64
+ describe(`value matrix: ${shard}`, () => {
65
+ let results: CellResult[] = [];
66
+
67
+ beforeAll(async () => {
68
+ results = await runValueMatrix(cells);
69
+ const pairs = results.reduce((n, r) => n + Object.keys(r.lanes).length, 0);
70
+ const failing = results.reduce((n, r) => n + failingLanes(r).length, 0);
71
+ console.log(
72
+ `value matrix [${shard}]: ${cells.length} cells, ${pairs} (cell, lane) pairs, ${failing} failing`
73
+ );
74
+ }, 900_000);
75
+
76
+ it('every cell has an oracle', () => {
77
+ expect(cells.length).toBeGreaterThan(50);
78
+ expect(results).toHaveLength(cells.length);
79
+ expect(results.filter(r => r.invalid).map(r => `${r.id}: ${r.invalid}`)).toEqual([]);
80
+ });
81
+
82
+ it('no failing pair is missing from the baseline', () => {
83
+ const { added } = diffBaseline(results, baseline);
84
+ expect(
85
+ capped(
86
+ added.map(
87
+ a => `${a.id} [${a.lane}] want ${JSON.stringify(a.want)}, got ${JSON.stringify(a.got)}`
88
+ )
89
+ )
90
+ ).toEqual([]);
91
+ });
92
+
93
+ it('no listed pair passes now (prune it with tools/regen-value-matrix-baseline.ts)', () => {
94
+ const { fixed } = diffBaseline(results, baseline);
95
+ expect(capped(fixed.map(f => `${f.id} [${f.lane}]`))).toEqual([]);
96
+ });
97
+
98
+ // The values shard owns its position's entries, phrase cells included.
99
+ it('no listed cell is gone from the generator', () => {
100
+ if (part === 'phrases') return;
101
+ const own = Object.fromEntries(
102
+ Object.entries(baseline.entries).filter(([id]) => id.startsWith(`${position}|`))
103
+ );
104
+ expect(orphanedEntries({ entries: own }, all)).toEqual([]);
105
+ });
106
+
107
+ // A phrase added to a position with no phrases shard would run nowhere.
108
+ it('every phrase cell of the position has its shard', () => {
109
+ if (part === 'phrases') return;
110
+ const phrases = all.filter(cell => cell.position === position && isPhraseCell(cell));
111
+ const file = path.join(
112
+ path.dirname(fileURLToPath(import.meta.url)),
113
+ `value-matrix.${position}-phrases.test.ts`
114
+ );
115
+ expect(phrases.length === 0 || existsSync(file), file).toBe(true);
116
+ });
117
+ });
118
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The value matrix's accepted pairs (ACCEPTED in value-matrix.ts): failures the
3
+ * owner decided to keep. A cell's entry carries the reason only when every
4
+ * failing lane is accepted, so a new failure in an accepted cell still reads as
5
+ * open work.
6
+ */
7
+ import { describe, it, expect } from 'vitest';
8
+ import {
9
+ ACCEPTED,
10
+ acceptedReason,
11
+ baselineFrom,
12
+ expandLanes,
13
+ generateCells,
14
+ type CellResult,
15
+ } from './value-matrix';
16
+ import { loadBaseline } from './value-matrix-gate';
17
+
18
+ describe('value matrix: accepted pairs', () => {
19
+ const [known, ambiguity] = ACCEPTED;
20
+
21
+ it('tags a cell whose failing lanes are all accepted', () => {
22
+ expect(acceptedReason('put|the textContent of #a as Int', ['en', 'es', 'ja'])).toBe(
23
+ known!.reason
24
+ );
25
+ expect(acceptedReason('increment|#a.textContent', ['it', 'it/up'])).toBe(ambiguity!.reason);
26
+ expect(acceptedReason('increment|#a.textContent', ['it', 'it/up', 'it/eng'])).toBe(
27
+ ambiguity!.reason
28
+ );
29
+ });
30
+
31
+ it('leaves it open when one failing lane is not', () => {
32
+ expect(acceptedReason('increment|#a.textContent', ['it', 'es'])).toBeUndefined();
33
+ expect(acceptedReason('put|the textContent of #a as Int', ['en', 'es/up'])).toBeUndefined();
34
+ });
35
+
36
+ it('a regenerated baseline carries the reason, and counts the pairs', () => {
37
+ const result = (lanes: Record<string, string>): CellResult => ({
38
+ id: 'increment|#a.textContent',
39
+ want: '7',
40
+ lanes: { en: '7', es: '7', ...lanes },
41
+ });
42
+ const kept = baselineFrom([result({ it: '1', 'it/up': '1' })], '');
43
+ expect(kept.entries['increment|#a.textContent']?.accepted).toBe(ambiguity!.reason);
44
+ expect(kept.accepted).toBe(2);
45
+ const open = baselineFrom([result({ it: '1', es: '1' })], '');
46
+ expect(open.entries['increment|#a.textContent']?.accepted).toBeUndefined();
47
+ expect(open.accepted).toBe(0);
48
+ });
49
+
50
+ it('accepts only the cells it names', () => {
51
+ expect(acceptedReason('put|textContent of #a', ['en'])).toBeUndefined();
52
+ });
53
+
54
+ it('names cells the generator makes, and the baseline lists them as accepted', () => {
55
+ const ids = new Set(generateCells().map(cell => cell.id));
56
+ const baseline = loadBaseline();
57
+ for (const entry of ACCEPTED) {
58
+ for (const id of entry.cells) {
59
+ expect(ids.has(id), id).toBe(true);
60
+ expect(baseline.entries[id]?.accepted, id).toBe(entry.reason);
61
+ expect(expandLanes(baseline.entries[id]!.lanes).length, id).toBeGreaterThan(0);
62
+ }
63
+ }
64
+ });
65
+ });
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `assign` cells. See value-matrix.ts for the matrix and
3
+ * value-matrix-gate.ts for the assertions; one position per file so the
4
+ * shards run in parallel.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('assign');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `chain` position's operator-phrase cells (`is equal
3
+ * to`, `includes`, `is an Element`, …). See value-matrix.ts for the matrix
4
+ * and value-matrix-gate.ts for the assertions.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('chain', 'phrases');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `chain` cells: a `set` value in the second command
3
+ * of a chain. See value-matrix.ts for the matrix and value-matrix-gate.ts for
4
+ * the assertions; one position per file so the shards run in parallel.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('chain');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `count` cells. See value-matrix.ts for the matrix and
3
+ * value-matrix-gate.ts for the assertions; one position per file so the
4
+ * shards run in parallel.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('count');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `get` position's operator-phrase cells (`is equal
3
+ * to`, `includes`, `is an Element`, …). See value-matrix.ts for the matrix
4
+ * and value-matrix-gate.ts for the assertions.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('get', 'phrases');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `get` cells, what a `get` reads. See value-matrix.ts
3
+ * for the matrix and value-matrix-gate.ts for the assertions; one position per
4
+ * file so the shards run in parallel.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('get');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `if` position's operator-phrase cells (`is equal
3
+ * to`, `includes`, `is an Element`, …). See value-matrix.ts for the matrix
4
+ * and value-matrix-gate.ts for the assertions.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('if', 'phrases');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `if` cells. See value-matrix.ts for the matrix and
3
+ * value-matrix-gate.ts for the assertions; one position per file so the
4
+ * shards run in parallel.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('if');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `increment` cells. See value-matrix.ts for the matrix and
3
+ * value-matrix-gate.ts for the assertions; one position per file so the
4
+ * shards run in parallel.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('increment');
@@ -0,0 +1,57 @@
1
+ /**
2
+ * The value matrix runs every (cell, lane) pair in one process, so no run may
3
+ * see another's writes. Two ways one did:
4
+ * - hyperfixi keeps global variables in a Map that every context shares, so
5
+ * one lane's `increment n` made every later run read `n` as 7, core's own
6
+ * English included;
7
+ * - a lane can remove the body (tr read `increment i by 2 * 2` as
8
+ * `increment *`), and the next run's reset then threw.
9
+ *
10
+ * One set of engines for the file: the engines bind the window they are first
11
+ * loaded with, so a second initMatrixEngines() would run on a stale document.
12
+ *
13
+ * @vitest-environment node
14
+ * Required, not a preference: see value-matrix.put.test.ts.
15
+ */
16
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
17
+ import { initMatrixEngines, type MatrixCell, type MatrixEngines } from './value-matrix';
18
+
19
+ const cell = (id: string, source: string): MatrixCell => ({
20
+ id,
21
+ position: 'put',
22
+ group: 'operand',
23
+ source,
24
+ });
25
+
26
+ const read = cell('reads', 'on click put n into #out');
27
+
28
+ describe('value matrix: runs are isolated', () => {
29
+ let engines: MatrixEngines;
30
+ beforeAll(async () => {
31
+ engines = await initMatrixEngines();
32
+ }, 120_000);
33
+ afterAll(async () => {
34
+ await engines.close();
35
+ });
36
+
37
+ it('a global one run writes is gone in the next', async () => {
38
+ const before = await engines.runCell(read);
39
+ // A cell whose oracle writes nothing runs no lane, so this one puts.
40
+ const writes = await engines.runCell(
41
+ cell('writes', 'on click increment n then put n into #out')
42
+ );
43
+ const after = await engines.runCell(read);
44
+ expect(writes.lanes.en).toBe('7');
45
+ expect(before.want).toBe('6');
46
+ expect(before.lanes.en).toBe('6');
47
+ expect(after.lanes).toEqual(before.lanes);
48
+ }, 120_000);
49
+
50
+ it('a run that removes the body leaves the next its fixture', async () => {
51
+ const before = await engines.runCell(read);
52
+ await engines.runCell(cell('removes', 'on click remove document.body'));
53
+ const after = await engines.runCell(read);
54
+ expect(before.lanes.en).toBe('6');
55
+ expect(after.lanes).toEqual(before.lanes);
56
+ }, 120_000);
57
+ });
@@ -0,0 +1,62 @@
1
+ /**
2
+ * The value matrix's colliding names (collidingNames in value-matrix.ts). The
3
+ * list is derived, so these pin what each source puts in and what each rule
4
+ * leaves out; the matrix shards run the names themselves.
5
+ */
6
+ import { describe, it, expect } from 'vitest';
7
+ import { collidingNames, generateCells } from './value-matrix';
8
+
9
+ const names = new Map(collidingNames().map(entry => [entry.name, entry]));
10
+
11
+ describe('value matrix: colliding names', () => {
12
+ it('takes a word a tokenizer reads as structure', () => {
13
+ expect(names.has('a')).toBe(true); // es, it, pt `to`; a tr particle
14
+ expect(names.has('y')).toBe(true); // es `and`
15
+ expect(names.has('wo')).toBe(true); // de `where`
16
+ });
17
+
18
+ it('takes a longer name as code writes it, which a tokenizer splits', () => {
19
+ expect(names.get('userData')?.pronounIn).toEqual([]); // qu `userDa` + `ta`
20
+ });
21
+
22
+ it('takes a schema marker the tokenizer leaves an identifier', () => {
23
+ expect(names.has('um')).toBe(true); // de `increment … by`
24
+ });
25
+
26
+ it('leaves out English keywords, but not the articles', () => {
27
+ expect(names.has('in')).toBe(false);
28
+ expect(names.has('on')).toBe(false);
29
+ expect(names.has('an')).toBe(true);
30
+ });
31
+
32
+ it("leaves out upstream's `no` and the templates' variables", () => {
33
+ expect(names.has('no')).toBe(false);
34
+ expect(names.has('i')).toBe(false);
35
+ });
36
+
37
+ it('leaves out a name that only ever collides with a pronoun', () => {
38
+ expect(names.has('eu')).toBe(false); // pt `me`
39
+ expect(names.has('io')).toBe(false); // it `me`
40
+ });
41
+
42
+ it("keeps a name that is a pronoun elsewhere, without that language's lanes", () => {
43
+ expect(names.get('o')?.pronounIn).toEqual(['tr']); // es and it `or`; tr `it`
44
+ expect(names.get('es')?.pronounIn).toEqual(['de']); // es `is`; de `it`
45
+ const cells = generateCells().filter(cell => cell.name === 'o');
46
+ expect(cells.map(cell => `${cell.position}|${cell.expression}`)).toEqual([
47
+ 'put|o',
48
+ 'set|o',
49
+ 'if|o',
50
+ 'increment|o',
51
+ 'chain|o',
52
+ 'get|o',
53
+ 'assign|o',
54
+ 'count|o',
55
+ 'put|o + 1',
56
+ 'set|1 + o',
57
+ 'if|o < 3',
58
+ 'if|not o',
59
+ ]);
60
+ expect(cells.every(cell => cell.skip?.join() === 'tr')).toBe(true);
61
+ });
62
+ });
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `put` position's operator-phrase cells (`is equal
3
+ * to`, `includes`, `is an Element`, …). See value-matrix.ts for the matrix
4
+ * and value-matrix-gate.ts for the assertions.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('put', 'phrases');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `put` cells. See value-matrix.ts for the matrix and
3
+ * value-matrix-gate.ts for the assertions; one position per file so the
4
+ * shards run in parallel.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('put');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `set` position's operator-phrase cells (`is equal
3
+ * to`, `includes`, `is an Element`, …). See value-matrix.ts for the matrix
4
+ * and value-matrix-gate.ts for the assertions.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('set', 'phrases');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `set` cells. See value-matrix.ts for the matrix and
3
+ * value-matrix-gate.ts for the assertions; one position per file so the
4
+ * shards run in parallel.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('set');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Value matrix gate — the `times` cells, a loop's count. See value-matrix.ts
3
+ * for the matrix and value-matrix-gate.ts for the assertions; one position per
4
+ * file so the shards run in parallel.
5
+ *
6
+ * @vitest-environment node
7
+ * Required, not a preference: under happy-dom the engines bind happy-dom's
8
+ * DOM constructors, not the jsdom window's (see
9
+ * shipped-examples-execution.test.ts).
10
+ */
11
+ import { describeValueMatrixShard } from './value-matrix-gate';
12
+
13
+ describeValueMatrixShard('times');