diff --git a/package-lock.json b/package-lock.json index 7074cfc6..357b6d09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1391,6 +1391,15 @@ "@types/range-parser": "*" } }, + "@types/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-UoOfVEzAUpeSPmjm7h1uk5MH6KZma2z2O7a75onTGjnNvAvMVrPzPL/vBbT65iIGHWj6rokwfmYcmxmlSf2uwg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz", @@ -1600,6 +1609,15 @@ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, + "@types/mkdirp": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-0.5.2.tgz", + "integrity": "sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/mocha": { "version": "2.2.44", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.44.tgz", diff --git a/package.json b/package.json index 8cd00bc2..b26b56d5 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "tslint": "5.18.0" }, "dependencies": { - "@dojo/webpack-contrib": "8.0.0-alpha.1", + "@dojo/webpack-contrib": "file:~/Projects/opensource/webpack-contrib/dist/release/dojo-webpack-contrib-8.0.0-pre.tgz", "@typescript-eslint/eslint-plugin": "2.34.0", "@typescript-eslint/parser": "2.34.0", "caniuse-lite": "1.0.30000973", diff --git a/src/dist.config.ts b/src/dist.config.ts index 2d428463..6f909020 100644 --- a/src/dist.config.ts +++ b/src/dist.config.ts @@ -1,6 +1,5 @@ import BuildTimeRender from '@dojo/webpack-contrib/build-time-render/BuildTimeRender'; import ExternalLoaderPlugin from '@dojo/webpack-contrib/external-loader-plugin/ExternalLoaderPlugin'; -import BundleAnalyzerPlugin from '@dojo/webpack-contrib/webpack-bundle-analyzer/BundleAnalyzerPlugin'; import ServiceWorkerPlugin, { ServiceWorkerOptions } from '@dojo/webpack-contrib/service-worker-plugin/ServiceWorkerPlugin'; @@ -84,13 +83,6 @@ function webpackConfig(args: any): webpack.Configuration { config.plugins = [ ...plugins!, assetsDirExists && new CopyWebpackPlugin([{ from: assetsDir, to: path.join(outputPath, 'assets') }]), - new BundleAnalyzerPlugin({ - analyzerMode: 'static', - openAnalyzer: false, - generateStatsFile: true, - reportFilename: '../info/report.html', - statsFilename: '../info/stats.json' - }), new HtmlWebpackPlugin({ base, inject: true, diff --git a/src/logger.ts b/src/logger.ts index b99e2bc1..0c4b7fa0 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,10 +1,10 @@ -import * as fs from 'fs'; import * as path from 'path'; import * as logUpdate from 'log-update'; import * as logSymbols from 'log-symbols'; -import * as gzipSize from 'gzip-size'; import * as typescript from 'typescript'; import * as jsonFile from 'jsonfile'; +import analyzeBundles from '@dojo/webpack-contrib/webpack-bundle-analyzer/AnalyzeBundles'; +import { findLargestPackage } from '@dojo/webpack-contrib/webpack-bundle-analyzer/parseUtils'; import chalk from 'chalk'; const pkgDir = require('pkg-dir'); @@ -15,58 +15,70 @@ const version = jsonFile.readFileSync(path.join(pkgDir.sync(__dirname), 'package export default function logger(stats: any, config: any, runningMessage: string = '', args: any = {}): boolean { const singleConfig = Array.isArray(config) ? config[0] : config; const outputPath = singleConfig.output.path; - const manifestPath = path.join(outputPath, 'manifest.json'); - let assets: undefined | string[]; + const loggerStats = stats.toJson({ warningsFilter }); let chunks: undefined | string[]; - if (fs.existsSync(manifestPath)) { - const manifestContent = JSON.parse(fs.readFileSync(path.join(outputPath, 'manifest.json'), 'utf8')); - assets = Object.keys(manifestContent).map((item) => { - const assetName = manifestContent[item]; - const filePath = path.join(outputPath, assetName); - if (fs.existsSync(filePath)) { - if (args.mode === 'dev' || args.mode === 'test') { - return `${assetName}`; - } else { - const fileStats = fs.statSync(filePath); - const size = (fileStats.size / 1000).toFixed(2); - if (/\.(gz|br)$/.test(filePath)) { - return `${assetName} ${chalk.blue(`(${size}kb)`)}`; + + let chunkMap: { [chunk: string]: any }; + const excludeChunks = /(^bootstrap$)|(^runtime\/)/; + if (args.mode === 'dist') { + chunkMap = analyzeBundles(stats, config, { + analyzerMode: 'static', + openAnalyzer: false, + generateStatsFile: true, + reportFilename: '../info/report.html', + statsFilename: '../info/stats.json', + excludeBundles: '(^bootstrap\\.)|(^runtime/)' + }); + } + chunks = (Array.isArray(config) + ? loggerStats.children.reduce((chunks: any[], current: any) => [...chunks, ...current.chunks], []) + : loggerStats.chunks + ) + .filter((chunk: any) => !excludeChunks.test(chunk.names[0] || '')) + .map((chunk: any) => { + const chunkName: string = chunk.names[0]; + if (!chunkMap) { + return chunkName; + } else { + const chunkStats = chunkMap[chunkName]; + const size = ((chunkStats && (chunkStats.parsedSize || chunkStats.statSize)) || 0) / 1000; + const gzipSize = ((chunkStats && chunkStats.gzipSize) || 0) / 1000; + + const chunkInfo = `${chunkName} ${chalk.yellow(`(${size}kB)`)}${ + gzipSize ? ` / ${chalk.blue(`(${gzipSize}kB gz)`)}` : '' + }`; + + if (size > 250) { + const largestPackage = findLargestPackage(chunkStats); + if (largestPackage) { + return `${chunkInfo}\nLargest dependency is ${largestPackage.name} ${chalk.yellow( + `(${largestPackage.size / 1000}kB)` + )}`; } - // Calculate and report size when gzipped - const content = fs.readFileSync(filePath, 'utf8'); - const compressedSize = (gzipSize.sync(content) / 1000).toFixed(2); - const assetInfo = `${assetName} ${chalk.yellow(`(${size}kb)`)}`; - return `${assetInfo} / ${chalk.blue(`(${compressedSize}kb gz)`)}`; } + return chunkInfo; } - return ''; }); - chunks = (Array.isArray(config) - ? stats.children.reduce((chunks: any[], current: any) => [...chunks, ...current.chunks], []) - : stats.chunks - ).map((chunk: any) => `${chunk.names[0]}`); - } - let errors = ''; let warnings = ''; let chunkAndAssetLog = ''; let signOff = chalk.green('The build completed successfully.'); - if (stats.warnings.length) { + if (loggerStats.warnings.length) { signOff = chalk.yellow('The build completed with warnings.'); warnings = ` ${chalk.yellow('warnings:')}${chalk.gray( - stats.warnings.reduce((warnings: string, warning: string) => `${warnings}\n${stripAnsi(warning)}`, '') + loggerStats.warnings.reduce((warnings: string, warning: string) => `${warnings}\n${stripAnsi(warning)}`, '') )} `; } - if (stats.errors.length) { + if (loggerStats.errors.length) { signOff = chalk.red('The build completed with errors.'); errors = ` ${chalk.yellow('errors:')}${chalk.red( - stats.errors.reduce((errors: string, error: string) => `${errors}\n${stripAnsi(error)}`, '') + loggerStats.errors.reduce((errors: string, error: string) => `${errors}\n${stripAnsi(error)}`, '') )} `; } @@ -80,18 +92,12 @@ ${chalk.yellow('errors:')}${chalk.red( ${columns(chunks)}`; } - if (assets) { - chunkAndAssetLog = `${chunkAndAssetLog} -${chalk.yellow('assets:')} -${columns(assets)}`; - } - logUpdate(` ${logSymbols.info} cli-build-app: ${version} ${logSymbols.info} typescript: ${typescript.version} -${logSymbols.success} hash: ${stats.hash} -${logSymbols.error} errors: ${stats.errors.length} -${logSymbols.warning} warnings: ${stats.warnings.length} +${logSymbols.success} hash: ${loggerStats.hash} +${logSymbols.error} errors: ${loggerStats.errors.length} +${logSymbols.warning} warnings: ${loggerStats.warnings.length} ${errors}${warnings} ${chunkAndAssetLog} ${chalk.yellow(`output at: ${chalk.cyan(chalk.underline(`file:///${outputPath}`))}`)} @@ -100,3 +106,7 @@ ${signOff} `); return !!errors; } + +function warningsFilter(warning: string) { + return warning.includes('[mini-css-extract-plugin]\nConflicting order between'); +} diff --git a/src/main.ts b/src/main.ts index ca3d961d..9c307012 100644 --- a/src/main.ts +++ b/src/main.ts @@ -93,7 +93,7 @@ function build(configs: webpack.Configuration[], args: any) { } if (stats) { const runningMessage = args.serve ? `Listening on port ${args.port}...` : ''; - const hasErrors = logger(stats.toJson({ warningsFilter }), configs, runningMessage, args); + const hasErrors = logger(stats, configs, runningMessage, args); if (hasErrors) { reject({}); return; @@ -143,7 +143,7 @@ function fileWatch(configs: webpack.Configuration[], args: any, shouldResolve = args.port }\nPlease note the serve option is not intended to be used to serve applications in production.` : 'watching...'; - logger(stats.toJson({ warningsFilter }), configs, runningMessage, args); + logger(stats, configs, runningMessage, args); } if (shouldResolve) { resolve(compiler); @@ -286,10 +286,6 @@ async function serve(configs: webpack.Configuration[], args: any) { }); } -function warningsFilter(warning: string) { - return warning.includes('[mini-css-extract-plugin]\nConflicting order between'); -} - const command: Command = { group: 'build', name: 'app', diff --git a/tests/unit/logger.ts b/tests/unit/logger.ts index 08ff136a..7795c410 100644 --- a/tests/unit/logger.ts +++ b/tests/unit/logger.ts @@ -14,27 +14,29 @@ let mockModule: MockModule; function assertOutput(isServing = false, hasManifest = true) { const logger = mockModule.getModuleUnderTest().default; const runningMessage = isServing ? 'running...' : undefined; + const toJson = sinon.stub().returns({ + hash: 'hash', + assets: [ + { + name: 'assetOne.js', + size: 1000 + }, + { + name: 'assetOne.js', + size: 1000 + } + ], + chunks: [ + { + names: ['chunkOne'] + } + ], + errors: [], + warnings: [] + }); + const hasErrors = logger( - { - hash: 'hash', - assets: [ - { - name: 'assetOne.js', - size: 1000 - }, - { - name: 'assetOne.js', - size: 1000 - } - ], - chunks: [ - { - names: ['chunkOne'] - } - ], - errors: [], - warnings: [] - }, + { toJson }, { output: { path: path.join(__dirname, '..', 'fixtures') @@ -43,18 +45,13 @@ function assertOutput(isServing = false, hasManifest = true) { runningMessage ); - let assetOne = `assetOne.js ${chalk.yellow('(0.03kb)')} / ${chalk.blue('(0.04kb gz)')}`; let signOff = chalk.green('The build completed successfully.'); if (runningMessage) { signOff += `\n\n${runningMessage}`; } - let chunksAndAssets = ''; - if (hasManifest) { - chunksAndAssets = `${chalk.yellow('chunks:')} -${columns(['chunkOne'])} -${chalk.yellow('assets:')} -${columns([assetOne, assetOne])}`; - } + let chunks = ''; + chunks = `${chalk.yellow('chunks:')} +${columns(['chunkOne'])}`; const expectedLog = ` ${logSymbols.info} cli-build-app: 9.9.9 @@ -63,7 +60,7 @@ ${logSymbols.success} hash: hash ${logSymbols.error} errors: 0 ${logSymbols.warning} warnings: 0 ${''}${''} -${chunksAndAssets} +${chunks} ${chalk.yellow(`output at: ${chalk.cyan(chalk.underline(`file:///${path.join(__dirname, '..', 'fixtures')}`))}`)} ${signOff} @@ -71,14 +68,40 @@ ${signOff} const mockedLogUpdate = mockModule.getMock('log-update').ctor; assert.isTrue(mockedLogUpdate.calledWith(expectedLog)); assert.isFalse(hasErrors); + + const [{ warningsFilter }] = toJson.firstCall.args; + assert.isTrue(warningsFilter('[mini-css-extract-plugin]\nConflicting order between')); + assert.isFalse(warningsFilter('[mini-css-extract-plugin]')); + assert.isFalse(warningsFilter('')); + assert.isFalse(warningsFilter('some other warning')); } describe('logger', () => { beforeEach(() => { mockModule = new MockModule('../../src/logger', require); - mockModule.dependencies(['typescript', 'jsonfile', 'log-update']); + mockModule.dependencies([ + 'typescript', + 'jsonfile', + 'log-update', + '@dojo/webpack-contrib/webpack-bundle-analyzer/AnalyzeBundles', + '@dojo/webpack-contrib/webpack-bundle-analyzer/parseUtils' + ]); mockModule.getMock('jsonfile').readFileSync = sinon.stub().returns({ version: '9.9.9' }); mockModule.getMock('typescript').version = '1.1.1'; + mockModule.getMock( + '@dojo/webpack-contrib/webpack-bundle-analyzer/AnalyzeBundles' + ).default = sinon.stub().returns({ + chunkOne: { + parsedSize: 251 * 1000, + gzipSize: 800 + } + }); + mockModule.getMock( + '@dojo/webpack-contrib/webpack-bundle-analyzer/parseUtils' + ).findLargestPackage = sinon.stub().returns({ + size: 1000, + name: 'foo' + }); }); afterEach(() => { @@ -98,35 +121,32 @@ describe('logger', () => { assertOutput(true); }); - it('logging output without manifest', () => { - sinon.stub(fs, 'existsSync').returns(false); - assertOutput(false, false); - }); - it('logging output with errors', () => { const errors: any = ['error', 'otherError']; const warnings: any = ['warning', 'otherWarning']; const logger = mockModule.getModuleUnderTest().default; const hasErrors = logger( { - hash: 'hash', - assets: [ - { - name: 'assetOne.js', - size: 1000 - }, - { - name: 'assetOne.js', - size: 1000 - } - ], - chunks: [ - { - names: ['chunkOne'] - } - ], - errors, - warnings + toJson: () => ({ + hash: 'hash', + assets: [ + { + name: 'assetOne.js', + size: 1000 + }, + { + name: 'assetOne.js', + size: 1000 + } + ], + chunks: [ + { + names: ['chunkOne'] + } + ], + errors, + warnings + }) }, { output: { @@ -152,11 +172,6 @@ ${logSymbols.warning} warnings: 2 ${expectedErrors}${expectedWarnings} ${chalk.yellow('chunks:')} ${columns(['chunkOne'])} -${chalk.yellow('assets:')} -${columns([ - `assetOne.js ${chalk.yellow('(0.03kb)')} / ${chalk.blue('(0.04kb gz)')}`, - `assetOne.js ${chalk.yellow('(0.03kb)')} / ${chalk.blue('(0.04kb gz)')}` - ])} ${chalk.yellow(`output at: ${chalk.cyan(chalk.underline(`file:///${path.join(__dirname, '..', 'fixtures')}`))}`)} ${chalk.red('The build completed with errors.')} @@ -167,34 +182,101 @@ ${chalk.red('The build completed with errors.')} assert.isTrue(hasErrors); }); - it('should skip assets that do not exist', () => { + it('logging output in dist mode with a large chunk', () => { const logger = mockModule.getModuleUnderTest().default; const hasErrors = logger( { - hash: 'hash', - assets: [ - { - name: 'assetOne.js', - size: 1000 - }, - { - name: 'assetTwo.js', - size: 1000 - } - ], - chunks: [ - { - names: ['chunkOne'] - } - ], - errors: [], - warnings: [] + toJson: () => ({ + hash: 'hash', + assets: [ + { + name: 'assetOne.js', + size: 1000 + }, + { + name: 'assetOne.js', + size: 1000 + } + ], + chunks: [ + { + names: ['chunkOne'] + } + ], + errors: [], + warnings: [] + }) }, { output: { - path: path.join(__dirname, '..', 'fixtures', 'missing-assets') + path: path.join(__dirname, '..', 'fixtures') } + }, + '', + { mode: 'dist' } + ); + + const expectedLog = ` +${logSymbols.info} cli-build-app: 9.9.9 +${logSymbols.info} typescript: 1.1.1 +${logSymbols.success} hash: hash +${logSymbols.error} errors: 0 +${logSymbols.warning} warnings: 0 +${''}${''} +${chalk.yellow('chunks:')} +${columns([ + `chunkOne ${chalk.yellow('(251kB)')} / ${chalk.blue( + '(0.8kB gz)' + )}\nLargest dependency is foo ${chalk.yellow('(1kB)')}` + ])} +${chalk.yellow(`output at: ${chalk.cyan(chalk.underline(`file:///${path.join(__dirname, '..', 'fixtures')}`))}`)} + +${chalk.green('The build completed successfully.')} + `; + const mockedLogUpdate = mockModule.getMock('log-update').ctor; + assert.strictEqual(mockedLogUpdate.firstCall.args[0], expectedLog); + assert.isTrue(mockedLogUpdate.calledWith(expectedLog)); + assert.isFalse(hasErrors); + }); + + it('logging output in dist mode with a small chunk', () => { + mockModule.getMock('@dojo/webpack-contrib/webpack-bundle-analyzer/AnalyzeBundles').default.returns({ + chunkOne: { + parsedSize: 249 * 1000, + gzipSize: 800 } + }); + const logger = mockModule.getModuleUnderTest().default; + const hasErrors = logger( + { + toJson: () => ({ + hash: 'hash', + assets: [ + { + name: 'assetOne.js', + size: 1000 + }, + { + name: 'assetOne.js', + size: 1000 + } + ], + chunks: [ + { + names: ['chunkOne'] + } + ], + errors: [], + warnings: [] + }) + }, + { + output: { + path: path.join(__dirname, '..', 'fixtures') + } + }, + '', + { mode: 'dist' } ); const expectedLog = ` @@ -205,14 +287,64 @@ ${logSymbols.error} errors: 0 ${logSymbols.warning} warnings: 0 ${''}${''} ${chalk.yellow('chunks:')} -${columns(['chunkOne'])} -${chalk.yellow('assets:')} -${columns([`assetOne.js ${chalk.yellow('(0.03kb)')} / ${chalk.blue('(0.04kb gz)')}`])} -${chalk.yellow( - `output at: ${chalk.cyan( - chalk.underline(`file:///${path.join(__dirname, '..', 'fixtures', 'missing-assets')}`) - )}` - )} +${columns([`chunkOne ${chalk.yellow('(249kB)')} / ${chalk.blue('(0.8kB gz)')}`])} +${chalk.yellow(`output at: ${chalk.cyan(chalk.underline(`file:///${path.join(__dirname, '..', 'fixtures')}`))}`)} + +${chalk.green('The build completed successfully.')} + `; + const mockedLogUpdate = mockModule.getMock('log-update').ctor; + assert.strictEqual(mockedLogUpdate.firstCall.args[0], expectedLog); + assert.isTrue(mockedLogUpdate.calledWith(expectedLog)); + assert.isFalse(hasErrors); + }); + + it('logging output in dist mode when unable to find packages', () => { + mockModule + .getMock('@dojo/webpack-contrib/webpack-bundle-analyzer/parseUtils') + .findLargestPackage.returns(undefined); + const logger = mockModule.getModuleUnderTest().default; + const hasErrors = logger( + { + toJson: () => ({ + hash: 'hash', + assets: [ + { + name: 'assetOne.js', + size: 1000 + }, + { + name: 'assetOne.js', + size: 1000 + } + ], + chunks: [ + { + names: ['chunkOne'] + } + ], + errors: [], + warnings: [] + }) + }, + { + output: { + path: path.join(__dirname, '..', 'fixtures') + } + }, + '', + { mode: 'dist' } + ); + + const expectedLog = ` +${logSymbols.info} cli-build-app: 9.9.9 +${logSymbols.info} typescript: 1.1.1 +${logSymbols.success} hash: hash +${logSymbols.error} errors: 0 +${logSymbols.warning} warnings: 0 +${''}${''} +${chalk.yellow('chunks:')} +${columns([`chunkOne ${chalk.yellow('(251kB)')} / ${chalk.blue('(0.8kB gz)')}`])} +${chalk.yellow(`output at: ${chalk.cyan(chalk.underline(`file:///${path.join(__dirname, '..', 'fixtures')}`))}`)} ${chalk.green('The build completed successfully.')} `; diff --git a/tests/unit/main.ts b/tests/unit/main.ts index c9ced38e..1885d916 100644 --- a/tests/unit/main.ts +++ b/tests/unit/main.ts @@ -133,7 +133,7 @@ describe('command', () => { const main = mockModule.getModuleUnderTest().default; main.run(getMockHelper(), { mode: 'dev' }).then(() => { assert.isTrue(mockDevConfig.called); - assert.isTrue(mockLogger.calledWith('stats', ['dev config'])); + assert.isTrue(mockLogger.calledWith(stats, ['dev config'])); }); }); @@ -141,7 +141,7 @@ describe('command', () => { const main = mockModule.getModuleUnderTest().default; return main.run(getMockHelper(), { mode: 'dist' }).then(() => { assert.isTrue(mockDistConfig.called); - assert.isTrue(mockLogger.calledWith('stats', ['dist config'])); + assert.isTrue(mockLogger.calledWith(stats, ['dist config'])); }); }); @@ -149,7 +149,7 @@ describe('command', () => { const main = mockModule.getModuleUnderTest().default; return main.run(getMockHelper(), { mode: 'unit' }).then(() => { assert.isTrue(mockUnitTestConfig.called); - assert.isTrue(mockLogger.calledWith('stats', ['unit config'])); + assert.isTrue(mockLogger.calledWith(stats, ['unit config'])); }); }); @@ -157,7 +157,7 @@ describe('command', () => { const main = mockModule.getModuleUnderTest().default; return main.run(getMockHelper(), { mode: 'functional' }).then(() => { assert.isTrue(mockFunctionalTestConfig.called); - assert.isTrue(mockLogger.calledWith('stats', ['functional config'])); + assert.isTrue(mockLogger.calledWith(stats, ['functional config'])); }); }); @@ -166,7 +166,7 @@ describe('command', () => { return main.run(getMockHelper(), { target: 'electron' }).then(() => { assert.isTrue(mockDistConfig.called); assert.isTrue(mockElectronTestConfig.called); - assert.isTrue(mockLogger.calledWith('stats', ['dist config', 'electron config'])); + assert.isTrue(mockLogger.calledWith(stats, ['dist config', 'electron config'])); }); }); @@ -174,7 +174,7 @@ describe('command', () => { const main = mockModule.getModuleUnderTest().default; return main.run(getMockHelper(), { mode: 'test' }).then(() => { assert.isTrue(mockUnitTestConfig.called); - assert.isTrue(mockLogger.calledWith('stats', ['unit config'])); + assert.isTrue(mockLogger.calledWith(stats, ['unit config'])); assert.isTrue(consoleWarnStub.calledOnce); assert.isTrue( consoleWarnStub.calledWith( @@ -193,17 +193,6 @@ describe('command', () => { }); }); - it('filters CSS module order warnings from the logger', () => { - const main = mockModule.getModuleUnderTest().default; - return main.run(getMockHelper(), { mode: 'unit' }).then(() => { - const [{ warningsFilter }] = stats.toJson.firstCall.args; - assert.isTrue(warningsFilter('[mini-css-extract-plugin]\nConflicting order between')); - assert.isFalse(warningsFilter('[mini-css-extract-plugin]')); - assert.isFalse(warningsFilter('')); - assert.isFalse(warningsFilter('some other warning')); - }); - }); - it('rejects if an error occurs', () => { isError = true; const main = mockModule.getModuleUnderTest().default; @@ -295,7 +284,7 @@ describe('command', () => { ); setTimeout( dfd.callback(() => { - assert.isTrue(mockLogger.calledWith('stats', ['dist config'], 'watching...')); + assert.isTrue(mockLogger.calledWith(stats, ['dist config'], 'watching...')); }), 1000 );