diff --git a/packages/webpack-cli/__tests__/serve/serve.test.js b/packages/webpack-cli/__tests__/serve/serve.test.js index 007cff90e95..edebe9bd2a5 100644 --- a/packages/webpack-cli/__tests__/serve/serve.test.js +++ b/packages/webpack-cli/__tests__/serve/serve.test.js @@ -14,14 +14,14 @@ describe('Serve', () => { it('should run with cli', async () => { const { stdout, stderr } = await runServe([], __dirname); expect(stdout).toContain('main.js'); - expect(stdout).not.toContain('hot/dev-server.js'); + expect(stdout).not.toContain('HotModuleReplacementPlugin'); expect(stderr).toHaveLength(0); }); it('should work with flags', async () => { const { stdout, stderr } = await runServe(['--hot'], __dirname); expect(stdout).toContain('main.js'); - expect(stdout).toContain('hot/dev-server.js'); + expect(stdout).toContain('HotModuleReplacementPlugin'); expect(stderr).toHaveLength(0); }); }); diff --git a/packages/webpack-cli/__tests__/serve/webpack.config.js b/packages/webpack-cli/__tests__/serve/webpack.config.js index 955bbdd3364..ef02e82b858 100644 --- a/packages/webpack-cli/__tests__/serve/webpack.config.js +++ b/packages/webpack-cli/__tests__/serve/webpack.config.js @@ -1,4 +1,8 @@ +// eslint-disable-next-line node/no-unpublished-require +const WebpackCLITestPlugin = require('../../../../test/utils/webpack-cli-test-plugin'); + module.exports = { mode: 'development', devtool: false, + plugins: [new WebpackCLITestPlugin(['plugins'], false)], }; diff --git a/packages/webpack-cli/lib/groups/HelpGroup.js b/packages/webpack-cli/lib/groups/HelpGroup.js index a640df64083..9ea63428eff 100644 --- a/packages/webpack-cli/lib/groups/HelpGroup.js +++ b/packages/webpack-cli/lib/groups/HelpGroup.js @@ -117,6 +117,11 @@ class HelpGroup { optionList: options.core .map((e) => { if (e.type.length > 1) e.type = e.type[0]; + // Here we replace special characters with chalk's escape + // syntax (`\$&`) to avoid chalk trying to re-process our input. + // This is needed because chalk supports a form of `{var}` + // interpolation. + e.description = e.description.replace(/[{}\\]/g, '\\$&'); return e; }) .concat(negatedFlags), diff --git a/test/config-name/config-name.test.js b/test/config-name/config-name.test.js index 53b66537ecf..dfc9c8ba805 100644 --- a/test/config-name/config-name.test.js +++ b/test/config-name/config-name.test.js @@ -8,9 +8,9 @@ describe('--config-name flag', () => { it('should select only the config whose name is passed with --config-name', (done) => { const { stderr, stdout } = run(__dirname, ['--config-name', 'first'], false); expect(stderr).toBeFalsy(); - expect(stdout).toContain('Child first'); - expect(stdout).not.toContain('Child second'); - expect(stdout).not.toContain('Child third'); + expect(stdout).toContain('first'); + expect(stdout).not.toContain('second'); + expect(stdout).not.toContain('third'); stat(resolve(__dirname, './dist/dist-first.js'), (err, stats) => { expect(err).toBe(null); @@ -22,9 +22,9 @@ describe('--config-name flag', () => { it('should work with multiple values for --config-name', (done) => { const { stderr, stdout } = run(__dirname, ['--config-name', 'first', '--config-name', 'third'], false); expect(stderr).toBeFalsy(); - expect(stdout).toContain('Child first'); - expect(stdout).not.toContain('Child second'); - expect(stdout).toContain('Child third'); + expect(stdout).toContain('first'); + expect(stdout).not.toContain('second'); + expect(stdout).toContain('third'); stat(resolve(__dirname, './dist/dist-first.js'), (err, stats) => { expect(err).toBe(null); diff --git a/test/config/defaults/basic-config/default-js-config.test.js b/test/config/defaults/basic-config/default-js-config.test.js index 785a6e02078..259fc8ee21d 100644 --- a/test/config/defaults/basic-config/default-js-config.test.js +++ b/test/config/defaults/basic-config/default-js-config.test.js @@ -1,6 +1,6 @@ const fs = require('fs'); const path = require('path'); -const { run } = require('../../../utils/test-utils'); +const { run, isWebpack5 } = require('../../../utils/test-utils'); describe('Zero Config', () => { it('runs when config is present but not supplied via flag', () => { @@ -8,11 +8,13 @@ describe('Zero Config', () => { // default entry should be used expect(stdout).toContain('./index.js'); // should pick up the output path from config - expect(stdout).toContain('Entrypoint main = test-output'); - expect(stdout).toContain('Hash'); - expect(stdout).toContain('Version'); - expect(stdout).toContain('Built at'); - expect(stdout).toContain('Time'); + expect(stdout).toContain('test-output'); + if (!isWebpack5) { + expect(stdout).toContain('Hash'); + expect(stdout).toContain('Version'); + expect(stdout).toContain('Built at'); + expect(stdout).toContain('Time'); + } // Should return the correct exit code expect(exitCode).toEqual(0); // check that the output file exists diff --git a/test/config/defaults/cjs-config/default-cjs-config.test.js b/test/config/defaults/cjs-config/default-cjs-config.test.js index 0adda400566..f64365e369e 100644 --- a/test/config/defaults/cjs-config/default-cjs-config.test.js +++ b/test/config/defaults/cjs-config/default-cjs-config.test.js @@ -1,6 +1,6 @@ const fs = require('fs'); const path = require('path'); -const { run } = require('../../../utils/test-utils'); +const { run, isWebpack5 } = require('../../../utils/test-utils'); describe('Default Config:', () => { it('Should be able to pick cjs config by default', () => { @@ -8,11 +8,13 @@ describe('Default Config:', () => { // default entry should be used expect(stdout).toContain('./index.js'); // should pick up the output path from config - expect(stdout).toContain('Entrypoint main = test-output'); - expect(stdout).toContain('Hash'); - expect(stdout).toContain('Version'); - expect(stdout).toContain('Built at'); - expect(stdout).toContain('Time'); + expect(stdout).toContain('test-output'); + if (!isWebpack5) { + expect(stdout).toContain('Hash'); + expect(stdout).toContain('Version'); + expect(stdout).toContain('Built at'); + expect(stdout).toContain('Time'); + } // Should return the correct exit code expect(exitCode).toEqual(0); // check that the output file exists diff --git a/test/config/multiple/multiple-config.test.js b/test/config/multiple/multiple-config.test.js index f040031bdbc..dedf892b115 100644 --- a/test/config/multiple/multiple-config.test.js +++ b/test/config/multiple/multiple-config.test.js @@ -9,8 +9,8 @@ describe('Multiple config flag: ', () => { // Should contain the correct exit code expect(exitCode).toEqual(0); // Should spawn multiple compilers - expect(stdout).toContain('Child amd:'); - expect(stdout).toContain('Child commonjs:'); + expect(stdout).toContain('amd:'); + expect(stdout).toContain('commonjs:'); expect(stderr).toBeFalsy(); diff --git a/test/core-flags/output-flags.test.js b/test/core-flags/output-flags.test.js index 93a9c79c606..7bda29b938f 100644 --- a/test/core-flags/output-flags.test.js +++ b/test/core-flags/output-flags.test.js @@ -8,7 +8,10 @@ const outputFlags = flagsFromCore.filter(({ name }) => name.startsWith('output-' describe('output config related flag', () => { outputFlags.forEach((flag) => { // extract property name from flag name - const property = flag.name.split('output-')[1]; + let property = flag.name.split('output-')[1]; + if (property.includes('environment-')) { + property = property.split('environment-')[1]; + } const propName = hyphenToUpperCase(property); if (flag.type === Boolean && !flag.name.includes('output-library')) { @@ -32,9 +35,13 @@ describe('output config related flag', () => { it(`should config --no-${flag.name} correctly`, () => { const { stderr, stdout } = run(__dirname, [`--no-${flag.name}`]); - if (flag.name === 'output-enabled-chunk-loading-types-reset') { + if (flag.name.includes('loading-types-reset')) { expect(stderr).toBeFalsy(); - expect(stdout).toContain(`enabledChunkLoadingTypes: [ 'jsonp' ]`); + if (flag.name === 'output-enabled-wasm-loading-types-reset') { + expect(stdout).toContain(`enabledWasmLoadingTypes: [ 'fetch' ]`); + } else { + expect(stdout).toContain(`enabledChunkLoadingTypes: [ 'jsonp', 'import-scripts' ]`); + } } else if (flag.name.includes('-reset')) { const option = propName.split('Reset')[0]; expect(stderr).toBeFalsy(); @@ -76,7 +83,7 @@ describe('output config related flag', () => { stdout = run(__dirname, [`--${flag.name}`, 'jsonp']).stdout; expect(stdout).toContain(`${propName}: 'jsonp'`); - } else if (flag.name === 'output-enabled-chunk-loading-types') { + } else if (flag.name === 'output-enabled-chunk-loading-types' || flag.name === 'output-enabled-wasm-loading-types') { stdout = run(__dirname, [`--${flag.name}`, 'async-node']).stdout; expect(stdout).toContain(`${propName}: [ 'async-node' ]`); @@ -103,6 +110,18 @@ describe('output config related flag', () => { expect(stdout).toContain(`${propName}: [ 'var' ]`); } else if (flag.name === 'output-path') { expect(stdout).toContain('test'); + } else if (flag.name === 'output-worker-chunk-loading') { + stdout = run(__dirname, [`--${flag.name}`, 'async-node']).stdout; + expect(stdout).toContain(`${propName}: 'async-node'`); + } else if (flag.name === 'output-worker-chunk-loading') { + stdout = run(__dirname, [`--${flag.name}`, 'async-node']).stdout; + expect(stdout).toContain(`${propName}: 'async-node'`); + } else if (flag.name === 'output-chunk-format') { + stdout = run(__dirname, [`--${flag.name}`, 'commonjs']).stdout; + expect(stdout).toContain(`${propName}: 'commonjs'`); + } else if (flag.name.includes('wasm')) { + stdout = run(__dirname, [`--${flag.name}`, 'async-node']).stdout; + expect(stdout).toContain(`${propName}: 'async-node'`); } else { expect(stderr).toBeFalsy(); expect(stdout).toContain(`${propName}: 'test'`); diff --git a/test/core-flags/stats-flags.test.js b/test/core-flags/stats-flags.test.js index c4033cf5ef7..be141e097e3 100644 --- a/test/core-flags/stats-flags.test.js +++ b/test/core-flags/stats-flags.test.js @@ -59,6 +59,9 @@ describe('stats config related flag', () => { expect(stdout).toContain(`stats: { ${propName}: 'log' }`); } else if (flag.name === 'stats-context') { expect(stdout).toContain('log'); + } else if (flag.name === 'stats-entrypoints') { + stdout = run(__dirname, [`--${flag.name}`, 'auto']).stdout; + expect(stdout).toContain(`stats: { ${propName}: 'auto' }`); } else { expect(stdout).toContain(`stats: { ${propName}: [ 'log' ] }`); } diff --git a/test/serve/basic/serve-basic.test.js b/test/serve/basic/serve-basic.test.js index 67f39c94d36..b7ff5d2c847 100644 --- a/test/serve/basic/serve-basic.test.js +++ b/test/serve/basic/serve-basic.test.js @@ -38,35 +38,35 @@ describe('basic serve usage', () => { it('should not invoke info subcommand', async () => { const { stdout, stderr } = await runServe(['--client-log-level', 'info'], testPath); expect(stdout).toContain('main.js'); - expect(stdout).not.toContain('hot/dev-server.js'); + expect(stdout).not.toContain('HotModuleReplacementPlugin'); expect(stderr).toHaveLength(0); }); it('compiles without flags', async () => { const { stdout, stderr } = await runServe(['--port', port], testPath); expect(stdout).toContain('main.js'); - expect(stdout).not.toContain('hot/dev-server.js'); + expect(stdout).not.toContain('HotModuleReplacementPlugin'); expect(stderr).toHaveLength(0); }); it('uses hot flag to alter bundle', async () => { const { stdout, stderr } = await runServe(['--port', port, '--hot'], testPath); expect(stdout).toContain('main.js'); - expect(stdout).toContain('hot/dev-server.js'); + expect(stdout).toContain('HotModuleReplacementPlugin'); expect(stderr).toHaveLength(0); }); it('uses no-hot flag', async () => { const { stdout, stderr } = await runServe(['--port', port, '--no-hot'], testPath); expect(stdout).toContain('main.js'); - expect(stdout).not.toContain('hot/dev-server.js'); + expect(stdout).not.toContain('HotModuleReplacementPlugin'); expect(stderr).toHaveLength(0); }); it('uses hot flag and progress flag', async () => { const { stdout, stderr } = await runServe(['--port', port, '--hot', '--progress'], testPath); expect(stdout).toContain('main.js'); - expect(stdout).toContain('hot/dev-server.js'); + expect(stdout).toContain('HotModuleReplacementPlugin'); // progress flag makes use of stderr expect(stderr).not.toHaveLength(0); }); diff --git a/test/serve/basic/webpack.config.js b/test/serve/basic/webpack.config.js index 955bbdd3364..8fdd96a616b 100644 --- a/test/serve/basic/webpack.config.js +++ b/test/serve/basic/webpack.config.js @@ -1,4 +1,8 @@ +// eslint-disable-next-line node/no-unpublished-require +const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin'); + module.exports = { mode: 'development', devtool: false, + plugins: [new WebpackCLITestPlugin(['plugins'], false)], }; diff --git a/test/serve/with-custom-port/serve-custom-config.test.js b/test/serve/with-custom-port/serve-custom-config.test.js index 15088616b6a..e0e0b55e8fb 100644 --- a/test/serve/with-custom-port/serve-custom-config.test.js +++ b/test/serve/with-custom-port/serve-custom-config.test.js @@ -27,7 +27,7 @@ describe('serve with devServer in config', () => { const { stdout, stderr } = await runServe([], testPath); // Should output the correct bundle file expect(stdout).toContain('main.js'); - expect(stdout).not.toContain('hot/dev-server.js'); + expect(stdout).not.toContain('HotModuleReplacementPlugin'); // Runs at correct host and port expect(stdout).toContain('http://0.0.0.0:1234'); expect(stderr).toBeFalsy(); @@ -37,7 +37,7 @@ describe('serve with devServer in config', () => { const { stdout, stderr } = await runServe(['--port', port], testPath); // Should output the correct bundle file expect(stdout).toContain('main.js'); - expect(stdout).not.toContain('hot/dev-server.js'); + expect(stdout).not.toContain('HotModuleReplacementPlugin'); // Runs at correct host and port expect(stdout).toContain(`http://0.0.0.0:${port}`); expect(stderr).toBeFalsy(); @@ -48,7 +48,7 @@ describe('serve with devServer in config', () => { // Should output the correct bundle file expect(stdout).toContain('main.js'); // HMR is being used - expect(stdout).toContain('hot/dev-server.js'); + expect(stdout).toContain('HotModuleReplacementPlugin'); // Runs at correct host and port expect(stdout).toContain(`http://0.0.0.0:${port}`); expect(stderr).toBeFalsy(); @@ -59,7 +59,7 @@ describe('serve with devServer in config', () => { // Should output the correct bundle file expect(stdout).toContain('main.js'); // HMR is not being used - expect(stdout).not.toContain('hot/dev-server.js'); + expect(stdout).not.toContain('HotModuleReplacementPlugin'); // Runs at correct host and port expect(stdout).toContain(`http://0.0.0.0:${port}`); expect(stderr).toBeFalsy(); diff --git a/test/serve/with-custom-port/webpack.config.js b/test/serve/with-custom-port/webpack.config.js index d031e6a24ee..3121fcb10ad 100644 --- a/test/serve/with-custom-port/webpack.config.js +++ b/test/serve/with-custom-port/webpack.config.js @@ -1,3 +1,6 @@ +// eslint-disable-next-line node/no-unpublished-require +const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin'); + module.exports = { mode: 'development', devtool: false, @@ -5,4 +8,5 @@ module.exports = { port: 1234, host: '0.0.0.0', }, + plugins: [new WebpackCLITestPlugin(['plugins'], false)], }; diff --git a/test/stats/cli-flags/stats.test.js b/test/stats/cli-flags/stats.test.js index d2aa7277e91..83cd0cc0f9c 100644 --- a/test/stats/cli-flags/stats.test.js +++ b/test/stats/cli-flags/stats.test.js @@ -1,8 +1,7 @@ /* eslint-disable node/no-extraneous-require */ /* eslint-disable node/no-unpublished-require */ 'use strict'; -const { run } = require('../../utils/test-utils'); -const { version } = require('webpack'); +const { run, isWebpack5 } = require('../../utils/test-utils'); const presets = ['normal', 'detailed', 'errors-only', 'errors-warnings', 'minimal', 'verbose', 'none']; @@ -11,7 +10,7 @@ describe('stats flag', () => { it(`should accept --stats "${preset}"`, () => { const { stderr, stdout } = run(__dirname, ['--stats', `${preset}`]); expect(stderr).toBeFalsy(); - if (version.startsWith('5')) { + if (isWebpack5) { expect(stdout).toContain(`stats: { preset: '${preset}' }`); } else { expect(stdout).toContain(`stats: '${preset}'`); @@ -22,7 +21,7 @@ describe('stats flag', () => { it('should accept stats as boolean', () => { const { stderr, stdout } = run(__dirname, ['--stats']); expect(stderr).toBeFalsy(); - if (version.startsWith('5')) { + if (isWebpack5) { expect(stdout).toContain(`stats: { preset: 'normal' }`); } else { expect(stdout).toContain('stats: true'); @@ -33,7 +32,13 @@ describe('stats flag', () => { const { stderr, stdout } = run(__dirname, ['--stats', 'foo']); expect(stderr).toBeTruthy(); expect(stderr).toContain('* configuration.stats should be one of these:'); - expect(stderr).toContain('"none" | "errors-only" | "minimal" | "normal" | "detailed" | "verbose" | "errors-warnings"'); + if (isWebpack5) { + expect(stderr).toContain( + `"none" | "summary" | "errors-only" | "errors-warnings" | "minimal" | "normal" | "detailed" | "verbose"`, + ); + } else { + expect(stderr).toContain('"none" | "errors-only" | "minimal" | "normal" | "detailed" | "verbose" | "errors-warnings"'); + } expect(stdout).toBeTruthy(); }); }); diff --git a/test/target/flag-test/target-flag.test.js b/test/target/flag-test/target-flag.test.js index 3a300d692bb..899bf401f98 100644 --- a/test/target/flag-test/target-flag.test.js +++ b/test/target/flag-test/target-flag.test.js @@ -1,7 +1,7 @@ 'use strict'; const { stat } = require('fs'); const { resolve } = require('path'); -const { run } = require('../../utils/test-utils'); +const { run, isWebpack5 } = require('../../utils/test-utils'); const targetValues = ['web', 'webworker', 'node', 'async-node', 'node-webkit', 'electron-main', 'electron-renderer', 'electron-preload']; @@ -34,6 +34,10 @@ describe('--target flag', () => { it(`should throw error with invalid value for --target`, () => { const { stderr } = run(__dirname, ['--target', 'invalid']); - expect(stderr).toContain('Invalid configuration object'); + if (isWebpack5) { + expect(stderr).toContain(`Error: Unknown target 'invalid'`); + } else { + expect(stderr).toContain('Invalid configuration object'); + } }); }); diff --git a/test/utils/cli-plugin-test/plugin.test.js b/test/utils/cli-plugin-test/plugin.test.js index 8bbf2687701..96a5ff20c27 100644 --- a/test/utils/cli-plugin-test/plugin.test.js +++ b/test/utils/cli-plugin-test/plugin.test.js @@ -10,6 +10,6 @@ describe('webpack-cli-test-plugin Test', () => { if (typeof cli !== 'undefined') { expect(stdout).toContain(`alias: { alias: [ 'alias1', 'alias2' ] }`); } - expect(stdout).toContain('plugins: [ WebpackCLITestPlugin { opts: [Array] } ]'); + expect(stdout).toContain('plugins: [ WebpackCLITestPlugin { opts: [Array], showAll: true } ]'); }); }); diff --git a/test/utils/test-utils.js b/test/utils/test-utils.js index 8d96d872333..032f15de886 100644 --- a/test/utils/test-utils.js +++ b/test/utils/test-utils.js @@ -5,9 +5,11 @@ const execa = require('execa'); const { sync: spawnSync, node: execaNode } = execa; const { Writable } = require('readable-stream'); const concat = require('concat-stream'); +const { version } = require('webpack'); const WEBPACK_PATH = path.resolve(__dirname, '../../packages/webpack-cli/bin/cli.js'); const ENABLE_LOG_COMPILATION = process.env.ENABLE_PIPE || false; +const isWebpack5 = version.startsWith('5'); /** * Run the webpack CLI for a test case. @@ -275,4 +277,5 @@ module.exports = { runInstall, runInfo, hyphenToUpperCase, + isWebpack5, }; diff --git a/test/utils/webpack-cli-test-plugin.js b/test/utils/webpack-cli-test-plugin.js index f1bd89b8827..b04869a16e4 100644 --- a/test/utils/webpack-cli-test-plugin.js +++ b/test/utils/webpack-cli-test-plugin.js @@ -1,11 +1,14 @@ class WebpackCLITestPlugin { - constructor(options) { + constructor(options, showAll = true) { this.opts = options; + this.showAll = showAll; } apply(compiler) { compiler.hooks.done.tap('webpack-cli Test Plugin', () => { - console.log(compiler.options); + if (this.showAll) { + console.log(compiler.options); + } if (this.opts) { this.opts.map((e) => { const config = Object.getOwnPropertyDescriptor(compiler.options, e); diff --git a/test/zero-config/entry-present/zero-config.test.js b/test/zero-config/entry-present/zero-config.test.js index 556db6c6b49..029c385cac3 100644 --- a/test/zero-config/entry-present/zero-config.test.js +++ b/test/zero-config/entry-present/zero-config.test.js @@ -8,7 +8,7 @@ describe('Zero Config tests', () => { // Should be able to find the entry file expect(stdout).toContain('./src/index.js'); // Should output at the default output dir and filename - expect(stdout).toContain('Entrypoint main = main.js'); + expect(stdout).toContain('main.js'); // check that the output file exists expect(fs.existsSync(path.join(__dirname, '/dist/main.js'))).toBeTruthy(); expect(stderr).toBeFalsy();