Skip to content

Commit 1947496

Browse files
psilosporecpojer
authored andcommitted
Created --notifyMode option for notifications on certain events (#5125)
* added notifyMode flag to specify when a notification should display forgot about other notifyMode configs add notifyMode to normalize Created TestSchedulerContext to save previous status of test to make the change option work updated docs minor linting fix Added additional options such as success-change and failure-change Put conditions back in if else clauses Fixed documentation on notifyMode Added notify reporter test (for review) Finished NotifyReporter tests. Testing against simulated sequences of events. * hipsters and their emojis 😞 * icons might not show in some envs * Update CHANGELOG.md
1 parent ad91d0a commit 1947496

17 files changed

Lines changed: 324 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
### Features
44

5+
* `[jest-cli]` Added `--notifyMode` to specify when to be notified.
6+
([#5125](https://github.com/facebook/jest/pull/5125))
57
* `[diff-sequences]` New package compares items in two sequences to find a
68
**longest common subsequence**.
79
([#5407](https://github.com/facebook/jest/pull/5407))

docs/Configuration.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,21 @@ Default: `false`
425425

426426
Activates notifications for test results.
427427

428+
### `notifyMode` [string]
429+
430+
Default: `always`
431+
432+
Specifies notification mode. Requires `notify: true`.
433+
434+
#### Modes
435+
436+
* `always`: always send a notification.
437+
* `failure`: send a notification when tests fail.
438+
* `success`: send a notification when tests pass.
439+
* `change`: send a notification when the status changed.
440+
* `success-change`: send a notification when tests pass or once when it fails.
441+
* `failure-success`: send a notification when tests fails or once when it passes.
442+
428443
### `preset` [string]
429444

430445
Default: `undefined`

integration-tests/__tests__/__snapshots__/show_config.test.js.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ exports[`--showConfig outputs config info and exits 1`] = `
8080
\\"noStackTrace\\": false,
8181
\\"nonFlagArgs\\": [],
8282
\\"notify\\": false,
83+
\\"notifyMode\\": \\"always\\",
8384
\\"passWithNoTests\\": false,
8485
\\"rootDir\\": \\"<<REPLACED_ROOT_DIR>>\\",
8586
\\"runTestsByPath\\": false,
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`test always 1`] = `
4+
Array [
5+
Object {
6+
"message": "3 tests passed",
7+
"title": "100% Passed",
8+
},
9+
Object {
10+
"message": "3 of 3 tests failed",
11+
"title": "100% Failed",
12+
},
13+
Object {
14+
"message": "3 tests passed",
15+
"title": "100% Passed",
16+
},
17+
Object {
18+
"message": "3 tests passed",
19+
"title": "100% Passed",
20+
},
21+
Object {
22+
"message": "3 of 3 tests failed",
23+
"title": "100% Failed",
24+
},
25+
Object {
26+
"message": "3 of 3 tests failed",
27+
"title": "100% Failed",
28+
},
29+
]
30+
`;
31+
32+
exports[`test change 1`] = `
33+
Array [
34+
Object {
35+
"message": "3 tests passed",
36+
"title": "100% Passed",
37+
},
38+
Object {
39+
"message": "3 of 3 tests failed",
40+
"title": "100% Failed",
41+
},
42+
Object {
43+
"message": "3 tests passed",
44+
"title": "100% Passed",
45+
},
46+
Object {
47+
"message": "3 of 3 tests failed",
48+
"title": "100% Failed",
49+
},
50+
]
51+
`;
52+
53+
exports[`test failure-change 1`] = `
54+
Array [
55+
Object {
56+
"message": "3 tests passed",
57+
"title": "100% Passed",
58+
},
59+
Object {
60+
"message": "3 of 3 tests failed",
61+
"title": "100% Failed",
62+
},
63+
Object {
64+
"message": "3 tests passed",
65+
"title": "100% Passed",
66+
},
67+
Object {
68+
"message": "3 of 3 tests failed",
69+
"title": "100% Failed",
70+
},
71+
Object {
72+
"message": "3 of 3 tests failed",
73+
"title": "100% Failed",
74+
},
75+
]
76+
`;
77+
78+
exports[`test success 1`] = `
79+
Array [
80+
Object {
81+
"message": "3 tests passed",
82+
"title": "100% Passed",
83+
},
84+
Object {
85+
"message": "3 tests passed",
86+
"title": "100% Passed",
87+
},
88+
Object {
89+
"message": "3 tests passed",
90+
"title": "100% Passed",
91+
},
92+
]
93+
`;
94+
95+
exports[`test success-change 1`] = `
96+
Array [
97+
Object {
98+
"message": "3 tests passed",
99+
"title": "100% Passed",
100+
},
101+
Object {
102+
"message": "3 of 3 tests failed",
103+
"title": "100% Failed",
104+
},
105+
Object {
106+
"message": "3 tests passed",
107+
"title": "100% Passed",
108+
},
109+
Object {
110+
"message": "3 tests passed",
111+
"title": "100% Passed",
112+
},
113+
Object {
114+
"message": "3 of 3 tests failed",
115+
"title": "100% Failed",
116+
},
117+
]
118+
`;
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/**
2+
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
*/
8+
9+
'use strict';
10+
11+
import TestScheduler from '../test_scheduler';
12+
import NotifyReporter from '../reporters/notify_reporter';
13+
import type {TestSchedulerContext} from '../test_scheduler';
14+
import type {AggregatedResult} from '../../../../types/TestResult';
15+
16+
jest.mock('../reporters/default_reporter');
17+
jest.mock('node-notifier', () => ({
18+
notify: jest.fn(),
19+
}));
20+
21+
const initialContext: TestSchedulerContext = {
22+
firstRun: true,
23+
previousSuccess: false,
24+
};
25+
26+
const aggregatedResultsSuccess: AggregatedResult = {
27+
numFailedTestSuites: 0,
28+
numFailedTests: 0,
29+
numPassedTestSuites: 1,
30+
numPassedTests: 3,
31+
numRuntimeErrorTestSuites: 0,
32+
numTotalTestSuites: 1,
33+
numTotalTests: 3,
34+
success: true,
35+
};
36+
37+
const aggregatedResultsFailure: AggregatedResult = {
38+
numFailedTestSuites: 1,
39+
numFailedTests: 3,
40+
numPassedTestSuites: 0,
41+
numPassedTests: 9,
42+
numRuntimeErrorTestSuites: 0,
43+
numTotalTestSuites: 1,
44+
numTotalTests: 3,
45+
success: false,
46+
};
47+
48+
// Simulated sequence of events for NotifyReporter
49+
const notifyEvents = [
50+
aggregatedResultsSuccess,
51+
aggregatedResultsFailure,
52+
aggregatedResultsSuccess,
53+
aggregatedResultsSuccess,
54+
aggregatedResultsFailure,
55+
aggregatedResultsFailure,
56+
];
57+
58+
test('.addReporter() .removeReporter()', () => {
59+
const scheduler = new TestScheduler(
60+
{},
61+
{},
62+
Object.assign({}, initialContext),
63+
);
64+
const reporter = new NotifyReporter();
65+
scheduler.addReporter(reporter);
66+
expect(scheduler._dispatcher._reporters).toContain(reporter);
67+
scheduler.removeReporter(NotifyReporter);
68+
expect(scheduler._dispatcher._reporters).not.toContain(reporter);
69+
});
70+
71+
const testModes = (notifyMode: string, arl: Array<AggregatedResult>) => {
72+
const notify = require('node-notifier');
73+
74+
let previousContext = initialContext;
75+
arl.forEach((ar, i) => {
76+
const newContext = Object.assign(previousContext, {
77+
firstRun: i === 0,
78+
previousSuccess: previousContext.previousSuccess,
79+
});
80+
const reporter = new NotifyReporter(
81+
{notify: true, notifyMode},
82+
{},
83+
newContext,
84+
);
85+
previousContext = newContext;
86+
reporter.onRunComplete(new Set(), ar);
87+
});
88+
89+
expect(
90+
notify.notify.mock.calls.map(([{message, title}]) => ({
91+
message: message.replace('\u26D4\uFE0F ', '').replace('\u2705 ', ''),
92+
title,
93+
})),
94+
).toMatchSnapshot();
95+
};
96+
97+
test('test always', () => {
98+
testModes('always', notifyEvents);
99+
});
100+
101+
test('test success', () => {
102+
testModes('success', notifyEvents);
103+
});
104+
105+
test('test change', () => {
106+
testModes('change', notifyEvents);
107+
});
108+
109+
test('test success-change', () => {
110+
testModes('success-change', notifyEvents);
111+
});
112+
113+
test('test failure-change', () => {
114+
testModes('failure-change', notifyEvents);
115+
});
116+
117+
afterEach(() => {
118+
jest.clearAllMocks();
119+
});

packages/jest-cli/src/cli/args.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,11 @@ export const options = {
363363
description: 'Activates notifications for test results.',
364364
type: 'boolean',
365365
},
366+
notifyMode: {
367+
default: 'always',
368+
description: 'Specifies when notifications will appear for test results.',
369+
type: 'string',
370+
},
366371
onlyChanged: {
367372
alias: 'o',
368373
default: undefined,

packages/jest-cli/src/reporters/notify_reporter.js

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import path from 'path';
1616
import util from 'util';
1717
import notifier from 'node-notifier';
1818
import BaseReporter from './base_reporter';
19+
import type {TestSchedulerContext} from '../test_scheduler';
1920

2021
const isDarwin = process.platform === 'darwin';
2122

@@ -24,29 +25,48 @@ const icon = path.resolve(__dirname, '../assets/jest_logo.png');
2425
export default class NotifyReporter extends BaseReporter {
2526
_startRun: (globalConfig: GlobalConfig) => *;
2627
_globalConfig: GlobalConfig;
27-
28+
_context: TestSchedulerContext;
2829
constructor(
2930
globalConfig: GlobalConfig,
3031
startRun: (globalConfig: GlobalConfig) => *,
32+
context: TestSchedulerContext,
3133
) {
3234
super();
3335
this._globalConfig = globalConfig;
3436
this._startRun = startRun;
37+
this._context = context;
3538
}
3639

3740
onRunComplete(contexts: Set<Context>, result: AggregatedResult): void {
3841
const success =
3942
result.numFailedTests === 0 && result.numRuntimeErrorTestSuites === 0;
4043

41-
if (success) {
44+
const notifyMode = this._globalConfig.notifyMode;
45+
const statusChanged =
46+
this._context.previousSuccess !== success || this._context.firstRun;
47+
if (
48+
success &&
49+
(notifyMode === 'always' ||
50+
notifyMode === 'success' ||
51+
notifyMode === 'success-change' ||
52+
(notifyMode === 'change' && statusChanged) ||
53+
(notifyMode === 'failure-change' && statusChanged))
54+
) {
4255
const title = util.format('%d%% Passed', 100);
4356
const message = util.format(
4457
(isDarwin ? '\u2705 ' : '') + '%d tests passed',
4558
result.numPassedTests,
4659
);
4760

4861
notifier.notify({icon, message, title});
49-
} else {
62+
} else if (
63+
!success &&
64+
(notifyMode === 'always' ||
65+
notifyMode === 'failure' ||
66+
notifyMode === 'failure-change' ||
67+
(notifyMode === 'change' && statusChanged) ||
68+
(notifyMode === 'success-change' && statusChanged))
69+
) {
5070
const failed = result.numFailedTests / result.numTotalTests;
5171

5272
const title = util.format(
@@ -83,5 +103,7 @@ export default class NotifyReporter extends BaseReporter {
83103
},
84104
);
85105
}
106+
this._context.previousSuccess = success;
107+
this._context.firstRun = false;
86108
}
87109
}

packages/jest-cli/src/run_jest.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ const processResults = (runResults, options) => {
8888
return options.onComplete && options.onComplete(runResults);
8989
};
9090

91+
const testSchedulerContext = {
92+
firstRun: true,
93+
previousSuccess: true,
94+
};
95+
9196
export default (async function runJest({
9297
contexts,
9398
globalConfig,
@@ -199,9 +204,13 @@ export default (async function runJest({
199204
// $FlowFixMe
200205
await require(globalConfig.globalSetup)();
201206
}
202-
const results = await new TestScheduler(globalConfig, {
203-
startRun,
204-
}).scheduleTests(allTests, testWatcher);
207+
const results = await new TestScheduler(
208+
globalConfig,
209+
{
210+
startRun,
211+
},
212+
testSchedulerContext,
213+
).scheduleTests(allTests, testWatcher);
205214

206215
sequencer.cacheResults(allTests, results);
207216

0 commit comments

Comments
 (0)