From 82de98ffd70a302f9c0f02b649155608f4e14c9e Mon Sep 17 00:00:00 2001 From: Loonride Date: Mon, 1 Jul 2019 11:43:01 -0500 Subject: [PATCH] feat(server/client): made progress option available to API (#1961) * feat(server/client): made progress option available to API * test(client): switched snapshot test to single line confirmation * refactor(server): removed this.profile * test(client): fixed progress test css path * test(client): remove jest timeout * test(e2e): change how use of progress on client checked * test(e2e): moved css unlink into afterAll * test(e2e): use port assigner * test(client): add full progress snapshot * test(client): reg exp progress test * test(client): check end of progress updates in console * test(client): more generalized test reg exp * test(client): test to isolate ci problem * test(client): made custom progress plugin to test * test(client): new progress plugin multi handler test * test(client): more testing to identify progress problem * test(client): test with 1 progress plugin * test(client): new console.log to test sending of data * feat(server): re-add two progress plugins * test(client): revert to original changes * test(progress): added progress and profile option tests * fix(test): fix profile test port map --- bin/options.js | 4 ++ bin/webpack-dev-server.js | 6 --- lib/Server.js | 26 ++++++----- lib/options.json | 4 ++ lib/utils/createConfig.js | 4 ++ test/cli/cli.test.js | 29 ++++++++++-- test/e2e/Progress.test.js | 71 +++++++++++++++++++++++++++++ test/options.test.js | 4 ++ test/ports-map.js | 3 ++ test/server/profile-option.test.js | 53 +++++++++++++++++++++ test/server/progress-option.test.js | 51 +++++++++++++++++++++ 11 files changed, 233 insertions(+), 22 deletions(-) create mode 100644 test/e2e/Progress.test.js create mode 100644 test/server/profile-option.test.js create mode 100644 test/server/progress-option.test.js diff --git a/bin/options.js b/bin/options.js index 3c46d9be9f..424ac2a21a 100644 --- a/bin/options.js +++ b/bin/options.js @@ -37,6 +37,10 @@ const options = { describe: 'Inline mode (set to false to disable including client scripts like livereload)', }, + profile: { + type: 'boolean', + describe: 'Print compilation profile data for progress steps', + }, progress: { type: 'boolean', describe: 'Print compilation progress in percentage', diff --git a/bin/webpack-dev-server.js b/bin/webpack-dev-server.js index deb015f6f1..26de7d4ba6 100755 --- a/bin/webpack-dev-server.js +++ b/bin/webpack-dev-server.js @@ -97,12 +97,6 @@ function startDevServer(config, options) { throw err; } - if (options.progress) { - new webpack.ProgressPlugin({ - profile: argv.profile, - }).apply(compiler); - } - try { server = new Server(compiler, options, log); } catch (err) { diff --git a/lib/Server.js b/lib/Server.js index 26d16dfadf..5538f6f454 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -154,23 +154,25 @@ class Server { } setupProgressPlugin() { - const progressPlugin = new webpack.ProgressPlugin( - (percent, msg, addInfo) => { - percent = Math.floor(percent * 100); + // for CLI output + new webpack.ProgressPlugin({ + profile: !!this.options.profile, + }).apply(this.compiler); - if (percent === 100) { - msg = 'Compilation completed'; - } + // for browser console output + new webpack.ProgressPlugin((percent, msg, addInfo) => { + percent = Math.floor(percent * 100); - if (addInfo) { - msg = `${msg} (${addInfo})`; - } + if (percent === 100) { + msg = 'Compilation completed'; + } - this.sockWrite(this.sockets, 'progress-update', { percent, msg }); + if (addInfo) { + msg = `${msg} (${addInfo})`; } - ); - progressPlugin.apply(this.compiler); + this.sockWrite(this.sockets, 'progress-update', { percent, msg }); + }).apply(this.compiler); } setupApp() { diff --git a/lib/options.json b/lib/options.json index da9cd0e978..7dd7000623 100644 --- a/lib/options.json +++ b/lib/options.json @@ -249,6 +249,9 @@ } ] }, + "profile": { + "type": "boolean" + }, "progress": { "type": "boolean" }, @@ -417,6 +420,7 @@ "pfx": "should be {String|Buffer} (https://webpack.js.org/configuration/dev-server/#devserverpfx)", "pfxPassphrase": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserverpfxpassphrase)", "port": "should be {Number|String|Null} (https://webpack.js.org/configuration/dev-server/#devserverport)", + "profile": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverprofile)", "progress": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverprogress---cli-only)", "proxy": "should be {Object|Array} (https://webpack.js.org/configuration/dev-server/#devserverproxy)", "public": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserverpublic)", diff --git a/lib/utils/createConfig.js b/lib/utils/createConfig.js index 1902466620..0211561235 100644 --- a/lib/utils/createConfig.js +++ b/lib/utils/createConfig.js @@ -47,6 +47,10 @@ function createConfig(config, argv, { port }) { options.liveReload = false; } + if (argv.profile) { + options.profile = argv.profile; + } + if (argv.progress) { options.progress = argv.progress; } diff --git a/test/cli/cli.test.js b/test/cli/cli.test.js index 404cff789c..4530b831ac 100644 --- a/test/cli/cli.test.js +++ b/test/cli/cli.test.js @@ -15,10 +15,31 @@ const keyPath = resolve(httpsCertificateDirectory, 'server.key'); const certPath = resolve(httpsCertificateDirectory, 'server.crt'); describe('CLI', () => { - it('--progress', async () => { - const { code, stderr } = await testBin('--progress'); - expect(code).toEqual(0); - expect(stderr.includes('0% compiling')).toBe(true); + it('--progress', (done) => { + testBin('--progress') + .then((output) => { + expect(output.code).toEqual(0); + expect(output.stderr.includes('0% compiling')).toBe(true); + // should not profile + expect( + output.stderr.includes('ms after chunk modules optimization') + ).toBe(false); + done(); + }) + .catch(done); + }); + + it('--progress --profile', (done) => { + testBin('--progress --profile') + .then((output) => { + expect(output.code).toEqual(0); + // should profile + expect( + output.stderr.includes('ms after chunk modules optimization') + ).toBe(true); + done(); + }) + .catch(done); }); it('--bonjour', async () => { diff --git a/test/e2e/Progress.test.js b/test/e2e/Progress.test.js new file mode 100644 index 0000000000..dd1a3588a6 --- /dev/null +++ b/test/e2e/Progress.test.js @@ -0,0 +1,71 @@ +'use strict'; + +/* eslint-disable + no-undef +*/ +const fs = require('fs'); +const { resolve } = require('path'); +const testServer = require('../helpers/test-server'); +const reloadConfig = require('../fixtures/reload-config/webpack.config'); +const runBrowser = require('../helpers/run-browser'); +const port = require('../ports-map').Progress; + +const cssFilePath = resolve(__dirname, '../fixtures/reload-config/main.css'); + +describe('client progress', () => { + describe('using hot', () => { + beforeAll((done) => { + fs.writeFileSync( + cssFilePath, + 'body { background-color: rgb(0, 0, 255); }' + ); + const options = { + port, + host: '0.0.0.0', + inline: true, + hot: true, + progress: true, + watchOptions: { + poll: 500, + }, + }; + testServer.startAwaitingCompilation(reloadConfig, options, done); + }); + + afterAll((done) => { + fs.unlinkSync(cssFilePath); + testServer.close(done); + }); + + describe('on browser client', () => { + it('should console.log progress', (done) => { + runBrowser().then(({ page, browser }) => { + const res = []; + page.waitForNavigation({ waitUntil: 'load' }).then(() => { + fs.writeFileSync( + cssFilePath, + 'body { background-color: rgb(255, 0, 0); }' + ); + page.waitFor(10000).then(() => { + browser.close().then(() => { + // check that there is some percentage progress output + const regExp = /^\[WDS\] [0-9]{1,3}% - /; + const match = res.find((line) => { + return regExp.test(line); + }); + // eslint-disable-next-line no-undefined + expect(match).not.toEqual(undefined); + done(); + }); + }); + }); + + page.goto(`http://localhost:${port}/main`); + page.on('console', (data) => { + res.push(data.text()); + }); + }); + }); + }); + }); +}); diff --git a/test/options.test.js b/test/options.test.js index 6d06ea6b3d..38446bbb6d 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -230,6 +230,10 @@ describe('options', () => { success: ['', 0, null], failure: [false], }, + profile: { + success: [false], + failure: [''], + }, progress: { success: [false], failure: [''], diff --git a/test/ports-map.js b/test/ports-map.js index cf44bbd1ee..32ae31048d 100644 --- a/test/ports-map.js +++ b/test/ports-map.js @@ -40,6 +40,9 @@ const portsList = { WebsocketServer: 1, ClientMode: 1, 'clientMode-option': 1, + Progress: 1, + 'progress-option': 1, + 'profile-option': 1, }; let startPort = 8079; diff --git a/test/server/profile-option.test.js b/test/server/profile-option.test.js new file mode 100644 index 0000000000..025e502d4f --- /dev/null +++ b/test/server/profile-option.test.js @@ -0,0 +1,53 @@ +'use strict'; + +const webpack = require('webpack'); +const Server = require('../../lib/Server'); +const config = require('../fixtures/simple-config/webpack.config'); +const port = require('../ports-map')['profile-option']; + +describe('profile', () => { + describe('output', () => { + let mockStderr; + + beforeAll(() => { + mockStderr = jest + .spyOn(process.stderr, 'write') + .mockImplementation(() => {}); + }); + + it('should show percentage progress with profile data', (done) => { + const compiler = webpack(config); + const server = new Server(compiler, { + port, + // profile will only have an effect when progress is enabled + progress: true, + profile: true, + }); + + compiler.hooks.done.tap('webpack-dev-server', () => { + const calls = mockStderr.mock.calls; + mockStderr.mockRestore(); + let foundProgress = false; + let foundProfile = false; + calls.forEach((call) => { + if (call[0].includes('0% compiling')) { + foundProgress = true; + } + + // this is an indicator that the profile option is enabled, + // so we should expect to find it in stderr since profile is enabled + if (call[0].includes('ms after chunk modules optimization')) { + foundProfile = true; + } + }); + expect(foundProgress).toBeTruthy(); + expect(foundProfile).toBeTruthy(); + + server.close(done); + }); + + compiler.run(() => {}); + server.listen(port, 'localhost'); + }); + }); +}); diff --git a/test/server/progress-option.test.js b/test/server/progress-option.test.js new file mode 100644 index 0000000000..ae2d23c07f --- /dev/null +++ b/test/server/progress-option.test.js @@ -0,0 +1,51 @@ +'use strict'; + +const webpack = require('webpack'); +const Server = require('../../lib/Server'); +const config = require('../fixtures/simple-config/webpack.config'); +const port = require('../ports-map')['progress-option']; + +describe('progress', () => { + describe('output', () => { + let mockStderr; + + beforeAll(() => { + mockStderr = jest + .spyOn(process.stderr, 'write') + .mockImplementation(() => {}); + }); + + it('should show percentage progress without profile data', (done) => { + const compiler = webpack(config); + const server = new Server(compiler, { + port, + progress: true, + }); + + compiler.hooks.done.tap('webpack-dev-server', () => { + const calls = mockStderr.mock.calls; + mockStderr.mockRestore(); + let foundProgress = false; + let foundProfile = false; + calls.forEach((call) => { + if (call[0].includes('0% compiling')) { + foundProgress = true; + } + + // this is an indicator that the profile option is enabled, + // so we should expect to not find it in stderr since it is not enabled + if (call[0].includes('ms after chunk modules optimization')) { + foundProfile = true; + } + }); + expect(foundProgress).toBeTruthy(); + expect(foundProfile).toBeFalsy(); + + server.close(done); + }); + + compiler.run(() => {}); + server.listen(port, 'localhost'); + }); + }); +});