From e2fd5a4be66717549693f02c1e2f53b8834c8be1 Mon Sep 17 00:00:00 2001 From: Timothy Shiu Date: Thu, 25 Jul 2019 12:59:47 -0700 Subject: [PATCH 1/2] extend --match to support hash (generated from unique title) --- lib/cli.js | 2 +- lib/reporters/colors.js | 1 + lib/reporters/verbose.js | 12 ++++++------ lib/runner.js | 25 ++++++++++++++++++++++--- lib/test.js | 7 +++++++ package-lock.json | 6 ++++++ package.json | 1 + test/api.js | 10 ++++++++++ 8 files changed, 54 insertions(+), 10 deletions(-) diff --git a/lib/cli.js b/lib/cli.js index b5d3c3497..e0e28d6fc 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -39,7 +39,7 @@ exports.run = async () => { // eslint-disable-line complexity Options --watch, -w Re-run tests when tests and source files change - --match, -m Only run tests with matching title (Can be repeated) + --match, -m Only run tests with matching title/hash (Can be repeated) --update-snapshots, -u Update snapshots --fail-fast Stop after first test failure --timeout, -T Set global timeout (milliseconds or human-readable, e.g. 10s, 2m) diff --git a/lib/reporters/colors.js b/lib/reporters/colors.js index a03dbaead..994cbaa8f 100644 --- a/lib/reporters/colors.js +++ b/lib/reporters/colors.js @@ -12,5 +12,6 @@ module.exports = { errorSource: chalk.gray, errorStack: chalk.gray, stack: chalk.red, + hash: chalk.dim, information: chalk.magenta }; diff --git a/lib/reporters/verbose.js b/lib/reporters/verbose.js index 9f80b0a9e..6f79df75d 100644 --- a/lib/reporters/verbose.js +++ b/lib/reporters/verbose.js @@ -125,16 +125,16 @@ class VerboseReporter { break; case 'hook-finished': if (evt.logs.length > 0) { - this.lineWriter.writeLine(` ${this.prefixTitle(evt.testFile, evt.title)}`); + this.lineWriter.writeLine(` ${evt.hash} ${this.prefixTitle(evt.testFile, evt.title)}`); this.writeLogs(evt); } break; case 'selected-test': if (evt.skip) { - this.lineWriter.writeLine(colors.skip(`- ${this.prefixTitle(evt.testFile, evt.title)}`)); + this.lineWriter.writeLine(colors.skip(`- ${evt.hash} ${this.prefixTitle(evt.testFile, evt.title)}`)); } else if (evt.todo) { - this.lineWriter.writeLine(colors.todo(`- ${this.prefixTitle(evt.testFile, evt.title)}`)); + this.lineWriter.writeLine(colors.todo(`- ${evt.hash} ${this.prefixTitle(evt.testFile, evt.title)}`)); } break; @@ -293,15 +293,15 @@ class VerboseReporter { writeTestSummary(evt) { if (evt.type === 'hook-failed' || evt.type === 'test-failed') { - this.lineWriter.writeLine(`${colors.error(figures.cross)} ${this.prefixTitle(evt.testFile, evt.title)} ${colors.error(evt.err.message)}`); + this.lineWriter.writeLine(`${colors.error(figures.cross)} ${colors.hash(evt.hash)} ${this.prefixTitle(evt.testFile, evt.title)} ${colors.error(evt.err.message)}`); } else if (evt.knownFailing) { - this.lineWriter.writeLine(`${colors.error(figures.tick)} ${colors.error(this.prefixTitle(evt.testFile, evt.title))}`); + this.lineWriter.writeLine(`${colors.error(figures.tick)} ${colors.hash(evt.hash)} ${colors.error(this.prefixTitle(evt.testFile, evt.title))}`); } else { // Display duration only over a threshold const threshold = 100; const duration = evt.duration > threshold ? colors.duration(' (' + prettyMs(evt.duration) + ')') : ''; - this.lineWriter.writeLine(`${colors.pass(figures.tick)} ${this.prefixTitle(evt.testFile, evt.title)}${duration}`); + this.lineWriter.writeLine(`${colors.pass(figures.tick)} ${colors.hash(evt.hash)} ${this.prefixTitle(evt.testFile, evt.title)}${duration}`); } this.writeLogs(evt); diff --git a/lib/runner.js b/lib/runner.js index 18af02f7a..b92025ff5 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -79,17 +79,22 @@ class Runner extends Emittery { uniqueTestTitles.add(specifiedTitle); } + const specifiedHash = Runnable.getTitleHash(specifiedTitle); + if (this.match.length > 0) { // --match selects TODO tests. - if (matcher([specifiedTitle], this.match).length === 1) { + const titleMatched = matcher([specifiedTitle], this.match).length === 1; + const hashMatched = matcher([specifiedHash], this.match).length === 1; + if (titleMatched || hashMatched) { metadata.exclusive = true; this.runOnlyExclusive = true; } } - this.tasks.todo.push({title: specifiedTitle, metadata}); + this.tasks.todo.push({hash: specifiedHash, title: specifiedTitle, metadata}); this.emit('stateChange', { type: 'declared-test', + hash: specifiedHash, title: specifiedTitle, knownFailing: false, todo: true @@ -126,7 +131,10 @@ class Runner extends Emittery { } } + const hash = Runnable.getTitleHash(title); + const task = { + hash, title, implementation, args, @@ -136,7 +144,9 @@ class Runner extends Emittery { if (metadata.type === 'test') { if (this.match.length > 0) { // --match overrides .only() - task.metadata.exclusive = matcher([title], this.match).length === 1; + const titleMatched = matcher([title], this.match).length === 1; + const hashMatched = matcher([hash], this.match).length === 1; + task.metadata.exclusive = titleMatched || hashMatched; } if (task.metadata.exclusive) { @@ -146,6 +156,7 @@ class Runner extends Emittery { this.tasks[metadata.serial ? 'serial' : 'concurrent'].push(task); this.emit('stateChange', { type: 'declared-test', + hash, title, knownFailing: metadata.failing, todo: false @@ -283,6 +294,7 @@ class Runner extends Emittery { if (result.passed) { this.emit('stateChange', { type: 'hook-finished', + hash: result.hash, title: result.title, duration: result.duration, logs: result.logs @@ -290,6 +302,7 @@ class Runner extends Emittery { } else { this.emit('stateChange', { type: 'hook-failed', + hash: result.hash, title: result.title, err: serializeError('Hook failure', true, result.error), duration: result.duration, @@ -316,6 +329,7 @@ class Runner extends Emittery { compareTestSnapshot: this.boundCompareTestSnapshot, updateSnapshots: this.updateSnapshots, metadata: task.metadata, + hash: task.hash, title: task.title }); @@ -323,6 +337,7 @@ class Runner extends Emittery { if (result.passed) { this.emit('stateChange', { type: 'test-passed', + hash: result.hash, title: result.title, duration: result.duration, knownFailing: result.metadata.failing, @@ -332,6 +347,7 @@ class Runner extends Emittery { } else { this.emit('stateChange', { type: 'test-failed', + hash: result.hash, title: result.title, err: serializeError('Test failure', true, result.error), duration: result.duration, @@ -356,6 +372,7 @@ class Runner extends Emittery { this.emit('stateChange', { type: 'selected-test', + hash: task.hash, title: task.title, knownFailing: task.metadata.failing, skip: task.metadata.skipped, @@ -374,6 +391,7 @@ class Runner extends Emittery { this.emit('stateChange', { type: 'selected-test', + hash: task.hash, title: task.title, knownFailing: task.metadata.failing, skip: task.metadata.skipped, @@ -396,6 +414,7 @@ class Runner extends Emittery { this.emit('stateChange', { type: 'selected-test', + hash: task.hash, title: task.title, knownFailing: false, skip: false, diff --git a/lib/test.js b/lib/test.js index 10b277ec8..659a053dc 100644 --- a/lib/test.js +++ b/lib/test.js @@ -4,6 +4,7 @@ const observableToPromise = require('observable-to-promise'); const isPromise = require('is-promise'); const isObservable = require('is-observable'); const plur = require('plur'); +const objectHash = require('object-hash'); const assert = require('./assert'); const nowAndTimers = require('./now-and-timers'); const concordanceOptions = require('./concordance-options').default; @@ -102,6 +103,7 @@ class Test { this.failWithoutAssertions = options.failWithoutAssertions; this.fn = options.fn; this.metadata = options.metadata; + this.hash = Test.getTitleHash(options.title); this.title = options.title; this.logs = []; @@ -140,6 +142,10 @@ class Test { this.timeoutMs = 0; } + static getTitleHash(title) { + return title ? objectHash(title).substring(0, 10) : undefined; + } + bindEndCallback() { if (this.metadata.callback) { return (error, savedError) => { @@ -481,6 +487,7 @@ class Test { logs: this.logs, metadata: this.metadata, passed, + hash: this.hash, title: this.title }; } diff --git a/package-lock.json b/package-lock.json index d5b03fcb8..910d1ccc9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6283,6 +6283,12 @@ } } }, + "object-hash": { + "version": "1.3.1", + "resolved": "http://sinopia.samsungmtv.com/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", + "dev": true + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", diff --git a/package.json b/package.json index 3dd582f64..6746efa5a 100644 --- a/package.json +++ b/package.json @@ -144,6 +144,7 @@ "git-branch": "^2.0.1", "has-ansi": "^3.0.0", "lolex": "^4.1.0", + "object-hash": "^1.3.1", "proxyquire": "^2.1.0", "react": "^16.8.6", "react-test-renderer": "^16.8.6", diff --git a/test/api.js b/test/api.js index b26984fce..5337d4077 100644 --- a/test/api.js +++ b/test/api.js @@ -94,11 +94,13 @@ test('fail-fast mode - single file & serial', t => { if (evt.type === 'test-failed') { tests.push({ ok: false, + hash: evt.hash, title: evt.title }); } else if (evt.type === 'test-passed') { tests.push({ ok: true, + hash: evt.hash, title: evt.title }); } @@ -137,12 +139,14 @@ test('fail-fast mode - multiple files & serial', t => { tests.push({ ok: false, testFile: evt.testFile, + hash: evt.hash, title: evt.title }); } else if (evt.type === 'test-passed') { tests.push({ ok: true, testFile: evt.testFile, + hash: evt.hash, title: evt.title }); } @@ -183,12 +187,14 @@ test('fail-fast mode - multiple files & interrupt', t => { tests.push({ ok: false, testFile: evt.testFile, + hash: evt.hash, title: evt.title }); } else if (evt.type === 'test-passed') { tests.push({ ok: true, testFile: evt.testFile, + hash: evt.hash, title: evt.title }); } @@ -237,11 +243,13 @@ test('fail-fast mode - crash & serial', t => { if (evt.type === 'test-failed') { tests.push({ ok: false, + hash: evt.hash, title: evt.title }); } else if (evt.type === 'test-passed') { tests.push({ ok: true, + hash: evt.hash, title: evt.title }); } else if (evt.type === 'worker-failed') { @@ -279,11 +287,13 @@ test('fail-fast mode - timeout & serial', t => { if (evt.type === 'test-failed') { tests.push({ ok: false, + hash: evt.hash, title: evt.title }); } else if (evt.type === 'test-passed') { tests.push({ ok: true, + hash: evt.hash, title: evt.title }); } else if (evt.type === 'timeout') { From 3312ec27996000b236b863b8b1eb4372ceb9b9af Mon Sep 17 00:00:00 2001 From: Timothy Shiu Date: Thu, 25 Jul 2019 15:46:49 -0700 Subject: [PATCH 2/2] update --match extension test result --- test/api.js | 9 +++ test/reporters/verbose.failfast.log | 2 +- test/reporters/verbose.failfast2.log | 2 +- test/reporters/verbose.only.log | 4 +- test/reporters/verbose.regular.log | 60 +++++++++---------- .../verbose.timeoutinmultiplefiles.log | 8 +-- .../reporters/verbose.timeoutinsinglefile.log | 4 +- test/reporters/verbose.timeoutwithmatch.log | 2 +- test/reporters/verbose.watch.log | 6 +- test/runner.js | 1 + 10 files changed, 54 insertions(+), 44 deletions(-) diff --git a/test/api.js b/test/api.js index 5337d4077..6472bfceb 100644 --- a/test/api.js +++ b/test/api.js @@ -112,12 +112,15 @@ test('fail-fast mode - single file & serial', t => { t.ok(api.options.failFast); t.strictDeepEqual(tests, [{ ok: true, + hash: '1221417f85', title: 'first pass' }, { ok: false, + hash: 'a9039c8aa0', title: 'second fail' }, { ok: true, + hash: '09fda0bbf9', title: 'third pass' }]); t.is(runStatus.stats.passedTests, 2); @@ -162,10 +165,12 @@ test('fail-fast mode - multiple files & serial', t => { t.strictDeepEqual(tests, [{ ok: true, testFile: path.join(__dirname, 'fixture/fail-fast/multiple-files/fails.js'), + hash: '1221417f85', title: 'first pass' }, { ok: false, testFile: path.join(__dirname, 'fixture/fail-fast/multiple-files/fails.js'), + hash: 'a9039c8aa0', title: 'second fail' }]); t.is(runStatus.stats.passedTests, 1); @@ -210,18 +215,22 @@ test('fail-fast mode - multiple files & interrupt', t => { t.strictDeepEqual(tests, [{ ok: true, testFile: path.join(__dirname, 'fixture/fail-fast/multiple-files/fails.js'), + hash: '1221417f85', title: 'first pass' }, { ok: false, testFile: path.join(__dirname, 'fixture/fail-fast/multiple-files/fails.js'), + hash: 'a9039c8aa0', title: 'second fail' }, { ok: true, testFile: path.join(__dirname, 'fixture/fail-fast/multiple-files/fails.js'), + hash: '09fda0bbf9', title: 'third pass' }, { ok: true, testFile: path.join(__dirname, 'fixture/fail-fast/multiple-files/passes-slow.js'), + hash: '1221417f85', title: 'first pass' }]); t.is(runStatus.stats.passedTests, 3); diff --git a/test/reporters/verbose.failfast.log b/test/reporters/verbose.failfast.log index b3d168d11..f2c2a6beb 100644 --- a/test/reporters/verbose.failfast.log +++ b/test/reporters/verbose.failfast.log @@ -1,6 +1,6 @@ ---tty-stream-chunk-separator - ✖ a › fails Test failed via `t.fail()` + ✖ 9eaac03e61 a › fails Test failed via `t.fail()` ---tty-stream-chunk-separator 1 test failed diff --git a/test/reporters/verbose.failfast2.log b/test/reporters/verbose.failfast2.log index 6e03d073b..f6f389871 100644 --- a/test/reporters/verbose.failfast2.log +++ b/test/reporters/verbose.failfast2.log @@ -1,6 +1,6 @@ ---tty-stream-chunk-separator - ✖ a › fails Test failed via `t.fail()` + ✖ 9eaac03e61 a › fails Test failed via `t.fail()` ---tty-stream-chunk-separator 1 test failed diff --git a/test/reporters/verbose.only.log b/test/reporters/verbose.only.log index 67c5e210e..dd8de9c62 100644 --- a/test/reporters/verbose.only.log +++ b/test/reporters/verbose.only.log @@ -1,8 +1,8 @@ ---tty-stream-chunk-separator - ✔ a › only + ✔ e90e64e828 a › only ---tty-stream-chunk-separator - ✔ b › passes + ✔ 63d04ac302 b › passes ---tty-stream-chunk-separator 2 tests passed diff --git a/test/reporters/verbose.regular.log b/test/reporters/verbose.regular.log index cc688a345..9546db10a 100644 --- a/test/reporters/verbose.regular.log +++ b/test/reporters/verbose.regular.log @@ -13,9 +13,9 @@ ---tty-stream-chunk-separator ✖ test/fixture/report/regular/bad-test-chain.js exited with a non-zero exit code: 1 ---tty-stream-chunk-separator - ✔ unhandled-rejection › passes + ✔ 63d04ac302 unhandled-rejection › passes ---tty-stream-chunk-separator - ✔ unhandled-rejection › unhandled non-error rejection + ✔ b44eae8674 unhandled-rejection › unhandled non-error rejection ---tty-stream-chunk-separator Unhandled rejection in test/fixture/report/regular/unhandled-rejection.js @@ -34,7 +34,7 @@ null ---tty-stream-chunk-separator - ✔ uncaught-exception › passes + ✔ 63d04ac302 uncaught-exception › passes ---tty-stream-chunk-separator Uncaught exception in test/fixture/report/regular/uncaught-exception.js @@ -50,71 +50,71 @@ ---tty-stream-chunk-separator ✖ test/fixture/report/regular/uncaught-exception.js exited with a non-zero exit code: 1 ---tty-stream-chunk-separator - ✖ traces-in-t-throws › throws + ✖ 9507681c96 traces-in-t-throws › throws ---tty-stream-chunk-separator - ✖ traces-in-t-throws › notThrows + ✖ 99e87f2b1a traces-in-t-throws › notThrows ---tty-stream-chunk-separator - ✖ traces-in-t-throws › notThrowsAsync + ✖ 23931cf3aa traces-in-t-throws › notThrowsAsync ---tty-stream-chunk-separator - ✖ traces-in-t-throws › throwsAsync + ✖ a1f7fc6863 traces-in-t-throws › throwsAsync ---tty-stream-chunk-separator - ✖ traces-in-t-throws › throwsAsync different error + ✖ 8cfa623137 traces-in-t-throws › throwsAsync different error ---tty-stream-chunk-separator stdout ---tty-stream-chunk-separator stderr ---tty-stream-chunk-separator - - test › skip + - dcdac2905b test › skip ---tty-stream-chunk-separator - - test › todo + - 19a13f2a6c test › todo ---tty-stream-chunk-separator - ✔ test › passes + ✔ 63d04ac302 test › passes ---tty-stream-chunk-separator - ✖ test › fails Test failed via `t.fail()` + ✖ 9eaac03e61 test › fails Test failed via `t.fail()` ---tty-stream-chunk-separator - ✔ test › known failure + ✔ a6ca6858c0 test › known failure ---tty-stream-chunk-separator - ✖ test › no longer failing Test was expected to fail, but succeeded, you should stop marking the test as failing + ✖ 81c2e00085 test › no longer failing Test was expected to fail, but succeeded, you should stop marking the test as failing ---tty-stream-chunk-separator - ✖ test › logs Test failed via `t.fail()` + ✖ 5f363d84ec test › logs Test failed via `t.fail()` ℹ hello ℹ world ---tty-stream-chunk-separator - ✖ test › formatted + ✖ 964fac7e8e test › formatted ---tty-stream-chunk-separator - ✖ test › power-assert + ✖ 66b52c3d09 test › power-assert ---tty-stream-chunk-separator - ✖ test › bad throws Improper usage of `t.throws()` detected + ✖ ea408ec6c1 test › bad throws Improper usage of `t.throws()` detected ---tty-stream-chunk-separator - ✖ test › bad notThrows Improper usage of `t.notThrows()` detected + ✖ 6b26aa87ad test › bad notThrows Improper usage of `t.notThrows()` detected ---tty-stream-chunk-separator - ✖ test › implementation throws non-error Error thrown in test + ✖ f86d05e5da test › implementation throws non-error Error thrown in test ---tty-stream-chunk-separator - ✔ slow › slow (000ms) + ✔ a172f324e1 slow › slow (000ms) ---tty-stream-chunk-separator - output-in-hook › before hook + e2795187d9 output-in-hook › before hook ℹ before ---tty-stream-chunk-separator - output-in-hook › beforeEach hook for passing test + 9a5cf57f11 output-in-hook › beforeEach hook for passing test ℹ beforeEach ---tty-stream-chunk-separator - output-in-hook › beforeEach hook for failing test + 0b958afd77 output-in-hook › beforeEach hook for failing test ℹ beforeEach ---tty-stream-chunk-separator - ✔ output-in-hook › passing test + ✔ 4f05f173c9 output-in-hook › passing test ---tty-stream-chunk-separator - ✖ output-in-hook › failing test Test failed via `t.fail()` + ✖ 222e7143b4 output-in-hook › failing test Test failed via `t.fail()` ---tty-stream-chunk-separator - output-in-hook › afterEach hook for passing test + f7fe2b1cfe output-in-hook › afterEach hook for passing test ℹ afterEach ---tty-stream-chunk-separator - output-in-hook › afterEach.always hook for failing test + b9941c5eef output-in-hook › afterEach.always hook for failing test ℹ afterEachAlways ---tty-stream-chunk-separator - output-in-hook › afterEach.always hook for passing test + ea197df294 output-in-hook › afterEach.always hook for passing test ℹ afterEachAlways ---tty-stream-chunk-separator - output-in-hook › cleanup + 2b9e0faadf output-in-hook › cleanup ℹ afterAlways ---tty-stream-chunk-separator diff --git a/test/reporters/verbose.timeoutinmultiplefiles.log b/test/reporters/verbose.timeoutinmultiplefiles.log index 02e02c241..590c05b32 100644 --- a/test/reporters/verbose.timeoutinmultiplefiles.log +++ b/test/reporters/verbose.timeoutinmultiplefiles.log @@ -1,8 +1,8 @@ ---tty-stream-chunk-separator - ✔ a › a passes + ✔ 63ae91b74d a › a passes ---tty-stream-chunk-separator - ✔ a › a passes two + ✔ a8686a7d01 a › a passes two ---tty-stream-chunk-separator  ✖ Timed out while running tests @@ -13,9 +13,9 @@ ◌ a › a slow two ---tty-stream-chunk-separator - ✔ b › b passes + ✔ 8bcd3711a1 b › b passes ---tty-stream-chunk-separator - ✔ b › b passes two + ✔ 45a4102d84 b › b passes two ---tty-stream-chunk-separator  ✖ Timed out while running tests diff --git a/test/reporters/verbose.timeoutinsinglefile.log b/test/reporters/verbose.timeoutinsinglefile.log index 8c69a4b66..b308e12e4 100644 --- a/test/reporters/verbose.timeoutinsinglefile.log +++ b/test/reporters/verbose.timeoutinsinglefile.log @@ -1,8 +1,8 @@ ---tty-stream-chunk-separator - ✔ passes + ✔ 63d04ac302 passes ---tty-stream-chunk-separator - ✔ passes two + ✔ 084c165aae passes two ---tty-stream-chunk-separator  ✖ Timed out while running tests diff --git a/test/reporters/verbose.timeoutwithmatch.log b/test/reporters/verbose.timeoutwithmatch.log index 38edccf4e..717d4379b 100644 --- a/test/reporters/verbose.timeoutwithmatch.log +++ b/test/reporters/verbose.timeoutwithmatch.log @@ -1,6 +1,6 @@ ---tty-stream-chunk-separator - ✔ passes needle + ✔ 581779f4d9 passes needle ---tty-stream-chunk-separator  ✖ Timed out while running tests diff --git a/test/reporters/verbose.watch.log b/test/reporters/verbose.watch.log index 31689cbd4..026b40d14 100644 --- a/test/reporters/verbose.watch.log +++ b/test/reporters/verbose.watch.log @@ -1,6 +1,6 @@ ---tty-stream-chunk-separator - ✔ test › passes + ✔ 63d04ac302 test › passes ---tty-stream-chunk-separator 1 test passed [17:19:12] @@ -10,7 +10,7 @@ ---tty-stream-chunk-separator ---tty-stream-chunk-separator - ✔ test › passes + ✔ 63d04ac302 test › passes ---tty-stream-chunk-separator 1 test passed [17:19:12] @@ -21,7 +21,7 @@ ---tty-stream-chunk-separator ---tty-stream-chunk-separator - ✔ test › passes + ✔ 63d04ac302 test › passes ---tty-stream-chunk-separator 1 test passed [17:19:12] diff --git a/test/runner.js b/test/runner.js index 1c1b1f63e..e3e9ae135 100644 --- a/test/runner.js +++ b/test/runner.js @@ -49,6 +49,7 @@ test('runner emits "stateChange" events', t => { if (evt.type === 'declared-test') { t.deepEqual(evt, { type: 'declared-test', + hash: '7cd3edacc4', title: 'foo', knownFailing: false, todo: false