Skip to content

Commit 3efdf3d

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

File tree

8 files changed

+54
-9
lines changed

8 files changed

+54
-9
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: 27 additions & 2 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
@@ -126,7 +132,10 @@ class Runner extends Emittery {
126132
}
127133
}
128134

135+
const hash = this.getTitleHash(title);
136+
129137
const task = {
138+
hash,
130139
title,
131140
implementation,
132141
args,
@@ -136,7 +145,9 @@ class Runner extends Emittery {
136145
if (metadata.type === 'test') {
137146
if (this.match.length > 0) {
138147
// --match overrides .only()
139-
task.metadata.exclusive = matcher([title], this.match).length === 1;
148+
const titleMatched = matcher([title], this.match).length === 1;
149+
const hashMatched = matcher([hash], this.match).length === 1;
150+
task.metadata.exclusive = titleMatched || hashMatched;
140151
}
141152

142153
if (task.metadata.exclusive) {
@@ -146,6 +157,7 @@ class Runner extends Emittery {
146157
this.tasks[metadata.serial ? 'serial' : 'concurrent'].push(task);
147158
this.emit('stateChange', {
148159
type: 'declared-test',
160+
hash,
149161
title,
150162
knownFailing: metadata.failing,
151163
todo: false
@@ -166,6 +178,10 @@ class Runner extends Emittery {
166178
}, meta);
167179
}
168180

181+
getTitleHash(title) {
182+
return title ? objectHash(title).substring(0, 10) : undefined;
183+
}
184+
169185
compareTestSnapshot(options) {
170186
if (!this.snapshots) {
171187
this.snapshots = snapshotManager.load({
@@ -276,20 +292,23 @@ class Runner extends Emittery {
276292
compareTestSnapshot: this.boundCompareTestSnapshot,
277293
updateSnapshots: this.updateSnapshots,
278294
metadata: task.metadata,
295+
hash: this.getTitleHash(`${task.title}${titleSuffix || ''}`),
279296
title: `${task.title}${titleSuffix || ''}`
280297
}));
281298
const outcome = await this.runMultiple(hooks, this.serial);
282299
for (const result of outcome.storedResults) {
283300
if (result.passed) {
284301
this.emit('stateChange', {
285302
type: 'hook-finished',
303+
hash: result.hash,
286304
title: result.title,
287305
duration: result.duration,
288306
logs: result.logs
289307
});
290308
} else {
291309
this.emit('stateChange', {
292310
type: 'hook-failed',
311+
hash: result.hash,
293312
title: result.title,
294313
err: serializeError('Hook failure', true, result.error),
295314
duration: result.duration,
@@ -316,13 +335,15 @@ class Runner extends Emittery {
316335
compareTestSnapshot: this.boundCompareTestSnapshot,
317336
updateSnapshots: this.updateSnapshots,
318337
metadata: task.metadata,
338+
hash: task.hash,
319339
title: task.title
320340
});
321341

322342
const result = await this.runSingle(test);
323343
if (result.passed) {
324344
this.emit('stateChange', {
325345
type: 'test-passed',
346+
hash: result.hash,
326347
title: result.title,
327348
duration: result.duration,
328349
knownFailing: result.metadata.failing,
@@ -332,6 +353,7 @@ class Runner extends Emittery {
332353
} else {
333354
this.emit('stateChange', {
334355
type: 'test-failed',
356+
hash: result.hash,
335357
title: result.title,
336358
err: serializeError('Test failure', true, result.error),
337359
duration: result.duration,
@@ -356,6 +378,7 @@ class Runner extends Emittery {
356378

357379
this.emit('stateChange', {
358380
type: 'selected-test',
381+
hash: task.hash,
359382
title: task.title,
360383
knownFailing: task.metadata.failing,
361384
skip: task.metadata.skipped,
@@ -374,6 +397,7 @@ class Runner extends Emittery {
374397

375398
this.emit('stateChange', {
376399
type: 'selected-test',
400+
hash: task.hash,
377401
title: task.title,
378402
knownFailing: task.metadata.failing,
379403
skip: task.metadata.skipped,
@@ -396,6 +420,7 @@ class Runner extends Emittery {
396420

397421
this.emit('stateChange', {
398422
type: 'selected-test',
423+
hash: task.hash,
399424
title: task.title,
400425
knownFailing: false,
401426
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)