UNPKG

17.3 kBJavaScriptView Raw
1const run = jest.fn();
2const close = jest.fn();
3const watch = jest.fn().mockReturnValue({ close });
4const compiler = jest.fn().mockReturnValue({ run, watch });
5
6jest.setMock('webpack', compiler); // try to get rid of this.
7jest.mock('../watchModeIPC');
8jest.mock('webpack/lib/Stats');
9
10let webpackWorker;
11let promiseMock;
12let webpackMock;
13let webpackStatsMock;
14let notifyIPCWatchCompileDone;
15
16describe('webpackWorker', () => {
17 beforeEach(() => {
18 promiseMock = require('bluebird');
19 webpackMock = require('webpack');
20 webpackStatsMock = require('webpack/lib/Stats');
21 webpackWorker = require('../webpackWorker.js');
22 notifyIPCWatchCompileDone = require('../watchModeIPC').notifyIPCWatchCompileDone;
23 jest.doMock('testConfig', () => ({ webpack: 'config' }), { virtual: true });
24 jest.resetModules();
25 jest.clearAllMocks();
26 process.removeAllListeners();
27 });
28
29 describe('arguments', () => {
30 describe('options', () => {
31
32 let _argv;
33 beforeEach(() => {
34 _argv = process.argv;
35 });
36 afterEach(() => {
37 process.argv = _argv;
38 });
39
40 const optionsTest = (options) => {
41 const finishStats = {
42 compilation: {},
43 startTime: 1500034498,
44 endTime: 1500054500,
45 };
46 const doneCallback = jest.fn();
47 jest.spyOn(console, 'log').mockImplementation(() => {});
48
49
50 webpackWorker('testConfig', options , 0, 1, doneCallback);
51 const thenCb = promiseMock.then.mock.calls[0][0];
52 thenCb({ webpack: 'config', name: 'testApp' });
53 const finishedCallback = run.mock.calls[0][0];
54 finishedCallback(null, finishStats);
55
56 expect(doneCallback).toHaveBeenCalled();
57 if (options.json) {
58 expect(console.log).not.toHaveBeenCalled();
59 } else {
60 expect(console.log).toHaveBeenCalledTimes(2);
61 expect(console.log).toHaveBeenLastCalledWith(
62 '%s Finished building %s within %s seconds',
63 '[WEBPACK]',
64 'testApp',
65 '20.002'
66 );
67 }
68
69 if (options.argv) {
70 expect(process.argv).toEqual(options.argv);
71 }
72 };
73
74
75 it('should report json only when json: true', () => {
76 optionsTest({ json: true });
77 });
78
79 it('should report to console as well only when json: false', () => {
80 optionsTest({ json: false });
81 });
82
83 it('should set process arguments to the passed ones', () => {
84 optionsTest({ json:true, argv: ['--watch', '--bail']});
85 });
86
87 it('should call done with stats when there is stats object', () => {
88 const doneCallback = jest.fn();
89 const statsObj = {
90 compilation: {
91 errors: [
92 { message: 'module not found' },
93 { message: 'module not found 2' },
94 ]
95 },
96 toJson: jest.fn().mockReturnThis()
97 };
98 webpackWorker('testConfig', {}, 0, 1, doneCallback);
99 const thenCb = promiseMock.then.mock.calls[0][0];
100 thenCb({ webpack: 'config', name: 'testApp' });
101 let finishedCallback = run.mock.calls[0][0];
102
103 expect(process.listenerCount('SIGINT')).toBe(1);
104 finishedCallback(null, statsObj);
105
106 expect(process.listenerCount('SIGINT')).toBe(0);
107 expect(doneCallback).toHaveBeenCalled();
108 expect(doneCallback.mock.calls[0][0]).toMatchSnapshot();
109
110 });
111
112 it('should log in watch mode instead of calling done callback', () => {
113 jest.useFakeTimers();
114 const _temp = global.Date;
115 global.Date = jest.fn(() => (
116 {
117 toTimeString: jest.fn().mockReturnValue({
118 split: jest.fn().mockReturnValue(["12:05:54"])
119 })
120 }
121 ));
122 jest.spyOn(console, 'log');
123 const doneCallback = jest.fn();
124 const statsObj = {
125 compilation: {
126 errors: [
127 { message: 'module not found' },
128 { message: 'module not found 2' },
129 ]
130 },
131 toJson: jest.fn().mockReturnThis()
132 };
133 webpackWorker('testConfig', { watch: true }, 0, 1, doneCallback);
134 const thenCb = promiseMock.then.mock.calls[0][0];
135 thenCb({ webpack: 'config', name: 'testApp' });
136 let finishedCallback = watch.mock.calls[0][1];
137
138 expect(process.listenerCount('SIGINT')).toBe(1);
139 finishedCallback(null, statsObj);
140
141 expect(process.listenerCount('SIGINT')).toBe(1);
142 expect(doneCallback).not.toHaveBeenCalled();
143 expect(console.log.mock.calls).toMatchSnapshot();
144 expect(notifyIPCWatchCompileDone).toHaveBeenCalledWith(0);
145 process.removeAllListeners('SIGINT');
146 jest.useRealTimers();
147 global.Date = _temp;
148 });
149
150 });
151
152 describe('multi config options', () => {
153 const multiConfigTest = options => {
154 const errorMessage = '[WEBPACK] There is a difference between the amount of the provided configs. Maybe you where expecting command line arguments to be passed to your webpack.config.js. If so, you\'ll need to separate them with a -- from the parallel-webpack options.'
155 jest.doMock('multiTestConfig', () => ( [{ fail: true}, { webpack: 'config'}]), { virtual: true });
156 jest.doMock('testConfig', () => ({ webpack: 'config' }), { virtual: true });
157 jest.spyOn(console, 'error').mockImplementation(() => {});
158
159 webpackWorker(
160 options.multi ? 'multiTestConfig' : 'testConfig',
161 { json: true },
162 options.configIndex,
163 options.expectedConfigs,
164 jest.fn()
165 );
166 const allConfigs = promiseMock.resolve.mock.calls[0][0];
167 const thenCb = promiseMock.then.mock.calls[0][0];
168 if (options.multi && options.expectedConfigs < 3) {
169 const targetConfig = allConfigs[options.configIndex];
170 thenCb(allConfigs)
171 expect(compiler.mock.calls[0][0]).toEqual(targetConfig);
172 } else {
173 expect(() => thenCb(allConfigs)).toThrow(errorMessage)
174 expect(console.error).toHaveBeenCalled();
175 }
176 }
177
178 it('should select the correct indexed one if configs are array', () => {
179 multiConfigTest({ multi: true, configIndex: 1, expectedConfigs: 2 });
180 });
181
182 it('should fail if expectedConfigLength > 1 in case of single config', () => {
183 multiConfigTest({ multi: false, configIndex: 1, expectedConfigs: 2 });
184 });
185
186 it('should fail if expectedConfigLength dont match with config.length', () => {
187 multiConfigTest({ multi: true, configIndex: 1, expectedConfigs: 3 });
188 });
189
190 it('should be able to handle config function return promise of array of config object', () => {
191 const originalConfigs = [{ webpack: 'config' }, { webpack: 'config2' }];
192 jest.doMock('promiseReturnConfigArray', () => Promise.resolve(originalConfigs), { virtual: true });
193 const configIndex = 1
194 const expectedConfigLength = 2
195 webpackWorker(
196 'promiseReturnConfigArray',
197 { json: true },
198 configIndex,
199 expectedConfigLength,
200 jest.fn()
201 )
202 const thenCb = promiseMock.then.mock.calls[0][0];
203 const targetConfig = originalConfigs[configIndex];
204 thenCb(originalConfigs);
205 expect(compiler.mock.calls[0][0]).toEqual(targetConfig);
206 })
207 })
208 });
209
210 describe('module functions', () => {
211 describe('getAppName', () => {
212 const getAppNameTest = (options, appName) => {
213 const doneCallback = jest.fn();
214 jest.spyOn(console, 'log');
215 webpackWorker('testConfig', { json: false }, 0, 1, doneCallback);
216
217 const thenCb = promiseMock.then.mock.calls[0][0];
218 thenCb(Object.assign({ webpack: 'config' }, options));
219
220 let finishedCallback = run.mock.calls[0][0];
221 finishedCallback(null, { compilation: {}});
222
223 expect(console.log.mock.calls[1][2]).toBe(appName);
224 };
225
226 it('should get the name from config.name', () => {
227 getAppNameTest({ name: 'testApp' }, 'testApp');
228 });
229
230 it('should get the name from output.filename', () => {
231 getAppNameTest(
232 {
233 output: {
234 filename: 'test.app.js'
235 }
236 },
237 'test.app.js'
238 );
239 });
240
241 it('should replace "[name]" pattern if there is one entry point', () => {
242 getAppNameTest(
243 {
244 output: {
245 filename: 'bundle.[name].js',
246 },
247 entry: {
248 testApp: 'filepath',
249 }
250 },
251 'bundle.testApp.js'
252 );
253 });
254
255 it('should replace all matches of "[name]" pattern if there is one entry point', () => {
256 getAppNameTest(
257 {
258 output: {
259 filename: 'bundle/[name]/[name].js',
260 },
261 entry: {
262 testApp: 'filepath',
263 }
264 },
265 'bundle/testApp/testApp.js'
266 );
267 });
268 });
269
270 describe('getOutputOptions', () => {
271 it('should get stats options if they set', () => {
272 const statsObj = {
273 compilation: {
274 },
275 toString: jest.fn().mockReturnValue('size: 321.kb'),
276 toJson: jest.fn().mockReturnValue('size: 321.kb')
277 };
278 jest.spyOn(console, 'log');
279 const doneCallback = jest.fn();
280 webpackWorker('testConfig', {
281 stats: true,
282 modulesSort: 'name',
283 chunksSort: 'size',
284 assetsSort: 'name',
285 exclude: ['file'],
286 colors: true
287 }, 0, 1, doneCallback);
288
289 expect(promiseMock.resolve.mock.calls[0][0]).toEqual({ webpack: 'config' });
290 const thenCb = promiseMock.then.mock.calls[0][0];
291 thenCb({ webpack: 'config', name: 'testApp' });
292
293
294 let finishedCallback = run.mock.calls[0][0];
295 finishedCallback(null, statsObj);
296 expect(statsObj.toString.mock.calls).toMatchSnapshot();
297 });
298
299 it('should translate stats string to object', () => {
300 jest.spyOn(console, 'log');
301 let presetToOptions = jest.spyOn(webpackStatsMock, 'presetToOptions');
302
303 const doneCallback = jest.fn();
304
305 webpackWorker('testConfig', {
306 stats: true,
307 modulesSort: 'name',
308 chunksSort: 'size',
309 assetsSort: 'name',
310 exclude: ['file'],
311 colors: true
312 }, 0, 1, doneCallback);
313
314 expect(promiseMock.resolve.mock.calls[0][0]).toEqual({ webpack: 'config' });
315 const thenCb = promiseMock.then.mock.calls[0][0];
316 thenCb({ webpack: 'config', name: 'testApp', 'stats': 'verbose' });
317
318 expect(presetToOptions).toHaveBeenCalled();
319 })
320 });
321 });
322
323 describe('creator function', () => {
324 describe('shutdownCallback', () => {
325
326 let _exit;
327 beforeEach(() => {
328 _exit = process.exit;
329 });
330 afterEach(() => {
331 process.exit = _exit;
332 process.removeAllListeners('SIGINT');
333 });
334
335 const shutdownCallbackTest = options => {
336 const doneCallback = jest.fn();
337 const statsObj = {
338 compilation: {
339 errors: [
340 { message: 'module not found' },
341 { message: 'module not found 2' },
342 ]
343 },
344 toJson: jest.fn().mockReturnThis()
345 };
346 process.exit = jest.fn();
347
348 webpackWorker('testConfig', options , 0, 1, doneCallback);
349 const thenCb = promiseMock.then.mock.calls[0][0];
350 thenCb({ webpack: 'config', name: 'testApp' });
351 const shutdownCallback = process.listeners('SIGINT')[0];
352 shutdownCallback();
353
354
355 if (options.watch) {
356 expect(close.mock.calls[0][0]).toBe(doneCallback);
357 expect(doneCallback.mock.calls[0][0]).toMatchSnapshot();
358 } else {
359 expect(close).not.toHaveBeenCalled();
360 expect(doneCallback.mock.calls[0][0]).toMatchSnapshot();
361 }
362 };
363
364 it('should watcher.close and done in watch mode on SIGINT', () => {
365 shutdownCallbackTest({ watch: true });
366 });
367
368 it('should call done callback', () => {
369 shutdownCallbackTest({ watch: false });
370 });
371 });
372
373 describe('finishedCallback', () => {
374 const finishCbTest = options => {
375 const statsObj = {
376 compilation: {
377 },
378 toString: jest.fn().mockReturnValue('size: 321.kb'),
379 toJson: jest.fn().mockReturnValue('size: 321.kb')
380 };
381 const doneCallback = jest.fn();
382 jest.spyOn(console, 'log');
383 jest.spyOn(console, 'error');
384
385 webpackWorker('testConfig', options.worker, 0, 1, doneCallback);
386 expect(promiseMock.resolve.mock.calls[0][0]).toEqual({ webpack: 'config' });
387
388 const thenCb = promiseMock.then.mock.calls[0][0];
389 thenCb({ webpack: 'config', name: 'testApp' });
390 expect(process.listenerCount('SIGINT')).toBe(1);
391
392 let finishedCallback = run.mock.calls[0][0];
393
394
395 if (options.isError) {
396 finishedCallback({ error: 'Exception' }, { compilation: {}});
397 expect(console.error).toHaveBeenCalledTimes(2);
398 expect(doneCallback.mock.calls[0]).toEqual([{error: 'Exception'}]);
399 } else if (options.isStats) {
400 finishedCallback(null, statsObj);
401 expect(doneCallback.mock.calls[0]).toMatchSnapshot();
402 expect(console.log.mock.calls[1]).toEqual(['size: 321.kb']);
403 } else { // success
404 finishedCallback(null, statsObj);
405 expect(doneCallback.mock.calls[0]).toEqual([null, '']);
406 }
407 expect(process.listenerCount('SIGINT')).toBe(0);
408
409 };
410
411 it('should spit out error, remove SIGINT and close when an exception happen', () => {
412 finishCbTest({
413 worker: { json: true },
414 isError: true
415 });
416 });
417
418 it('should remove SIGINT and call done with stats', () => {
419 finishCbTest({
420 worker: { stats: true },
421 isError: false,
422 isStats: true
423 });
424 });
425
426 it('should set the promise and call done on success', () => {
427 finishCbTest({
428 worker: { json: true },
429 isError: false,
430 isStats: false
431 });
432 });
433 });
434 });
435});