From bbe410e6f257ae45e65ca97c708118c8d7ec01ce Mon Sep 17 00:00:00 2001 From: Loonride Date: Thu, 8 Aug 2019 05:41:14 -0500 Subject: [PATCH] fix(server): fix setupExitSignals usage (#2181) * fix(server): pass server data to exit signal setup as object * test(server): add exit signal tests * style(test): fix lint problem --- bin/webpack-dev-server.js | 11 ++++- lib/utils/setupExitSignals.js | 6 +-- test/server/utils/setupExitSignals.test.js | 57 ++++++++++++++++++++++ 3 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 test/server/utils/setupExitSignals.test.js diff --git a/bin/webpack-dev-server.js b/bin/webpack-dev-server.js index 7c3456f5d3..286cad93b9 100755 --- a/bin/webpack-dev-server.js +++ b/bin/webpack-dev-server.js @@ -19,8 +19,14 @@ const getVersions = require('../lib/utils/getVersions'); const options = require('./options'); let server; - -setupExitSignals(server); +const serverData = { + server: null, +}; +// we must pass an object that contains the server object as a property so that +// we can update this server property later, and setupExitSignals will be able to +// recognize that the server has been instantiated, because we will set +// serverData.server to the new server object. +setupExitSignals(serverData); // Prefer the local installation of webpack-dev-server if (importLocal(__filename)) { @@ -98,6 +104,7 @@ function startDevServer(config, options) { try { server = new Server(compiler, options, log); + serverData.server = server; } catch (err) { if (err.name === 'ValidationError') { log.error(colors.error(options.stats.colors, err.message)); diff --git a/lib/utils/setupExitSignals.js b/lib/utils/setupExitSignals.js index 786fc6b2f3..105b2b4273 100644 --- a/lib/utils/setupExitSignals.js +++ b/lib/utils/setupExitSignals.js @@ -2,11 +2,11 @@ const signals = ['SIGINT', 'SIGTERM']; -function setupExitSignals(server) { +function setupExitSignals(serverData) { signals.forEach((signal) => { process.on(signal, () => { - if (server) { - server.close(() => { + if (serverData.server) { + serverData.server.close(() => { // eslint-disable-next-line no-process-exit process.exit(); }); diff --git a/test/server/utils/setupExitSignals.test.js b/test/server/utils/setupExitSignals.test.js new file mode 100644 index 0000000000..0f6f835591 --- /dev/null +++ b/test/server/utils/setupExitSignals.test.js @@ -0,0 +1,57 @@ +'use strict'; + +const setupExitSignals = require('../../../lib/utils/setupExitSignals'); + +describe('setupExitSignals', () => { + let server; + let exitSpy; + const signals = ['SIGINT', 'SIGTERM']; + + beforeAll(() => { + exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {}); + server = { + close: jest.fn((callback) => { + callback(); + }), + }; + }); + + afterEach(() => { + exitSpy.mockReset(); + server.close.mockClear(); + signals.forEach((signal) => { + process.removeAllListeners(signal); + }); + }); + + signals.forEach((signal) => { + it(`should exit process (${signal}, server never defined)`, (done) => { + setupExitSignals({ + server: null, + }); + process.emit(signal); + setTimeout(() => { + expect(exitSpy.mock.calls.length).toEqual(1); + done(); + }, 1000); + }); + + it(`should close server, then exit process (${signal}, server defined before signal)`, (done) => { + const serverData = { + server: null, + }; + setupExitSignals(serverData); + + setTimeout(() => { + serverData.server = server; + process.emit(signal); + }, 500); + + setTimeout(() => { + expect(server.close.mock.calls.length).toEqual(1); + expect(exitSpy.mock.calls.length).toEqual(1); + done(); + }, 1500); + }); + }); +});