Skip to content

Commit 62fce79

Browse files
committed
feat: make node-notifier an optional dependency
1 parent 736edd2 commit 62fce79

File tree

4 files changed

+65
-6
lines changed

4 files changed

+65
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@
2929
- `[jest-fake-timers]` `getTimerCount` will not include cancelled immediates ([#8764](https://github.com/facebook/jest/pull/8764))
3030
- `[jest-leak-detector]` [**BREAKING**] Use `weak-napi` instead of `weak` package ([#8686](https://github.com/facebook/jest/pull/8686))
3131
- `[jest-mock]` Fix for mockReturnValue overriding mockImplementationOnce ([#8398](https://github.com/facebook/jest/pull/8398))
32-
- `[jest-snapshot]` Remove only the added newlines in multiline snapshots ([#8859](https://github.com/facebook/jest/pull/8859))
32+
- `[jest-reporters]` Make node-notifer an optional dependency ([#8918](https://github.com/facebook/jest/pull/8918))
3333
- `[jest-snapshot]` Distinguish empty string from external snapshot not written ([#8880](https://github.com/facebook/jest/pull/8880))
34+
- `[jest-snapshot]` Remove only the added newlines in multiline snapshots ([#8859](https://github.com/facebook/jest/pull/8859))
3435
- `[jest-snapshot]` [**BREAKING**] Distinguish empty string from internal snapshot not written ([#8898](https://github.com/facebook/jest/pull/8898))
3536
- `[jest-transform]` Properly cache transformed files across tests ([#8890](https://github.com/facebook/jest/pull/8890))
3637

packages/jest-reporters/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
"jest-runtime": "^24.9.0",
2424
"jest-util": "^24.9.0",
2525
"jest-worker": "^24.6.0",
26-
"node-notifier": "^5.4.3",
2726
"slash": "^3.0.0",
2827
"source-map": "^0.6.0",
2928
"string-length": "^3.1.0"
@@ -39,6 +38,9 @@
3938
"@types/node-notifier": "^5.4.0",
4039
"strip-ansi": "^5.0.0"
4140
},
41+
"optionalDependencies": {
42+
"node-notifier": "^5.4.3"
43+
},
4244
"engines": {
4345
"node": ">= 8"
4446
},

packages/jest-reporters/src/__tests__/notify_reporter.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,48 @@ test('test failure-change with moduleName', () => {
207207
});
208208
});
209209

210+
describe('node-notifier is an optional dependency', () => {
211+
beforeEach(() => {
212+
jest.resetModules();
213+
});
214+
215+
const ctor = () => {
216+
const config = makeGlobalConfig({
217+
notify: true,
218+
notifyMode: 'success',
219+
rootDir: 'some-test',
220+
});
221+
return new NotifyReporter(config, () => {}, initialContext);
222+
};
223+
224+
test('without node-notifier uses mock function that throws an error', () => {
225+
jest.doMock('node-notifier', () => {
226+
const error: any = new Error("Cannot find module 'node-notifier'");
227+
error.code = 'MODULE_NOT_FOUND';
228+
throw error;
229+
});
230+
231+
expect(ctor).toThrow(
232+
'notify reporter requires optional dependeny node-notifier but it was not found',
233+
);
234+
});
235+
236+
test('throws the error when require throws an unexpected error', () => {
237+
const error = new Error('unexpected require error');
238+
jest.doMock('node-notifier', () => {
239+
throw error;
240+
});
241+
expect(ctor).toThrow(error);
242+
});
243+
244+
test('uses node-notifier when it is available', () => {
245+
const mockNodeNotifier = {notify: jest.fn()};
246+
jest.doMock('node-notifier', () => mockNodeNotifier);
247+
const result = ctor();
248+
expect(result['_notifier']).toBe(mockNodeNotifier);
249+
});
250+
});
251+
210252
afterEach(() => {
211253
jest.clearAllMocks();
212254
});

packages/jest-reporters/src/notify_reporter.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import * as util from 'util';
1010
import exit = require('exit');
1111
import {Config} from '@jest/types';
1212
import {AggregatedResult} from '@jest/test-result';
13-
import {notify} from 'node-notifier';
1413
import {Context, TestSchedulerContext} from './types';
1514
import BaseReporter from './base_reporter';
1615

@@ -19,6 +18,7 @@ const isDarwin = process.platform === 'darwin';
1918
const icon = path.resolve(__dirname, '../assets/jest_logo.png');
2019

2120
export default class NotifyReporter extends BaseReporter {
21+
private _notifier = loadNotifier();
2222
private _startRun: (globalConfig: Config.GlobalConfig) => any;
2323
private _globalConfig: Config.GlobalConfig;
2424
private _context: TestSchedulerContext;
@@ -78,7 +78,7 @@ export default class NotifyReporter extends BaseReporter {
7878
result.numPassedTests,
7979
);
8080

81-
notify({icon, message, title});
81+
this._notifier.notify({icon, message, title});
8282
} else if (
8383
testsHaveRun &&
8484
!success &&
@@ -106,9 +106,9 @@ export default class NotifyReporter extends BaseReporter {
106106
const quitAnswer = 'Exit tests';
107107

108108
if (!watchMode) {
109-
notify({icon, message, title});
109+
this._notifier.notify({icon, message, title});
110110
} else {
111-
notify(
111+
this._notifier.notify(
112112
{
113113
actions: [restartAnswer, quitAnswer],
114114
closeLabel: 'Close',
@@ -137,3 +137,17 @@ export default class NotifyReporter extends BaseReporter {
137137
this._context.firstRun = false;
138138
}
139139
}
140+
141+
function loadNotifier(): typeof import('node-notifier') {
142+
try {
143+
return require('node-notifier');
144+
} catch (err) {
145+
if (err.code !== 'MODULE_NOT_FOUND') {
146+
throw err;
147+
} else {
148+
throw Error(
149+
'notify reporter requires optional dependeny node-notifier but it was not found',
150+
);
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)