Skip to content

Commit d617ffe

Browse files
author
Timothy Shiu
committed
extend --match to support hash (generated from unique title)
1 parent 2fc7d56 commit d617ffe

File tree

8 files changed

+52
-10
lines changed

8 files changed

+52
-10
lines changed

lib/cli.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ exports.run = async () => { // eslint-disable-line complexity
3939
4040
Options
4141
--watch, -w Re-run tests when tests and source files change
42-
--match, -m Only run tests with matching title (Can be repeated)
42+
--match, -m Only run tests with matching title/hash (Can be repeated)
4343
--update-snapshots, -u Update snapshots
4444
--fail-fast Stop after first test failure
4545
--timeout, -T Set global timeout (milliseconds or human-readable, e.g. 10s, 2m)

lib/reporters/colors.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ module.exports = {
1212
errorSource: chalk.gray,
1313
errorStack: chalk.gray,
1414
stack: chalk.red,
15+
hash: chalk.dim,
1516
information: chalk.magenta
1617
};

lib/reporters/verbose.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,16 @@ class VerboseReporter {
125125
break;
126126
case 'hook-finished':
127127
if (evt.logs.length > 0) {
128-
this.lineWriter.writeLine(` ${this.prefixTitle(evt.testFile, evt.title)}`);
128+
this.lineWriter.writeLine(` ${evt.hash} ${this.prefixTitle(evt.testFile, evt.title)}`);
129129
this.writeLogs(evt);
130130
}
131131

132132
break;
133133
case 'selected-test':
134134
if (evt.skip) {
135-
this.lineWriter.writeLine(colors.skip(`- ${this.prefixTitle(evt.testFile, evt.title)}`));
135+
this.lineWriter.writeLine(colors.skip(`- ${evt.hash} ${this.prefixTitle(evt.testFile, evt.title)}`));
136136
} else if (evt.todo) {
137-
this.lineWriter.writeLine(colors.todo(`- ${this.prefixTitle(evt.testFile, evt.title)}`));
137+
this.lineWriter.writeLine(colors.todo(`- ${evt.hash} ${this.prefixTitle(evt.testFile, evt.title)}`));
138138
}
139139

140140
break;
@@ -293,15 +293,15 @@ class VerboseReporter {
293293

294294
writeTestSummary(evt) {
295295
if (evt.type === 'hook-failed' || evt.type === 'test-failed') {
296-
this.lineWriter.writeLine(`${colors.error(figures.cross)} ${this.prefixTitle(evt.testFile, evt.title)} ${colors.error(evt.err.message)}`);
296+
this.lineWriter.writeLine(`${colors.error(figures.cross)} ${colors.hash(evt.hash)} ${this.prefixTitle(evt.testFile, evt.title)} ${colors.error(evt.err.message)}`);
297297
} else if (evt.knownFailing) {
298-
this.lineWriter.writeLine(`${colors.error(figures.tick)} ${colors.error(this.prefixTitle(evt.testFile, evt.title))}`);
298+
this.lineWriter.writeLine(`${colors.error(figures.tick)} ${colors.hash(evt.hash)} ${colors.error(this.prefixTitle(evt.testFile, evt.title))}`);
299299
} else {
300300
// Display duration only over a threshold
301301
const threshold = 100;
302302
const duration = evt.duration > threshold ? colors.duration(' (' + prettyMs(evt.duration) + ')') : '';
303303

304-
this.lineWriter.writeLine(`${colors.pass(figures.tick)} ${this.prefixTitle(evt.testFile, evt.title)}${duration}`);
304+
this.lineWriter.writeLine(`${colors.pass(figures.tick)} ${colors.hash(evt.hash)} ${this.prefixTitle(evt.testFile, evt.title)}${duration}`);
305305
}
306306

307307
this.writeLogs(evt);

lib/runner.js

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22
const Emittery = require('emittery');
33
const matcher = require('matcher');
4+
const objectHash = require('object-hash');
45
const ContextRef = require('./context-ref');
56
const createChain = require('./create-chain');
67
const snapshotManager = require('./snapshot-manager');
@@ -79,9 +80,13 @@ class Runner extends Emittery {
7980
uniqueTestTitles.add(specifiedTitle);
8081
}
8182

83+
const specifiedHash = this.getTitleHash(specifiedTitle)
84+
8285
if (this.match.length > 0) {
8386
// --match selects TODO tests.
84-
if (matcher([specifiedTitle], this.match).length === 1) {
87+
const titleMatched = matcher([specifiedTitle], this.match).length === 1;
88+
const hashMatched = matcher([specifiedHash], this.match).length === 1;
89+
if (titleMatched || hashMatched) {
8590
metadata.exclusive = true;
8691
this.runOnlyExclusive = true;
8792
}
@@ -90,6 +95,7 @@ class Runner extends Emittery {
9095
this.tasks.todo.push({title: specifiedTitle, metadata});
9196
this.emit('stateChange', {
9297
type: 'declared-test',
98+
hash: specifiedHash,
9399
title: specifiedTitle,
94100
knownFailing: false,
95101
todo: true
@@ -125,8 +131,10 @@ class Runner extends Emittery {
125131
uniqueTestTitles.add(title);
126132
}
127133
}
134+
const hash = this.getTitleHash(title);
128135

129136
const task = {
137+
hash,
130138
title,
131139
implementation,
132140
args,
@@ -136,7 +144,9 @@ class Runner extends Emittery {
136144
if (metadata.type === 'test') {
137145
if (this.match.length > 0) {
138146
// --match overrides .only()
139-
task.metadata.exclusive = matcher([title], this.match).length === 1;
147+
const titleMatched = matcher([title], this.match).length === 1;
148+
const hashMatched = matcher([hash], this.match).length === 1;
149+
task.metadata.exclusive = titleMatched || hashMatched;
140150
}
141151

142152
if (task.metadata.exclusive) {
@@ -146,6 +156,7 @@ class Runner extends Emittery {
146156
this.tasks[metadata.serial ? 'serial' : 'concurrent'].push(task);
147157
this.emit('stateChange', {
148158
type: 'declared-test',
159+
hash,
149160
title,
150161
knownFailing: metadata.failing,
151162
todo: false
@@ -165,7 +176,9 @@ class Runner extends Emittery {
165176
always: false
166177
}, meta);
167178
}
168-
179+
getTitleHash(title) {
180+
return title ? objectHash(title).substring(0, 10) : undefined;
181+
}
169182
compareTestSnapshot(options) {
170183
if (!this.snapshots) {
171184
this.snapshots = snapshotManager.load({
@@ -276,20 +289,23 @@ class Runner extends Emittery {
276289
compareTestSnapshot: this.boundCompareTestSnapshot,
277290
updateSnapshots: this.updateSnapshots,
278291
metadata: task.metadata,
292+
hash: this.getTitleHash(`${task.title}${titleSuffix || ''}`),
279293
title: `${task.title}${titleSuffix || ''}`
280294
}));
281295
const outcome = await this.runMultiple(hooks, this.serial);
282296
for (const result of outcome.storedResults) {
283297
if (result.passed) {
284298
this.emit('stateChange', {
285299
type: 'hook-finished',
300+
hash: result.hash,
286301
title: result.title,
287302
duration: result.duration,
288303
logs: result.logs
289304
});
290305
} else {
291306
this.emit('stateChange', {
292307
type: 'hook-failed',
308+
hash: result.hash,
293309
title: result.title,
294310
err: serializeError('Hook failure', true, result.error),
295311
duration: result.duration,
@@ -316,13 +332,15 @@ class Runner extends Emittery {
316332
compareTestSnapshot: this.boundCompareTestSnapshot,
317333
updateSnapshots: this.updateSnapshots,
318334
metadata: task.metadata,
335+
hash: task.hash,
319336
title: task.title
320337
});
321338

322339
const result = await this.runSingle(test);
323340
if (result.passed) {
324341
this.emit('stateChange', {
325342
type: 'test-passed',
343+
hash: result.hash,
326344
title: result.title,
327345
duration: result.duration,
328346
knownFailing: result.metadata.failing,
@@ -332,6 +350,7 @@ class Runner extends Emittery {
332350
} else {
333351
this.emit('stateChange', {
334352
type: 'test-failed',
353+
hash: result.hash,
335354
title: result.title,
336355
err: serializeError('Test failure', true, result.error),
337356
duration: result.duration,
@@ -356,6 +375,7 @@ class Runner extends Emittery {
356375

357376
this.emit('stateChange', {
358377
type: 'selected-test',
378+
hash: task.hash,
359379
title: task.title,
360380
knownFailing: task.metadata.failing,
361381
skip: task.metadata.skipped,
@@ -374,6 +394,7 @@ class Runner extends Emittery {
374394

375395
this.emit('stateChange', {
376396
type: 'selected-test',
397+
hash: task.hash,
377398
title: task.title,
378399
knownFailing: task.metadata.failing,
379400
skip: task.metadata.skipped,
@@ -396,6 +417,7 @@ class Runner extends Emittery {
396417

397418
this.emit('stateChange', {
398419
type: 'selected-test',
420+
hash: task.hash,
399421
title: task.title,
400422
knownFailing: false,
401423
skip: false,

lib/test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ class Test {
102102
this.failWithoutAssertions = options.failWithoutAssertions;
103103
this.fn = options.fn;
104104
this.metadata = options.metadata;
105+
this.hash = options.hash;
105106
this.title = options.title;
106107
this.logs = [];
107108

@@ -481,6 +482,7 @@ class Test {
481482
logs: this.logs,
482483
metadata: this.metadata,
483484
passed,
485+
hash: this.hash,
484486
title: this.title
485487
};
486488
}

package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@
144144
"git-branch": "^2.0.1",
145145
"has-ansi": "^3.0.0",
146146
"lolex": "^4.1.0",
147+
"object-hash": "^1.3.1",
147148
"proxyquire": "^2.1.0",
148149
"react": "^16.8.6",
149150
"react-test-renderer": "^16.8.6",

test/api.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,13 @@ test('fail-fast mode - single file & serial', t => {
9494
if (evt.type === 'test-failed') {
9595
tests.push({
9696
ok: false,
97+
hash: evt.hash,
9798
title: evt.title
9899
});
99100
} else if (evt.type === 'test-passed') {
100101
tests.push({
101102
ok: true,
103+
hash: evt.hash,
102104
title: evt.title
103105
});
104106
}
@@ -137,12 +139,14 @@ test('fail-fast mode - multiple files & serial', t => {
137139
tests.push({
138140
ok: false,
139141
testFile: evt.testFile,
142+
hash: evt.hash,
140143
title: evt.title
141144
});
142145
} else if (evt.type === 'test-passed') {
143146
tests.push({
144147
ok: true,
145148
testFile: evt.testFile,
149+
hash: evt.hash,
146150
title: evt.title
147151
});
148152
}
@@ -183,12 +187,14 @@ test('fail-fast mode - multiple files & interrupt', t => {
183187
tests.push({
184188
ok: false,
185189
testFile: evt.testFile,
190+
hash: evt.hash,
186191
title: evt.title
187192
});
188193
} else if (evt.type === 'test-passed') {
189194
tests.push({
190195
ok: true,
191196
testFile: evt.testFile,
197+
hash: evt.hash,
192198
title: evt.title
193199
});
194200
}
@@ -237,11 +243,13 @@ test('fail-fast mode - crash & serial', t => {
237243
if (evt.type === 'test-failed') {
238244
tests.push({
239245
ok: false,
246+
hash: evt.hash,
240247
title: evt.title
241248
});
242249
} else if (evt.type === 'test-passed') {
243250
tests.push({
244251
ok: true,
252+
hash: evt.hash,
245253
title: evt.title
246254
});
247255
} else if (evt.type === 'worker-failed') {
@@ -279,11 +287,13 @@ test('fail-fast mode - timeout & serial', t => {
279287
if (evt.type === 'test-failed') {
280288
tests.push({
281289
ok: false,
290+
hash: evt.hash,
282291
title: evt.title
283292
});
284293
} else if (evt.type === 'test-passed') {
285294
tests.push({
286295
ok: true,
296+
hash: evt.hash,
287297
title: evt.title
288298
});
289299
} else if (evt.type === 'timeout') {

0 commit comments

Comments
 (0)