| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent bacba16 commit f5803cc
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,7 @@ | |||
| 1 | 1 | 'use strict'; | |
| 2 | 2 | ||
| 3 | 3 | const { | |
| 4 | + ArrayPrototypeMap, | ||
| 4 | 5 | ArrayPrototypePush, | |
| 5 | 6 | JSONStringify, | |
| 6 | 7 | } = primordials; | |
@@ -11,19 +12,55 @@ function reportReruns(previousRuns, globalOptions) { | |||
| 11 | 12 | return async function reporter(source) { | |
| 12 | 13 | const obj = { __proto__: null }; | |
| 13 | 14 | const disambiguator = { __proto__: null }; | |
| 15 | + let currentSuite = null; | ||
| 16 | + const roots = []; | ||
| 17 | + | ||
| 18 | + function getTestId(data) { | ||
| 19 | + return `${relative(globalOptions.cwd, data.file)}:${data.line}:${data.column}`; | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + function startTest(data) { | ||
| 23 | + const originalSuite = currentSuite; | ||
| 24 | + currentSuite = { __proto__: null, data, parent: currentSuite, children: [] }; | ||
| 25 | + if (originalSuite?.children) { | ||
| 26 | + ArrayPrototypePush(originalSuite.children, currentSuite); | ||
| 27 | + } | ||
| 28 | + if (!currentSuite.parent) { | ||
| 29 | + ArrayPrototypePush(roots, currentSuite); | ||
| 30 | + } | ||
| 31 | + } | ||
| 14 | 32 | ||
| 15 | 33 | for await (const { type, data } of source) { | |
| 34 | + let currentTest; | ||
| 35 | + if (type === 'test:start') { | ||
| 36 | + startTest(data); | ||
| 37 | + } else if (type === 'test:fail' || type === 'test:pass') { | ||
| 38 | + if (!currentSuite) { | ||
| 39 | + startTest({ __proto__: null, name: 'root', nesting: 0 }); | ||
| 40 | + } | ||
| 41 | + if (currentSuite.data.name !== data.name || currentSuite.data.nesting !== data.nesting) { | ||
| 42 | + startTest(data); | ||
| 43 | + } | ||
| 44 | + currentTest = currentSuite; | ||
| 45 | + if (currentSuite?.data.nesting === data.nesting) { | ||
| 46 | + currentSuite = currentSuite.parent; | ||
| 47 | + } | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + | ||
| 16 | 51 | if (type === 'test:pass') { | |
| 17 | - let identifier = `${relative(globalOptions.cwd, data.file)}:${data.line}:${data.column}`; | ||
| 52 | + let identifier = getTestId(data); | ||
| 18 | 53 | if (disambiguator[identifier] !== undefined) { | |
| 19 | 54 | identifier += `:(${disambiguator[identifier]})`; | |
| 20 | 55 | disambiguator[identifier] += 1; | |
| 21 | 56 | } else { | |
| 22 | 57 | disambiguator[identifier] = 1; | |
| 23 | 58 | } | |
| 59 | + const children = ArrayPrototypeMap(currentTest.children, (child) => child.data); | ||
| 24 | 60 | obj[identifier] = { | |
| 25 | 61 | __proto__: null, | |
| 26 | 62 | name: data.name, | |
| 63 | + children, | ||
| 27 | 64 | passed_on_attempt: data.details.passed_on_attempt ?? data.details.attempt, | |
| 28 | 65 | }; | |
| 29 | 66 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -699,10 +699,18 @@ class Test extends AsyncResource { | |||
| 699 | 699 | this.root.testDisambiguator.set(testIdentifier, 1); | |
| 700 | 700 | } | |
| 701 | 701 | this.attempt = this.root.harness.previousRuns.length; | |
| 702 | - const previousAttempt = this.root.harness.previousRuns[this.attempt - 1]?.[testIdentifier]?.passed_on_attempt; | ||
| 702 | + const previousAttempt = this.root.harness.previousRuns[this.attempt - 1]?.[testIdentifier]; | ||
| 703 | 703 | if (previousAttempt != null) { | |
| 704 | - this.passedAttempt = previousAttempt; | ||
| 705 | - this.fn = noop; | ||
| 704 | + this.passedAttempt = previousAttempt.passed_on_attempt; | ||
| 705 | + this.fn = () => { | ||
| 706 | + for (let i = 0; i < (previousAttempt.children?.length ?? 0); i++) { | ||
| 707 | + const child = previousAttempt.children[i]; | ||
| 708 | + this.createSubtest(Test, child.name, { __proto__: null }, noop, { | ||
| 709 | + __proto__: null, | ||
| 710 | + loc: [child.line, child.column, child.file], | ||
| 711 | + }, noop).start(); | ||
| 712 | + } | ||
| 713 | + }; | ||
| 706 | 714 | } | |
| 707 | 715 | } | |
| 708 | 716 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,4 +22,19 @@ function ambiguousTest(expectedAttempts) { | |||
| 22 | 22 | } | |
| 23 | 23 | ||
| 24 | 24 | ambiguousTest(0); | |
| 25 | - ambiguousTest(1); | ||
| 25 | + ambiguousTest(1); | ||
| 26 | + | ||
| 27 | + function nestedAmbiguousTest(expectedAttempts) { | ||
| 28 | + return async (t) => { | ||
| 29 | + await t.test('nested', async (tt) => { | ||
| 30 | + await tt.test('2 levels deep', () => {}); | ||
| 31 | + if (t.attempt < expectedAttempts) { | ||
| 32 | + throw new Error(`This test is expected to fail on the first ${expectedAttempts} attempts`); | ||
| 33 | + } | ||
| 34 | + }); | ||
| 35 | + await t.test('ok', () => {}); | ||
| 36 | + }; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + test('nested ambiguous (expectedAttempts=0)', nestedAmbiguousTest(0)); | ||
| 40 | + test('nested ambiguous (expectedAttempts=1)', nestedAmbiguousTest(2)); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,46 +15,74 @@ afterEach(() => rm(stateFile, { force: true })); | |||
| 15 | 15 | ||
| 16 | 16 | const expectedStateFile = [ | |
| 17 | 17 | { | |
| 18 | - 'test/fixtures/test-runner/rerun.js:17:3': { passed_on_attempt: 0, name: 'ambiguous (expectedAttempts=0)' }, | ||
| 19 | 18 | 'test/fixtures/test-runner/rerun.js:9:1': { passed_on_attempt: 0, name: 'ok' }, | |
| 19 | + 'test/fixtures/test-runner/rerun.js:17:3': { passed_on_attempt: 0, name: 'ambiguous (expectedAttempts=0)' }, | ||
| 20 | + 'test/fixtures/test-runner/rerun.js:30:16': { passed_on_attempt: 0, name: '2 levels deep' }, | ||
| 21 | + 'test/fixtures/test-runner/rerun.js:29:13': { passed_on_attempt: 0, name: 'nested' }, | ||
| 22 | + 'test/fixtures/test-runner/rerun.js:35:13': { passed_on_attempt: 0, name: 'ok' }, | ||
| 23 | + 'test/fixtures/test-runner/rerun.js:39:1': { passed_on_attempt: 0, name: 'nested ambiguous (expectedAttempts=0)' }, | ||
| 24 | + 'test/fixtures/test-runner/rerun.js:30:16:(1)': { passed_on_attempt: 0, name: '2 levels deep' }, | ||
| 25 | + 'test/fixtures/test-runner/rerun.js:35:13:(1)': { passed_on_attempt: 0, name: 'ok' }, | ||
| 20 | 26 | }, | |
| 21 | 27 | { | |
| 28 | + 'test/fixtures/test-runner/rerun.js:9:1': { passed_on_attempt: 0, name: 'ok' }, | ||
| 22 | 29 | 'test/fixtures/test-runner/rerun.js:17:3': { passed_on_attempt: 0, name: 'ambiguous (expectedAttempts=0)' }, | |
| 23 | 30 | 'test/fixtures/test-runner/rerun.js:17:3:(1)': { passed_on_attempt: 1, name: 'ambiguous (expectedAttempts=1)' }, | |
| 24 | - 'test/fixtures/test-runner/rerun.js:9:1': { passed_on_attempt: 0, name: 'ok' }, | ||
| 31 | + 'test/fixtures/test-runner/rerun.js:30:16': { passed_on_attempt: 0, name: '2 levels deep' }, | ||
| 32 | + 'test/fixtures/test-runner/rerun.js:29:13': { passed_on_attempt: 0, name: 'nested' }, | ||
| 33 | + 'test/fixtures/test-runner/rerun.js:35:13': { passed_on_attempt: 0, name: 'ok' }, | ||
| 34 | + 'test/fixtures/test-runner/rerun.js:39:1': { passed_on_attempt: 0, name: 'nested ambiguous (expectedAttempts=0)' }, | ||
| 35 | + 'test/fixtures/test-runner/rerun.js:30:16:(1)': { passed_on_attempt: 0, name: '2 levels deep' }, | ||
| 36 | + 'test/fixtures/test-runner/rerun.js:35:13:(1)': { passed_on_attempt: 0, name: 'ok' }, | ||
| 25 | 37 | }, | |
| 26 | 38 | { | |
| 39 | + 'test/fixtures/test-runner/rerun.js:3:1': { passed_on_attempt: 2, name: 'should fail on first two attempts' }, | ||
| 40 | + 'test/fixtures/test-runner/rerun.js:9:1': { passed_on_attempt: 0, name: 'ok' }, | ||
| 27 | 41 | 'test/fixtures/test-runner/rerun.js:17:3': { passed_on_attempt: 0, name: 'ambiguous (expectedAttempts=0)' }, | |
| 28 | 42 | 'test/fixtures/test-runner/rerun.js:17:3:(1)': { passed_on_attempt: 1, name: 'ambiguous (expectedAttempts=1)' }, | |
| 29 | - 'test/fixtures/test-runner/rerun.js:9:1': { passed_on_attempt: 0, name: 'ok' }, | ||
| 30 | - 'test/fixtures/test-runner/rerun.js:3:1': { passed_on_attempt: 2, name: 'should fail on first two attempts' }, | ||
| 43 | + 'test/fixtures/test-runner/rerun.js:30:16': { passed_on_attempt: 0, name: '2 levels deep' }, | ||
| 44 | + 'test/fixtures/test-runner/rerun.js:29:13': { passed_on_attempt: 0, name: 'nested' }, | ||
| 45 | + 'test/fixtures/test-runner/rerun.js:35:13': { passed_on_attempt: 0, name: 'ok' }, | ||
| 46 | + 'test/fixtures/test-runner/rerun.js:39:1': { passed_on_attempt: 0, name: 'nested ambiguous (expectedAttempts=0)' }, | ||
| 47 | + 'test/fixtures/test-runner/rerun.js:29:13:(1)': { passed_on_attempt: 2, name: 'nested' }, | ||
| 48 | + 'test/fixtures/test-runner/rerun.js:30:16:(1)': { passed_on_attempt: 0, name: '2 levels deep' }, | ||
| 49 | + 'test/fixtures/test-runner/rerun.js:35:13:(1)': { passed_on_attempt: 0, name: 'ok' }, | ||
| 50 | + 'test/fixtures/test-runner/rerun.js:40:1': { passed_on_attempt: 2, name: 'nested ambiguous (expectedAttempts=1)' }, | ||
| 31 | 51 | }, | |
| 32 | 52 | ]; | |
| 33 | 53 | ||
| 34 | - const getStateFile = async () => JSON.parse((await readFile(stateFile, 'utf8')).replaceAll('\\\\', '/')); | ||
| 54 | + const getStateFile = async () => { | ||
| 55 | + const res = JSON.parse((await readFile(stateFile, 'utf8')).replaceAll('\\\\', '/')); | ||
| 56 | + res.forEach((entry) => { | ||
| 57 | + for (const item in entry) { | ||
| 58 | + delete entry[item].children; | ||
| 59 | + } | ||
| 60 | + }); | ||
| 61 | + return res; | ||
| 62 | + }; | ||
| 35 | 63 | ||
| 36 | 64 | test('test should pass on third rerun', async () => { | |
| 37 | 65 | const args = ['--test-rerun-failures', stateFile, fixture]; | |
| 38 | 66 | ||
| 39 | 67 | let { code, stdout, signal } = await common.spawnPromisified(process.execPath, args); | |
| 40 | 68 | assert.strictEqual(code, 1); | |
| 41 | 69 | assert.strictEqual(signal, null); | |
| 42 | - assert.match(stdout, /pass 2/); | ||
| 43 | - assert.match(stdout, /fail 2/); | ||
| 70 | + assert.match(stdout, /pass 8/); | ||
| 71 | + assert.match(stdout, /fail 4/); | ||
| 44 | 72 | assert.deepStrictEqual(await getStateFile(), expectedStateFile.slice(0, 1)); | |
| 45 | 73 | ||
| 46 | 74 | ({ code, stdout, signal } = await common.spawnPromisified(process.execPath, args)); | |
| 47 | 75 | assert.strictEqual(code, 1); | |
| 48 | 76 | assert.strictEqual(signal, null); | |
| 49 | - assert.match(stdout, /pass 3/); | ||
| 50 | - assert.match(stdout, /fail 1/); | ||
| 77 | + assert.match(stdout, /pass 9/); | ||
| 78 | + assert.match(stdout, /fail 3/); | ||
| 51 | 79 | assert.deepStrictEqual(await getStateFile(), expectedStateFile.slice(0, 2)); | |
| 52 | 80 | ||
| 53 | 81 | ||
| 54 | 82 | ({ code, stdout, signal } = await common.spawnPromisified(process.execPath, args)); | |
| 55 | 83 | assert.strictEqual(code, 0); | |
| 56 | 84 | assert.strictEqual(signal, null); | |
| 57 | - assert.match(stdout, /pass 4/); | ||
| 85 | + assert.match(stdout, /pass 12/); | ||
| 58 | 86 | assert.match(stdout, /fail 0/); | |
| 59 | 87 | assert.deepStrictEqual(await getStateFile(), expectedStateFile); | |
| 60 | 88 | }); | |
@@ -65,30 +93,30 @@ test('test should pass on third rerun with `--test`', async () => { | |||
| 65 | 93 | let { code, stdout, signal } = await common.spawnPromisified(process.execPath, args); | |
| 66 | 94 | assert.strictEqual(code, 1); | |
| 67 | 95 | assert.strictEqual(signal, null); | |
| 68 | - assert.match(stdout, /pass 2/); | ||
| 69 | - assert.match(stdout, /fail 2/); | ||
| 96 | + assert.match(stdout, /pass 8/); | ||
| 97 | + assert.match(stdout, /fail 4/); | ||
| 70 | 98 | assert.deepStrictEqual(await getStateFile(), expectedStateFile.slice(0, 1)); | |
| 71 | 99 | ||
| 72 | 100 | ({ code, stdout, signal } = await common.spawnPromisified(process.execPath, args)); | |
| 73 | 101 | assert.strictEqual(code, 1); | |
| 74 | 102 | assert.strictEqual(signal, null); | |
| 75 | - assert.match(stdout, /pass 3/); | ||
| 76 | - assert.match(stdout, /fail 1/); | ||
| 103 | + assert.match(stdout, /pass 9/); | ||
| 104 | + assert.match(stdout, /fail 3/); | ||
| 77 | 105 | assert.deepStrictEqual(await getStateFile(), expectedStateFile.slice(0, 2)); | |
| 78 | 106 | ||
| 79 | 107 | ||
| 80 | 108 | ({ code, stdout, signal } = await common.spawnPromisified(process.execPath, args)); | |
| 81 | 109 | assert.strictEqual(code, 0); | |
| 82 | 110 | assert.strictEqual(signal, null); | |
| 83 | - assert.match(stdout, /pass 4/); | ||
| 111 | + assert.match(stdout, /pass 12/); | ||
| 84 | 112 | assert.match(stdout, /fail 0/); | |
| 85 | 113 | assert.deepStrictEqual(await getStateFile(), expectedStateFile); | |
| 86 | 114 | }); | |
| 87 | 115 | ||
| 88 | 116 | test('using `run` api', async () => { | |
| 89 | 117 | let stream = run({ files: [fixture], rerunFailuresFilePath: stateFile }); | |
| 90 | - stream.on('test:pass', common.mustCall(2)); | ||
| 91 | - stream.on('test:fail', common.mustCall(2)); | ||
| 118 | + stream.on('test:pass', common.mustCall(8)); | ||
| 119 | + stream.on('test:fail', common.mustCall(4)); | ||
| 92 | 120 | ||
| 93 | 121 | // eslint-disable-next-line no-unused-vars | |
| 94 | 122 | for await (const _ of stream); | |
@@ -97,8 +125,8 @@ test('using `run` api', async () => { | |||
| 97 | 125 | ||
| 98 | 126 | ||
| 99 | 127 | stream = run({ files: [fixture], rerunFailuresFilePath: stateFile }); | |
| 100 | - stream.on('test:pass', common.mustCall(3)); | ||
| 101 | - stream.on('test:fail', common.mustCall(1)); | ||
| 128 | + stream.on('test:pass', common.mustCall(9)); | ||
| 129 | + stream.on('test:fail', common.mustCall(3)); | ||
| 102 | 130 | ||
| 103 | 131 | // eslint-disable-next-line no-unused-vars | |
| 104 | 132 | for await (const _ of stream); | |
@@ -107,7 +135,7 @@ test('using `run` api', async () => { | |||
| 107 | 135 | ||
| 108 | 136 | ||
| 109 | 137 | stream = run({ files: [fixture], rerunFailuresFilePath: stateFile }); | |
| 110 | - stream.on('test:pass', common.mustCall(4)); | ||
| 138 | + stream.on('test:pass', common.mustCall(12)); | ||
| 111 | 139 | stream.on('test:fail', common.mustNotCall()); | |
| 112 | 140 | ||
| 113 | 141 | // eslint-disable-next-line no-unused-vars | |
| Back | FazBrowse Home | New Git URL |
0 commit comments