From a48bf852c0eacd655c192b02691a2563c8ee461e Mon Sep 17 00:00:00 2001 From: Jack Alden Barry Date: Sun, 15 Dec 2019 02:04:08 -0600 Subject: [PATCH] Add Prettier and improve ESLint (#51) --- .eslintrc | 17 - .eslintrc.json | 35 + .prettierignore | 7 + book.json | 9 +- package.json | 22 +- src/MochaWebpack.ts | 173 +-- src/cli/index.ts | 144 +-- src/cli/parseArgv.ts | 120 +- src/cli/parseConfig.ts | 52 +- src/cli/requireWebpackConfig.ts | 106 +- src/createMochaWebpack.ts | 10 +- src/runner/TestRunner.ts | 395 ++++--- src/runner/configureMocha.ts | 59 +- src/runner/loadReporter.ts | 22 +- src/runner/loadUI.ts | 15 +- src/runner/testRunnerReporter.ts | 201 ++-- src/util/exists.ts | 9 +- src/util/glob.ts | 60 +- src/util/paths.ts | 9 +- src/util/registerRequireHook.ts | 101 +- src/webpack/compiler/createCompiler.ts | 7 +- src/webpack/compiler/createWatchCompiler.ts | 54 +- .../compiler/registerInMemoryCompiler.ts | 66 +- src/webpack/compiler/registerReadyCallback.ts | 20 +- src/webpack/loader/entryLoader.ts | 42 +- src/webpack/loader/includeFilesLoader.ts | 23 +- src/webpack/plugin/buildProgressPlugin.ts | 29 +- src/webpack/types.ts | 89 +- src/webpack/util/createEntry.ts | 17 +- src/webpack/util/createStatsFormatter.ts | 95 +- src/webpack/util/formatUtil.ts | 69 +- src/webpack/util/getAffectedModuleIds.ts | 145 ++- src/webpack/util/getBuildStats.ts | 65 +- src/webpack/util/sortChunks.ts | 47 +- test/integration/cli/code-splitting.test.ts | 164 +-- test/integration/cli/config.test.ts | 85 +- .../cli/custom-output-path.test.ts | 72 +- test/integration/cli/entry.test.ts | 969 ++++++++------- test/integration/cli/forbidOnly.test.ts | 26 +- test/integration/cli/include.test.ts | 157 +-- test/integration/cli/interactive.test.ts | 33 +- test/integration/cli/quiet.test.ts | 66 +- test/integration/cli/reporter.test.ts | 64 +- test/integration/cli/ui.test.ts | 66 +- test/integration/cli/util/childProcess.ts | 21 +- test/integration/cli/version.test.ts | 32 +- test/integration/cli/watch.test.js | 593 ---------- test/integration/cli/watch.test.ts | 926 ++++++++------- test/integration/cli/webworker.test.ts | 46 +- .../statsFormatter/mock/json-loader.ts | 4 +- .../critical-dependencies-warning/entry.ts | 2 +- .../src/critical-dependencies.ts | 2 +- .../css-strip-loader/entry.ts | 2 +- .../module-not-found-error/entry.ts | 2 +- .../entry.ts | 2 +- .../sass-loader-syntax-error/entry.ts | 2 +- .../statsFormatter/statsFormatter.test.ts | 199 ++-- test/unit/MochaWebpack.test.ts | 871 +++++++++----- .../optsTestCases/default/expected.json | 4 +- .../optsTestCases/quoted-double/expected.json | 4 +- .../optsTestCases/quoted-single/expected.json | 4 +- .../webpackConfig/webpack.config-ts.ts | 9 +- test/unit/cli/parseArgv.test.ts | 1036 +++++++++-------- test/unit/cli/parseConfig.test.ts | 71 +- test/unit/cli/requireWebpackConfig.test.ts | 106 +- test/unit/createMochaWebpack.test.ts | 22 +- test/unit/runner/configureMocha.test.ts | 143 +-- test/unit/runner/loadReporter.test.ts | 129 +- test/unit/runner/loadUI.test.ts | 104 +- test/unit/util/glob.test.ts | 200 ++-- test/unit/util/registerRequireHook.test.ts | 52 +- tsconfig.json | 11 +- tsconfig.lint.json | 8 + yarn.lock | 491 ++++---- 74 files changed, 4831 insertions(+), 4303 deletions(-) delete mode 100644 .eslintrc create mode 100644 .eslintrc.json create mode 100644 .prettierignore delete mode 100644 test/integration/cli/watch.test.js create mode 100644 tsconfig.lint.json diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 0b3c3e0..0000000 --- a/.eslintrc +++ /dev/null @@ -1,17 +0,0 @@ -{ - "parser": "babel-eslint", - "extends": [ - "airbnb-base" - ], - "env": { - "node": true - }, - "rules": { - "arrow-parens": ["error", "always"], - "max-len": ["error", 120], - "no-duplicate-imports": "off", - "no-restricted-syntax": "off", - "generator-star-spacing": "off", - "import/no-extraneous-dependencies": ["error", {"peerDependencies": true}] - } -} diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..80d2e21 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "env": { + "node": true + }, + "extends": ["airbnb-base", "prettier"], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig.lint.json" + }, + "plugins": ["@typescript-eslint"], + "rules": { + "import/extensions": [ + "error", + "ignorePackages", + { + "js": "never", + "ts": "never" + } + ], + "import/no-extraneous-dependencies": [ + "error", + { "peerDependencies": true } + ], + "no-duplicate-imports": "off", + "no-restricted-syntax": "off", + "no-unused-vars": "off" + }, + "settings": { + "import/resolver": { + "node": { + "extensions": [".js", ".ts"] + } + } + } +} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..1206160 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +**/*.coffee +**/*.opts +**/*.gitignore +**/*.txt +**/*.css +**/*.scss +test/**/*.js \ No newline at end of file diff --git a/book.json b/book.json index 84897a3..ab3b4f9 100644 --- a/book.json +++ b/book.json @@ -2,7 +2,14 @@ "gitbook": "3.2.2", "title": "mochapack", "description": "mocha cli with webpack support", - "plugins": ["edit-link", "-search", "github", "anchors", "prism", "-highlight"], + "plugins": [ + "edit-link", + "-search", + "github", + "anchors", + "prism", + "-highlight" + ], "pluginsConfig": { "edit-link": { "base": "https://github.com/sysgears/mochapack/tree/master", diff --git a/package.json b/package.json index be7afab..b94b856 100644 --- a/package.json +++ b/package.json @@ -18,10 +18,11 @@ "clean-lib": "del-cli \"lib/**\" \"!lib\" \"!lib/reporters\" \"!lib/utils.js\" \"!lib/entry.js\" \"!lib/reporters/base.js\"", "clean-tmp": "del-cli \".tmp/**\"", "build": "yarn run clean-lib && tsc", - "lint": "eslint src test bin --fix", + "format": "prettier {src,test}/**/* ./*.json --write --loglevel warn", + "lint": "eslint src/**/*.ts test/**/*.ts --fix", "test": "yarn run clean-tmp && yarn run build && ts-mocha --timeout 10000 --recursive --require @babel/register --exit \"test/**/*.test.ts\"", "cover": "cross-env BABEL_ENV=coverage nyc --reporter=lcov --reporter=text npm test", - "posttest": "yarn run lint", + "posttest": "yarn run format && yarn run lint", "docs:clean": "del-cli _book", "docs:prepare": "gitbook install", "docs:build": "yarn run docs:clean && yarn run docs:prepare && gitbook build", @@ -60,9 +61,13 @@ "@babel/preset-typescript": "^7.7.4", "@babel/register": "^7.0.0", "@babel/runtime": "^7.7.6", + "@types/chai": "^4.2.7", "@types/lodash": "^4.14.149", + "@types/mocha": "^5.2.7", "@types/node": "^12.12.17", "@types/webpack": "^4.41.0", + "@typescript-eslint/eslint-plugin": "^2.11.0", + "@typescript-eslint/parser": "^2.11.0", "anymatch": "3.1.1", "babel-eslint": "^9.0.0", "babel-loader": "^8.0.0", @@ -75,8 +80,9 @@ "css-loader": "3.2.0", "del": "5.1.0", "del-cli": "3.0.0", - "eslint": "4.19.1", + "eslint": "^6.7.2", "eslint-config-airbnb-base": "12.1.0", + "eslint-config-prettier": "^6.7.0", "eslint-plugin-import": "^2.9.0", "fs-extra": "5.0.0", "gh-pages": "1.2.0", @@ -90,6 +96,7 @@ "node-sass": "^4.11.0", "np": "5.1.0", "nyc": "14.1.1", + "prettier": "^1.19.1", "sass-loader": "6.0.7", "sinon": "7.5.0", "strip-ansi": "^5.2.0", @@ -130,11 +137,18 @@ ] }, "nyc": { - "extension": [".ts"], + "extension": [ + ".ts" + ], "include": [ "src/**/*.ts" ] }, + "prettier": { + "semi": false, + "singleQuote": true, + "endOfLine": "lf" + }, "resolutions": { "js-yaml": ">=3.13.0", "lodash.mergewith": ">=4.6.2", diff --git a/src/MochaWebpack.ts b/src/MochaWebpack.ts index 9edb49b..8b5fa3e 100644 --- a/src/MochaWebpack.ts +++ b/src/MochaWebpack.ts @@ -1,32 +1,31 @@ - -import TestRunner from "./runner/TestRunner"; -import testRunnerReporter from "./runner/testRunnerReporter"; +import TestRunner from './runner/TestRunner' +import testRunnerReporter from './runner/testRunnerReporter' export type MochaWebpackOptions = { - cwd: string; - webpackConfig: {}; - bail: boolean; - reporter: string | (() => void); - reporterOptions: {}; - ui: string; - fgrep?: string; - grep?: string | RegExp; - invert: boolean; - ignoreLeaks: boolean; - fullStackTrace: boolean; - colors?: boolean; - useInlineDiffs: boolean; - timeout: number; - retries?: number; - slow: number; - asyncOnly: boolean; - delay: boolean; - interactive: boolean; - clearTerminal: boolean; - quiet: boolean; - growl?: boolean; - forbidOnly: boolean; -}; + cwd: string + webpackConfig: {} + bail: boolean + reporter: string | ReporterConstructor + reporterOptions: {} + ui: string + fgrep?: string + grep?: string | RegExp + invert: boolean + ignoreLeaks: boolean + fullStackTrace: boolean + colors?: boolean + useInlineDiffs: boolean + timeout: number + retries?: number + slow: number + asyncOnly: boolean + delay: boolean + interactive: boolean + clearTerminal: boolean + quiet: boolean + growl?: boolean + forbidOnly: boolean +} export default class MochaWebpack { /** @@ -34,14 +33,14 @@ export default class MochaWebpack { * * @private */ - entries: Array = []; + entries: Array = [] /** * Files to include into the bundle * * @private */ - includes: Array = []; + includes: Array = [] /** * Options @@ -67,7 +66,7 @@ export default class MochaWebpack { clearTerminal: false, quiet: false, forbidOnly: false - }; + } /** * Add file run test against @@ -77,8 +76,8 @@ export default class MochaWebpack { * @return {MochaWebpack} */ addEntry(file: string): MochaWebpack { - this.entries = [...this.entries, file]; - return this; + this.entries = [...this.entries, file] + return this } /** @@ -89,8 +88,8 @@ export default class MochaWebpack { * @return {MochaWebpack} */ addInclude(file: string): MochaWebpack { - this.includes = [...this.includes, file]; - return this; + this.includes = [...this.includes, file] + return this } /** @@ -104,8 +103,8 @@ export default class MochaWebpack { this.options = { ...this.options, cwd - }; - return this; + } + return this } /** @@ -119,8 +118,8 @@ export default class MochaWebpack { this.options = { ...this.options, webpackConfig: config - }; - return this; + } + return this } /** @@ -134,8 +133,8 @@ export default class MochaWebpack { this.options = { ...this.options, bail - }; - return this; + } + return this } /** @@ -145,13 +144,16 @@ export default class MochaWebpack { * @param {Object} reporterOptions optional options * @return {MochaWebpack} */ - reporter(reporter: string | (() => void), reporterOptions: {}): MochaWebpack { + reporter( + reporter: string | ReporterConstructor, + reporterOptions: {} + ): MochaWebpack { this.options = { ...this.options, reporter, reporterOptions - }; - return this; + } + return this } /** @@ -165,8 +167,8 @@ export default class MochaWebpack { this.options = { ...this.options, ui - }; - return this; + } + return this } /** @@ -180,8 +182,8 @@ export default class MochaWebpack { this.options = { ...this.options, fgrep: str - }; - return this; + } + return this } /** @@ -195,8 +197,8 @@ export default class MochaWebpack { this.options = { ...this.options, grep: pattern - }; - return this; + } + return this } /** @@ -209,8 +211,8 @@ export default class MochaWebpack { this.options = { ...this.options, invert: true - }; - return this; + } + return this } /** @@ -224,8 +226,8 @@ export default class MochaWebpack { this.options = { ...this.options, ignoreLeaks: ignore - }; - return this; + } + return this } /** @@ -238,8 +240,8 @@ export default class MochaWebpack { this.options = { ...this.options, fullStackTrace: true - }; - return this; + } + return this } /** @@ -253,8 +255,8 @@ export default class MochaWebpack { this.options = { ...this.options, colors - }; - return this; + } + return this } /** @@ -267,8 +269,8 @@ export default class MochaWebpack { this.options = { ...this.options, quiet: true - }; - return this; + } + return this } /** @@ -282,8 +284,8 @@ export default class MochaWebpack { this.options = { ...this.options, useInlineDiffs: inlineDiffs - }; - return this; + } + return this } /** @@ -297,8 +299,8 @@ export default class MochaWebpack { this.options = { ...this.options, timeout - }; - return this; + } + return this } /** @@ -312,11 +314,10 @@ export default class MochaWebpack { this.options = { ...this.options, retries: count - }; - return this; + } + return this } - /** * Set slowness threshold in milliseconds. * @@ -328,8 +329,8 @@ export default class MochaWebpack { this.options = { ...this.options, slow: threshold - }; - return this; + } + return this } /** @@ -342,8 +343,8 @@ export default class MochaWebpack { this.options = { ...this.options, asyncOnly: true - }; - return this; + } + return this } /** @@ -356,8 +357,8 @@ export default class MochaWebpack { this.options = { ...this.options, delay: true - }; - return this; + } + return this } /** @@ -371,8 +372,8 @@ export default class MochaWebpack { this.options = { ...this.options, interactive - }; - return this; + } + return this } /** @@ -386,8 +387,8 @@ export default class MochaWebpack { this.options = { ...this.options, clearTerminal - }; - return this; + } + return this } /** @@ -401,8 +402,8 @@ export default class MochaWebpack { this.options = { ...this.options, growl: true - }; - return this; + } + return this } /** @@ -416,8 +417,8 @@ export default class MochaWebpack { this.options = { ...this.options, forbidOnly: true - }; - return this; + } + return this } /** @@ -427,15 +428,15 @@ export default class MochaWebpack { * @return {Promise} a Promise that gets resolved with the number of failed tests or rejected with build error */ async run(): Promise { - const runner = new TestRunner(this.entries, this.includes, this.options); + const runner = new TestRunner(this.entries, this.includes, this.options) testRunnerReporter({ eventEmitter: runner, interactive: this.options.interactive, quiet: this.options.quiet, cwd: this.options.cwd, clearTerminal: this.options.clearTerminal - }); - return runner.run(); + }) + return runner.run() } /** @@ -443,14 +444,14 @@ export default class MochaWebpack { * @public */ async watch(): Promise { - const runner = new TestRunner(this.entries, this.includes, this.options); + const runner = new TestRunner(this.entries, this.includes, this.options) testRunnerReporter({ eventEmitter: runner, interactive: this.options.interactive, quiet: this.options.quiet, cwd: this.options.cwd, clearTerminal: this.options.clearTerminal - }); - await runner.watch(); + }) + await runner.watch() } } diff --git a/src/cli/index.ts b/src/cli/index.ts index 0d17574..c7d1ed1 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,128 +1,138 @@ -import path from "path"; -import _ from "lodash"; - -import parseArgv from "./parseArgv"; -import { existsFileSync } from "../util/exists"; -import parseConfig from "./parseConfig"; -import requireWebpackConfig from "./requireWebpackConfig"; -import { ensureGlob, extensionsToGlob } from "../util/glob"; -import { createMochaWebpack } from "../createMochaWebpack"; +import path from 'path' +import _ from 'lodash' +import parseArgv from './parseArgv' +import { existsFileSync } from '../util/exists' +import parseConfig from './parseConfig' +import requireWebpackConfig from './requireWebpackConfig' +import { ensureGlob, extensionsToGlob } from '../util/glob' +import createMochaWebpack from '../createMochaWebpack' function resolve(mod) { - const absolute = existsFileSync(mod) || existsFileSync(`${mod}.js`); - const file = absolute ? path.resolve(mod) : mod; - return file; + const absolute = existsFileSync(mod) || existsFileSync(`${mod}.js`) + const file = absolute ? path.resolve(mod) : mod + return file } function exit(lazy, code) { if (lazy) { process.on('exit', () => { - process.exit(code); - }); + process.exit(code) + }) } else { - process.exit(code); + process.exit(code) } } async function cli() { - const cliOptions = parseArgv(process.argv.slice(2), true); - const configOptions = parseConfig(cliOptions.opts); - const requiresWebpackConfig = cliOptions.webpackConfig != null || configOptions.webpackConfig != null; - const defaultOptions = parseArgv([]); + const cliOptions = parseArgv(process.argv.slice(2), true) + const configOptions = parseConfig(cliOptions.opts) + const requiresWebpackConfig = + cliOptions.webpackConfig != null || configOptions.webpackConfig != null + const defaultOptions = parseArgv([]) - const options = _.defaults({}, cliOptions, configOptions, defaultOptions); + const options = _.defaults({}, cliOptions, configOptions, defaultOptions) options.require.forEach(mod => { - require(resolve(mod)); // eslint-disable-line global-require, import/no-dynamic-require - }); + require(resolve(mod)) // eslint-disable-line global-require, import/no-dynamic-require + }) - options.include = options.include.map(resolve); + options.include = options.include.map(resolve) - options.webpackConfig = await requireWebpackConfig(options.webpackConfig, requiresWebpackConfig, options.webpackEnv, options.mode); + options.webpackConfig = await requireWebpackConfig( + options.webpackConfig, + requiresWebpackConfig, + options.webpackEnv, + options.mode + ) - const mochaWebpack = createMochaWebpack(); + const mochaWebpack = createMochaWebpack() - options.include.forEach(f => mochaWebpack.addInclude(f)); + options.include.forEach(f => mochaWebpack.addInclude(f)) - const extensions = _.get(options.webpackConfig, 'resolve.extensions', ['.js']); - const fallbackFileGlob = extensionsToGlob(extensions); - const fileGlob = options.glob != null ? options.glob : fallbackFileGlob; + const extensions = _.get(options.webpackConfig, 'resolve.extensions', ['.js']) + const fallbackFileGlob = extensionsToGlob(extensions) + const fileGlob = options.glob != null ? options.glob : fallbackFileGlob - options.files.forEach(f => mochaWebpack.addEntry(ensureGlob(f, options.recursive, fileGlob))); + options.files.forEach(f => + mochaWebpack.addEntry(ensureGlob(f, options.recursive, fileGlob)) + ) - mochaWebpack.cwd(process.cwd()); - mochaWebpack.webpackConfig(options.webpackConfig); - mochaWebpack.bail(options.bail); - mochaWebpack.reporter(options.reporter, options.reporterOptions); - mochaWebpack.ui(options.ui); - mochaWebpack.interactive(options.interactive); - mochaWebpack.clearTerminal(options.clearTerminal); + mochaWebpack.cwd(process.cwd()) + mochaWebpack.webpackConfig(options.webpackConfig) + mochaWebpack.bail(options.bail) + mochaWebpack.reporter(options.reporter, options.reporterOptions) + mochaWebpack.ui(options.ui) + mochaWebpack.interactive(options.interactive) + mochaWebpack.clearTerminal(options.clearTerminal) if (options.fgrep) { - mochaWebpack.fgrep(options.fgrep); + mochaWebpack.fgrep(options.fgrep) } if (options.grep) { - mochaWebpack.grep(options.grep); + mochaWebpack.grep(options.grep) } if (options.invert) { - mochaWebpack.invert(); + mochaWebpack.invert() } if (options.checkLeaks) { - mochaWebpack.ignoreLeaks(false); + mochaWebpack.ignoreLeaks(false) } if (options.fullTrace) { - mochaWebpack.fullStackTrace(); + mochaWebpack.fullStackTrace() } if (options.quiet) { - mochaWebpack.quiet(); + mochaWebpack.quiet() } - mochaWebpack.useColors(options.colors); - mochaWebpack.useInlineDiffs(options.inlineDiffs); - mochaWebpack.timeout(options.timeout); + mochaWebpack.useColors(options.colors) + mochaWebpack.useInlineDiffs(options.inlineDiffs) + mochaWebpack.timeout(options.timeout) if (options.retries) { - mochaWebpack.retries(options.retries); + mochaWebpack.retries(options.retries) } - mochaWebpack.slow(options.slow); + mochaWebpack.slow(options.slow) if (options.asyncOnly) { - mochaWebpack.asyncOnly(); + mochaWebpack.asyncOnly() } if (options.delay) { - mochaWebpack.delay(); + mochaWebpack.delay() } if (options.growl) { - mochaWebpack.growl(); + mochaWebpack.growl() } if (options.forbidOnly) { - mochaWebpack.forbidOnly(); + mochaWebpack.forbidOnly() } - // @ts-ignore - await Promise.resolve().then(() => { - if (options.watch) { - return mochaWebpack.watch(); - } - return mochaWebpack.run(); - }).then(failures => { - exit(options.exit, failures); - }).catch(e => { - if (e) { - console.error(e.stack); // eslint-disable-line - } - exit(options.exit, 1); - }); + await Promise.resolve() + // @ts-ignore + .then(() => { + if (options.watch) { + return mochaWebpack.watch() + } + return mochaWebpack.run() + }) + .then(failures => { + exit(options.exit, failures) + }) + .catch(e => { + if (e) { + console.error(e.stack) // eslint-disable-line + } + exit(options.exit, 1) + }) } -cli(); +cli() diff --git a/src/cli/parseArgv.ts b/src/cli/parseArgv.ts index 4e1b54e..39b7187 100644 --- a/src/cli/parseArgv.ts +++ b/src/cli/parseArgv.ts @@ -1,9 +1,9 @@ -import yargs from "yargs"; -import _ from "lodash"; +import yargs from 'yargs' +import _ from 'lodash' -const BASIC_GROUP = 'Basic options:'; -const OUTPUT_GROUP = 'Output options:'; -const ADVANCED_GROUP = 'Advanced options:'; +const BASIC_GROUP = 'Basic options:' +const OUTPUT_GROUP = 'Output options:' +const ADVANCED_GROUP = 'Advanced options:' const options = { 'async-only': { @@ -76,7 +76,8 @@ const options = { }, glob: { type: 'string', - describe: 'only test files matching (only valid for directory entry)', + describe: + 'only test files matching (only valid for directory entry)', group: ADVANCED_GROUP, requiresArg: true }, @@ -166,7 +167,8 @@ const options = { }, exit: { type: 'boolean', - describe: 'require a clean shutdown of the event loop: mocha will not call process.exit', + describe: + 'require a clean shutdown of the event loop: mocha will not call process.exit', group: ADVANCED_GROUP, default: false }, @@ -211,102 +213,122 @@ const options = { group: ADVANCED_GROUP, default: false } -}; +} -const paramList = opts => _.map(_.keys(opts), _.camelCase); -const parameters = paramList(options); // camel case parameters +const paramList = opts => _.map(_.keys(opts), _.camelCase) +const parameters = paramList(options) // camel case parameters // @ts-ignore -const parametersWithMultipleArgs = paramList(_.pickBy(_.mapValues(options, v => !!v.requiresArg && v.multiple === true))); // eslint-disable-line max-len +const parametersWithMultipleArgs = paramList( + // @ts-ignore + _.pickBy(_.mapValues(options, v => !!v.requiresArg && v.multiple === true)) +) // eslint-disable-line max-len // @ts-ignore -const groupedAliases = _.values(_.mapValues(options, (value, key) => [_.camelCase(key), key, value.alias].filter(_.identity))); // eslint-disable-line max-len +const groupedAliases = _.values( + _.mapValues(options, (value, key) => + // @ts-ignore + [_.camelCase(key), key, value.alias].filter(_.identity) + ) +) // eslint-disable-line max-len function parse(argv, ignoreDefaults) { - const parsedArgs = yargs().help('help').alias('help', 'h').version().options(options).strict().parse(argv); + const parsedArgs = yargs + .help('help') + .alias('help', 'h') + .version() + // @ts-ignore + .options(options) + .strict() + .parse(argv) - let files = parsedArgs._; + let files = parsedArgs._ if (!files.length) { - files = ['./test']; + files = ['./test'] } - - const parsedOptions = _.pick(parsedArgs, parameters); // pick all parameters as new object - const validOptions = _.omitBy(parsedOptions, _.isUndefined); // remove all undefined values + const parsedOptions = _.pick(parsedArgs, parameters) // pick all parameters as new object + const validOptions = _.omitBy(parsedOptions, _.isUndefined) // remove all undefined values _.forEach(parametersWithMultipleArgs, key => { if (_.has(validOptions, key)) { - const value = validOptions[key]; + const value = validOptions[key] if (!Array.isArray(value)) { - validOptions[key] = [value]; + validOptions[key] = [value] } } - }); + }) _.forOwn(validOptions, (value, key) => { // validate all non-array options with required arg that it is not duplicated // see https://github.com/yargs/yargs/issues/229 if (parametersWithMultipleArgs.indexOf(key) === -1 && _.isArray(value)) { - const arg = _.kebabCase(key); - const provided = value.map(v => `--${arg} ${v}`).join(' '); - const expected = `--${arg} ${value[0]}`; + const arg = _.kebabCase(key) + const provided = value.map(v => `--${arg} ${v}`).join(' ') + const expected = `--${arg} ${value[0]}` - throw new Error(`Duplicating arguments for "--${arg}" is not allowed. "${provided}" was provided, but expected "${expected}"`); // eslint-disable-line max-len + throw new Error( + `Duplicating arguments for "--${arg}" is not allowed. "${provided}" was provided, but expected "${expected}"` + ) // eslint-disable-line max-len } - }); + }) - validOptions.files = files; + validOptions.files = files - const reporterOptions = {}; + const reporterOptions = {} if (validOptions.reporterOptions) { validOptions.reporterOptions.split(',').forEach(opt => { - const L = opt.split('='); + const L = opt.split('=') if (L.length > 2 || L.length === 0) { - throw new Error(`invalid reporter option ${opt}`); + throw new Error(`invalid reporter option ${opt}`) } else if (L.length === 2) { - reporterOptions[L[0]] = L[1]; // eslint-disable-line prefer-destructuring + reporterOptions[L[0]] = L[1] // eslint-disable-line prefer-destructuring } else { - reporterOptions[L[0]] = true; + reporterOptions[L[0]] = true } - }); + }) } - validOptions.reporterOptions = reporterOptions; - validOptions.require = validOptions.require || []; - validOptions.include = validOptions.include || []; + validOptions.reporterOptions = reporterOptions + validOptions.require = validOptions.require || [] + validOptions.include = validOptions.include || [] if (validOptions.webpackEnv) { _.mapValues(validOptions.webpackEnv, (value, key) => { if (Array.isArray(value)) { - const [first] = value; - validOptions.webpackEnv[key] = first; + const [first] = value + validOptions.webpackEnv[key] = first } - }); + }) } if (ignoreDefaults) { - const userOptions = yargs(argv).argv; - const providedKeys = _.keys(userOptions); - const usedAliases = _.flatten(_.filter(groupedAliases, aliases => _.some(aliases, alias => providedKeys.indexOf(alias) !== -1))); + const userOptions = yargs(argv).argv + const providedKeys = _.keys(userOptions) + const usedAliases = _.flatten( + _.filter(groupedAliases, aliases => + _.some(aliases, alias => providedKeys.indexOf(alias) !== -1) + ) + ) if (parsedArgs._.length) { - usedAliases.push('files'); + usedAliases.push('files') } - return _.pick(validOptions, usedAliases); + return _.pick(validOptions, usedAliases) } - return validOptions; + return validOptions } export default function parseArgv(argv, ignoreDefaults = false) { - const origMainFilename = require.main.filename; + const origMainFilename = require.main.filename try { // yargs searches for package.json up starting from `require.main.filename` path with `yargs` parser configuration // it results in finding mocha `package.json` with config for yargs, which is different then we need - require.main.filename = require.resolve('../../bin/_mocha'); - return parse(argv, ignoreDefaults); + require.main.filename = require.resolve('../../bin/_mocha') + return parse(argv, ignoreDefaults) } finally { - require.main.filename = origMainFilename; + require.main.filename = origMainFilename } } diff --git a/src/cli/parseConfig.ts b/src/cli/parseConfig.ts index 2b8b79f..24b58f6 100644 --- a/src/cli/parseConfig.ts +++ b/src/cli/parseConfig.ts @@ -1,45 +1,55 @@ -import fs from "fs"; -import { existsFileSync } from "../util/exists"; -import parseArgv from "./parseArgv"; +import fs from 'fs' +import { existsFileSync } from '../util/exists' +import parseArgv from './parseArgv' -const defaultConfig = 'mochapack.opts'; +const defaultConfig = 'mochapack.opts' function handleMissingConfig(config) { if (config) { - throw new Error(`Options file '${config}' not found`); + throw new Error(`Options file '${config}' not found`) } - return {}; + return {} } const createStripSurroundingChar = c => s => { - if (s.indexOf(c) === 0 && s.lastIndexOf(c) === s.length - 1 && s.indexOf(c) !== s.lastIndexOf(c)) { - return s.substring(1, s.length - 1); + if ( + s.indexOf(c) === 0 && + s.lastIndexOf(c) === s.length - 1 && + s.indexOf(c) !== s.lastIndexOf(c) + ) { + return s.substring(1, s.length - 1) } - return s; -}; + return s +} -const stripSingleQuotes = createStripSurroundingChar("'"); -const stripDoubleQuotes = createStripSurroundingChar('"'); +const stripSingleQuotes = createStripSurroundingChar("'") +const stripDoubleQuotes = createStripSurroundingChar('"') const removeSurroundingQuotes = str => { - const stripped = stripDoubleQuotes(str); + const stripped = stripDoubleQuotes(str) if (stripped !== str) { // strip only once - return stripped; + return stripped } - return stripSingleQuotes(str); -}; + return stripSingleQuotes(str) +} export default function parseConfig(explicitConfig?: any) { - const config = explicitConfig || defaultConfig; + const config = explicitConfig || defaultConfig if (!existsFileSync(config)) { - return handleMissingConfig(explicitConfig); + return handleMissingConfig(explicitConfig) } - const argv = fs.readFileSync(config, 'utf8').replace(/\\\s/g, '%20').split(/\s/).filter(Boolean).map(value => value.replace(/%20/g, ' ')).map(removeSurroundingQuotes); - const defaultOptions = parseArgv(argv, true); - return defaultOptions; + const argv = fs + .readFileSync(config, 'utf8') + .replace(/\\\s/g, '%20') + .split(/\s/) + .filter(Boolean) + .map(value => value.replace(/%20/g, ' ')) + .map(removeSurroundingQuotes) + const defaultOptions = parseArgv(argv, true) + return defaultOptions } diff --git a/src/cli/requireWebpackConfig.ts b/src/cli/requireWebpackConfig.ts index e0b5ad5..6ddf25c 100644 --- a/src/cli/requireWebpackConfig.ts +++ b/src/cli/requireWebpackConfig.ts @@ -1,121 +1,133 @@ -import path from "path"; -import fs from "fs"; -import interpret from "interpret"; -import { Configuration as WebpackConfig } from "webpack"; +import path from 'path' +import fs from 'fs' +import interpret from 'interpret' +import { Configuration as WebpackConfig } from 'webpack' type WebpackConfigMode = 'production' | 'development' | 'none' function sortExtensions(ext1, ext2) { if (ext1 === '.js') { - return -1; + return -1 } if (ext2 === '.js') { - return 1; + return 1 } - return ext1.length - ext2.length; + return ext1.length - ext2.length } -const extensions = Object.keys(interpret.extensions).sort(sortExtensions); +const extensions = Object.keys(interpret.extensions).sort(sortExtensions) function fileExists(filePath) { try { - return fs.existsSync(filePath); + return fs.existsSync(filePath) } catch (e) { - return false; + return false } } function findConfigFile(dirPath, baseName) { for (let i = 0; i < extensions.length; i += 1) { - const filePath = path.resolve(dirPath, `${baseName}${extensions[i]}`); + const filePath = path.resolve(dirPath, `${baseName}${extensions[i]}`) if (fileExists(filePath)) { - return filePath; + return filePath } } - return null; + return null } function getConfigExtension(configPath) { for (let i = extensions.length - 1; i >= 0; i -= 1) { - const extension = extensions[i]; - if (configPath.indexOf(extension, configPath.length - extension.length) > -1) { - return extension; + const extension = extensions[i] + if ( + configPath.indexOf(extension, configPath.length - extension.length) > -1 + ) { + return extension } } - return path.extname(configPath); + return path.extname(configPath) } function registerCompiler(moduleDescriptor) { if (!moduleDescriptor) { - return; + return } if (typeof moduleDescriptor === 'string') { - require(moduleDescriptor); // eslint-disable-line global-require, import/no-dynamic-require + require(moduleDescriptor) // eslint-disable-line global-require, import/no-dynamic-require } else if (!Array.isArray(moduleDescriptor)) { - const module = require(moduleDescriptor.module); // eslint-disable-line global-require, import/no-dynamic-require - moduleDescriptor.register(module); + const module = require(moduleDescriptor.module) // eslint-disable-line global-require, import/no-dynamic-require + moduleDescriptor.register(module) } else { for (let i = 0; i < moduleDescriptor.length; i += 1) { try { - registerCompiler(moduleDescriptor[i]); - break; - } catch (e) {// do nothing + registerCompiler(moduleDescriptor[i]) + break + } catch (e) { + // do nothing } } } } -export default async function requireWebpackConfig(webpackConfig, required?: boolean, env?: string, mode?: WebpackConfigMode) { - const configPath = path.resolve(webpackConfig); - const configExtension = getConfigExtension(configPath); - let configFound = false; - let config: WebpackConfig | ((...args: any[]) => Promise) = {}; +export default async function requireWebpackConfig( + webpackConfig, + required?: boolean, + env?: string, + mode?: WebpackConfigMode +) { + const configPath = path.resolve(webpackConfig) + const configExtension = getConfigExtension(configPath) + let configFound = false + let config: WebpackConfig | ((...args: any[]) => Promise) = {} if (fileExists(configPath)) { // config exists, register compiler for non-js extensions - registerCompiler(interpret.extensions[configExtension]); + registerCompiler(interpret.extensions[configExtension]) // require config - config = require(configPath); // eslint-disable-line global-require, import/no-dynamic-require - configFound = true; + config = require(configPath) // eslint-disable-line global-require, import/no-dynamic-require + configFound = true } else if (configExtension === '.js') { // config path does not exist, try to require it with precompiler - const configDirPath = path.dirname(configPath); - const configBaseName = path.basename(configPath, configExtension); - const configPathPrecompiled = findConfigFile(configDirPath, configBaseName); + const configDirPath = path.dirname(configPath) + const configBaseName = path.basename(configPath, configExtension) + const configPathPrecompiled = findConfigFile(configDirPath, configBaseName) if (configPathPrecompiled != null) { // found a config that needs to be precompiled - const configExtensionPrecompiled = getConfigExtension(configPathPrecompiled); + const configExtensionPrecompiled = getConfigExtension( + configPathPrecompiled + ) // register compiler & require config - registerCompiler(interpret.extensions[configExtensionPrecompiled]); - config = require(configPathPrecompiled); // eslint-disable-line global-require, import/no-dynamic-require - configFound = true; + registerCompiler(interpret.extensions[configExtensionPrecompiled]) + config = require(configPathPrecompiled) // eslint-disable-line global-require, import/no-dynamic-require + configFound = true } } if (!configFound) { if (required) { - throw new Error(`Webpack config could not be found: ${webpackConfig}`); + throw new Error(`Webpack config could not be found: ${webpackConfig}`) } else if (mode != null) { - (config as WebpackConfig).mode = mode; + ;(config as WebpackConfig).mode = mode } - return config; + return config } // @ts-ignore - config = config.default || config; + config = config.default || config if (typeof config === 'function') { - config = await Promise.resolve(config(env)); + config = await Promise.resolve(config(env)) } if (mode != null) { - config.mode = mode; + config.mode = mode } if (Array.isArray(config)) { - throw new Error('Passing multiple configs as an Array is not supported. Please provide a single config instead.'); + throw new Error( + 'Passing multiple configs as an Array is not supported. Please provide a single config instead.' + ) } - return config; + return config } diff --git a/src/createMochaWebpack.ts b/src/createMochaWebpack.ts index 1f6a4c6..3e7af16 100644 --- a/src/createMochaWebpack.ts +++ b/src/createMochaWebpack.ts @@ -1,7 +1,5 @@ +import MochaWebpack from './MochaWebpack' -import MochaWebpack from "./MochaWebpack"; - -// module.exports cause of babel 6 -export function createMochaWebpack(): MochaWebpack { - return new MochaWebpack(); -}; +export default function createMochaWebpack(): MochaWebpack { + return new MochaWebpack() +} diff --git a/src/runner/TestRunner.ts b/src/runner/TestRunner.ts index 8b30b39..44460c9 100644 --- a/src/runner/TestRunner.ts +++ b/src/runner/TestRunner.ts @@ -1,210 +1,226 @@ - -import path from "path"; -import EventEmitter from "events"; -import _ from "lodash"; -import chokidar from "chokidar"; -import minimatch from "minimatch"; - -import { glob } from "../util/glob"; -import createCompiler from "../webpack/compiler/createCompiler"; -import createWatchCompiler from "../webpack/compiler/createWatchCompiler"; -import registerInMemoryCompiler from "../webpack/compiler/registerInMemoryCompiler"; -import registerReadyCallback from "../webpack/compiler/registerReadyCallback"; - -import { EntryConfig } from "../webpack/loader/entryLoader"; -import configureMocha from "./configureMocha"; -import getBuildStats from "../webpack/util/getBuildStats"; -import buildProgressPlugin from "../webpack/plugin/buildProgressPlugin"; - -import { MochaWebpackOptions } from "../MochaWebpack"; -import { BuildStats } from "../webpack/util/getBuildStats"; -import { WatchCompiler } from "../webpack/compiler/createWatchCompiler"; -import { Configuration as WebpackConfig, Compiler, Stats } from "webpack"; - -const entryPath = path.resolve(__dirname, '../entry.js'); -const entryLoaderPath = path.resolve(__dirname, '../webpack/loader/entryLoader.js'); -const includeLoaderPath = path.resolve(__dirname, '../webpack/loader/includeFilesLoader.js'); -const noop = () => undefined; - +import path from 'path' +import EventEmitter from 'events' +import _ from 'lodash' +import chokidar from 'chokidar' +import minimatch from 'minimatch' +import { Configuration as WebpackConfig, Compiler, Stats } from 'webpack' + +import { glob } from '../util/glob' +import createCompiler from '../webpack/compiler/createCompiler' +import createWatchCompiler, { + WatchCompiler +} from '../webpack/compiler/createWatchCompiler' +import registerInMemoryCompiler from '../webpack/compiler/registerInMemoryCompiler' +import registerReadyCallback from '../webpack/compiler/registerReadyCallback' +import { EntryConfig } from '../webpack/loader/entryLoader' +import configureMocha from './configureMocha' +import getBuildStats, { BuildStats } from '../webpack/util/getBuildStats' +import buildProgressPlugin from '../webpack/plugin/buildProgressPlugin' + +import { MochaWebpackOptions } from '../MochaWebpack' + +const entryPath = path.resolve(__dirname, '../entry.js') +const entryLoaderPath = path.resolve( + __dirname, + '../webpack/loader/entryLoader.js' +) +const includeLoaderPath = path.resolve( + __dirname, + '../webpack/loader/includeFilesLoader.js' +) +const noop = () => undefined type MochaRunner = { - abort: () => void; + abort: () => void currentRunnable?: { - retries: (count: number) => void; - enableTimeouts: (enabled: boolean) => void; - timeout: (ms: number) => void; - resetTimeout: (ms: number) => void; - }; -}; + retries: (count: number) => void + enableTimeouts: (enabled: boolean) => void + timeout: (ms: number) => void + resetTimeout: (ms: number) => void + } +} type Mocha = { - run: (cb: (failures: number) => void) => MochaRunner; -}; + run: (cb: (failures: number) => void) => MochaRunner +} export default class TestRunner extends EventEmitter { - - entries: Array; - includes: Array; - options: MochaWebpackOptions; - - constructor(entries: Array, includes: Array, options: MochaWebpackOptions) { - super(); - this.entries = entries; - this.includes = includes; - - this.options = options; + entries: Array + includes: Array + options: MochaWebpackOptions + + constructor( + entries: Array, + includes: Array, + options: MochaWebpackOptions + ) { + super() + this.entries = entries + this.includes = includes + + this.options = options } prepareMocha(webpackConfig: WebpackConfig, stats: Stats): Mocha { - const mocha: Mocha = configureMocha(this.options); - const outputPath = webpackConfig.output.path; - const buildStats: BuildStats = getBuildStats(stats, outputPath); + const mocha: Mocha = configureMocha(this.options) + const outputPath = webpackConfig.output.path + const buildStats: BuildStats = getBuildStats(stats, outputPath) // @ts-ignore - global.__webpackManifest__ = buildStats.affectedModules; // eslint-disable-line + global.__webpackManifest__ = buildStats.affectedModules // eslint-disable-line // clear up require cache for changed files to make sure that we get the latest changes buildStats.affectedFiles.forEach(filePath => { - delete require.cache[filePath]; - }); + delete require.cache[filePath] + }) // pass webpack's entry files to mocha - (mocha as any).files = buildStats.entries; - return mocha; + ;(mocha as any).files = buildStats.entries + return mocha } async run(): Promise { - const { - webpackConfig: config - } = await this.createWebpackConfig(); - let failures = 0; - const compiler: Compiler = createCompiler(config); + const { webpackConfig: config } = await this.createWebpackConfig() + let failures = 0 + const compiler: Compiler = createCompiler(config) compiler.hooks.run.tapAsync('mochapack', (c, cb) => { - this.emit('webpack:start'); - cb(); - }); + this.emit('webpack:start') + cb() + }) - const dispose = registerInMemoryCompiler(compiler); + const dispose = registerInMemoryCompiler(compiler) try { failures = await new Promise((resolve, reject) => { - registerReadyCallback(compiler, (err: (Error | string) | null, webpackStats: Stats | null) => { - this.emit('webpack:ready', err, webpackStats); - if (err || !webpackStats) { - reject(); - return; - } - try { - const mocha = this.prepareMocha(config, webpackStats); - this.emit('mocha:begin'); + registerReadyCallback( + compiler, + (err: (Error | string) | null, webpackStats: Stats | null) => { + this.emit('webpack:ready', err, webpackStats) + if (err || !webpackStats) { + reject() + return + } try { - mocha.run(fails => { - this.emit('mocha:finished', fails); - resolve(fails); - }); + const mocha = this.prepareMocha(config, webpackStats) + this.emit('mocha:begin') + try { + mocha.run(fails => { + this.emit('mocha:finished', fails) + resolve(fails) + }) + } catch (e) { + this.emit('exception', e) + resolve(1) + } } catch (e) { - this.emit('exception', e); - resolve(1); + reject(e) } - } catch (e) { - reject(e); } - }); - compiler.run(noop); - }); + ) + compiler.run(noop) + }) } finally { // clean up single run - dispose(); + dispose() } - return failures; + return failures } async watch(): Promise { const { webpackConfig: config, entryConfig - } = await this.createWebpackConfig(); + } = await this.createWebpackConfig() - let mochaRunner: MochaRunner | null = null; - let stats: Stats | null = null; - let compilationScheduler: () => void | null = null; + let mochaRunner: MochaRunner | null = null + let stats: Stats | null = null + let compilationScheduler: () => void | null = null const uncaughtExceptionListener = err => { // mocha catches uncaughtException only while tests are running, // that's why we register a custom error handler to keep this process alive - this.emit('uncaughtException', err); - }; + this.emit('uncaughtException', err) + } const runMocha = () => { try { - const mocha = this.prepareMocha(config, stats); + const mocha = this.prepareMocha(config, stats) // unregister our custom exception handler (see declaration) - process.removeListener('uncaughtException', uncaughtExceptionListener); + process.removeListener('uncaughtException', uncaughtExceptionListener) // run tests - this.emit('mocha:begin'); - mochaRunner = mocha.run(_.once(failures => { - // register custom exception handler to catch all errors that may happen after mocha think tests are done - process.on('uncaughtException', uncaughtExceptionListener); - - // need to wait until next tick, otherwise mochaRunner = null doesn't work.. - process.nextTick(() => { - mochaRunner = null; - if (compilationScheduler != null) { - this.emit('mocha:aborted'); - compilationScheduler(); - compilationScheduler = null; - } else { - this.emit('mocha:finished', failures); - } - }); - })); + this.emit('mocha:begin') + mochaRunner = mocha.run( + _.once(failures => { + // register custom exception handler to catch all errors that may happen after mocha think tests are done + process.on('uncaughtException', uncaughtExceptionListener) + + // need to wait until next tick, otherwise mochaRunner = null doesn't work.. + process.nextTick(() => { + mochaRunner = null + if (compilationScheduler != null) { + this.emit('mocha:aborted') + compilationScheduler() + compilationScheduler = null + } else { + this.emit('mocha:finished', failures) + } + }) + }) + ) } catch (err) { - this.emit('exception', err); + this.emit('exception', err) } - }; + } - const compiler = createCompiler(config); - registerInMemoryCompiler(compiler); + const compiler = createCompiler(config) + registerInMemoryCompiler(compiler) // register webpack start callback compiler.hooks.watchRun.tapAsync('mochapack', (c, cb) => { // check if mocha tests are still running, abort them and start compiling if (mochaRunner) { compilationScheduler = () => { - this.emit('webpack:start'); - cb(); - }; + this.emit('webpack:start') + cb() + } - mochaRunner.abort(); + mochaRunner.abort() // make sure that the current running test will be aborted when timeouts are disabled for async tests if (mochaRunner.currentRunnable) { - const runnable = mochaRunner.currentRunnable; - runnable.retries(0); - runnable.enableTimeouts(true); - runnable.timeout(1); - runnable.resetTimeout(1); + const runnable = mochaRunner.currentRunnable + runnable.retries(0) + runnable.enableTimeouts(true) + runnable.timeout(1) + runnable.resetTimeout(1) } } else { - this.emit('webpack:start'); - cb(); + this.emit('webpack:start') + cb() } - }); + }) // register webpack ready callback - registerReadyCallback(compiler, (err: (Error | string) | null, webpackStats: Stats | null) => { - this.emit('webpack:ready', err, webpackStats); - if (err) { - // wait for fixed tests - return; + registerReadyCallback( + compiler, + (err: (Error | string) | null, webpackStats: Stats | null) => { + this.emit('webpack:ready', err, webpackStats) + if (err) { + // wait for fixed tests + return + } + stats = webpackStats + runMocha() } - stats = webpackStats; - runMocha(); - }); + ) - const watchCompiler: WatchCompiler = createWatchCompiler(compiler, (config as any).watchOptions); + const watchCompiler: WatchCompiler = createWatchCompiler( + compiler, + (config as any).watchOptions + ) // start webpack build immediately - watchCompiler.watch(); + watchCompiler.watch() // webpack enhances watch options, that's why we use them instead - const watchOptions = watchCompiler.getWatchOptions(); - const pollingInterval = typeof watchOptions.poll === 'number' ? watchOptions.poll : undefined; + const watchOptions = watchCompiler.getWatchOptions() + const pollingInterval = + typeof watchOptions.poll === 'number' ? watchOptions.poll : undefined // create own file watcher for entry files to detect created or deleted files const watcher = chokidar.watch(this.entries, { cwd: this.options.cwd, @@ -217,75 +233,88 @@ export default class TestRunner extends EventEmitter { usePolling: watchOptions.poll ? true : undefined, interval: pollingInterval, binaryInterval: pollingInterval - }); + }) - const restartWebpackBuild = _.debounce(() => watchCompiler.watch(), watchOptions.aggregateTimeout); + const restartWebpackBuild = _.debounce( + () => watchCompiler.watch(), + watchOptions.aggregateTimeout + ) const fileDeletedOrAdded = (file, deleted) => { - const matchesGlob = this.entries.some(pattern => minimatch(file, pattern)); + const matchesGlob = this.entries.some(pattern => minimatch(file, pattern)) // Chokidar gives files not matching pattern sometimes, prevent this if (matchesGlob) { - const filePath = path.join(this.options.cwd, file); + const filePath = path.join(this.options.cwd, file) if (deleted) { - this.emit('entry:removed', file); - entryConfig.removeFile(filePath); + this.emit('entry:removed', file) + entryConfig.removeFile(filePath) } else { - this.emit('entry:added', file); - entryConfig.addFile(filePath); + this.emit('entry:added', file) + entryConfig.addFile(filePath) } // pause webpack watch immediately before webpack will be notified - watchCompiler.pause(); + watchCompiler.pause() // call debounced webpack runner to rebuild files - restartWebpackBuild(); + restartWebpackBuild() } - }; + } // add listener for entry creation & deletion events - watcher.on('add', file => fileDeletedOrAdded(file, false)); - watcher.on('unlink', file => fileDeletedOrAdded(file, true)); + watcher.on('add', file => fileDeletedOrAdded(file, false)) + watcher.on('unlink', file => fileDeletedOrAdded(file, true)) - return new Promise(() => undefined); // never ending story + return new Promise(() => undefined) // never ending story } async createWebpackConfig() { - const { - webpackConfig - } = this.options; + const { webpackConfig } = this.options const files = await glob(this.entries, { cwd: this.options.cwd, absolute: true - }); - - const entryConfig = new EntryConfig(); - files.forEach(f => entryConfig.addFile(f)); - - const tmpPath = path.join(this.options.cwd, '.tmp', 'mochapack', Date.now().toString()); - const withCustomPath = _.has(webpackConfig, 'output.path'); - const outputPath = path.normalize(_.get(webpackConfig, 'output.path', tmpPath)); - const publicPath = withCustomPath ? _.get(webpackConfig, 'output.publicPath', undefined) : outputPath + path.sep; - - const plugins = []; + }) + + const entryConfig = new EntryConfig() + files.forEach(f => entryConfig.addFile(f)) + + const tmpPath = path.join( + this.options.cwd, + '.tmp', + 'mochapack', + Date.now().toString() + ) + const withCustomPath = _.has(webpackConfig, 'output.path') + const outputPath = path.normalize( + _.get(webpackConfig, 'output.path', tmpPath) + ) + const publicPath = withCustomPath + ? _.get(webpackConfig, 'output.publicPath', undefined) + : outputPath + path.sep + + const plugins = [] if (this.options.interactive) { - plugins.push(buildProgressPlugin()); + plugins.push(buildProgressPlugin()) } - const userLoaders = _.get(webpackConfig, 'module.rules', []); + const userLoaders = _.get(webpackConfig, 'module.rules', []) userLoaders.unshift({ test: entryPath, - use: [{ - loader: includeLoaderPath, - options: { - include: this.includes - } - }, { - loader: entryLoaderPath, - options: { - entryConfig + use: [ + { + loader: includeLoaderPath, + options: { + include: this.includes + } + }, + { + loader: entryLoaderPath, + options: { + entryConfig + } } - }] - }); + ] + }) const config = { ...webpackConfig, @@ -300,10 +329,10 @@ export default class TestRunner extends EventEmitter { publicPath }, plugins: [...((webpackConfig as any).plugins || []), ...plugins] - }; + } return { webpackConfig: config, entryConfig - }; + } } } diff --git a/src/runner/configureMocha.ts b/src/runner/configureMocha.ts index 3800616..fded8b0 100644 --- a/src/runner/configureMocha.ts +++ b/src/runner/configureMocha.ts @@ -1,94 +1,91 @@ - -import Mocha from "mocha"; -import loadReporter from "./loadReporter"; -import loadUI from "./loadUI"; -import { MochaWebpackOptions } from "../MochaWebpack"; - +import Mocha from 'mocha' +import loadReporter from './loadReporter' +import loadUI from './loadUI' +import { MochaWebpackOptions } from '../MochaWebpack' export default function configureMocha(options: MochaWebpackOptions) { // infinite stack traces - Error.stackTraceLimit = Infinity; + Error.stackTraceLimit = Infinity // init mocha - const mocha = new Mocha(); + const mocha = new Mocha() // reporter - const reporter = loadReporter(options.reporter, options.cwd); - mocha.reporter(reporter, options.reporterOptions); + const reporter = loadReporter(options.reporter, options.cwd) + mocha.reporter(reporter, options.reporterOptions) // colors - mocha.useColors(options.colors); + mocha.useColors(options.colors) // inline-diffs - mocha.useInlineDiffs(options.useInlineDiffs); - + mocha.useInlineDiffs(options.useInlineDiffs) // slow - mocha.suite.slow(options.slow); + mocha.suite.slow(options.slow) // timeout if (options.timeout === 0) { - mocha.enableTimeouts(false); + mocha.enableTimeouts(false) } else { - mocha.suite.timeout(options.timeout); + mocha.suite.timeout(options.timeout) } // bail - mocha.suite.bail(options.bail); + mocha.suite.bail(options.bail) // grep if (options.grep) { - mocha.grep(new RegExp(options.grep)); + mocha.grep(new RegExp(options.grep)) } // fgrep if (options.fgrep) { - mocha.grep(options.fgrep); + mocha.grep(options.fgrep) } // invert if (options.invert) { - mocha.invert(); + mocha.invert() } // check-leaks if (options.ignoreLeaks === false) { - mocha.checkLeaks(); + mocha.checkLeaks() } // full-trace if (options.fullStackTrace) { - mocha.fullTrace(); + mocha.fullTrace() } // growl if (options.growl) { - mocha.growl(); + mocha.growl() } // async-only if (options.asyncOnly) { - mocha.asyncOnly(); + mocha.asyncOnly() } // delay if (options.delay) { - mocha.delay(); + mocha.delay() } // retries if (options.retries) { - mocha.suite.retries(options.retries); + mocha.suite.retries(options.retries) } // forbid-only if (options.forbidOnly) { - mocha.forbidOnly(); + mocha.forbidOnly() } // interface - const ui = loadUI(options.ui, options.cwd); - mocha.ui(ui); + const ui = loadUI(options.ui, options.cwd) + mocha.ui(ui) - return mocha; -} \ No newline at end of file + return mocha +} diff --git a/src/runner/loadReporter.ts b/src/runner/loadReporter.ts index ba0c7b0..11c7c42 100644 --- a/src/runner/loadReporter.ts +++ b/src/runner/loadReporter.ts @@ -1,26 +1,28 @@ +import path from 'path' +import { reporters } from 'mocha' -import path from "path"; -import { reporters, Spec } from "mocha"; - -export default function loadReporter(reporter: string | (() => void) | Spec, cwd?: string) { +export default function loadReporter( + reporter: string | ReporterConstructor, + cwd?: string +) { // if reporter is already loaded, just return it if (typeof reporter === 'function') { - return reporter; + return reporter } // try to load built-in reporter like 'spec' if (typeof reporters[reporter] !== 'undefined') { - return reporters[reporter]; + return reporters[reporter] } - let loadedReporter = null; + let loadedReporter = null try { // try to load reporter from node_modules - loadedReporter = require(reporter); // eslint-disable-line global-require, import/no-dynamic-require + loadedReporter = require(reporter) // eslint-disable-line global-require, import/no-dynamic-require } catch (e) { // try to load reporter from cwd // eslint-disable-next-line global-require, import/no-dynamic-require - loadedReporter = require(path.resolve(cwd, reporter)); + loadedReporter = require(path.resolve(cwd, reporter)) } - return loadedReporter; + return loadedReporter } diff --git a/src/runner/loadUI.ts b/src/runner/loadUI.ts index 1780f8c..3c7dc11 100644 --- a/src/runner/loadUI.ts +++ b/src/runner/loadUI.ts @@ -1,20 +1,19 @@ - -import path from "path"; -import { interfaces } from "mocha"; +import path from 'path' +import { interfaces } from 'mocha' export default function loadUI(ui: string, cwd?: string) { // try to load built-in ui like 'bdd' if (typeof interfaces[ui] !== 'undefined') { - return ui; + return ui } - let loadedUI = null; + let loadedUI = null try { // try to load reporter from node_modules - loadedUI = require.resolve(ui); + loadedUI = require.resolve(ui) } catch (e) { // try to load reporter from cwd - loadedUI = require.resolve(path.resolve(cwd, ui)); + loadedUI = require.resolve(path.resolve(cwd, ui)) } - return loadedUI; + return loadedUI } diff --git a/src/runner/testRunnerReporter.ts b/src/runner/testRunnerReporter.ts index d28ad35..c641912 100644 --- a/src/runner/testRunnerReporter.ts +++ b/src/runner/testRunnerReporter.ts @@ -1,161 +1,178 @@ - -import EventEmitter from "events"; -import chalk from "chalk"; -import { Stats } from "webpack"; -import createStatsFormatter from "../webpack/util/createStatsFormatter"; +import EventEmitter from 'events' +import chalk from 'chalk' +import { Stats } from 'webpack' +import createStatsFormatter from '../webpack/util/createStatsFormatter' type ReporterOptions = { - eventEmitter: EventEmitter; - interactive: boolean; - clearTerminal: boolean; - quiet: boolean; - cwd: string; -}; + eventEmitter: EventEmitter + interactive: boolean + clearTerminal: boolean + quiet: boolean + cwd: string +} const log = (...args: Array) => { - console.log(...args); // eslint-disable-line no-console - console.log(); // eslint-disable-line no-console -}; + console.log(...args) // eslint-disable-line no-console + console.log() // eslint-disable-line no-console +} -const formatTitleInfo = title => chalk.inverse('', title, ''); -const formatTitleWarn = title => chalk.black.bgYellow('', title, ''); -const formatTitleError = title => chalk.white.bold.bgRed('', title, ''); +const formatTitleInfo = title => chalk.inverse('', title, '') +const formatTitleWarn = title => chalk.black.bgYellow('', title, '') +const formatTitleError = title => chalk.white.bold.bgRed('', title, '') class Reporter { - - added: Array; - removed: Array; - options: ReporterOptions; - formatStats: (stats: Stats) => {warnings: Array;errors: Array;}; + added: Array + removed: Array + options: ReporterOptions + formatStats: ( + stats: Stats + ) => { warnings: Array; errors: Array } constructor(options: ReporterOptions) { - const { - cwd, - eventEmitter - } = options; - - this.options = options; - this.added = []; - this.removed = []; - this.formatStats = createStatsFormatter(cwd); - - eventEmitter.on('uncaughtException', this.onUncaughtException); - eventEmitter.on('exception', this.onLoadingException); - eventEmitter.on('webpack:start', this.onWebpackStart); - eventEmitter.on('webpack:ready', this.onWebpackReady); - eventEmitter.on('mocha:begin', this.onMochaStart); - eventEmitter.on('mocha:aborted', this.onMochaAbort); - eventEmitter.on('mocha:finished', this.onMochaReady); - eventEmitter.on('entry:added', this.onEntryAdded); - eventEmitter.on('entry:removed', this.onEntryRemoved); + const { cwd, eventEmitter } = options + + this.options = options + this.added = [] + this.removed = [] + this.formatStats = createStatsFormatter(cwd) + + eventEmitter.on('uncaughtException', this.onUncaughtException) + eventEmitter.on('exception', this.onLoadingException) + eventEmitter.on('webpack:start', this.onWebpackStart) + eventEmitter.on('webpack:ready', this.onWebpackReady) + eventEmitter.on('mocha:begin', this.onMochaStart) + eventEmitter.on('mocha:aborted', this.onMochaAbort) + eventEmitter.on('mocha:finished', this.onMochaReady) + eventEmitter.on('entry:added', this.onEntryAdded) + eventEmitter.on('entry:removed', this.onEntryRemoved) } logInfo(...args: Array) { if (!this.options.quiet) { - log(...args); + log(...args) } } clearTerminal() { if (this.options.clearTerminal && this.options.interactive) { - process.stdout.write(process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H'); + process.stdout.write( + process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H' + ) } } static displayErrors(severity: string, errors: Array) { - const errorCount = errors.length; + const errorCount = errors.length - const message = severity === 'error' ? `Failed to compile with ${chalk.red(`${errorCount} ${severity}(s)`)}` : `Compiled with ${chalk.yellow(`${errorCount} ${severity}(s)`)}`; + const message = + severity === 'error' + ? `Failed to compile with ${chalk.red(`${errorCount} ${severity}(s)`)}` + : `Compiled with ${chalk.yellow(`${errorCount} ${severity}(s)`)}` - const titleColor = severity === 'error' ? formatTitleError : formatTitleWarn; - log(titleColor('WEBPACK'), message); - errors.forEach(err => log(err)); + const titleColor = severity === 'error' ? formatTitleError : formatTitleWarn + log(titleColor('WEBPACK'), message) + errors.forEach(err => log(err)) } onUncaughtException = (err: Error) => { - log(formatTitleError('UNCAUGHT EXCEPTION'), 'Exception occurred after running tests'); - log(err.stack); - }; + log( + formatTitleError('UNCAUGHT EXCEPTION'), + 'Exception occurred after running tests' + ) + log(err.stack) + } onLoadingException = (err: Error) => { - log(formatTitleError('RUNTIME EXCEPTION'), 'Exception occurred while loading your tests'); - log(err.stack); - }; + log( + formatTitleError('RUNTIME EXCEPTION'), + 'Exception occurred while loading your tests' + ) + log(err.stack) + } onWebpackStart = () => { - this.clearTerminal(); + this.clearTerminal() if (this.added.length > 0) { - this.logInfo(formatTitleInfo('MOCHA'), 'The following test entry files were added:'); - this.logInfo(this.added.map(f => `+ ${f}`).join('\n')); + this.logInfo( + formatTitleInfo('MOCHA'), + 'The following test entry files were added:' + ) + this.logInfo(this.added.map(f => `+ ${f}`).join('\n')) } if (this.removed.length > 0) { - this.logInfo(formatTitleInfo('MOCHA'), 'The following test entry files were removed:'); - this.logInfo(this.removed.map(f => `- ${f}`).join('\n')); + this.logInfo( + formatTitleInfo('MOCHA'), + 'The following test entry files were removed:' + ) + this.logInfo(this.removed.map(f => `- ${f}`).join('\n')) } - this.logInfo(formatTitleInfo('WEBPACK'), 'Compiling...'); + this.logInfo(formatTitleInfo('WEBPACK'), 'Compiling...') - this.added.length = 0; - this.removed.length = 0; - }; + this.added.length = 0 + this.removed.length = 0 + } onWebpackReady = (err?: Error, stats?: Stats) => { - this.clearTerminal(); + this.clearTerminal() if (stats != null) { - const { - errors, - warnings - } = this.formatStats(stats); + const { errors, warnings } = this.formatStats(stats) if (errors.length === 0 && warnings.length === 0) { - const { - startTime, - endTime - } = stats; - const compileTime = endTime - startTime; - this.logInfo(formatTitleInfo('WEBPACK'), `Compiled successfully in ${chalk.green(`${compileTime}ms`)}`); - return; + const { startTime, endTime } = stats + const compileTime = endTime - startTime + this.logInfo( + formatTitleInfo('WEBPACK'), + `Compiled successfully in ${chalk.green(`${compileTime}ms`)}` + ) + return } if (errors.length > 0) { - Reporter.displayErrors('error', errors); - return; + Reporter.displayErrors('error', errors) + return } if (warnings.length > 0) { - Reporter.displayErrors('warning', warnings); + Reporter.displayErrors('warning', warnings) } } else { - Reporter.displayErrors('error', [err]); + Reporter.displayErrors('error', [err]) } - }; + } onMochaStart = () => { - this.logInfo(formatTitleInfo('MOCHA'), 'Testing...'); - }; + this.logInfo(formatTitleInfo('MOCHA'), 'Testing...') + } onMochaAbort = () => { - this.logInfo(formatTitleInfo('MOCHA'), 'Tests aborted'); - }; + this.logInfo(formatTitleInfo('MOCHA'), 'Tests aborted') + } onMochaReady = (failures: number) => { if (failures === 0) { - this.logInfo(formatTitleInfo('MOCHA'), `Tests completed ${chalk.green('successfully')}`); + this.logInfo( + formatTitleInfo('MOCHA'), + `Tests completed ${chalk.green('successfully')}` + ) } else { - this.logInfo(formatTitleInfo('MOCHA'), `Tests completed with ${chalk.red(`${failures} failure(s)`)}`); + this.logInfo( + formatTitleInfo('MOCHA'), + `Tests completed with ${chalk.red(`${failures} failure(s)`)}` + ) } - }; + } onEntryAdded = (file: string) => { - this.added.push(file); - }; + this.added.push(file) + } onEntryRemoved = (file: string) => { - this.removed.push(file); - }; + this.removed.push(file) + } } export default function testRunnerReporter(options: ReporterOptions) { - new Reporter(options); // eslint-disable-line no-new + new Reporter(options) // eslint-disable-line no-new } diff --git a/src/util/exists.ts b/src/util/exists.ts index 04a4028..26d85e1 100644 --- a/src/util/exists.ts +++ b/src/util/exists.ts @@ -1,13 +1,12 @@ - -import fs from "fs"; +import fs from 'fs' /* eslint-disable import/prefer-default-export */ export function existsFileSync(file: string): boolean { try { - fs.accessSync(file, fs.constants.F_OK); - return true; + fs.accessSync(file, fs.constants.F_OK) + return true } catch (e) { - return false; + return false } } diff --git a/src/util/glob.ts b/src/util/glob.ts index 3e0f0d9..8a2bfc3 100644 --- a/src/util/glob.ts +++ b/src/util/glob.ts @@ -1,43 +1,51 @@ - -import path from "path"; -import globby from "globby"; -import isGlob from "is-glob"; -import globParent from "glob-parent"; -import normalizePath from "normalize-path"; - -const isDirectory = filePath => path.extname(filePath).length === 0; - -export const glob = async (patterns: Array, options: {}): Promise> => globby(patterns, options); - -export const ensureGlob = (entry: string, recursive: boolean = false, pattern: string = '*.js'): string => { - const normalized = normalizePath(entry); +import path from 'path' +import globby from 'globby' +import isGlob from 'is-glob' +import globParent from 'glob-parent' +import normalizePath from 'normalize-path' + +const isDirectory = filePath => path.extname(filePath).length === 0 + +export const glob = async ( + patterns: Array, + options: {} +): Promise> => globby(patterns, options) + +export const ensureGlob = ( + entry: string, + recursive: boolean = false, + pattern: string = '*.js' +): string => { + const normalized = normalizePath(entry) if (isGlob(normalized)) { - return normalized; + return normalized } else if (isDirectory(normalized)) { if (!isGlob(pattern)) { - throw new Error(`Provided Glob ${pattern} is not a valid glob pattern`); + throw new Error(`Provided Glob ${pattern} is not a valid glob pattern`) } - const parent = globParent(pattern); + const parent = globParent(pattern) if (parent !== '.' || pattern.indexOf('**') !== -1) { - throw new Error(`Provided Glob ${pattern} must be a file pattern like *.js`); + throw new Error( + `Provided Glob ${pattern} must be a file pattern like *.js` + ) } - const globstar = recursive ? '**/' : ''; + const globstar = recursive ? '**/' : '' - return `${normalized}/${globstar}${pattern}`; + return `${normalized}/${globstar}${pattern}` } - return normalized; -}; + return normalized +} export const extensionsToGlob = (extensions: Array) => { - const filtered = extensions.filter(Boolean); + const filtered = extensions.filter(Boolean) if (filtered.length === 0) { - return '*.js'; + return '*.js' } else if (filtered.length === 1) { - return `*${filtered[0]}`; + return `*${filtered[0]}` } - return `*{${filtered.join(',')}}`; -}; \ No newline at end of file + return `*{${filtered.join(',')}}` +} diff --git a/src/util/paths.ts b/src/util/paths.ts index 9d5d871..9232a5b 100644 --- a/src/util/paths.ts +++ b/src/util/paths.ts @@ -1,7 +1,8 @@ - -import { join, posix, win32 } from "path"; +import { join, posix, win32 } from 'path' // eslint-disable-next-line import/prefer-default-export export function ensureAbsolutePath(path: string, basePath: string) { - return posix.isAbsolute(path) || win32.isAbsolute(path) ? path : join(basePath, path); -} \ No newline at end of file + return posix.isAbsolute(path) || win32.isAbsolute(path) + ? path + : join(basePath, path) +} diff --git a/src/util/registerRequireHook.ts b/src/util/registerRequireHook.ts index 2e1ff76..208f3f3 100644 --- a/src/util/registerRequireHook.ts +++ b/src/util/registerRequireHook.ts @@ -1,120 +1,119 @@ - - /* eslint-disable no-underscore-dangle */ // see https://github.com/nodejs/node/blob/master/lib/module.js -import Module from "module"; +import Module from 'module' // the module in which the require() call originated -let requireCaller; +let requireCaller // all custom registered resolvers -let pathResolvers = []; +let pathResolvers = [] // keep original Module._resolveFilename // @ts-ignore -const originalResolveFilename = Module._resolveFilename; +const originalResolveFilename = Module._resolveFilename // override Module._resolveFilename // @ts-ignore Module._resolveFilename = function _resolveFilename(...parameters) { - const parent = parameters[1]; + const parent = parameters[1] // store require() caller (the module in which this require() call originated) - requireCaller = parent; - return originalResolveFilename.apply(this, parameters); -}; + requireCaller = parent + return originalResolveFilename.apply(this, parameters) +} // keep original Module._findPath // @ts-ignore -const originalFindPath = Module._findPath; +const originalFindPath = Module._findPath // override Module._findPath // @ts-ignore Module._findPath = function _findPath(...parameters) { - const request = parameters[0]; + const request = parameters[0] // try to resolve the path with custom resolvers for (const resolve of pathResolvers) { - const resolved = resolve(request, requireCaller); + const resolved = resolve(request, requireCaller) if (typeof resolved !== 'undefined') { - return resolved; + return resolved } } // and when none found try to resolve path with original resolver - const filename = originalFindPath.apply(this, parameters); + const filename = originalFindPath.apply(this, parameters) if (filename !== false) { - return filename; + return filename } - return false; -}; - + return false +} -export default function registerRequireHook(dotExt: string, resolve: (path: string, parent: Module) => {path: string | null;source: string | null;}) { +export default function registerRequireHook( + dotExt: string, + resolve: ( + path: string, + parent: Module + ) => { path: string | null; source: string | null } +) { // cache source code after resolving to avoid another access to the fs - const sourceCache = {}; + const sourceCache = {} // store all files that were affected by this hook - const affectedFiles = {}; + const affectedFiles = {} const resolvePath = (path, parent) => { // get CommonJS module source code for this require() call - const { - path: resolvedPath, - source - } = resolve(path, parent); + const { path: resolvedPath, source } = resolve(path, parent) // if no CommonJS module source code returned - skip this require() hook if (resolvedPath == null) { - return undefined; + return undefined } // flush require() cache - delete require.cache[resolvedPath]; + delete require.cache[resolvedPath] // put the CommonJS module source code into the hash - sourceCache[resolvedPath] = source; + sourceCache[resolvedPath] = source // return the path to be require()d in order to get the CommonJS module source code - return resolvedPath; - }; + return resolvedPath + } const resolveSource = path => { - const source = sourceCache[path]; - delete sourceCache[path]; - return source; - }; - - pathResolvers.push(resolvePath); + const source = sourceCache[path] + delete sourceCache[path] + return source + } + pathResolvers.push(resolvePath) // keep original extension loader // @ts-ignore - const originalLoader = Module._extensions[dotExt]; + const originalLoader = Module._extensions[dotExt] // override extension loader // @ts-ignore Module._extensions[dotExt] = (module, filename) => { - const source = resolveSource(filename); + const source = resolveSource(filename) if (typeof source === 'undefined') { // load the file with the original loader // @ts-ignore - (originalLoader || Module._extensions['.js'])(module, filename); - return; + ;(originalLoader || Module._extensions['.js'])(module, filename) + return } - affectedFiles[filename] = true; + affectedFiles[filename] = true // compile javascript module from its source - module._compile(source, filename); - }; + module._compile(source, filename) + } return function unmout() { - pathResolvers = pathResolvers.filter(r => r !== resolvePath); + pathResolvers = pathResolvers.filter(r => r !== resolvePath) // @ts-ignore - Module._extensions[dotExt] = originalLoader; + Module._extensions[dotExt] = originalLoader Object.keys(affectedFiles).forEach(path => { - delete require.cache[path]; - delete sourceCache[path]; - delete affectedFiles[path]; - }); - }; + delete require.cache[path] + delete sourceCache[path] + delete affectedFiles[path] + }) + } } diff --git a/src/webpack/compiler/createCompiler.ts b/src/webpack/compiler/createCompiler.ts index 28b1189..1b16e47 100644 --- a/src/webpack/compiler/createCompiler.ts +++ b/src/webpack/compiler/createCompiler.ts @@ -1,8 +1,7 @@ - -import webpack, { Compiler } from "webpack"; +import webpack, { Compiler } from 'webpack' export default function createCompiler(webpackConfig: {}): Compiler { - const compiler = webpack(webpackConfig); + const compiler = webpack(webpackConfig) - return compiler; + return compiler } diff --git a/src/webpack/compiler/createWatchCompiler.ts b/src/webpack/compiler/createWatchCompiler.ts index c686bfd..43a66cd 100644 --- a/src/webpack/compiler/createWatchCompiler.ts +++ b/src/webpack/compiler/createWatchCompiler.ts @@ -1,57 +1,61 @@ - -import _ from "lodash"; -import Watching from "webpack/lib/Watching"; -import { Compiler } from "webpack"; +import _ from 'lodash' +import Watching from 'webpack/lib/Watching' +import { Compiler } from 'webpack' export type WatchCompiler = { - watch: () => void; - pause: () => void; + watch: () => void + pause: () => void getWatchOptions: () => { - aggregateTimeout: number; - ignored?: RegExp | string; - poll?: number | boolean; - }; -}; + aggregateTimeout: number + ignored?: RegExp | string + poll?: number | boolean + } +} -const noop = () => undefined; -export default function createWatchCompiler(compiler: Compiler, watchOptions: {}): WatchCompiler { +const noop = () => undefined +export default function createWatchCompiler( + compiler: Compiler, + watchOptions: {} +): WatchCompiler { // this ugly statement to create a watch compiler is unfortunately necessary, // as webpack clears the file timestamps with the official compiler.watch() - const createWatcher = () => new Watching(compiler, watchOptions, noop); - let watchCompiler = null; + const createWatcher = () => new Watching(compiler, watchOptions, noop) + let watchCompiler = null return { watch() { if (watchCompiler === null) { - watchCompiler = createWatcher(); + watchCompiler = createWatcher() } else { // @ts-ignore - const times = compiler.watchFileSystem.watcher.getTimes(); + const times = compiler.watchFileSystem.watcher.getTimes() // check if we can store some collected file timestamps // the non-empty check is necessary as the times will be reseted after .close() // and we don't want to reset already existing timestamps if (Object.keys(times).length > 0) { - const timesMap = new Map(Object.keys(times).map(key => [key, times[key]])); + const timesMap = new Map( + Object.keys(times).map(key => [key, times[key]]) + ) // set already collected file timestamps to cache compiled files // webpack will do this only after a file change, but that will not happen when we add or delete files // and this means that we have to test the whole test suite again ... - compiler.fileTimestamps = timesMap; // eslint-disable-line no-param-reassign - compiler.contextTimestamps = timesMap; // eslint-disable-line no-param-reassign + compiler.fileTimestamps = timesMap // eslint-disable-line no-param-reassign + compiler.contextTimestamps = timesMap // eslint-disable-line no-param-reassign } watchCompiler.close(() => { - watchCompiler = createWatcher(); - }); + watchCompiler = createWatcher() + }) } }, pause() { if (watchCompiler !== null && watchCompiler.watcher) { - watchCompiler.watcher.pause(); + watchCompiler.watcher.pause() } }, getWatchOptions() { // 200 is the default value by webpack - return _.get(watchCompiler, 'watchOptions', { aggregateTimeout: 200 }); + return _.get(watchCompiler, 'watchOptions', { aggregateTimeout: 200 }) } - }; + } } diff --git a/src/webpack/compiler/registerInMemoryCompiler.ts b/src/webpack/compiler/registerInMemoryCompiler.ts index 48b4b86..cb4609a 100644 --- a/src/webpack/compiler/registerInMemoryCompiler.ts +++ b/src/webpack/compiler/registerInMemoryCompiler.ts @@ -1,60 +1,62 @@ - -import path from "path"; -import sourceMapSupport from "source-map-support"; -import MemoryFileSystem from "memory-fs"; -import registerRequireHook from "../../util/registerRequireHook"; -import { ensureAbsolutePath } from "../../util/paths"; -import { Compiler, Stats } from "webpack"; +import path from 'path' +import sourceMapSupport from 'source-map-support' +import MemoryFileSystem from 'memory-fs' +import { Compiler, Stats } from 'webpack' +import registerRequireHook from '../../util/registerRequireHook' +import { ensureAbsolutePath } from '../../util/paths' export default function registerInMemoryCompiler(compiler: Compiler) { // register memory fs to webpack - const memoryFs = new MemoryFileSystem(); - compiler.outputFileSystem = memoryFs; // eslint-disable-line no-param-reassign + const memoryFs = new MemoryFileSystem() + compiler.outputFileSystem = memoryFs // eslint-disable-line no-param-reassign // build asset map to allow fast checks for file existence - const assetMap = new Map(); + const assetMap = new Map() compiler.hooks.done.tap('mochapack', (stats: Stats) => { - assetMap.clear(); + assetMap.clear() if (!stats.hasErrors()) { - Object.keys(stats.compilation.assets).forEach(assetPath => assetMap.set(ensureAbsolutePath(assetPath, compiler.options.output.path), true)); + Object.keys(stats.compilation.assets).forEach(assetPath => + assetMap.set( + ensureAbsolutePath(assetPath, compiler.options.output.path), + true + ) + ) } - }); + }) // provide file reader to read from memory fs let readFile = filePath => { if (assetMap.has(filePath)) { try { - const code = memoryFs.readFileSync(filePath, 'utf8'); - return code; + const code = memoryFs.readFileSync(filePath, 'utf8') + return code } catch (e) { - return null; + return null } } - return null; - }; + return null + } // module resolver for require calls from memory fs const resolveFile = (filePath, requireCaller) => { // try to read file from memory-fs as it is - let code = readFile(filePath); - let resolvedPath = filePath; + let code = readFile(filePath) + let resolvedPath = filePath if (code === null && requireCaller != null) { - const { - filename - } = requireCaller; + const { filename } = requireCaller if (filename != null) { // if that didn't work, resolve the file relative to it's parent - resolvedPath = path.resolve(path.dirname(filename), filePath); - code = readFile(resolvedPath); + resolvedPath = path.resolve(path.dirname(filename), filePath) + code = readFile(resolvedPath) } } - return { path: code !== null ? resolvedPath : null, source: code }; - }; + return { path: code !== null ? resolvedPath : null, source: code } + } // install require hook to be able to require webpack bundles from memory - const unmountHook = registerRequireHook('.js', resolveFile); + const unmountHook = registerRequireHook('.js', resolveFile) // install source map support to read source map from memory sourceMapSupport.install({ @@ -62,10 +64,10 @@ export default function registerInMemoryCompiler(compiler: Compiler) { handleUncaughtExceptions: false, environment: 'node', retrieveFile: f => readFile(f) // wrapper function to fake an unmount function - }); + }) return function unmount() { - unmountHook(); - readFile = filePath => null; // eslint-disable-line no-unused-vars - }; + unmountHook() + readFile = filePath => null // eslint-disable-line no-unused-vars + } } diff --git a/src/webpack/compiler/registerReadyCallback.ts b/src/webpack/compiler/registerReadyCallback.ts index f21a6a9..ce808fc 100644 --- a/src/webpack/compiler/registerReadyCallback.ts +++ b/src/webpack/compiler/registerReadyCallback.ts @@ -1,15 +1,17 @@ +import { Compiler, Stats } from 'webpack' -import { Compiler, Stats } from "webpack"; - -export default function registerReadyCallback(compiler: Compiler, cb: (err: (Error | string) | null, stats: Stats | null) => void) { - compiler.hooks.failed.tap('mochapack', cb); +export default function registerReadyCallback( + compiler: Compiler, + cb: (err: (Error | string) | null, stats: Stats | null) => void +) { + compiler.hooks.failed.tap('mochapack', cb) compiler.hooks.done.tap('mochapack', (stats: Stats) => { if (stats.hasErrors()) { - const jsonStats = stats.toJson(); - const [err] = jsonStats.errors; - cb(err, stats); + const jsonStats = stats.toJson() + const [err] = jsonStats.errors + cb(err, stats) } else { - cb(null, stats); + cb(null, stats) } - }); + }) } diff --git a/src/webpack/loader/entryLoader.ts b/src/webpack/loader/entryLoader.ts index 4abdc40..74fd155 100644 --- a/src/webpack/loader/entryLoader.ts +++ b/src/webpack/loader/entryLoader.ts @@ -1,47 +1,47 @@ - -import loaderUtils from "loader-utils"; -import normalizePath from "normalize-path"; -import createEntry from "../util/createEntry"; +import loaderUtils from 'loader-utils' +import normalizePath from 'normalize-path' +import createEntry from '../util/createEntry' export class EntryConfig { - - files: Array; + files: Array constructor() { - this.files = []; + this.files = [] } addFile(file: string): void { - const normalizedFile = normalizePath(file); - this.files.push(normalizedFile); + const normalizedFile = normalizePath(file) + this.files.push(normalizedFile) } removeFile(file: string): void { - const normalizedFile = normalizePath(file); - this.files = this.files.filter(f => f !== normalizedFile); + const normalizedFile = normalizePath(file) + this.files = this.files.filter(f => f !== normalizedFile) } getFiles(): Array { - return this.files; + return this.files } } export const entryLoader = function entryLoader() { - const loaderOptions = loaderUtils.getOptions(this); - const config: EntryConfig = loaderOptions.entryConfig; + const loaderOptions = loaderUtils.getOptions(this) + const config: EntryConfig = loaderOptions.entryConfig // Remove all dependencies of the loader result - this.clearDependencies(); + this.clearDependencies() - const dependencies: Array = config.getFiles().map(file => loaderUtils.stringifyRequest(this, file)); + const dependencies: Array = config + .getFiles() + .map(file => loaderUtils.stringifyRequest(this, file)) // add all entries as dependencies - dependencies.forEach(this.addDependency.bind(this)); + dependencies.forEach(this.addDependency.bind(this)) // build source code - const sourceCode: string = createEntry(dependencies); + const sourceCode: string = createEntry(dependencies) - this.callback(null, sourceCode, null); -}; + this.callback(null, sourceCode, null) +} -export default entryLoader; +export default entryLoader diff --git a/src/webpack/loader/includeFilesLoader.ts b/src/webpack/loader/includeFilesLoader.ts index 8fb5c0e..0c2bcba 100644 --- a/src/webpack/loader/includeFilesLoader.ts +++ b/src/webpack/loader/includeFilesLoader.ts @@ -1,21 +1,24 @@ - -import loaderUtils from "loader-utils"; +import loaderUtils from 'loader-utils' // Note: no export default here cause of Babel 6 module.exports = function includeFilesLoader(sourceCode: string) { if (this.cacheable) { - this.cacheable(); + this.cacheable() } - const loaderOptions = loaderUtils.getOptions(this); + const loaderOptions = loaderUtils.getOptions(this) if (loaderOptions.include && loaderOptions.include.length) { - const includes = loaderOptions.include.map(modPath => `require(${loaderUtils.stringifyRequest(this, modPath)});`).join('\n'); + const includes = loaderOptions.include + .map( + modPath => `require(${loaderUtils.stringifyRequest(this, modPath)});` + ) + .join('\n') - const code = [includes, sourceCode].join('\n'); + const code = [includes, sourceCode].join('\n') - this.callback(null, code, null); - return; + this.callback(null, code, null) + return } - this.callback(null, sourceCode, null); -}; \ No newline at end of file + this.callback(null, sourceCode, null) +} diff --git a/src/webpack/plugin/buildProgressPlugin.ts b/src/webpack/plugin/buildProgressPlugin.ts index 82b1486..5da8589 100644 --- a/src/webpack/plugin/buildProgressPlugin.ts +++ b/src/webpack/plugin/buildProgressPlugin.ts @@ -1,20 +1,23 @@ -import chalk from "chalk"; -import ProgressBar from "progress"; -import { ProgressPlugin } from "webpack"; +import chalk from 'chalk' +import ProgressBar from 'progress' +import { ProgressPlugin } from 'webpack' export default function buildProgressPlugin() { - const bar = new ProgressBar(` [:bar] ${chalk.bold(':percent')} (${chalk.dim(':msg')})`, { - total: 100, - complete: '=', - incomplete: ' ', - width: 25 - }); + const bar = new ProgressBar( + ` [:bar] ${chalk.bold(':percent')} (${chalk.dim(':msg')})`, + { + total: 100, + complete: '=', + incomplete: ' ', + width: 25 + } + ) return new ProgressPlugin((percent, msg) => { bar.update(percent, { msg: percent === 1 ? 'completed' : msg - }); + }) if (percent === 1) { - bar.terminate(); + bar.terminate() } - }); -} \ No newline at end of file + }) +} diff --git a/src/webpack/types.ts b/src/webpack/types.ts index 721eb91..cbcce57 100644 --- a/src/webpack/types.ts +++ b/src/webpack/types.ts @@ -1,80 +1,79 @@ -import { Compiler } from "webpack"; +import { Compiler } from 'webpack' export type SourceMap = { - sources: Array; - version: number; - mappings: any; - sourcesContent: any; -}; + sources: Array + version: number + mappings: any + sourcesContent: any +} /** * webpack/lib/Module.js */ export type Module = { - id: number; - rawRequest: string; - built: boolean; - dependencies: Array<{module: Module;}>; - readableIdentifier: any | null; - chunks: Array; // eslint-disable-line no-use-before-define - getChunks: () => Array; // eslint-disable-line no-use-before-define - blocks: Array; // eslint-disable-line no-use-before-define -}; + id: number + rawRequest: string + built: boolean + dependencies: Array<{ module: Module }> + readableIdentifier: any | null + chunks: Array // eslint-disable-line no-use-before-define + getChunks: () => Array // eslint-disable-line no-use-before-define + blocks: Array // eslint-disable-line no-use-before-define +} /** * Webpack build error or warning */ export type WebpackError = Error & { - message: string; - file?: string | null; - module?: Module | null; -}; - + message: string + file?: string | null + module?: Module | null +} /** * webpack/lib/Chunk.js */ export type Chunk = { - id: number | string; - modules: Array; - chunks: Array; - parents: Array; - files: Array; - isOnlyInitial: () => boolean; - getModules: () => Array; -}; + id: number | string + modules: Array + chunks: Array + parents: Array + files: Array + isOnlyInitial: () => boolean + getModules: () => Array +} /** * webpack/lib/ChunkGroup.js */ export type ChunkGroup = { - chunks: Array; -}; + chunks: Array +} /** * webpack/lib/DependenciesBlock.js * webpack/lib/AsyncDependenciesBlock.js */ export type DependenciesBlock = { - chunkGroup?: ChunkGroup; -}; + chunkGroup?: ChunkGroup +} /** * webpack/lib/Compilation.js */ export type Compilation = { - compiler: Compiler; - plugin: (hook: string, fn: () => void) => void; - modules: Module[]; - chunks: Chunk[]; - chunkGroups: ChunkGroup[]; - errors: Array; - warnings: Array; + compiler: Compiler + plugin: (hook: string, fn: () => void) => void + modules: Module[] + chunks: Chunk[] + chunkGroups: ChunkGroup[] + errors: Array + warnings: Array assets: { [key: string]: { - size: () => number; - source: () => string; - map: () => SourceMap; - }; - }; -}; + size: () => number + source: () => string + map: () => SourceMap + } + } +} diff --git a/src/webpack/util/createEntry.ts b/src/webpack/util/createEntry.ts index 47a9395..14ec00b 100644 --- a/src/webpack/util/createEntry.ts +++ b/src/webpack/util/createEntry.ts @@ -1,5 +1,14 @@ - - export default function createEntry(filePaths: Array): string { - return ['// runtime helper', 'function inManifest(id) { return global.__webpackManifest__.indexOf(id) >= 0;}', 'function run(id) { __webpack_require__(id);}', '', '// modules to execute goes here', 'var ids = [', filePaths.map(path => `require.resolve(${path})`).join(','), '];', '', 'ids.filter(inManifest).forEach(run)'].join('\n'); -} \ No newline at end of file + return [ + '// runtime helper', + 'function inManifest(id) { return global.__webpackManifest__.indexOf(id) >= 0;}', + 'function run(id) { __webpack_require__(id);}', + '', + '// modules to execute goes here', + 'var ids = [', + filePaths.map(path => `require.resolve(${path})`).join(','), + '];', + '', + 'ids.filter(inManifest).forEach(run)' + ].join('\n') +} diff --git a/src/webpack/util/createStatsFormatter.ts b/src/webpack/util/createStatsFormatter.ts index af9c64e..c60b685 100644 --- a/src/webpack/util/createStatsFormatter.ts +++ b/src/webpack/util/createStatsFormatter.ts @@ -1,72 +1,87 @@ +import { EOL } from 'os' +import chalk from 'chalk' +import { Stats } from 'webpack' +import RequestShortener from 'webpack/lib/RequestShortener' +import { formatErrorMessage, stripLoaderFromPath } from './formatUtil' +import { WebpackError } from '../types' -import { EOL } from "os"; -import chalk from "chalk"; -import { Stats } from "webpack"; -import RequestShortener from "webpack/lib/RequestShortener"; -import { formatErrorMessage, stripLoaderFromPath } from "./formatUtil"; -import { WebpackError } from "../types"; - -const createGetFile = (requestShortener: RequestShortener) => (e: WebpackError): string | null => { +const createGetFile = (requestShortener: RequestShortener) => ( + e: WebpackError +): string | null => { /* istanbul ignore if */ if (e.file) { // webpack does this also, so there must be case when this happens - return e.file; - } else if (e.module && e.module.readableIdentifier && typeof e.module.readableIdentifier === 'function') { + return e.file + } else if ( + e.module && + e.module.readableIdentifier && + typeof e.module.readableIdentifier === 'function' + ) { // if we got a module, build a file path to the module without loader information - return stripLoaderFromPath(e.module.readableIdentifier(requestShortener)); + return stripLoaderFromPath(e.module.readableIdentifier(requestShortener)) } /* istanbul ignore next */ - return null; -}; + return null +} // helper to transform strings in errors -const ensureWebpackErrors = (errors: Array): Array => errors.map((e: string | WebpackError) => { - /* istanbul ignore if */ - if (typeof e === 'string') { - // webpack does this also, so there must be case when this happens - return (({ message: e } as any) as WebpackError); - } - return e; -}); +const ensureWebpackErrors = ( + errors: Array +): Array => + errors.map((e: string | WebpackError) => { + /* istanbul ignore if */ + if (typeof e === 'string') { + // webpack does this also, so there must be case when this happens + return ({ message: e } as any) as WebpackError + } + return e + }) -const prependWarning = (message: string) => `${chalk.yellow('Warning')} ${message}`; -const prependError = (message: string) => `${chalk.red('Error')} ${message}`; +const prependWarning = (message: string) => + `${chalk.yellow('Warning')} ${message}` +const prependError = (message: string) => `${chalk.red('Error')} ${message}` export default function createStatsFormatter(rootPath: string) { - const requestShortener = new RequestShortener(rootPath); - const getFile = createGetFile(requestShortener); + const requestShortener = new RequestShortener(rootPath) + const getFile = createGetFile(requestShortener) const formatError = (err: WebpackError) => { - const lines: Array = []; + const lines: Array = [] - const file = getFile(err); + const file = getFile(err) /* istanbul ignore else */ if (file != null) { - lines.push(`in ${chalk.underline(file)}`); - lines.push(''); + lines.push(`in ${chalk.underline(file)}`) + lines.push('') } else { // got no file, that happens only for more generic errors like the following from node-sass // Missing binding /mochapack-example/node_modules/node-sass/vendor/linux-x64-48/binding.node // Node Sass could not find a binding for your current environment: Linux 64-bit with Node.js 6.x // ... // just print 2 lines like file - lines.push(''); - lines.push(''); + lines.push('') + lines.push('') } - lines.push(formatErrorMessage(err.message)); + lines.push(formatErrorMessage(err.message)) - return lines.join(EOL); - }; + return lines.join(EOL) + } - return function statsFormatter(stats: Stats): {errors: Array;warnings: Array;} { - const { compilation } = stats; + return function statsFormatter( + stats: Stats + ): { errors: Array; warnings: Array } { + const { compilation } = stats return { - errors: ensureWebpackErrors(compilation.errors).map(formatError).map(prependError), - warnings: ensureWebpackErrors(compilation.warnings).map(formatError).map(prependWarning) - }; - }; + errors: ensureWebpackErrors(compilation.errors) + .map(formatError) + .map(prependError), + warnings: ensureWebpackErrors(compilation.warnings) + .map(formatError) + .map(prependWarning) + } + } } diff --git a/src/webpack/util/formatUtil.ts b/src/webpack/util/formatUtil.ts index d084f5f..b628aa5 100644 --- a/src/webpack/util/formatUtil.ts +++ b/src/webpack/util/formatUtil.ts @@ -1,59 +1,76 @@ +import { EOL } from 'os' +import _ from 'lodash' -import { EOL } from "os"; -import _ from "lodash"; - -const syntaxErrorLabel = 'Syntax error:'; +const syntaxErrorLabel = 'Syntax error:' // we replace all EOL combinations with \n and replace to work in a consistent way -const replaceEol = message => message.replace(/\r?\n/g, '\n'); +const replaceEol = message => message.replace(/\r?\n/g, '\n') // undo eol replacements -const useValidEol = (message: string) => message.replace('\n', EOL); +const useValidEol = (message: string) => message.replace('\n', EOL) // strip stacks for module builds as they are useless and just show what happened inside the loader // strip at ... ...:x:y -const stripStackTrace = (message: string) => message.replace(/^\s*at\s.*\(.+\)\n?/gm, ''); +const stripStackTrace = (message: string) => + message.replace(/^\s*at\s.*\(.+\)\n?/gm, '') const cleanUpModuleNotFoundMessage = (message: string) => { if (message.indexOf('Module not found:') === 0) { - return message.replace('Cannot resolve \'file\' or \'directory\' ', '').replace('Cannot resolve module ', '').replace('Error: Can\'t resolve ', '').replace('Error: ', ''); + return message + .replace("Cannot resolve 'file' or 'directory' ", '') + .replace('Cannot resolve module ', '') + .replace("Error: Can't resolve ", '') + .replace('Error: ', '') } - return message; -}; + return message +} const cleanUpBuildError = (message: string) => { if (message.indexOf('Module build failed:') === 0) { // check if first line of message just contains 'Module build failed: ' if (/Module build failed:\s*$/.test(message.split('\n')[0])) { - const lines = message.split('\n'); - let replacement = lines[0]; + const lines = message.split('\n') + let replacement = lines[0] // try to detect real type of build error if (/File to import not found or unreadable/.test(message)) { // sass-loader file not found -> module not found - replacement = 'Module not found:'; + replacement = 'Module not found:' } else if (/Invalid CSS/.test(message)) { // sass-loader css error -> syntax error - replacement = syntaxErrorLabel; + replacement = syntaxErrorLabel } - lines[0] = replacement; - message = lines.join('\n'); // eslint-disable-line no-param-reassign + lines[0] = replacement + message = lines.join('\n') // eslint-disable-line no-param-reassign } - return message.replace('Module build failed: SyntaxError:', syntaxErrorLabel) // babel-loader error - .replace('Module build failed:', ''); // otherwise remove it as it's already clear that this is an module error + return message + .replace('Module build failed: SyntaxError:', syntaxErrorLabel) // babel-loader error + .replace('Module build failed:', '') // otherwise remove it as it's already clear that this is an module error } - return message; -}; + return message +} // removes new line characters at the end of message -const cleanUpUnwantedEol = message => message.replace(/\s*\n\s*$/, ''); +const cleanUpUnwantedEol = message => message.replace(/\s*\n\s*$/, '') // indent all lines by 2 spaces -const indent = (message: string) => message.split('\n').map(l => ` ${l}`).join('\n'); +const indent = (message: string) => + message + .split('\n') + .map(l => ` ${l}`) + .join('\n') // gets executed from top to bottom -export const formatErrorMessage: (message: string) => string = _.flow([replaceEol, stripStackTrace, cleanUpModuleNotFoundMessage, cleanUpBuildError, cleanUpUnwantedEol, indent, useValidEol]); +export const formatErrorMessage: (message: string) => string = _.flow([ + replaceEol, + stripStackTrace, + cleanUpModuleNotFoundMessage, + cleanUpBuildError, + cleanUpUnwantedEol, + indent, + useValidEol +]) export const stripLoaderFromPath = (file: string) => { // Remove webpack-specific loader notation from filename. @@ -62,7 +79,7 @@ export const stripLoaderFromPath = (file: string) => { // After: // ../mochapack/lib/entry.js if (file.lastIndexOf('!') !== -1) { - return file.substr(file.lastIndexOf('!') + 1); + return file.substr(file.lastIndexOf('!') + 1) } - return file; -}; \ No newline at end of file + return file +} diff --git a/src/webpack/util/getAffectedModuleIds.ts b/src/webpack/util/getAffectedModuleIds.ts index cabdd75..64f481b 100644 --- a/src/webpack/util/getAffectedModuleIds.ts +++ b/src/webpack/util/getAffectedModuleIds.ts @@ -1,32 +1,36 @@ - -import { Module, Chunk } from "../types"; +import { Module, Chunk } from '../types' type ModuleMap = { - [key: string ]: Module; -}; + [key: string]: Module +} type ModuleUsageMap = { // child id - [key: string ]: ModuleMap; -}; -const isBuilt = (module: Module): boolean => module.built; -const getId = (module: any): number | string => module.id; + [key: string]: ModuleMap +} +const isBuilt = (module: Module): boolean => module.built +const getId = (module: any): number | string => module.id -const affectedModules = (map: ModuleMap, usageMap: ModuleUsageMap, affected: ModuleMap, moduleId: string | number) => { +const affectedModules = ( + map: ModuleMap, + usageMap: ModuleUsageMap, + affected: ModuleMap, + moduleId: string | number +) => { if (typeof affected[moduleId] !== 'undefined') { // module was already inspected, stop here otherwise we get into endless recursion - return; + return } // module is identified as affected by this function call - const module = map[moduleId]; - affected[module.id] = module; // eslint-disable-line no-param-reassign + const module = map[moduleId] + affected[module.id] = module // eslint-disable-line no-param-reassign // next we need to mark all usages aka parents also as affected - const usages = usageMap[module.id]; + const usages = usageMap[module.id] if (typeof usages !== 'undefined') { - const ids = Object.keys(usages); - ids.forEach((id: string) => affectedModules(map, usageMap, affected, id)); + const ids = Object.keys(usages) + ids.forEach((id: string) => affectedModules(map, usageMap, affected, id)) } -}; +} /** * Builds a map where all modules are indexed by it's id @@ -35,9 +39,12 @@ const affectedModules = (map: ModuleMap, usageMap: ModuleUsageMap, affected: Mod * } */ const buildModuleMap = (modules: Array): ModuleMap => { - const moduleMap = modules.reduce((memo, module: Module) => ({ ...memo, [module.id]: module }), {}); - return moduleMap; -}; + const moduleMap = modules.reduce( + (memo, module: Module) => ({ ...memo, [module.id]: module }), + {} + ) + return moduleMap +} /** * Builds a map with all modules that are used in other modules (child -> parent relation) @@ -51,7 +58,10 @@ const buildModuleMap = (modules: Array): ModuleMap => { * @param modules Array * @return ModuleUsageMap */ -const buildModuleUsageMap = (chunks: Array, modules: Array): ModuleUsageMap => { +const buildModuleUsageMap = ( + chunks: Array, + modules: Array +): ModuleUsageMap => { // build a map of all modules with their parent // { // [childModuleId]: { @@ -59,20 +69,23 @@ const buildModuleUsageMap = (chunks: Array, modules: Array): Modu // } // } // - const moduleUsageMap: ModuleUsageMap = modules.reduce((memo, module: Module) => { - module.dependencies.forEach(dependency => { - const dependentModule = dependency.module; + const moduleUsageMap: ModuleUsageMap = modules.reduce( + (memo, module: Module) => { + module.dependencies.forEach(dependency => { + const dependentModule = dependency.module - if (!dependentModule) { - return; - } - if (typeof memo[dependentModule.id] === 'undefined') { - memo[dependentModule.id] = {}; // eslint-disable-line no-param-reassign - } - memo[dependentModule.id][module.id] = module; // eslint-disable-line no-param-reassign - }); - return memo; - }, {}); + if (!dependentModule) { + return + } + if (typeof memo[dependentModule.id] === 'undefined') { + memo[dependentModule.id] = {} // eslint-disable-line no-param-reassign + } + memo[dependentModule.id][module.id] = module // eslint-disable-line no-param-reassign + }) + return memo + }, + {} + ) // build a map of all chunks with their modules // { @@ -82,35 +95,38 @@ const buildModuleUsageMap = (chunks: Array, modules: Array): Modu // } const chunkModuleMap: ModuleUsageMap = chunks.reduce((memo, chunk: Chunk) => { // build chunk map first to get also empty chunks (without modules) - memo[chunk.id] = {}; // eslint-disable-line no-param-reassign - return memo; - }, {}); + memo[chunk.id] = {} // eslint-disable-line no-param-reassign + return memo + }, {}) modules.reduce((memo, module: Module) => { module.getChunks().forEach((chunk: Chunk) => { - memo[chunk.id][module.id] = module; // eslint-disable-line no-param-reassign - }); - return memo; - }, chunkModuleMap); + memo[chunk.id][module.id] = module // eslint-disable-line no-param-reassign + }) + return memo + }, chunkModuleMap) // detect modules with code split points (e.g. require.ensure) and enhance moduleUsageMap with that information modules.forEach((module: Module) => { module.blocks // chunkGroup can be invalid in in some cases - .filter(block => block.chunkGroup != null).forEach(block => { - // loop through all generated chunks by this module - block.chunkGroup.chunks.map(getId).forEach(chunkId => { - // and mark all modules of this chunk as a direct dependency of the original module - Object.values((chunkModuleMap[chunkId] as ModuleMap)).forEach((childModule: any) => { - if (typeof moduleUsageMap[childModule.id] === 'undefined') { - moduleUsageMap[childModule.id] = {}; - } - moduleUsageMap[childModule.id][module.id] = module; - }); - }); - }); - }); + .filter(block => block.chunkGroup != null) + .forEach(block => { + // loop through all generated chunks by this module + block.chunkGroup.chunks.map(getId).forEach(chunkId => { + // and mark all modules of this chunk as a direct dependency of the original module + Object.values(chunkModuleMap[chunkId] as ModuleMap).forEach( + (childModule: any) => { + if (typeof moduleUsageMap[childModule.id] === 'undefined') { + moduleUsageMap[childModule.id] = {} + } + moduleUsageMap[childModule.id][module.id] = module + } + ) + }) + }) + }) - return moduleUsageMap; -}; + return moduleUsageMap +} /** * Builds a list with ids of all affected modules in the following way: @@ -121,13 +137,18 @@ const buildModuleUsageMap = (chunks: Array, modules: Array): Modu * @param modules Array * @return {Array.} */ -export default function getAffectedModuleIds(chunks: Array, modules: Array): Array { - const moduleMap: ModuleMap = buildModuleMap(modules); - const moduleUsageMap: ModuleUsageMap = buildModuleUsageMap(chunks, modules); +export default function getAffectedModuleIds( + chunks: Array, + modules: Array +): Array { + const moduleMap: ModuleMap = buildModuleMap(modules) + const moduleUsageMap: ModuleUsageMap = buildModuleUsageMap(chunks, modules) - const builtModules = modules.filter(isBuilt); - const affectedMap: ModuleMap = {}; - builtModules.forEach((module: Module) => affectedModules(moduleMap, moduleUsageMap, affectedMap, module.id)); + const builtModules = modules.filter(isBuilt) + const affectedMap: ModuleMap = {} + builtModules.forEach((module: Module) => + affectedModules(moduleMap, moduleUsageMap, affectedMap, module.id) + ) - return Object.values(affectedMap).map(getId); + return Object.values(affectedMap).map(getId) } diff --git a/src/webpack/util/getBuildStats.ts b/src/webpack/util/getBuildStats.ts index 3209e20..14a1904 100644 --- a/src/webpack/util/getBuildStats.ts +++ b/src/webpack/util/getBuildStats.ts @@ -1,56 +1,55 @@ - -import path from "path"; -import sortChunks from "./sortChunks"; -import getAffectedModuleIds from "./getAffectedModuleIds"; - -import { Chunk, Module } from "../types"; -import { Stats } from "webpack"; +import path from 'path' +import { Stats } from 'webpack' +import sortChunks from './sortChunks' +import getAffectedModuleIds from './getAffectedModuleIds' +import { Chunk, Module } from '../types' export type BuildStats = { - affectedModules: Array; - affectedFiles: Array; - entries: Array; -}; - - -export default function getBuildStats(stats: Stats, outputPath: string): BuildStats { - const { - chunks, - chunkGroups, - modules - } = stats.compilation; + affectedModules: Array + affectedFiles: Array + entries: Array +} - const sortedChunks = sortChunks(chunks, chunkGroups); - const affectedModules = getAffectedModuleIds(chunks, modules); +export default function getBuildStats( + stats: Stats, + outputPath: string +): BuildStats { + const { chunks, chunkGroups, modules } = stats.compilation - const entries = []; - const js = []; - const pathHelper = f => path.join(outputPath, f); + const sortedChunks = sortChunks(chunks, chunkGroups) + const affectedModules = getAffectedModuleIds(chunks, modules) + const entries = [] + const js = [] + const pathHelper = f => path.join(outputPath, f) sortedChunks.forEach((chunk: Chunk) => { - const files = Array.isArray(chunk.files) ? chunk.files : [chunk.files]; + const files = Array.isArray(chunk.files) ? chunk.files : [chunk.files] if (chunk.isOnlyInitial()) { // only entry files - const entry = files[0]; - entries.push(entry); + const entry = files[0] + entries.push(entry) } - if (chunk.getModules().some((module: Module) => affectedModules.indexOf(module.id) !== -1)) { + if ( + chunk + .getModules() + .some((module: Module) => affectedModules.indexOf(module.id) !== -1) + ) { files.forEach(file => { if (/\.js$/.test(file)) { - js.push(file); + js.push(file) } - }); + }) } - }); + }) const buildStats: BuildStats = { affectedModules, affectedFiles: js.map(pathHelper), entries: entries.map(pathHelper) - }; + } - return buildStats; + return buildStats } diff --git a/src/webpack/util/sortChunks.ts b/src/webpack/util/sortChunks.ts index afc9ce9..485557a 100644 --- a/src/webpack/util/sortChunks.ts +++ b/src/webpack/util/sortChunks.ts @@ -1,25 +1,40 @@ -import toposort from "toposort"; +import toposort from 'toposort' // see https://github.com/jantimon/html-webpack-plugin/blob/8131d8bb1dc9b185b3c1709264a3baf32ef799bc/lib/chunksorter.js export default function sortChunks(chunks, chunkGroups) { // We build a map (chunk-id -> chunk) for faster access during graph building. - const nodeMap = {}; + const nodeMap = {} chunks.forEach(chunk => { - nodeMap[chunk.id] = chunk; - }); + nodeMap[chunk.id] = chunk + }) // Add an edge for each parent (parent -> child) - const edges = chunkGroups.reduce((result, chunkGroup) => result.concat(Array.from(chunkGroup.parentsIterable, parentGroup => [parentGroup, chunkGroup])), []); - const sortedGroups = toposort.array(chunkGroups, edges); + const edges = chunkGroups.reduce( + (result, chunkGroup) => + result.concat( + Array.from(chunkGroup.parentsIterable, parentGroup => [ + parentGroup, + chunkGroup + ]) + ), + [] + ) + const sortedGroups = toposort.array(chunkGroups, edges) // flatten chunkGroup into chunks - const sortedChunks = sortedGroups.reduce((result, chunkGroup) => result.concat(chunkGroup.chunks), []).map(chunk => // use the chunk from the list passed in, since it may be a filtered list - nodeMap[chunk.id]).filter((chunk, index, self) => { - // make sure exists (ie excluded chunks not in nodeMap) - const exists = !!chunk; - // make sure we have a unique list - const unique = self.indexOf(chunk) === index; - return exists && unique; - }); - return sortedChunks; -} \ No newline at end of file + const sortedChunks = sortedGroups + .reduce((result, chunkGroup) => result.concat(chunkGroup.chunks), []) + .map( + ( + chunk // use the chunk from the list passed in, since it may be a filtered list + ) => nodeMap[chunk.id] + ) + .filter((chunk, index, self) => { + // make sure exists (ie excluded chunks not in nodeMap) + const exists = !!chunk + // make sure we have a unique list + const unique = self.indexOf(chunk) === index + return exists && unique + }) + return sortedChunks +} diff --git a/test/integration/cli/code-splitting.test.ts b/test/integration/cli/code-splitting.test.ts index 8a0e89b..164dc7c 100644 --- a/test/integration/cli/code-splitting.test.ts +++ b/test/integration/cli/code-splitting.test.ts @@ -2,76 +2,106 @@ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import path from "path"; -import normalizePath from "normalize-path"; -import { exec } from "./util/childProcess"; +import { assert } from 'chai' +import path from 'path' +import normalizePath from 'normalize-path' +import exec from './util/childProcess' +const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')) +const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')) -const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); +describe('code-splitting', function() { + context('with static require', function() { + before(function() { + this.passingTest = normalizePath( + path.join(fixtureDir, 'code-splitting/test/lazy-load-entry-static.js') + ) + this.webpackConfig = normalizePath( + path.join(fixtureDir, 'code-splitting/webpack.config-test.js') + ) + }) + it('runs successful test', function(done) { + exec( + `node ${binPath} --webpack-config "${this.webpackConfig}" "${this.passingTest}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, 'entry1.js') + assert.include(output, 'entry2.js') + assert.include(output, '1 passing') + done() + } + ) + }) + }) -describe('code-splitting', function () { - context('with static require', function () { - before(function () { - this.passingTest = normalizePath(path.join(fixtureDir, 'code-splitting/test/lazy-load-entry-static.js')); - this.webpackConfig = normalizePath(path.join(fixtureDir, 'code-splitting/webpack.config-test.js')); - }); - it('runs successful test', function (done) { - exec(`node ${binPath} --webpack-config "${this.webpackConfig}" "${this.passingTest}"`, (err, output) => { - assert.isNull(err); - assert.include(output, 'entry1.js'); - assert.include(output, 'entry2.js'); - assert.include(output, '1 passing'); - done(); - }); - }); - }); + context('with dynamic require', function() { + before(function() { + this.passingTest = normalizePath( + path.join(fixtureDir, 'code-splitting/test/lazy-load-entry-dynamic.js') + ) + this.webpackConfig = normalizePath( + path.join(fixtureDir, 'code-splitting/webpack.config-test.js') + ) + }) + it('runs successfull test', function(done) { + exec( + `node ${binPath} --webpack-config "${this.webpackConfig}" "${this.passingTest}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, 'entry1.js') + assert.notInclude(output, 'entry2.js') + assert.include(output, '1 passing') + done() + } + ) + }) + }) - context('with dynamic require', function () { - before(function () { - this.passingTest = normalizePath(path.join(fixtureDir, 'code-splitting/test/lazy-load-entry-dynamic.js')); - this.webpackConfig = normalizePath(path.join(fixtureDir, 'code-splitting/webpack.config-test.js')); - }); - it('runs successfull test', function (done) { - exec(`node ${binPath} --webpack-config "${this.webpackConfig}" "${this.passingTest}"`, (err, output) => { - assert.isNull(err); - assert.include(output, 'entry1.js'); - assert.notInclude(output, 'entry2.js'); - assert.include(output, '1 passing'); - done(); - }); - }); - }); + context( + 'with dynamic require (self referencing require statements)', + function() { + before(function() { + this.passingTest = normalizePath( + path.join(fixtureDir, 'code-splitting/test/cyclic-load-entry.js') + ) + this.webpackConfig = normalizePath( + path.join(fixtureDir, 'code-splitting/webpack.config-test.js') + ) + }) - context('with dynamic require (self referencing require statements)', function () { - before(function () { - this.passingTest = normalizePath(path.join(fixtureDir, 'code-splitting/test/cyclic-load-entry.js')); - this.webpackConfig = normalizePath(path.join(fixtureDir, 'code-splitting/webpack.config-test.js')); - }); + it('runs successfull test with cylic dependencies (entry matches itself)', function(done) { + exec( + `node ${binPath} --webpack-config "${this.webpackConfig}" "${this.passingTest}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, 'entry1.js') + assert.notInclude(output, 'entry2.js') + assert.include(output, '1 passing') + done() + } + ) + }) + } + ) - it('runs successfull test with cylic dependencies (entry matches itself)', function (done) { - exec(`node ${binPath} --webpack-config "${this.webpackConfig}" "${this.passingTest}"`, (err, output) => { - assert.isNull(err); - assert.include(output, 'entry1.js'); - assert.notInclude(output, 'entry2.js'); - assert.include(output, '1 passing'); - done(); - }); - }); - }); - - context('without any require statements (empty require.ensure)', function () { - before(function () { - this.passingTest = normalizePath(path.join(fixtureDir, 'code-splitting/test/lazy-load-none.js')); - this.webpackConfig = normalizePath(path.join(fixtureDir, 'code-splitting/webpack.config-test.js')); - }); - it('runs successfull test', function (done) { - exec(`node ${binPath} --webpack-config "${this.webpackConfig}" "${this.passingTest}"`, (err, output) => { - assert.isNull(err); - assert.include(output, '1 passing'); - done(); - }); - }); - }); -}); + context('without any require statements (empty require.ensure)', function() { + before(function() { + this.passingTest = normalizePath( + path.join(fixtureDir, 'code-splitting/test/lazy-load-none.js') + ) + this.webpackConfig = normalizePath( + path.join(fixtureDir, 'code-splitting/webpack.config-test.js') + ) + }) + it('runs successfull test', function(done) { + exec( + `node ${binPath} --webpack-config "${this.webpackConfig}" "${this.passingTest}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, '1 passing') + done() + } + ) + }) + }) +}) diff --git a/test/integration/cli/config.test.ts b/test/integration/cli/config.test.ts index ac4ea69..1b0ca0a 100644 --- a/test/integration/cli/config.test.ts +++ b/test/integration/cli/config.test.ts @@ -2,48 +2,57 @@ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import path from "path"; -import { exec } from "./util/childProcess"; +import { assert } from 'chai' +import path from 'path' +import exec from './util/childProcess' -const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); -const testSimple = path.join(fixtureDir, 'simple/simple.js'); +const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')) +const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')) +const testSimple = path.join(fixtureDir, 'simple/simple.js') -describe('cli --webpack-config', function () { - it('does not throw for missing default config', function (done) { +describe('cli --webpack-config', function() { + it('does not throw for missing default config', function(done) { exec(`node ${binPath} "${testSimple}"`, err => { - assert.isNull(err); - done(); - }); - }); + assert.isNull(err) + done() + }) + }) - it('throws when not found', function (done) { - const configNotFound = 'xxxxxxx.js'; - const command = `node ${binPath} --webpack-config ${configNotFound} "${testSimple}"`; + it('throws when not found', function(done) { + const configNotFound = 'xxxxxxx.js' + const command = `node ${binPath} --webpack-config ${configNotFound} "${testSimple}"` exec(command, (err, output) => { - assert.include(output, `Webpack config could not be found: ${configNotFound}`); - done(); - }); - }); + assert.include( + output, + `Webpack config could not be found: ${configNotFound}` + ) + done() + }) + }) - it('passes --webpack-env random to config', function (done) { - const config = path.join(fixtureDir, 'config/config.env.js'); - const env = Math.random(); - exec(`node ${binPath} --webpack-config ${config} --webpack-env ${env} "${testSimple}"`, (err, output) => { - assert.isNull(err); - assert.include(output, env); - done(); - }); - }); + it('passes --webpack-env random to config', function(done) { + const config = path.join(fixtureDir, 'config/config.env.js') + const env = Math.random() + exec( + `node ${binPath} --webpack-config ${config} --webpack-env ${env} "${testSimple}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, env) + done() + } + ) + }) - it('passes --webpack-env object to config', function (done) { - const config = path.join(fixtureDir, 'config/config.env.js'); - const env = Math.random(); - exec(`node ${binPath} --webpack-config ${config} --webpack-env.test ${env} "${testSimple}"`, (err, output) => { - assert.isNull(err); - assert.include(output, `{ test: '${env}' }`); - done(); - }); - }); -}); \ No newline at end of file + it('passes --webpack-env object to config', function(done) { + const config = path.join(fixtureDir, 'config/config.env.js') + const env = Math.random() + exec( + `node ${binPath} --webpack-config ${config} --webpack-env.test ${env} "${testSimple}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, `{ test: '${env}' }`) + done() + } + ) + }) +}) diff --git a/test/integration/cli/custom-output-path.test.ts b/test/integration/cli/custom-output-path.test.ts index e618ad8..76562cf 100644 --- a/test/integration/cli/custom-output-path.test.ts +++ b/test/integration/cli/custom-output-path.test.ts @@ -1,37 +1,51 @@ /* eslint-env node, mocha */ /* eslint-disable func-names, prefer-arrow-callback, max-len */ -import { assert } from "chai"; -import path from "path"; -import fs from "fs"; -import del from "del"; -import normalizePath from "normalize-path"; -import { exec } from "./util/childProcess"; +import { assert } from 'chai' +import path from 'path' +import fs from 'fs' +import del from 'del' +import normalizePath from 'normalize-path' +import exec from './util/childProcess' -const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); +const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')) +const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')) -describe('custom output path', function () { - before(function () { - this.passingTest = normalizePath(path.join(fixtureDir, 'custom-output-path/test/test.js')); - this.webpackConfigPath = normalizePath(path.join(fixtureDir, 'custom-output-path/webpack.config-test.js')); - this.webpackConfig = require('./fixture/custom-output-path/webpack.config-test.js'); // eslint-disable-line global-require - }); +describe('custom output path', function() { + before(function() { + this.passingTest = normalizePath( + path.join(fixtureDir, 'custom-output-path/test/test.js') + ) + this.webpackConfigPath = normalizePath( + path.join(fixtureDir, 'custom-output-path/webpack.config-test.js') + ) + this.webpackConfig = require('./fixture/custom-output-path/webpack.config-test.js') // eslint-disable-line global-require + }) - beforeEach(function () { - return del(this.webpackConfig.output.path); - }); + beforeEach(function() { + return del(this.webpackConfig.output.path) + }) - it('runs test successfully', function (done) { - exec(`node ${binPath} --webpack-config "${this.webpackConfigPath}" "${this.passingTest}"`, (err, output) => { - assert.isNull(err); - assert.include(output, '1 passing'); - assert.isTrue(fs.existsSync(path.join(this.webpackConfig.output.path, this.webpackConfig.output.filename))); - done(); - }); - }); + it('runs test successfully', function(done) { + exec( + `node ${binPath} --webpack-config "${this.webpackConfigPath}" "${this.passingTest}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, '1 passing') + assert.isTrue( + fs.existsSync( + path.join( + this.webpackConfig.output.path, + this.webpackConfig.output.filename + ) + ) + ) + done() + } + ) + }) - afterEach(function () { - return del(this.webpackConfig.output.path); - }); -}); + afterEach(function() { + return del(this.webpackConfig.output.path) + }) +}) diff --git a/test/integration/cli/entry.test.ts b/test/integration/cli/entry.test.ts index 3d84d8a..938ec4c 100644 --- a/test/integration/cli/entry.test.ts +++ b/test/integration/cli/entry.test.ts @@ -2,16 +2,16 @@ /* eslint-disable func-names, prefer-arrow-callback, max-len */ -import { assert } from "chai"; -import _ from "lodash"; -import fs from "fs-extra"; -import del from "del"; -import path from "path"; -import anymatch from "anymatch"; -import normalizePath from "normalize-path"; -import { exec } from "./util/childProcess"; +import { assert } from 'chai' +import _ from 'lodash' +import fs from 'fs-extra' +import del from 'del' +import path from 'path' +import anymatch from 'anymatch' +import normalizePath from 'normalize-path' +import exec from './util/childProcess' -const escapePath = p => p.replace(/\\/gm, '\\\\'); +const escapePath = p => p.replace(/\\/gm, '\\\\') function createTest(filePath, passing) { const content = ` @@ -21,8 +21,8 @@ function createTest(filePath, passing) { assert.ok(${passing}); }); }); - `; - fs.outputFileSync(filePath, content); + ` + fs.outputFileSync(filePath, content) } function createCorruptedTest(filePath) { @@ -32,8 +32,8 @@ function createCorruptedTest(filePath) { it('runs test', function () { assert.ok(false); }); - `; - fs.outputFileSync(filePath, content); + ` + fs.outputFileSync(filePath, content) } function createRuntimeErrorTest(filePath, passing) { @@ -45,429 +45,558 @@ function createRuntimeErrorTest(filePath, passing) { assert.ok(${passing}); }); }); - `; - fs.outputFileSync(filePath, content); + ` + fs.outputFileSync(filePath, content) } -const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const fixtureDirTmp = path.relative(process.cwd(), path.join(__dirname, 'fixtureTmp')); -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); - -describe('cli - entry', function () { - context('single test file as option', function () { - before(function () { - this.passingTest = normalizePath(path.join(fixtureDirTmp, 'passing-test.js')); - this.failingTest = normalizePath(path.join(fixtureDirTmp, 'failing-test.js')); - this.corruptedTest = normalizePath(path.join(fixtureDirTmp, 'corrupted-test.js')); - this.runtimeErrorTest = normalizePath(path.join(fixtureDirTmp, 'runtime-error-test.js')); - createTest(this.passingTest, true); - createTest(this.failingTest, false); - createCorruptedTest(this.corruptedTest); - createRuntimeErrorTest(this.runtimeErrorTest); - }); - - it('handles failed module with syntax errors', function (done) { - exec(`node ${binPath} --mode development "${this.corruptedTest}"`, err => { - assert.isNotNull(err); - assert.isAbove(err.code, 0); - done(); - }); - }); - - it('handles module with runtime errors', function (done) { - exec(`node ${binPath} --mode development "${this.runtimeErrorTest}"`, err => { - assert.isNotNull(err); - assert.isAbove(err.code, 0); - done(); - }); - }); - - - it('runs successfull test', function (done) { - exec(`node ${binPath} --mode development "${this.passingTest}"`, (err, output) => { - assert.isNull(err); - assert.include(output, this.passingTest); - assert.include(output, '1 passing'); - done(); - }); - }); - - it('runs failing test', function (done) { - exec(`node ${binPath} --mode development "${this.failingTest}"`, (err, output) => { - assert.isNotNull(err); - assert.strictEqual(err.code, 1); - assert.include(output, this.failingTest); - assert.include(output, '0 passing'); - assert.include(output, '1 failing'); - done(); - }); - }); - - after(function () { - return del([this.passingTest, this.failingTest, this.corruptedTest, this.runtimeErrorTest]); - }); - }); - - context('multiple test files as option', function () { - before(function () { - this.passingTest = normalizePath(path.join(fixtureDirTmp, 'passing-test.js')); - this.passingTest2 = normalizePath(path.join(fixtureDirTmp, 'passing-test2.js')); - this.failingTest = normalizePath(path.join(fixtureDirTmp, 'failing-test.js')); - this.failingTest2 = normalizePath(path.join(fixtureDirTmp, 'failing-test2.js')); - this.corruptedTest = normalizePath(path.join(fixtureDirTmp, 'corrupted-test.js')); - this.corruptedTest2 = normalizePath(path.join(fixtureDirTmp, 'corrupted-test2.js')); - createTest(this.passingTest, true); - createTest(this.passingTest2, true); - createTest(this.failingTest, false); - createTest(this.failingTest2, false); - createCorruptedTest(this.corruptedTest); - createCorruptedTest(this.corruptedTest2); - }); - - it('handles failed module with syntax errors', function (done) { - exec(`node ${binPath} --mode development "${this.corruptedTest}" "${this.corruptedTest2}"`, err => { - assert.isNotNull(err); - assert.isAbove(err.code, 0); - done(); - }); - }); - - it('runs successfull test', function (done) { - exec(`node ${binPath} --mode development "${this.passingTest}" "${this.passingTest2}"`, (err, output) => { - assert.isNull(err); - assert.include(output, this.passingTest); - assert.include(output, this.passingTest2); - assert.include(output, '2 passing'); - done(); - }); - }); - - it('runs failing test', function (done) { - exec(`node ${binPath} --mode development "${this.failingTest}" "${this.failingTest2}"`, (err, output) => { - assert.isNotNull(err); - assert.strictEqual(err.code, 2); - assert.include(output, this.failingTest); - assert.include(output, this.failingTest2); - assert.include(output, '0 passing'); - assert.include(output, '2 failing'); - done(); - }); - }); - - after(function () { - return del([this.passingTest, this.passingTest2, this.failingTest, this.failingTest2, this.corruptedTest, this.corruptedTest2]); - }); - }); - - context('entry with absolute paths', function () { - before(function () { - this.passingTest = path.join(process.cwd(), fixtureDirTmp, 'passing-test.js'); - createTest(this.passingTest, true); - }); - - it('runs test with absolute entry', function (done) { - exec(`node ${binPath} --mode development "${this.passingTest}"`, (err, output) => { - assert.isNull(err); - assert.include(output, this.passingTest); - assert.include(output, '1 passing'); - done(); - }); - }); - - after(function () { - return del([this.passingTest]); - }); - }); - - context('glob pattern as option', function () { - const testFiles = _.range(1, 30).map(x => { - if (parseInt(x / 10, 10) === 0) { - if (x <= 4) { - return path.join(fixtureDirTmp, `passing-test-${x}.js`); - } else if (x <= 8) { - return path.join(fixtureDirTmp, `failing-test-${x}.js`); +const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')) +const fixtureDirTmp = path.relative( + process.cwd(), + path.join(__dirname, 'fixtureTmp') +) +const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')) + +describe('cli - entry', function() { + context('single test file as option', function() { + before(function() { + this.passingTest = normalizePath( + path.join(fixtureDirTmp, 'passing-test.js') + ) + this.failingTest = normalizePath( + path.join(fixtureDirTmp, 'failing-test.js') + ) + this.corruptedTest = normalizePath( + path.join(fixtureDirTmp, 'corrupted-test.js') + ) + this.runtimeErrorTest = normalizePath( + path.join(fixtureDirTmp, 'runtime-error-test.js') + ) + createTest(this.passingTest, true) + createTest(this.failingTest, false) + createCorruptedTest(this.corruptedTest) + createRuntimeErrorTest(this.runtimeErrorTest) + }) + + it('handles failed module with syntax errors', function(done) { + exec( + `node ${binPath} --mode development "${this.corruptedTest}"`, + err => { + assert.isNotNull(err) + assert.isAbove(err.code, 0) + done() + } + ) + }) + + it('handles module with runtime errors', function(done) { + exec( + `node ${binPath} --mode development "${this.runtimeErrorTest}"`, + err => { + assert.isNotNull(err) + assert.isAbove(err.code, 0) + done() + } + ) + }) + + it('runs successfull test', function(done) { + exec( + `node ${binPath} --mode development "${this.passingTest}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, this.passingTest) + assert.include(output, '1 passing') + done() + } + ) + }) + + it('runs failing test', function(done) { + exec( + `node ${binPath} --mode development "${this.failingTest}"`, + (err, output) => { + assert.isNotNull(err) + assert.strictEqual(err.code, 1) + assert.include(output, this.failingTest) + assert.include(output, '0 passing') + assert.include(output, '1 failing') + done() + } + ) + }) + + after(function() { + return del([ + this.passingTest, + this.failingTest, + this.corruptedTest, + this.runtimeErrorTest + ]) + }) + }) + + context('multiple test files as option', function() { + before(function() { + this.passingTest = normalizePath( + path.join(fixtureDirTmp, 'passing-test.js') + ) + this.passingTest2 = normalizePath( + path.join(fixtureDirTmp, 'passing-test2.js') + ) + this.failingTest = normalizePath( + path.join(fixtureDirTmp, 'failing-test.js') + ) + this.failingTest2 = normalizePath( + path.join(fixtureDirTmp, 'failing-test2.js') + ) + this.corruptedTest = normalizePath( + path.join(fixtureDirTmp, 'corrupted-test.js') + ) + this.corruptedTest2 = normalizePath( + path.join(fixtureDirTmp, 'corrupted-test2.js') + ) + createTest(this.passingTest, true) + createTest(this.passingTest2, true) + createTest(this.failingTest, false) + createTest(this.failingTest2, false) + createCorruptedTest(this.corruptedTest) + createCorruptedTest(this.corruptedTest2) + }) + + it('handles failed module with syntax errors', function(done) { + exec( + `node ${binPath} --mode development "${this.corruptedTest}" "${this.corruptedTest2}"`, + err => { + assert.isNotNull(err) + assert.isAbove(err.code, 0) + done() } - return path.join(fixtureDirTmp, `corrupted-test-${x}.js`); - } else if (parseInt(x / 10, 10) === 1) { - return path.join(fixtureDirTmp, 'sub1', `passing-test-${x}.js`); - } - return path.join(fixtureDirTmp, 'sub2', `passing-test-${x}.js`); - }).map(normalizePath); - - before(function () { + ) + }) + + it('runs successfull test', function(done) { + exec( + `node ${binPath} --mode development "${this.passingTest}" "${this.passingTest2}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, this.passingTest) + assert.include(output, this.passingTest2) + assert.include(output, '2 passing') + done() + } + ) + }) + + it('runs failing test', function(done) { + exec( + `node ${binPath} --mode development "${this.failingTest}" "${this.failingTest2}"`, + (err, output) => { + assert.isNotNull(err) + assert.strictEqual(err.code, 2) + assert.include(output, this.failingTest) + assert.include(output, this.failingTest2) + assert.include(output, '0 passing') + assert.include(output, '2 failing') + done() + } + ) + }) + + after(function() { + return del([ + this.passingTest, + this.passingTest2, + this.failingTest, + this.failingTest2, + this.corruptedTest, + this.corruptedTest2 + ]) + }) + }) + + context('entry with absolute paths', function() { + before(function() { + this.passingTest = path.join( + process.cwd(), + fixtureDirTmp, + 'passing-test.js' + ) + createTest(this.passingTest, true) + }) + + it('runs test with absolute entry', function(done) { + exec( + `node ${binPath} --mode development "${this.passingTest}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, this.passingTest) + assert.include(output, '1 passing') + done() + } + ) + }) + + after(function() { + return del([this.passingTest]) + }) + }) + + context('glob pattern as option', function() { + const testFiles = _.range(1, 30) + .map(x => { + if (parseInt(x / 10, 10) === 0) { + if (x <= 4) { + return path.join(fixtureDirTmp, `passing-test-${x}.js`) + } else if (x <= 8) { + return path.join(fixtureDirTmp, `failing-test-${x}.js`) + } + return path.join(fixtureDirTmp, `corrupted-test-${x}.js`) + } else if (parseInt(x / 10, 10) === 1) { + return path.join(fixtureDirTmp, 'sub1', `passing-test-${x}.js`) + } + return path.join(fixtureDirTmp, 'sub2', `passing-test-${x}.js`) + }) + .map(normalizePath) + + before(function() { testFiles.forEach(file => { if (file.indexOf('passing-test') !== -1) { - createTest(file, true); + createTest(file, true) } else if (file.indexOf('failing-test') !== -1) { - createTest(file, false); + createTest(file, false) } else { - createCorruptedTest(file); + createCorruptedTest(file) } - }); - }); + }) + }) - const corruptedPatterns = [path.join(fixtureDirTmp, 'corrupted-*.js')].map(normalizePath); + const corruptedPatterns = [path.join(fixtureDirTmp, 'corrupted-*.js')].map( + normalizePath + ) corruptedPatterns.forEach(pattern => { - it(`handles corrupted modules with pattern '${pattern}'`, function (done) { + it(`handles corrupted modules with pattern '${pattern}'`, function(done) { exec(`node ${binPath} --mode development "${pattern}"`, err => { - assert.isNotNull(err); - assert.isAbove(err.code, 0); - done(); - }); - }); - }); - - const passingPatterns = [path.join(fixtureDirTmp, 'passing-*.js'), path.join(fixtureDirTmp, 'passing-*-1.js'), path.join(fixtureDirTmp, '**/passing-*.js')].map(normalizePath); + assert.isNotNull(err) + assert.isAbove(err.code, 0) + done() + }) + }) + }) + + const passingPatterns = [ + path.join(fixtureDirTmp, 'passing-*.js'), + path.join(fixtureDirTmp, 'passing-*-1.js'), + path.join(fixtureDirTmp, '**/passing-*.js') + ].map(normalizePath) passingPatterns.forEach(pattern => { - const matcher = anymatch(pattern); - const files = testFiles.filter(matcher); - - it(`runs ${files.length} passing tests of ${testFiles.length} with pattern '${pattern}'`, function (done) { - exec(`node ${binPath} --mode development "${pattern}"`, (err, output) => { - assert.isNull(err); - files.forEach(file => { - assert.include(output, file); - }); - assert.include(output, `${files.length} passing`); - done(); - }); - }); - }); - - const failingPatterns = [path.join(fixtureDirTmp, 'failing-*.js'), path.join(fixtureDirTmp, 'failing-*-7.js'), path.join(fixtureDirTmp, 'failing-*-@(5|6).js')].map(normalizePath); + const matcher = anymatch(pattern) + const files = testFiles.filter(matcher) + + it(`runs ${files.length} passing tests of ${testFiles.length} with pattern '${pattern}'`, function(done) { + exec( + `node ${binPath} --mode development "${pattern}"`, + (err, output) => { + assert.isNull(err) + files.forEach(file => { + assert.include(output, file) + }) + assert.include(output, `${files.length} passing`) + done() + } + ) + }) + }) + + const failingPatterns = [ + path.join(fixtureDirTmp, 'failing-*.js'), + path.join(fixtureDirTmp, 'failing-*-7.js'), + path.join(fixtureDirTmp, 'failing-*-@(5|6).js') + ].map(normalizePath) failingPatterns.forEach(pattern => { - const matcher = anymatch(pattern); - const files = testFiles.filter(matcher); - - it(`runs ${files.length} failing tests of ${testFiles.length} with pattern '${pattern}'`, function (done) { - exec(`node ${binPath} --mode development "${pattern}"`, (err, output) => { - assert.isNotNull(err); - assert.strictEqual(err.code, files.length); - files.forEach(file => { - assert.include(output, file); - }); - - assert.include(output, '0 passing'); - assert.include(output, `${files.length} failing`); - done(); - }); - }); - }); - - const multiPassingPatterns = [path.join(fixtureDirTmp, 'passing-*-1.js'), path.join(fixtureDirTmp, 'passing-*-2.js'), path.join(fixtureDirTmp, 'passing-*-3.js')].map(normalizePath); - - const pattern = multiPassingPatterns.map(str => `"${str}"`).join(' '); - const matcher = anymatch(multiPassingPatterns); - const files = testFiles.filter(matcher); - - it(`runs ${files.length} passing tests of ${testFiles.length} with pattern '${pattern}'`, function (done) { + const matcher = anymatch(pattern) + const files = testFiles.filter(matcher) + + it(`runs ${files.length} failing tests of ${testFiles.length} with pattern '${pattern}'`, function(done) { + exec( + `node ${binPath} --mode development "${pattern}"`, + (err, output) => { + assert.isNotNull(err) + assert.strictEqual(err.code, files.length) + files.forEach(file => { + assert.include(output, file) + }) + + assert.include(output, '0 passing') + assert.include(output, `${files.length} failing`) + done() + } + ) + }) + }) + + const multiPassingPatterns = [ + path.join(fixtureDirTmp, 'passing-*-1.js'), + path.join(fixtureDirTmp, 'passing-*-2.js'), + path.join(fixtureDirTmp, 'passing-*-3.js') + ].map(normalizePath) + + const pattern = multiPassingPatterns.map(str => `"${str}"`).join(' ') + const matcher = anymatch(multiPassingPatterns) + const files = testFiles.filter(matcher) + + it(`runs ${files.length} passing tests of ${testFiles.length} with pattern '${pattern}'`, function(done) { exec(`node ${binPath} --mode development ${pattern}`, (err, output) => { - assert.isNull(err); + assert.isNull(err) files.forEach(file => { - assert.include(output, file); - }); - assert.include(output, `${files.length} passing`); - done(); - }); - }); - - after(function () { - return del(testFiles); - }); - }); - - context('directory as option', function () { - const subdirectories = ['', 'sub1', 'sub2']; - - context('directory with passing tests', function () { - before(function () { - this.testFiles = _.range(1, 10).map(x => { - const subdir = subdirectories[x % 3]; - return path.join(fixtureDirTmp, subdir, `passing-test-${x}.js`); - }).map(normalizePath); - this.testFiles.forEach(file => createTest(file, true)); - }); - - it('runs all tests in directory\'', function (done) { - const matcher = anymatch(normalizePath(`${fixtureDirTmp}/*.js`)); - const files = this.testFiles.filter(matcher); - - exec(`node ${binPath} --mode development "${fixtureDirTmp}"`, (err, output) => { - assert.isNull(err); - files.forEach(file => { - assert.include(output, file); - }); - assert.include(output, `${files.length} passing`); - done(); - }); - }); - - it('runs all tests matching file glob\'', function (done) { - const matcher = anymatch(normalizePath(`${fixtureDirTmp}/*-test-3.js`)); - const files = this.testFiles.filter(matcher); - exec(`node ${binPath} --mode development --glob "*-test-3.js" "${fixtureDirTmp}"`, (err, output) => { - assert.isNull(err); - files.forEach(file => { - assert.include(output, file); - }); - assert.include(output, `${files.length} passing`); - done(); - }); - }); - - - it('runs all tests in directory & subdirectories\'', function (done) { - const matcher = anymatch(normalizePath(`${fixtureDirTmp}/**/*.js`)); - const files = this.testFiles.filter(matcher); - - exec(`node ${binPath} --mode development --recursive "${fixtureDirTmp}"`, (err, output) => { - assert.isNull(err); - files.forEach(file => { - assert.include(output, file); - }); - assert.include(output, `${files.length} passing`); - done(); - }); - }); - - after(function () { - return del(this.testFiles); - }); - }); - - context('directory with failing tests', function () { - before(function () { - this.testFiles = _.range(1, 10).map(x => { - const subdir = subdirectories[x % 3]; - return path.join(fixtureDirTmp, subdir, `failing-test-${x}.js`); - }).map(normalizePath); - this.testFiles.forEach(file => createTest(file, false)); - }); - - it('runs all tests in directory\'', function (done) { - const matcher = anymatch(normalizePath(`${fixtureDirTmp}/*.js`)); - const files = this.testFiles.filter(matcher); - - exec(`node ${binPath} --mode development "${fixtureDirTmp}"`, (err, output) => { - assert.isNotNull(err); - assert.strictEqual(err.code, files.length); - files.forEach(file => { - assert.include(output, file); - }); - - assert.include(output, '0 passing'); - assert.include(output, `${files.length} failing`); - done(); - }); - }); - - it('runs all tests in directory & subdirectories\'', function (done) { - const matcher = anymatch(normalizePath(`${fixtureDirTmp}/**/*.js`)); - const files = this.testFiles.filter(matcher); - - exec(`node ${binPath} --mode development --recursive "${fixtureDirTmp}"`, (err, output) => { - assert.isNotNull(err); - assert.strictEqual(err.code, files.length); - files.forEach(file => { - assert.include(output, file); - }); - - assert.include(output, '0 passing'); - assert.include(output, `${files.length} failing`); - done(); - }); - }); - - after(function () { - return del(this.testFiles); - }); - }); - - context('directory with corrupted modules', function () { - before(function () { - this.testFiles = _.range(1, 10).map(x => { - const subdir = subdirectories[x % 3]; - return path.join(fixtureDirTmp, subdir, `corrupted-test-${x}.js`); - }).map(file => normalizePath(file)); - this.testFiles.forEach(file => createCorruptedTest(file)); - }); - - it('fails before running tests of directory', function (done) { + assert.include(output, file) + }) + assert.include(output, `${files.length} passing`) + done() + }) + }) + + after(function() { + return del(testFiles) + }) + }) + + context('directory as option', function() { + const subdirectories = ['', 'sub1', 'sub2'] + + context('directory with passing tests', function() { + before(function() { + this.testFiles = _.range(1, 10) + .map(x => { + const subdir = subdirectories[x % 3] + return path.join(fixtureDirTmp, subdir, `passing-test-${x}.js`) + }) + .map(normalizePath) + this.testFiles.forEach(file => createTest(file, true)) + }) + + it("runs all tests in directory'", function(done) { + const matcher = anymatch(normalizePath(`${fixtureDirTmp}/*.js`)) + const files = this.testFiles.filter(matcher) + + exec( + `node ${binPath} --mode development "${fixtureDirTmp}"`, + (err, output) => { + assert.isNull(err) + files.forEach(file => { + assert.include(output, file) + }) + assert.include(output, `${files.length} passing`) + done() + } + ) + }) + + it("runs all tests matching file glob'", function(done) { + const matcher = anymatch(normalizePath(`${fixtureDirTmp}/*-test-3.js`)) + const files = this.testFiles.filter(matcher) + exec( + `node ${binPath} --mode development --glob "*-test-3.js" "${fixtureDirTmp}"`, + (err, output) => { + assert.isNull(err) + files.forEach(file => { + assert.include(output, file) + }) + assert.include(output, `${files.length} passing`) + done() + } + ) + }) + + it("runs all tests in directory & subdirectories'", function(done) { + const matcher = anymatch(normalizePath(`${fixtureDirTmp}/**/*.js`)) + const files = this.testFiles.filter(matcher) + + exec( + `node ${binPath} --mode development --recursive "${fixtureDirTmp}"`, + (err, output) => { + assert.isNull(err) + files.forEach(file => { + assert.include(output, file) + }) + assert.include(output, `${files.length} passing`) + done() + } + ) + }) + + after(function() { + return del(this.testFiles) + }) + }) + + context('directory with failing tests', function() { + before(function() { + this.testFiles = _.range(1, 10) + .map(x => { + const subdir = subdirectories[x % 3] + return path.join(fixtureDirTmp, subdir, `failing-test-${x}.js`) + }) + .map(normalizePath) + this.testFiles.forEach(file => createTest(file, false)) + }) + + it("runs all tests in directory'", function(done) { + const matcher = anymatch(normalizePath(`${fixtureDirTmp}/*.js`)) + const files = this.testFiles.filter(matcher) + + exec( + `node ${binPath} --mode development "${fixtureDirTmp}"`, + (err, output) => { + assert.isNotNull(err) + assert.strictEqual(err.code, files.length) + files.forEach(file => { + assert.include(output, file) + }) + + assert.include(output, '0 passing') + assert.include(output, `${files.length} failing`) + done() + } + ) + }) + + it("runs all tests in directory & subdirectories'", function(done) { + const matcher = anymatch(normalizePath(`${fixtureDirTmp}/**/*.js`)) + const files = this.testFiles.filter(matcher) + + exec( + `node ${binPath} --mode development --recursive "${fixtureDirTmp}"`, + (err, output) => { + assert.isNotNull(err) + assert.strictEqual(err.code, files.length) + files.forEach(file => { + assert.include(output, file) + }) + + assert.include(output, '0 passing') + assert.include(output, `${files.length} failing`) + done() + } + ) + }) + + after(function() { + return del(this.testFiles) + }) + }) + + context('directory with corrupted modules', function() { + before(function() { + this.testFiles = _.range(1, 10) + .map(x => { + const subdir = subdirectories[x % 3] + return path.join(fixtureDirTmp, subdir, `corrupted-test-${x}.js`) + }) + .map(file => normalizePath(file)) + this.testFiles.forEach(file => createCorruptedTest(file)) + }) + + it('fails before running tests of directory', function(done) { exec(`node ${binPath} --mode development "${fixtureDirTmp}"`, err => { - assert.isNotNull(err); - assert.isAbove(err.code, 0); - done(); - }); - }); - - it('fails before running tests of directory directory & subdirectories\'', function (done) { - exec(`node ${binPath} --mode development --recursive "${fixtureDirTmp}"`, err => { - assert.isNotNull(err); - assert.isAbove(err.code, 0); - done(); - }); - }); - - after(function () { - return del(this.testFiles); - }); - }); - }); - - - context('respect file extensions in webpack config via resolve.extensions for directory entries', function () { - before(function () { - this.index = 0; - this.configPath = path.join(fixtureDir, 'config', 'config.resolve-extensions.js'); - this.testDir = path.join(fixtureDirTmp, 'resolve-test'); - this.testFiles = ['ts', 'tsx', 'js', 'jsx'].map(ext => { - const file = path.join(this.testDir, `passing-test-${this.index}.${ext}`); - this.index += 1; - return file; - }).map(file => normalizePath(file)); - - this.ignoredFiles = ['coffee'].map(ext => { - const file = path.join(this.testDir, `passing-test-${this.index}.${ext}`); - this.index += 1; - return file; - }).map(file => normalizePath(file)); - - this.testFiles.forEach(file => createTest(file, true)); - this.ignoredFiles.forEach(file => createTest(file, true)); - }); - - it('resolve.extensions will be used for module resolution when no --glob is given', function (done) { - exec(`node ${binPath} --mode development --webpack-config "${this.configPath}" "${this.testDir}"`, (err, output) => { - assert.isNull(err); - this.testFiles.forEach(file => { - assert.include(output, file); - }); - this.ignoredFiles.forEach(file => { - assert.notInclude(output, file); - }); - assert.include(output, `${this.testFiles.length} passing`); - done(); - }); - }); - - it('resolve.extensions will not be used for module resolution when --glob is given', function (done) { - const matcher = anymatch(normalizePath(`${this.testDir}/*.js`)); - const files = this.testFiles.filter(matcher); - exec(`node ${binPath} --mode development --webpack-config "${this.configPath}" --glob "*.js" "${this.testDir}"`, (err, output) => { - assert.isNull(err); - files.forEach(file => { - assert.include(output, file); - }); - assert.include(output, `${files.length} passing`); - done(); - }); - }); - - after(function () { - return del([].concat(this.testFiles, this.ignoredFiles)); - }); - }); -}); \ No newline at end of file + assert.isNotNull(err) + assert.isAbove(err.code, 0) + done() + }) + }) + + it("fails before running tests of directory directory & subdirectories'", function(done) { + exec( + `node ${binPath} --mode development --recursive "${fixtureDirTmp}"`, + err => { + assert.isNotNull(err) + assert.isAbove(err.code, 0) + done() + } + ) + }) + + after(function() { + return del(this.testFiles) + }) + }) + }) + + context( + 'respect file extensions in webpack config via resolve.extensions for directory entries', + function() { + before(function() { + this.index = 0 + this.configPath = path.join( + fixtureDir, + 'config', + 'config.resolve-extensions.js' + ) + this.testDir = path.join(fixtureDirTmp, 'resolve-test') + this.testFiles = ['ts', 'tsx', 'js', 'jsx'] + .map(ext => { + const file = path.join( + this.testDir, + `passing-test-${this.index}.${ext}` + ) + this.index += 1 + return file + }) + .map(file => normalizePath(file)) + + this.ignoredFiles = ['coffee'] + .map(ext => { + const file = path.join( + this.testDir, + `passing-test-${this.index}.${ext}` + ) + this.index += 1 + return file + }) + .map(file => normalizePath(file)) + + this.testFiles.forEach(file => createTest(file, true)) + this.ignoredFiles.forEach(file => createTest(file, true)) + }) + + it('resolve.extensions will be used for module resolution when no --glob is given', function(done) { + exec( + `node ${binPath} --mode development --webpack-config "${this.configPath}" "${this.testDir}"`, + (err, output) => { + assert.isNull(err) + this.testFiles.forEach(file => { + assert.include(output, file) + }) + this.ignoredFiles.forEach(file => { + assert.notInclude(output, file) + }) + assert.include(output, `${this.testFiles.length} passing`) + done() + } + ) + }) + + it('resolve.extensions will not be used for module resolution when --glob is given', function(done) { + const matcher = anymatch(normalizePath(`${this.testDir}/*.js`)) + const files = this.testFiles.filter(matcher) + exec( + `node ${binPath} --mode development --webpack-config "${this.configPath}" --glob "*.js" "${this.testDir}"`, + (err, output) => { + assert.isNull(err) + files.forEach(file => { + assert.include(output, file) + }) + assert.include(output, `${files.length} passing`) + done() + } + ) + }) + + after(function() { + return del([].concat(this.testFiles, this.ignoredFiles)) + }) + } + ) +}) diff --git a/test/integration/cli/forbidOnly.test.ts b/test/integration/cli/forbidOnly.test.ts index 4b12778..6130fbf 100644 --- a/test/integration/cli/forbidOnly.test.ts +++ b/test/integration/cli/forbidOnly.test.ts @@ -2,19 +2,19 @@ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import path from "path"; -import { exec } from "./util/childProcess"; +import { assert } from 'chai' +import path from 'path' +import exec from './util/childProcess' -const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); -const test = path.join(fixtureDir, 'only/simple-only.js'); +const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')) +const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')) +const test = path.join(fixtureDir, 'only/simple-only.js') -describe('cli --forbid-only', function () { - it('gets really angry if there is an only in the test', function (done) { +describe('cli --forbid-only', function() { + it('gets really angry if there is an only in the test', function(done) { exec(`node ${binPath} --mode development --forbid-only "${test}"`, err => { - assert.isNotNull(err); - done(); - }); - }); -}); \ No newline at end of file + assert.isNotNull(err) + done() + }) + }) +}) diff --git a/test/integration/cli/include.test.ts b/test/integration/cli/include.test.ts index 2a94cef..f6e5c70 100644 --- a/test/integration/cli/include.test.ts +++ b/test/integration/cli/include.test.ts @@ -2,100 +2,101 @@ /* eslint-disable func-names, prefer-arrow-callback */ -import path from "path"; -import { assert } from "chai"; -import { exec } from "./util/childProcess"; +import path from 'path' +import { assert } from 'chai' +import exec from './util/childProcess' -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); +const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')) -const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const helperDir = path.join(fixtureDir, 'include', 'helper'); -const testDir = path.join(fixtureDir, 'include', 'test'); - - -const helper1 = `${path.join(helperDir, 'test-helper.js')}`; -const helper2 = `${path.join(helperDir, 'test-helper-2.js')}`; +const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')) +const helperDir = path.join(fixtureDir, 'include', 'helper') +const testDir = path.join(fixtureDir, 'include', 'test') +const helper1 = `${path.join(helperDir, 'test-helper.js')}` +const helper2 = `${path.join(helperDir, 'test-helper-2.js')}` function test(entry, options, cb) { - exec(`node ${binPath} --mode development "${entry}" ${options.join(' ')} `, cb); + exec( + `node ${binPath} --mode development "${entry}" ${options.join(' ')} `, + cb + ) } function testInclude(entry, includes, cb) { - const options = includes.map(value => `--include ${value}`); - test(entry, options, cb); + const options = includes.map(value => `--include ${value}`) + test(entry, options, cb) } function testSingleInclude(entry, done) { return testInclude(entry, [helper1], (err, output) => { - assert.isNull(err); - assert.include(output, 'first --include works'); - done(); - }); + assert.isNull(err) + assert.include(output, 'first --include works') + done() + }) } function testMultiInclude(entry, done) { return testInclude(entry, [helper1, helper2], (err, output) => { - assert.isNull(err); - assert.include(output, 'first --include works'); - assert.include(output, 'second --include works'); - done(); - }); + assert.isNull(err) + assert.include(output, 'first --include works') + assert.include(output, 'second --include works') + done() + }) } -describe('cli --include', function () { - context('file as entry', function () { - beforeEach(function () { - this.entry = path.join(testDir, 'dependent-test.js'); - }); - - it('single --include', function (done) { - testSingleInclude(this.entry, done); - }); - - it('multiple --include', function (done) { - testMultiInclude(this.entry, done); - }); - }); - - context('dir as entry', function () { - beforeEach(function () { - this.entry = testDir; - }); - - it('single --include', function (done) { - testSingleInclude(this.entry, done); - }); - - it('multiple --include', function (done) { - testMultiInclude(this.entry, done); - }); - }); - - context('glob as entry', function () { - beforeEach(function () { - this.entry = path.join(testDir, '*.js'); - }); - - it('single --include', function (done) { - testSingleInclude(this.entry, done); - }); - - it('multiple --include', function (done) { - testMultiInclude(this.entry, done); - }); - }); - - context('include types', function () { - it('include project file', function (done) { - testSingleInclude(testDir, done); - }); - - it('include node_module', function (done) { +describe('cli --include', function() { + context('file as entry', function() { + beforeEach(function() { + this.entry = path.join(testDir, 'dependent-test.js') + }) + + it('single --include', function(done) { + testSingleInclude(this.entry, done) + }) + + it('multiple --include', function(done) { + testMultiInclude(this.entry, done) + }) + }) + + context('dir as entry', function() { + beforeEach(function() { + this.entry = testDir + }) + + it('single --include', function(done) { + testSingleInclude(this.entry, done) + }) + + it('multiple --include', function(done) { + testMultiInclude(this.entry, done) + }) + }) + + context('glob as entry', function() { + beforeEach(function() { + this.entry = path.join(testDir, '*.js') + }) + + it('single --include', function(done) { + testSingleInclude(this.entry, done) + }) + + it('multiple --include', function(done) { + testMultiInclude(this.entry, done) + }) + }) + + context('include types', function() { + it('include project file', function(done) { + testSingleInclude(testDir, done) + }) + + it('include node_module', function(done) { testInclude(path.join(testDir, 'test.js'), ['chai'], err => { - assert.isNull(err); - done(); - }); - }); - }); -}); \ No newline at end of file + assert.isNull(err) + done() + }) + }) + }) +}) diff --git a/test/integration/cli/interactive.test.ts b/test/integration/cli/interactive.test.ts index e999437..59e5f60 100644 --- a/test/integration/cli/interactive.test.ts +++ b/test/integration/cli/interactive.test.ts @@ -2,20 +2,23 @@ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import path from "path"; -import { exec } from "./util/childProcess"; +import { assert } from 'chai' +import path from 'path' +import exec from './util/childProcess' -const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); -const test = path.join(fixtureDir, 'simple/simple.js'); +const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')) +const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')) +const test = path.join(fixtureDir, 'simple/simple.js') -describe('cli --interactive', function () { - it('just runs', function (done) { - exec(`node ${binPath} --mode development --interactive "${test}"`, (err, output) => { - assert.isNull(err); - assert.include(output, '1 passing'); - done(); - }); - }); -}); \ No newline at end of file +describe('cli --interactive', function() { + it('just runs', function(done) { + exec( + `node ${binPath} --mode development --interactive "${test}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, '1 passing') + done() + } + ) + }) +}) diff --git a/test/integration/cli/quiet.test.ts b/test/integration/cli/quiet.test.ts index 4020b3a..c5d6224 100644 --- a/test/integration/cli/quiet.test.ts +++ b/test/integration/cli/quiet.test.ts @@ -2,38 +2,44 @@ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import path from "path"; -import { exec } from "./util/childProcess"; +import { assert } from 'chai' +import path from 'path' +import exec from './util/childProcess' -const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); -const test = path.join(fixtureDir, 'simple/simple.js'); +const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')) +const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')) +const test = path.join(fixtureDir, 'simple/simple.js') -describe('cli --quiet', function () { - it('shows info messages when not set', function (done) { +describe('cli --quiet', function() { + it('shows info messages when not set', function(done) { exec(`node ${binPath} --mode development "${test}"`, (err, output) => { - assert.isNull(err); - assert.include(output, 'WEBPACK Compiling...'); - done(); - }); - }); + assert.isNull(err) + assert.include(output, 'WEBPACK Compiling...') + done() + }) + }) - it('does not show info messages', function (done) { - exec(`node ${binPath} --mode development --quiet "${test}"`, (err, output) => { - assert.isNull(err); - assert.notInclude(output, 'WEBPACK'); - assert.notInclude(output, 'MOCHA'); - assert.notInclude(output, 'successfully'); - done(); - }); - }); + it('does not show info messages', function(done) { + exec( + `node ${binPath} --mode development --quiet "${test}"`, + (err, output) => { + assert.isNull(err) + assert.notInclude(output, 'WEBPACK') + assert.notInclude(output, 'MOCHA') + assert.notInclude(output, 'successfully') + done() + } + ) + }) - it('still shows mocha output', function (done) { - exec(`node ${binPath} --mode development --quiet "${test}"`, (err, output) => { - assert.isNull(err); - assert.include(output, '1 passing'); - done(); - }); - }); -}); \ No newline at end of file + it('still shows mocha output', function(done) { + exec( + `node ${binPath} --mode development --quiet "${test}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, '1 passing') + done() + } + ) + }) +}) diff --git a/test/integration/cli/reporter.test.ts b/test/integration/cli/reporter.test.ts index 609beee..05e9268 100644 --- a/test/integration/cli/reporter.test.ts +++ b/test/integration/cli/reporter.test.ts @@ -2,37 +2,43 @@ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import path from "path"; -import { exec } from "./util/childProcess"; +import { assert } from 'chai' +import path from 'path' +import exec from './util/childProcess' -const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); -const reporter = './test/fixture/customMochaReporter'; -const test = path.join(fixtureDir, 'simple/simple.js'); +const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')) +const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')) +const reporter = './test/fixture/customMochaReporter' +const test = path.join(fixtureDir, 'simple/simple.js') -describe('cli --reporter', function () { - it('uses spec reporter', function (done) { - exec(`node ${binPath} --mode development --reporter spec "${test}"`, (err, output) => { - assert.isNull(err); - assert.include(output, '1 passing'); - done(); - }); - }); +describe('cli --reporter', function() { + it('uses spec reporter', function(done) { + exec( + `node ${binPath} --mode development --reporter spec "${test}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, '1 passing') + done() + } + ) + }) - it('uses custom reporter', function (done) { - exec(`node ${binPath} --mode development --reporter "${reporter}" "${test}"`, (err, output) => { - assert.isNull(err); - assert.include(output, 'customMochaReporter started'); - assert.include(output, 'customMochaReporter finished'); - done(); - }); - }); + it('uses custom reporter', function(done) { + exec( + `node ${binPath} --mode development --reporter "${reporter}" "${test}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, 'customMochaReporter started') + assert.include(output, 'customMochaReporter finished') + done() + } + ) + }) - it('shows notifications with --growl', function (done) { + it('shows notifications with --growl', function(done) { exec(`node ${binPath} --mode development --growl "${test}"`, err => { - assert.isNull(err); - done(); - }); - }); -}); + assert.isNull(err) + done() + }) + }) +}) diff --git a/test/integration/cli/ui.test.ts b/test/integration/cli/ui.test.ts index 8a26ed9..5de2c16 100644 --- a/test/integration/cli/ui.test.ts +++ b/test/integration/cli/ui.test.ts @@ -2,38 +2,44 @@ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import path from "path"; -import { exec } from "./util/childProcess"; +import { assert } from 'chai' +import path from 'path' +import exec from './util/childProcess' -const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); -const testBdd = path.join(fixtureDir, 'ui/bdd.js'); -const testTdd = path.join(fixtureDir, 'ui/tdd.js'); -const testBddLazy = path.join(fixtureDir, 'ui/bdd-lazy-var.js'); +const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')) +const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')) +const testBdd = path.join(fixtureDir, 'ui/bdd.js') +const testTdd = path.join(fixtureDir, 'ui/tdd.js') +const testBddLazy = path.join(fixtureDir, 'ui/bdd-lazy-var.js') -describe('cli --ui', function () { - it('uses bdd as default', function (done) { +describe('cli --ui', function() { + it('uses bdd as default', function(done) { exec(`node ${binPath} --mode development "${testBdd}"`, (err, output) => { - assert.isNull(err); - assert.include(output, '1 passing'); - done(); - }); - }); + assert.isNull(err) + assert.include(output, '1 passing') + done() + }) + }) - it('uses tdd', function (done) { - exec(`node ${binPath} --mode development --ui tdd "${testTdd}"`, (err, output) => { - assert.isNull(err); - assert.include(output, '1 passing'); - done(); - }); - }); + it('uses tdd', function(done) { + exec( + `node ${binPath} --mode development --ui tdd "${testTdd}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, '1 passing') + done() + } + ) + }) - it('uses bdd-lazy-var', function (done) { - exec(`node ${binPath} --mode development --ui bdd-lazy-var/getter "${testBddLazy}"`, (err, output) => { - assert.isNull(err); - assert.include(output, '1 passing'); - done(); - }); - }); -}); \ No newline at end of file + it('uses bdd-lazy-var', function(done) { + exec( + `node ${binPath} --mode development --ui bdd-lazy-var/getter "${testBddLazy}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, '1 passing') + done() + } + ) + }) +}) diff --git a/test/integration/cli/util/childProcess.ts b/test/integration/cli/util/childProcess.ts index 20ba3c7..8ac2d3d 100644 --- a/test/integration/cli/util/childProcess.ts +++ b/test/integration/cli/util/childProcess.ts @@ -1,15 +1,16 @@ -import { exec as execProcess } from "child_process"; +import { exec as execProcess } from 'child_process' -export function exec(command, cb) {// eslint-disable-line import/prefer-default-export - let data = ''; +export default function exec(command, cb) { + // eslint-disable-line import/prefer-default-export + let data = '' const ps = execProcess(command, err => { - cb(err, data !== '' ? data : null); - }); + cb(err, data !== '' ? data : null) + }) ps.stdout.on('data', d => { - data += d; - }); + data += d + }) ps.stderr.on('data', d => { - data += d; - }); -} \ No newline at end of file + data += d + }) +} diff --git a/test/integration/cli/version.test.ts b/test/integration/cli/version.test.ts index c769cf7..b143dac 100644 --- a/test/integration/cli/version.test.ts +++ b/test/integration/cli/version.test.ts @@ -2,23 +2,23 @@ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import path from "path"; -import { exec } from "./util/childProcess"; -import { version } from "../../../package.json"; +import { assert } from 'chai' +import path from 'path' +import exec from './util/childProcess' +import { version } from '../../../package.json' -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); +const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')) -describe('cli - version', function () { - before(function () { - this.version = version; - }); +describe('cli - version', function() { + before(function() { + this.version = version + }) - it('--version prints the correct version', function (done) { + it('--version prints the correct version', function(done) { exec(`node ${binPath} --version`, (err, output) => { - assert.isNull(err); - assert.include(output, this.version); - done(); - }); - }); -}); \ No newline at end of file + assert.isNull(err) + assert.include(output, this.version) + done() + }) + }) +}) diff --git a/test/integration/cli/watch.test.js b/test/integration/cli/watch.test.js deleted file mode 100644 index 2d53f36..0000000 --- a/test/integration/cli/watch.test.js +++ /dev/null @@ -1,593 +0,0 @@ -/* eslint-env node, mocha */ -/* eslint-disable func-names, max-len */ - -import { assert } from 'chai'; -import path from 'path'; -import { spawn } from 'child_process'; -import del from 'del'; -import fs from 'fs-extra'; - -const fixtureDir = path.join(process.cwd(), '.tmp/fixture'); - -const deleteTest = (fileName) => del(path.join(fixtureDir, fileName)); - -const createTest = (fileName, testName, passing) => { - const content = ` - var assert = require('assert'); - describe('${fileName} - ${testName}', function () { - it('runs test', function () { - assert.ok(${passing}); - }); - }); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); -}; - -function createSyntaxErrorTest(fileName, testName) { - const content = ` - var assert = require('assert'); - describe('${fileName} - ${testName}', function () { - it('runs test', function () { - assert.ok(false); - }); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); -} - -function createUncaughtErrorTest(fileName, testName) { - const content = ` - describe('${fileName} - ${testName}', function () { - it('runs test', function () { - setTimeout(function () { - done(); // done is undefined -> uncaught error - }, 1000); - }); - }); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); -} - -function createErrorFile(fileName, testName) { - const content = ` - throw new Error('Error ${fileName} ${testName}'); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); -} - -const createLongRunningTest = (fileName, testName) => { - const content = ` - var assert = require('assert'); - describe('${fileName} - ${testName} - 1', function () { - it('runs test 1' , function (done) { - this.timeout(3000); - console.log('starting ${testName} - 1'); - setTimeout(function() { - console.log('finished ${testName} - 1'); - done(); - }, 2000); - }); - }); - - describe('${fileName} - ${testName}', function () { - it('runs test 2' , function (done) { - this.timeout(3000); - console.log('starting ${testName} - 2'); - setTimeout(function() { - console.log('finished ${testName} - 2'); - done(); - }, 2000); - }); - }); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); -}; - -const createNeverEndingTest = (fileName, testName) => { - const content = ` - var assert = require('assert'); - describe('${fileName} - ${testName} - 1', function () { - it('runs test 1' , function (done) { - console.log('starting ${testName}'); - }); - }); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); -}; - - -const waitFor = (condition, timeoutInMs) => new Promise((resolve, reject) => { - const startTime = Date.now(); - const endTime = startTime + timeoutInMs; - - const remainingTime = () => Math.max(endTime - Date.now(), 0); - const timeoutDelay = () => Math.min(remainingTime(), 500); - - const run = () => { - let result = false; - let error = null; - try { - result = condition(); - } catch (e) { - error = e; - result = false; - } - - if (result !== false && error === null) { - resolve(); - } else if (remainingTime() > 0) { - setTimeout(run, timeoutDelay()); - } else if (error != null) { - reject(error); - } else { - reject(new Error(`Condition not met within time: ${condition.toString()}`)); - } - }; - setTimeout(run, timeoutDelay()); -}); - -const spawnMochaWebpack = (...args) => { - let data = ''; - const binPath = path.relative(process.cwd(), path.join('bin', 'mochapack')); - - const child = spawn('node', [binPath, '--mode', 'development', ...args]); - const receiveData = (d) => { - data += d.toString(); - }; - - child.stdout.on('data', receiveData); - child.stderr.on('data', receiveData); - - return { - get log() { - return data; - }, - clearLog() { - data = ''; - }, - kill() { - child.stdout.removeListener('data', receiveData); - child.stderr.removeListener('data', receiveData); - child.kill(); - }, - }; -}; - -// eslint-disable-next-line -// FIXME These tests have proven unreliable in the past and are thus disabled -xdescribe('cli --watch', function () { - // Retry all tests in this suite up to 4 times - this.retries(4); - - beforeEach(function () { - this.testGlob = path.join(fixtureDir, '*.js'); - this.entryGlob = path.relative(process.cwd(), this.testGlob); - }); - - it('should log syntax error and wait until that is fixed before running tests', function () { - this.timeout(10000); - const testFile = 'test1.js'; - const testId = Date.now(); - createSyntaxErrorTest(testFile, testId); - const mw = spawnMochaWebpack('--watch', this.entryGlob); - - return Promise - .resolve() - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, 'Unexpected token'), 5000)) - // output matched our condition - .then(() => { - assert.notInclude(mw.log, testId); - assert.notInclude(mw.log, 'failing'); - assert.notInclude(mw.log, 'passing'); - - // clear log to receive only changes - mw.clearLog(); - - // fix test - const updatedTestId = testId + 100; - createTest(testFile, updatedTestId, true); - return updatedTestId; - }) - // wait until the output matches our condition - .then((updatedTestId) => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) - // output matched our condition - .then(() => { - // check if test was updated - assert.notInclude(mw.log, testId); - }) - .catch((e) => e) - .then((e) => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should catch other errors outside of tests', function () { - this.timeout(10000); - const testFile = 'test1.js'; - const testId = Date.now(); - createErrorFile(testFile, testId); - const mw = spawnMochaWebpack('--watch', this.entryGlob); - - return Promise - .resolve() - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, `Error ${testFile}`), 5000)) - // output matched our condition - .then(() => { - assert.include(mw.log, 'Exception occurred while loading your tests'); - assert.include(mw.log, testId); - - // clear log to receive only changes - mw.clearLog(); - - // fix test - const updatedTestId = testId + 100; - createTest(testFile, updatedTestId, true); - return updatedTestId; - }) - // wait until the output matches our condition - .then((updatedTestId) => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) - // output matched our condition - .then(() => { - // check if test was updated - assert.notInclude(mw.log, testId); - }) - .catch((e) => e) - .then((e) => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should catch uncaught errors that occur after tests are done', function () { - this.timeout(10000); - const testFile = 'test1.js'; - const testId = Date.now(); - createUncaughtErrorTest(testFile, testId); - const mw = spawnMochaWebpack('--watch', this.entryGlob); - - return Promise - .resolve() - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, 'UNCAUGHT EXCEPTION'), 5000)) - // output matched our condition - .then(() => { - assert.include(mw.log, 'Exception occurred after running tests'); - assert.include(mw.log, '1 passing'); - assert.include(mw.log, testFile); - assert.include(mw.log, testId); - - // clear log to receive only changes - mw.clearLog(); - - // fix test - const updatedTestId = testId + 100; - createTest(testFile, updatedTestId, true); - return updatedTestId; - }) - // wait until the output matches our condition - .then((updatedTestId) => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) - // output matched our condition - .then(() => { - // check if test was updated - assert.notInclude(mw.log, testId); - }) - .catch((e) => e) - .then((e) => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should run a test', function () { - this.timeout(5000); - const testFile = 'test1.js'; - const testId = Date.now(); - createTest(testFile, testId, true); - - const mw = spawnMochaWebpack('--watch', this.entryGlob); - - return Promise - .resolve() - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, testId) && assert.include(mw.log, '1 passing'), 5000)) - .catch((e) => e) - .then((e) => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should run a test again when it changes', function () { - this.timeout(15000); - const testFile = 'test1.js'; - const testId = Date.now(); - createTest(testFile, testId, true); - const mw = spawnMochaWebpack('--watch', this.entryGlob); - - return Promise - .resolve() - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, testId) && assert.include(mw.log, '1 passing'), 5000)) - // output matched our condition - .then(() => { - // clear log to receive only changes - mw.clearLog(); - - // update test - const updatedTestId = testId + 100; - createTest(testFile, updatedTestId, true); - return updatedTestId; - }) - // wait until the output matches our condition - .then((updatedTestId) => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) - // output matched our condition - .then(() => { - // check if test was updated - assert.notInclude(mw.log, testId); - }) - .catch((e) => e) - .then((e) => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should run only the changed test again when it changes', function () { - this.timeout(15000); - const testFile1 = 'test1.js'; - const testFile2 = 'test2.js'; - const testId1 = Date.now() + 1; - const testId2 = testId1 + 2; - createTest(testFile1, testId1, true); - createTest(testFile2, testId2, true); - const mw = spawnMochaWebpack('--watch', this.entryGlob); - - return Promise - .resolve() - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, '2 passing'), 5000)) - // output matched our condition - .then(() => { - // check if both tests were tested - assert.include(mw.log, testId1); - assert.include(mw.log, testFile1); - assert.include(mw.log, testId2); - assert.include(mw.log, testFile2); - - // clear log to receive only changes - mw.clearLog(); - - // update test - const updatedTestId = testId2 + 100; - createTest(testFile2, updatedTestId, true); - return updatedTestId; - }) - // wait until the output matches our condition - .then((updatedTestId) => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) - // output matched our condition - .then(() => { - // check if just updated test was tested again - assert.notInclude(mw.log, testFile1); - assert.notInclude(mw.log, testId1); - }) - .catch((e) => e) - .then((e) => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should abort test suite when a file changes while running tests and then test again', function () { - this.timeout(15000); - const testFile = 'test1.js'; - const testId = Date.now(); - const updatedTestId = testId + 100; - createLongRunningTest(testFile, testId); - const mw = spawnMochaWebpack('--watch', this.entryGlob); - - return Promise - .resolve() - // wait until the first async test start - .then(() => waitFor(() => assert.include(mw.log, `starting ${testId} - 1`), 5000)) - .then(() => { - // check if tests were not ready yet - assert.notInclude(mw.log, `starting ${testId} - 2`); - assert.notInclude(mw.log, `finished ${testId} - 2`); - - // clear log to receive only changes - mw.clearLog(); - - // update test - createTest(testFile, updatedTestId, true); - }) - // wait until tests were aborted - .then(() => waitFor(() => assert.include(mw.log, '0 passing'), 5000)) - .then(() => { - // check if tests were aborted - assert.notInclude(mw.log, `finished ${testId} - 2`); - }) - // wait until tests were tested again - .then(() => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) - .catch((e) => e) - .then((e) => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should also abort tests that will never finish (e.g. by mistake) when timeouts are disabled and run tests again', function () { - this.timeout(15000); - const testFile = 'test1.js'; - const testId = Date.now(); - const updatedTestId = testId + 100; - createNeverEndingTest(testFile, testId); - const mw = spawnMochaWebpack('--timeout', 0, '--watch', this.entryGlob); - - return Promise - .resolve() - // wait until the first async test start - .then(() => waitFor(() => assert.include(mw.log, `starting ${testId}`), 5000)) - .then(() => { - // clear log to receive only changes - mw.clearLog(); - - // update test - createTest(testFile, updatedTestId, true); - }) - // wait until tests were aborted - .then(() => waitFor(() => assert.include(mw.log, 'Tests aborted'), 5000)) - .then(() => { - // check if tests were aborted - assert.notInclude(mw.log, `finished ${testId} - 2`); - }) - // wait until tests were tested again - .then(() => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) - .catch((e) => e) - .then((e) => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should recognize new test entries that match the pattern', function () { - this.timeout(10000); - const testFile1 = 'test1.js'; - const testId1 = Date.now() + 1; - const testFile2 = 'test2.js'; - const testId2 = testId1 + 2; - createTest(testFile1, testId1, true); - const mw = spawnMochaWebpack('--watch', this.entryGlob); - - return Promise - .resolve() - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, testId1) && assert.include(mw.log, '1 passing'), 5000)) - // output matched our condition - .then(() => { - // clear log to receive only changes - mw.clearLog(); - // create new test - createTest(testFile2, testId2, true); - }) - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, testId2) && assert.include(mw.log, '1 passing'), 5000)) - .then(() => { - assert.notInclude(mw.log, testId1); - assert.notInclude(mw.log, testFile1); - }) - // output matched our condition - .catch((e) => e) - .then((e) => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should recognize multiple new test entries that match the pattern', function () { - this.timeout(10000); - const testFile1 = 'test1.js'; - const testId1 = Date.now() + 1; - const testFile2 = 'test2.js'; - const testId2 = testId1 + 2; - const testFile3 = 'test3.js'; - const testId3 = testId2 + 3; - createTest(testFile1, testId1, true); - const mw = spawnMochaWebpack('--watch', this.entryGlob); - - return Promise - .resolve() - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, '1 passing'), 5000)) - // output matched our condition - .then(() => { - assert.include(mw.log, testId1); - assert.include(mw.log, testFile1); - - // clear log to receive only changes - mw.clearLog(); - - // create new tests - createTest(testFile2, testId2, true); - createTest(testFile3, testId3, true); - }) - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, testId2) && assert.include(mw.log, testId3) && assert.include(mw.log, '2 passing'), 5000)) - .then(() => { - assert.notInclude(mw.log, testId1); - assert.notInclude(mw.log, testFile1); - }) - // output matched our condition - .catch((e) => e) - .then((e) => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should recognize deleted test entries that match the pattern', function () { - this.timeout(10000); - const testFile1 = 'test1.js'; - const testFile2 = 'test2.js'; - const testId1 = Date.now() + 1; - const testId2 = Date.now() + 2; - createTest(testFile1, testId1, true); - createTest(testFile2, testId2, true); - const mw = spawnMochaWebpack('--watch', this.entryGlob); - - return Promise - .resolve() - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, '2 passing'), 5000)) - // output matched our condition - .then(() => { - assert.include(mw.log, testId1); - assert.include(mw.log, testFile1); - assert.include(mw.log, testId2); - assert.include(mw.log, testFile2); - - // clear log to receive only changes - mw.clearLog(); - - // delete test - deleteTest(testFile2); - }) - // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, 'passing'), 5000)) - .then(() => { - assert.notInclude(mw.log, testId2); - }) - .catch((e) => e) - .then((e) => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - afterEach(function () { - return del(this.testGlob); - }); -}); diff --git a/test/integration/cli/watch.test.ts b/test/integration/cli/watch.test.ts index dc45cc0..275a8af 100644 --- a/test/integration/cli/watch.test.ts +++ b/test/integration/cli/watch.test.ts @@ -2,15 +2,15 @@ /* eslint-disable func-names, max-len */ -import { assert } from "chai"; -import path from "path"; -import { spawn } from "child_process"; -import del from "del"; -import fs from "fs-extra"; +import { assert } from 'chai' +import path from 'path' +import { spawn } from 'child_process' +import del from 'del' +import fs from 'fs-extra' -const fixtureDir = path.join(process.cwd(), '.tmp/fixture'); +const fixtureDir = path.join(process.cwd(), '.tmp/fixture') -const deleteTest = fileName => del(path.join(fixtureDir, fileName)); +const deleteTest = fileName => del(path.join(fixtureDir, fileName)) const createTest = (fileName, testName, passing) => { const content = ` @@ -20,9 +20,9 @@ const createTest = (fileName, testName, passing) => { assert.ok(${passing}); }); }); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); -}; + ` + fs.outputFileSync(path.join(fixtureDir, fileName), content) +} function createSyntaxErrorTest(fileName, testName) { const content = ` @@ -31,8 +31,8 @@ function createSyntaxErrorTest(fileName, testName) { it('runs test', function () { assert.ok(false); }); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); + ` + fs.outputFileSync(path.join(fixtureDir, fileName), content) } function createUncaughtErrorTest(fileName, testName) { @@ -44,15 +44,15 @@ function createUncaughtErrorTest(fileName, testName) { }, 1000); }); }); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); + ` + fs.outputFileSync(path.join(fixtureDir, fileName), content) } function createErrorFile(fileName, testName) { const content = ` throw new Error('Error ${fileName} ${testName}'); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); + ` + fs.outputFileSync(path.join(fixtureDir, fileName), content) } const createLongRunningTest = (fileName, testName) => { @@ -79,9 +79,9 @@ const createLongRunningTest = (fileName, testName) => { }, 2000); }); }); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); -}; + ` + fs.outputFileSync(path.join(fixtureDir, fileName), content) +} const createNeverEndingTest = (fileName, testName) => { const content = ` @@ -91,428 +91,552 @@ const createNeverEndingTest = (fileName, testName) => { console.log('starting ${testName}'); }); }); - `; - fs.outputFileSync(path.join(fixtureDir, fileName), content); -}; - - -const waitFor = (condition, timeoutInMs) => new Promise((resolve, reject) => { - const startTime = Date.now(); - const endTime = startTime + timeoutInMs; - - const remainingTime = () => Math.max(endTime - Date.now(), 0); - const timeoutDelay = () => Math.min(remainingTime(), 500); - - const run = () => { - let result = false; - let error = null; - try { - result = condition(); - } catch (e) { - error = e; - result = false; - } + ` + fs.outputFileSync(path.join(fixtureDir, fileName), content) +} - if (result !== false && error === null) { - resolve(); - } else if (remainingTime() > 0) { - setTimeout(run, timeoutDelay()); - } else if (error != null) { - reject(error); - } else { - reject(new Error(`Condition not met within time: ${condition.toString()}`)); +const waitFor = (condition, timeoutInMs) => + new Promise((resolve, reject) => { + const startTime = Date.now() + const endTime = startTime + timeoutInMs + + const remainingTime = () => Math.max(endTime - Date.now(), 0) + const timeoutDelay = () => Math.min(remainingTime(), 500) + + const run = () => { + let result = false + let error = null + try { + result = condition() + } catch (e) { + error = e + result = false + } + + if (result !== false && error === null) { + resolve() + } else if (remainingTime() > 0) { + setTimeout(run, timeoutDelay()) + } else if (error != null) { + reject(error) + } else { + reject( + new Error(`Condition not met within time: ${condition.toString()}`) + ) + } } - }; - setTimeout(run, timeoutDelay()); -}); + setTimeout(run, timeoutDelay()) + }) const spawnMochaWebpack = (...args) => { - let data = ''; - const binPath = path.relative(process.cwd(), path.join('bin', 'mochapack')); + let data = '' + const binPath = path.relative(process.cwd(), path.join('bin', 'mochapack')) - const child = spawn('node', [binPath, '--mode', 'development', ...args]); + const child = spawn('node', [binPath, '--mode', 'development', ...args]) const receiveData = d => { - data += d.toString(); - }; + data += d.toString() + } - child.stdout.on('data', receiveData); - child.stderr.on('data', receiveData); + child.stdout.on('data', receiveData) + child.stderr.on('data', receiveData) return { get log() { - return data; + return data }, clearLog() { - data = ''; + data = '' }, kill() { - child.stdout.removeListener('data', receiveData); - child.stderr.removeListener('data', receiveData); - child.kill(); + child.stdout.removeListener('data', receiveData) + child.stderr.removeListener('data', receiveData) + child.kill() } - }; -}; + } +} // eslint-disable-next-line // FIXME These tests have proven unreliable in the past and are thus disabled -xdescribe('cli --watch', function () { +xdescribe('cli --watch', function() { // Retry all tests in this suite up to 4 times - this.retries(4); + this.retries(4) - beforeEach(function () { - this.testGlob = path.join(fixtureDir, '*.js'); - this.entryGlob = path.relative(process.cwd(), this.testGlob); - }); + beforeEach(function() { + this.testGlob = path.join(fixtureDir, '*.js') + this.entryGlob = path.relative(process.cwd(), this.testGlob) + }) - it('should log syntax error and wait until that is fixed before running tests', function () { - this.timeout(10000); - const testFile = 'test1.js'; - const testId = Date.now(); - createSyntaxErrorTest(testFile, testId); - const mw = spawnMochaWebpack('--watch', this.entryGlob); + it('should log syntax error and wait until that is fixed before running tests', function() { + this.timeout(10000) + const testFile = 'test1.js' + const testId = Date.now() + createSyntaxErrorTest(testFile, testId) + const mw = spawnMochaWebpack('--watch', this.entryGlob) return Promise.resolve() // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, 'Unexpected token'), 5000)) // output matched our condition - .then(() => { - assert.notInclude(mw.log, testId); - assert.notInclude(mw.log, 'failing'); - assert.notInclude(mw.log, 'passing'); - - // clear log to receive only changes - mw.clearLog(); - - // fix test - const updatedTestId = testId + 100; - createTest(testFile, updatedTestId, true); - return updatedTestId; - }) // wait until the output matches our condition - .then(updatedTestId => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition - .then(() => { - // check if test was updated - assert.notInclude(mw.log, testId); - }).catch(e => e).then(e => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should catch other errors outside of tests', function () { - this.timeout(10000); - const testFile = 'test1.js'; - const testId = Date.now(); - createErrorFile(testFile, testId); - const mw = spawnMochaWebpack('--watch', this.entryGlob); + .then(() => + waitFor(() => assert.include(mw.log, 'Unexpected token'), 5000) + ) // output matched our condition + .then(() => { + assert.notInclude(mw.log, testId) + assert.notInclude(mw.log, 'failing') + assert.notInclude(mw.log, 'passing') + + // clear log to receive only changes + mw.clearLog() + + // fix test + const updatedTestId = testId + 100 + createTest(testFile, updatedTestId, true) + return updatedTestId + }) // wait until the output matches our condition + .then(updatedTestId => + waitFor( + () => + assert.include(mw.log, updatedTestId) && + assert.include(mw.log, '1 passing'), + 5000 + ) + ) // output matched our condition + .then(() => { + // check if test was updated + assert.notInclude(mw.log, testId) + }) + .catch(e => e) + .then(e => { + // finally, kill watch process + mw.kill() + // maybe rethrow error + assert.ifError(e) + }) + }) + + it('should catch other errors outside of tests', function() { + this.timeout(10000) + const testFile = 'test1.js' + const testId = Date.now() + createErrorFile(testFile, testId) + const mw = spawnMochaWebpack('--watch', this.entryGlob) return Promise.resolve() // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, `Error ${testFile}`), 5000)) // output matched our condition - .then(() => { - assert.include(mw.log, 'Exception occurred while loading your tests'); - assert.include(mw.log, testId); - - // clear log to receive only changes - mw.clearLog(); - - // fix test - const updatedTestId = testId + 100; - createTest(testFile, updatedTestId, true); - return updatedTestId; - }) // wait until the output matches our condition - .then(updatedTestId => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition - .then(() => { - // check if test was updated - assert.notInclude(mw.log, testId); - }).catch(e => e).then(e => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should catch uncaught errors that occur after tests are done', function () { - this.timeout(10000); - const testFile = 'test1.js'; - const testId = Date.now(); - createUncaughtErrorTest(testFile, testId); - const mw = spawnMochaWebpack('--watch', this.entryGlob); + .then(() => + waitFor(() => assert.include(mw.log, `Error ${testFile}`), 5000) + ) // output matched our condition + .then(() => { + assert.include(mw.log, 'Exception occurred while loading your tests') + assert.include(mw.log, testId) + + // clear log to receive only changes + mw.clearLog() + + // fix test + const updatedTestId = testId + 100 + createTest(testFile, updatedTestId, true) + return updatedTestId + }) // wait until the output matches our condition + .then(updatedTestId => + waitFor( + () => + assert.include(mw.log, updatedTestId) && + assert.include(mw.log, '1 passing'), + 5000 + ) + ) // output matched our condition + .then(() => { + // check if test was updated + assert.notInclude(mw.log, testId) + }) + .catch(e => e) + .then(e => { + // finally, kill watch process + mw.kill() + // maybe rethrow error + assert.ifError(e) + }) + }) + + it('should catch uncaught errors that occur after tests are done', function() { + this.timeout(10000) + const testFile = 'test1.js' + const testId = Date.now() + createUncaughtErrorTest(testFile, testId) + const mw = spawnMochaWebpack('--watch', this.entryGlob) return Promise.resolve() // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, 'UNCAUGHT EXCEPTION'), 5000)) // output matched our condition - .then(() => { - assert.include(mw.log, 'Exception occurred after running tests'); - assert.include(mw.log, '1 passing'); - assert.include(mw.log, testFile); - assert.include(mw.log, testId); - - // clear log to receive only changes - mw.clearLog(); - - // fix test - const updatedTestId = testId + 100; - createTest(testFile, updatedTestId, true); - return updatedTestId; - }) // wait until the output matches our condition - .then(updatedTestId => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition - .then(() => { - // check if test was updated - assert.notInclude(mw.log, testId); - }).catch(e => e).then(e => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should run a test', function () { - this.timeout(5000); - const testFile = 'test1.js'; - const testId = Date.now(); - createTest(testFile, testId, true); - - const mw = spawnMochaWebpack('--watch', this.entryGlob); + .then(() => + waitFor(() => assert.include(mw.log, 'UNCAUGHT EXCEPTION'), 5000) + ) // output matched our condition + .then(() => { + assert.include(mw.log, 'Exception occurred after running tests') + assert.include(mw.log, '1 passing') + assert.include(mw.log, testFile) + assert.include(mw.log, testId) + + // clear log to receive only changes + mw.clearLog() + + // fix test + const updatedTestId = testId + 100 + createTest(testFile, updatedTestId, true) + return updatedTestId + }) // wait until the output matches our condition + .then(updatedTestId => + waitFor( + () => + assert.include(mw.log, updatedTestId) && + assert.include(mw.log, '1 passing'), + 5000 + ) + ) // output matched our condition + .then(() => { + // check if test was updated + assert.notInclude(mw.log, testId) + }) + .catch(e => e) + .then(e => { + // finally, kill watch process + mw.kill() + // maybe rethrow error + assert.ifError(e) + }) + }) + + it('should run a test', function() { + this.timeout(5000) + const testFile = 'test1.js' + const testId = Date.now() + createTest(testFile, testId, true) + + const mw = spawnMochaWebpack('--watch', this.entryGlob) return Promise.resolve() // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, testId) && assert.include(mw.log, '1 passing'), 5000)).catch(e => e).then(e => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should run a test again when it changes', function () { - this.timeout(15000); - const testFile = 'test1.js'; - const testId = Date.now(); - createTest(testFile, testId, true); - const mw = spawnMochaWebpack('--watch', this.entryGlob); + .then(() => + waitFor( + () => + assert.include(mw.log, testId) && + assert.include(mw.log, '1 passing'), + 5000 + ) + ) + .catch(e => e) + .then(e => { + // finally, kill watch process + mw.kill() + // maybe rethrow error + assert.ifError(e) + }) + }) + + it('should run a test again when it changes', function() { + this.timeout(15000) + const testFile = 'test1.js' + const testId = Date.now() + createTest(testFile, testId, true) + const mw = spawnMochaWebpack('--watch', this.entryGlob) return Promise.resolve() // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, testId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition - .then(() => { - // clear log to receive only changes - mw.clearLog(); - - // update test - const updatedTestId = testId + 100; - createTest(testFile, updatedTestId, true); - return updatedTestId; - }) // wait until the output matches our condition - .then(updatedTestId => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition - .then(() => { - // check if test was updated - assert.notInclude(mw.log, testId); - }).catch(e => e).then(e => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should run only the changed test again when it changes', function () { - this.timeout(15000); - const testFile1 = 'test1.js'; - const testFile2 = 'test2.js'; - const testId1 = Date.now() + 1; - const testId2 = testId1 + 2; - createTest(testFile1, testId1, true); - createTest(testFile2, testId2, true); - const mw = spawnMochaWebpack('--watch', this.entryGlob); + .then(() => + waitFor( + () => + assert.include(mw.log, testId) && + assert.include(mw.log, '1 passing'), + 5000 + ) + ) // output matched our condition + .then(() => { + // clear log to receive only changes + mw.clearLog() + + // update test + const updatedTestId = testId + 100 + createTest(testFile, updatedTestId, true) + return updatedTestId + }) // wait until the output matches our condition + .then(updatedTestId => + waitFor( + () => + assert.include(mw.log, updatedTestId) && + assert.include(mw.log, '1 passing'), + 5000 + ) + ) // output matched our condition + .then(() => { + // check if test was updated + assert.notInclude(mw.log, testId) + }) + .catch(e => e) + .then(e => { + // finally, kill watch process + mw.kill() + // maybe rethrow error + assert.ifError(e) + }) + }) + + it('should run only the changed test again when it changes', function() { + this.timeout(15000) + const testFile1 = 'test1.js' + const testFile2 = 'test2.js' + const testId1 = Date.now() + 1 + const testId2 = testId1 + 2 + createTest(testFile1, testId1, true) + createTest(testFile2, testId2, true) + const mw = spawnMochaWebpack('--watch', this.entryGlob) return Promise.resolve() // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, '2 passing'), 5000)) // output matched our condition - .then(() => { - // check if both tests were tested - assert.include(mw.log, testId1); - assert.include(mw.log, testFile1); - assert.include(mw.log, testId2); - assert.include(mw.log, testFile2); - - // clear log to receive only changes - mw.clearLog(); - - // update test - const updatedTestId = testId2 + 100; - createTest(testFile2, updatedTestId, true); - return updatedTestId; - }) // wait until the output matches our condition - .then(updatedTestId => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition - .then(() => { - // check if just updated test was tested again - assert.notInclude(mw.log, testFile1); - assert.notInclude(mw.log, testId1); - }).catch(e => e).then(e => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should abort test suite when a file changes while running tests and then test again', function () { - this.timeout(15000); - const testFile = 'test1.js'; - const testId = Date.now(); - const updatedTestId = testId + 100; - createLongRunningTest(testFile, testId); - const mw = spawnMochaWebpack('--watch', this.entryGlob); + .then(() => waitFor(() => assert.include(mw.log, '2 passing'), 5000)) // output matched our condition + .then(() => { + // check if both tests were tested + assert.include(mw.log, testId1) + assert.include(mw.log, testFile1) + assert.include(mw.log, testId2) + assert.include(mw.log, testFile2) + + // clear log to receive only changes + mw.clearLog() + + // update test + const updatedTestId = testId2 + 100 + createTest(testFile2, updatedTestId, true) + return updatedTestId + }) // wait until the output matches our condition + .then(updatedTestId => + waitFor( + () => + assert.include(mw.log, updatedTestId) && + assert.include(mw.log, '1 passing'), + 5000 + ) + ) // output matched our condition + .then(() => { + // check if just updated test was tested again + assert.notInclude(mw.log, testFile1) + assert.notInclude(mw.log, testId1) + }) + .catch(e => e) + .then(e => { + // finally, kill watch process + mw.kill() + // maybe rethrow error + assert.ifError(e) + }) + }) + + it('should abort test suite when a file changes while running tests and then test again', function() { + this.timeout(15000) + const testFile = 'test1.js' + const testId = Date.now() + const updatedTestId = testId + 100 + createLongRunningTest(testFile, testId) + const mw = spawnMochaWebpack('--watch', this.entryGlob) return Promise.resolve() // wait until the first async test start - .then(() => waitFor(() => assert.include(mw.log, `starting ${testId} - 1`), 5000)).then(() => { - // check if tests were not ready yet - assert.notInclude(mw.log, `starting ${testId} - 2`); - assert.notInclude(mw.log, `finished ${testId} - 2`); - - // clear log to receive only changes - mw.clearLog(); - - // update test - createTest(testFile, updatedTestId, true); - }) // wait until tests were aborted - .then(() => waitFor(() => assert.include(mw.log, '0 passing'), 5000)).then(() => { - // check if tests were aborted - assert.notInclude(mw.log, `finished ${testId} - 2`); - }) // wait until tests were tested again - .then(() => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)).catch(e => e).then(e => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should also abort tests that will never finish (e.g. by mistake) when timeouts are disabled and run tests again', function () { - this.timeout(15000); - const testFile = 'test1.js'; - const testId = Date.now(); - const updatedTestId = testId + 100; - createNeverEndingTest(testFile, testId); - const mw = spawnMochaWebpack('--timeout', 0, '--watch', this.entryGlob); + .then(() => + waitFor(() => assert.include(mw.log, `starting ${testId} - 1`), 5000) + ) + .then(() => { + // check if tests were not ready yet + assert.notInclude(mw.log, `starting ${testId} - 2`) + assert.notInclude(mw.log, `finished ${testId} - 2`) + + // clear log to receive only changes + mw.clearLog() + + // update test + createTest(testFile, updatedTestId, true) + }) // wait until tests were aborted + .then(() => waitFor(() => assert.include(mw.log, '0 passing'), 5000)) + .then(() => { + // check if tests were aborted + assert.notInclude(mw.log, `finished ${testId} - 2`) + }) // wait until tests were tested again + .then(() => + waitFor( + () => + assert.include(mw.log, updatedTestId) && + assert.include(mw.log, '1 passing'), + 5000 + ) + ) + .catch(e => e) + .then(e => { + // finally, kill watch process + mw.kill() + // maybe rethrow error + assert.ifError(e) + }) + }) + + it('should also abort tests that will never finish (e.g. by mistake) when timeouts are disabled and run tests again', function() { + this.timeout(15000) + const testFile = 'test1.js' + const testId = Date.now() + const updatedTestId = testId + 100 + createNeverEndingTest(testFile, testId) + const mw = spawnMochaWebpack('--timeout', 0, '--watch', this.entryGlob) return Promise.resolve() // wait until the first async test start - .then(() => waitFor(() => assert.include(mw.log, `starting ${testId}`), 5000)).then(() => { - // clear log to receive only changes - mw.clearLog(); - - // update test - createTest(testFile, updatedTestId, true); - }) // wait until tests were aborted - .then(() => waitFor(() => assert.include(mw.log, 'Tests aborted'), 5000)).then(() => { - // check if tests were aborted - assert.notInclude(mw.log, `finished ${testId} - 2`); - }) // wait until tests were tested again - .then(() => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)).catch(e => e).then(e => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should recognize new test entries that match the pattern', function () { - this.timeout(10000); - const testFile1 = 'test1.js'; - const testId1 = Date.now() + 1; - const testFile2 = 'test2.js'; - const testId2 = testId1 + 2; - createTest(testFile1, testId1, true); - const mw = spawnMochaWebpack('--watch', this.entryGlob); + .then(() => + waitFor(() => assert.include(mw.log, `starting ${testId}`), 5000) + ) + .then(() => { + // clear log to receive only changes + mw.clearLog() + + // update test + createTest(testFile, updatedTestId, true) + }) // wait until tests were aborted + .then(() => waitFor(() => assert.include(mw.log, 'Tests aborted'), 5000)) + .then(() => { + // check if tests were aborted + assert.notInclude(mw.log, `finished ${testId} - 2`) + }) // wait until tests were tested again + .then(() => + waitFor( + () => + assert.include(mw.log, updatedTestId) && + assert.include(mw.log, '1 passing'), + 5000 + ) + ) + .catch(e => e) + .then(e => { + // finally, kill watch process + mw.kill() + // maybe rethrow error + assert.ifError(e) + }) + }) + + it('should recognize new test entries that match the pattern', function() { + this.timeout(10000) + const testFile1 = 'test1.js' + const testId1 = Date.now() + 1 + const testFile2 = 'test2.js' + const testId2 = testId1 + 2 + createTest(testFile1, testId1, true) + const mw = spawnMochaWebpack('--watch', this.entryGlob) return Promise.resolve() // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, testId1) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition - .then(() => { - // clear log to receive only changes - mw.clearLog(); - // create new test - createTest(testFile2, testId2, true); - }) // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, testId2) && assert.include(mw.log, '1 passing'), 5000)).then(() => { - assert.notInclude(mw.log, testId1); - assert.notInclude(mw.log, testFile1); - }) // output matched our condition - .catch(e => e).then(e => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should recognize multiple new test entries that match the pattern', function () { - this.timeout(10000); - const testFile1 = 'test1.js'; - const testId1 = Date.now() + 1; - const testFile2 = 'test2.js'; - const testId2 = testId1 + 2; - const testFile3 = 'test3.js'; - const testId3 = testId2 + 3; - createTest(testFile1, testId1, true); - const mw = spawnMochaWebpack('--watch', this.entryGlob); + .then(() => + waitFor( + () => + assert.include(mw.log, testId1) && + assert.include(mw.log, '1 passing'), + 5000 + ) + ) // output matched our condition + .then(() => { + // clear log to receive only changes + mw.clearLog() + // create new test + createTest(testFile2, testId2, true) + }) // wait until the output matches our condition + .then(() => + waitFor( + () => + assert.include(mw.log, testId2) && + assert.include(mw.log, '1 passing'), + 5000 + ) + ) + .then(() => { + assert.notInclude(mw.log, testId1) + assert.notInclude(mw.log, testFile1) + }) // output matched our condition + .catch(e => e) + .then(e => { + // finally, kill watch process + mw.kill() + // maybe rethrow error + assert.ifError(e) + }) + }) + + it('should recognize multiple new test entries that match the pattern', function() { + this.timeout(10000) + const testFile1 = 'test1.js' + const testId1 = Date.now() + 1 + const testFile2 = 'test2.js' + const testId2 = testId1 + 2 + const testFile3 = 'test3.js' + const testId3 = testId2 + 3 + createTest(testFile1, testId1, true) + const mw = spawnMochaWebpack('--watch', this.entryGlob) return Promise.resolve() // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, '1 passing'), 5000)) // output matched our condition - .then(() => { - assert.include(mw.log, testId1); - assert.include(mw.log, testFile1); - - // clear log to receive only changes - mw.clearLog(); - - // create new tests - createTest(testFile2, testId2, true); - createTest(testFile3, testId3, true); - }) // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, testId2) && assert.include(mw.log, testId3) && assert.include(mw.log, '2 passing'), 5000)).then(() => { - assert.notInclude(mw.log, testId1); - assert.notInclude(mw.log, testFile1); - }) // output matched our condition - .catch(e => e).then(e => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - it('should recognize deleted test entries that match the pattern', function () { - this.timeout(10000); - const testFile1 = 'test1.js'; - const testFile2 = 'test2.js'; - const testId1 = Date.now() + 1; - const testId2 = Date.now() + 2; - createTest(testFile1, testId1, true); - createTest(testFile2, testId2, true); - const mw = spawnMochaWebpack('--watch', this.entryGlob); + .then(() => waitFor(() => assert.include(mw.log, '1 passing'), 5000)) // output matched our condition + .then(() => { + assert.include(mw.log, testId1) + assert.include(mw.log, testFile1) + + // clear log to receive only changes + mw.clearLog() + + // create new tests + createTest(testFile2, testId2, true) + createTest(testFile3, testId3, true) + }) // wait until the output matches our condition + .then(() => + waitFor( + () => + assert.include(mw.log, testId2) && + assert.include(mw.log, testId3) && + assert.include(mw.log, '2 passing'), + 5000 + ) + ) + .then(() => { + assert.notInclude(mw.log, testId1) + assert.notInclude(mw.log, testFile1) + }) // output matched our condition + .catch(e => e) + .then(e => { + // finally, kill watch process + mw.kill() + // maybe rethrow error + assert.ifError(e) + }) + }) + + it('should recognize deleted test entries that match the pattern', function() { + this.timeout(10000) + const testFile1 = 'test1.js' + const testFile2 = 'test2.js' + const testId1 = Date.now() + 1 + const testId2 = Date.now() + 2 + createTest(testFile1, testId1, true) + createTest(testFile2, testId2, true) + const mw = spawnMochaWebpack('--watch', this.entryGlob) return Promise.resolve() // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, '2 passing'), 5000)) // output matched our condition - .then(() => { - assert.include(mw.log, testId1); - assert.include(mw.log, testFile1); - assert.include(mw.log, testId2); - assert.include(mw.log, testFile2); - - // clear log to receive only changes - mw.clearLog(); - - // delete test - deleteTest(testFile2); - }) // wait until the output matches our condition - .then(() => waitFor(() => assert.include(mw.log, 'passing'), 5000)).then(() => { - assert.notInclude(mw.log, testId2); - }).catch(e => e).then(e => { - // finally, kill watch process - mw.kill(); - // maybe rethrow error - assert.ifError(e); - }); - }); - - afterEach(function () { - return del(this.testGlob); - }); -}); \ No newline at end of file + .then(() => waitFor(() => assert.include(mw.log, '2 passing'), 5000)) // output matched our condition + .then(() => { + assert.include(mw.log, testId1) + assert.include(mw.log, testFile1) + assert.include(mw.log, testId2) + assert.include(mw.log, testFile2) + + // clear log to receive only changes + mw.clearLog() + + // delete test + deleteTest(testFile2) + }) // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, 'passing'), 5000)) + .then(() => { + assert.notInclude(mw.log, testId2) + }) + .catch(e => e) + .then(e => { + // finally, kill watch process + mw.kill() + // maybe rethrow error + assert.ifError(e) + }) + }) + + afterEach(function() { + return del(this.testGlob) + }) +}) diff --git a/test/integration/cli/webworker.test.ts b/test/integration/cli/webworker.test.ts index fb8f14d..f46f47c 100644 --- a/test/integration/cli/webworker.test.ts +++ b/test/integration/cli/webworker.test.ts @@ -1,25 +1,31 @@ /* eslint-env node, mocha */ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import path from "path"; -import normalizePath from "normalize-path"; -import { exec } from "./util/childProcess"; +import { assert } from 'chai' +import path from 'path' +import normalizePath from 'normalize-path' +import exec from './util/childProcess' +const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')) +const binPath = path.relative(process.cwd(), path.resolve('bin', '_mocha')) -const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const binPath = path.relative(process.cwd(), path.resolve('bin', '_mocha')); - -describe('webworker', function () { - before(function () { - this.passingTest = normalizePath(path.join(fixtureDir, 'webworker/test/worker.js')); - this.webpackConfig = normalizePath(path.join(fixtureDir, 'webworker/webpack.config-test.js')); - }); - it('runs test successfully', function (done) { - exec(`node ${binPath} --webpack-config "${this.webpackConfig}" "${this.passingTest}"`, (err, output) => { - assert.isNull(err); - assert.include(output, '1 passing'); - done(); - }); - }); -}); \ No newline at end of file +describe('webworker', function() { + before(function() { + this.passingTest = normalizePath( + path.join(fixtureDir, 'webworker/test/worker.js') + ) + this.webpackConfig = normalizePath( + path.join(fixtureDir, 'webworker/webpack.config-test.js') + ) + }) + it('runs test successfully', function(done) { + exec( + `node ${binPath} --webpack-config "${this.webpackConfig}" "${this.passingTest}"`, + (err, output) => { + assert.isNull(err) + assert.include(output, '1 passing') + done() + } + ) + }) +}) diff --git a/test/integration/statsFormatter/mock/json-loader.ts b/test/integration/statsFormatter/mock/json-loader.ts index 8edc8ea..d93f506 100644 --- a/test/integration/statsFormatter/mock/json-loader.ts +++ b/test/integration/statsFormatter/mock/json-loader.ts @@ -4,5 +4,5 @@ * The original json-loader uses native JSON.parse which throws inconsistent errors in different node versions. */ module.exports = function mockJsonLoader() { - throw new SyntaxError('Unexpected token'); -}; \ No newline at end of file + throw new SyntaxError('Unexpected token') +} diff --git a/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/entry.ts b/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/entry.ts index d6dbf90..c23afdf 100644 --- a/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/entry.ts +++ b/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/entry.ts @@ -1 +1 @@ -import "./src/critical-dependencies"; \ No newline at end of file +import './src/critical-dependencies' diff --git a/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/src/critical-dependencies.ts b/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/src/critical-dependencies.ts index dee187c..86f913a 100644 --- a/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/src/critical-dependencies.ts +++ b/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/src/critical-dependencies.ts @@ -1 +1 @@ -if (global.test) test(require); \ No newline at end of file +if (global.test) test(require) diff --git a/test/integration/statsFormatter/statsCasesFixture/css-strip-loader/entry.ts b/test/integration/statsFormatter/statsCasesFixture/css-strip-loader/entry.ts index f2b9eb2..42ef820 100644 --- a/test/integration/statsFormatter/statsCasesFixture/css-strip-loader/entry.ts +++ b/test/integration/statsFormatter/statsCasesFixture/css-strip-loader/entry.ts @@ -1 +1 @@ -import "./main.css"; \ No newline at end of file +import './main.css' diff --git a/test/integration/statsFormatter/statsCasesFixture/module-not-found-error/entry.ts b/test/integration/statsFormatter/statsCasesFixture/module-not-found-error/entry.ts index bb29849..80a50a9 100644 --- a/test/integration/statsFormatter/statsCasesFixture/module-not-found-error/entry.ts +++ b/test/integration/statsFormatter/statsCasesFixture/module-not-found-error/entry.ts @@ -1 +1 @@ -import "xxx-does-not-exist-xxx"; \ No newline at end of file +import 'xxx-does-not-exist-xxx' diff --git a/test/integration/statsFormatter/statsCasesFixture/sass-loader-module-not-found-error/entry.ts b/test/integration/statsFormatter/statsCasesFixture/sass-loader-module-not-found-error/entry.ts index a615168..87c1bbd 100644 --- a/test/integration/statsFormatter/statsCasesFixture/sass-loader-module-not-found-error/entry.ts +++ b/test/integration/statsFormatter/statsCasesFixture/sass-loader-module-not-found-error/entry.ts @@ -1 +1 @@ -import "./main.scss"; \ No newline at end of file +import './main.scss' diff --git a/test/integration/statsFormatter/statsCasesFixture/sass-loader-syntax-error/entry.ts b/test/integration/statsFormatter/statsCasesFixture/sass-loader-syntax-error/entry.ts index a615168..87c1bbd 100644 --- a/test/integration/statsFormatter/statsCasesFixture/sass-loader-syntax-error/entry.ts +++ b/test/integration/statsFormatter/statsCasesFixture/sass-loader-syntax-error/entry.ts @@ -1 +1 @@ -import "./main.scss"; \ No newline at end of file +import './main.scss' diff --git a/test/integration/statsFormatter/statsFormatter.test.ts b/test/integration/statsFormatter/statsFormatter.test.ts index 3c4c5b0..80cc6e9 100644 --- a/test/integration/statsFormatter/statsFormatter.test.ts +++ b/test/integration/statsFormatter/statsFormatter.test.ts @@ -1,21 +1,23 @@ /* eslint-env node, mocha */ /* eslint-disable func-names, prefer-arrow-callback */ -import fs from "fs-extra"; -import path from "path"; +import fs from 'fs-extra' +import path from 'path' -import _ from "lodash"; -import stripAnsi from "strip-ansi"; -import webpack from "webpack"; -import { version as WEBPACK_VERSION } from "webpack/package.json"; -import MemoryFileSystem from "memory-fs"; -import { assert } from "chai"; -import createStatsFormatter from "../../../src/webpack/util/createStatsFormatter"; +import _ from 'lodash' +import stripAnsi from 'strip-ansi' +import webpack from 'webpack' +import { version as WEBPACK_VERSION } from 'webpack/package.json' +import MemoryFileSystem from 'memory-fs' +import { assert } from 'chai' +import createStatsFormatter from '../../../src/webpack/util/createStatsFormatter' -const webpackMajorVersion = WEBPACK_VERSION.charAt(0); +const webpackMajorVersion = WEBPACK_VERSION.charAt(0) -const base = path.join(__dirname, 'statsCasesFixture'); -const tests = fs.readdirSync(base).filter(testName => fs.existsSync(path.join(base, testName, 'entry.js'))); +const base = path.join(__dirname, 'statsCasesFixture') +const tests = fs + .readdirSync(base) + .filter(testName => fs.existsSync(path.join(base, testName, 'entry.js'))) const webpackConfig = { mode: 'development', @@ -29,98 +31,145 @@ const webpackConfig = { test: /.js$/, loader: 'babel-loader', options: { - presets: ['@babel/preset-env'], - }, + presets: ['@babel/preset-env'] + } }, { test: /\.css$/, - loader: 'css-loader', + loader: 'css-loader' }, { test: /\.scss$/, - loader: 'sass-loader', - }, - ], - }, -}; - -describe('statsFormatter', function () { - before(function () { + loader: 'sass-loader' + } + ] + } +} + +describe('statsFormatter', function() { + before(function() { if (process.platform === 'win32') { - this.skip(); + this.skip() } - }); + }) tests.forEach(testName => { - const testDirPath = path.join(base, testName); - const entryPath = path.join(testDirPath, 'entry.js'); + const testDirPath = path.join(base, testName) + const entryPath = path.join(testDirPath, 'entry.js') // make os & location independent messages without colors const ensureConsistentCompare = _.flow([ - stripAnsi, - message => message.replace(/\r?\n/g, '\n'), - message => message.replace(new RegExp(testDirPath, 'g'), `Xdir/${testName}`), + stripAnsi, + message => message.replace(/\r?\n/g, '\n'), + message => + message.replace(new RegExp(testDirPath, 'g'), `Xdir/${testName}`), message => message.replace(new RegExp(process.cwd(), 'g'), 'Cdir') - ]); + ]) - it(`should print correct stats for ${path.basename(testDirPath)}`, function (done) { - const formatter = createStatsFormatter(testDirPath); - assert.isFunction(formatter, 'createStatsFormatter should return a function'); + it(`should print correct stats for ${path.basename( + testDirPath + )}`, function(done) { + const formatter = createStatsFormatter(testDirPath) + assert.isFunction( + formatter, + 'createStatsFormatter should return a function' + ) const config = { ...webpackConfig, context: testDirPath, entry: `./${path.basename(entryPath)}` - }; + } - const memoryFs = new MemoryFileSystem(); + const memoryFs = new MemoryFileSystem() - const compiler = webpack(config); - compiler.outputFileSystem = memoryFs; + const compiler = webpack(config) + compiler.outputFileSystem = memoryFs compiler.run((err, stats) => { if (err) { - done(err); - return; + done(err) + return } - const { - warnings, - errors - } = formatter(stats); - - assert.isArray(warnings, 'statsFormatter should return an Array of warnings'); - assert.lengthOf(warnings, stats.compilation.warnings.length, 'Length of warnings should match original length'); - assert.isArray(errors, 'statsFormatter should return an Array of errors'); - assert.lengthOf(errors, stats.compilation.errors.length, 'Length of errors should match original length'); - - const warningsContent = ensureConsistentCompare(warnings.join('\n')); - const errorsContent = ensureConsistentCompare(errors.join('\n')); + const { warnings, errors } = formatter(stats) - let fixtureNodeId = ''; + assert.isArray( + warnings, + 'statsFormatter should return an Array of warnings' + ) + assert.lengthOf( + warnings, + stats.compilation.warnings.length, + 'Length of warnings should match original length' + ) + assert.isArray( + errors, + 'statsFormatter should return an Array of errors' + ) + assert.lengthOf( + errors, + stats.compilation.errors.length, + 'Length of errors should match original length' + ) + + const warningsContent = ensureConsistentCompare(warnings.join('\n')) + const errorsContent = ensureConsistentCompare(errors.join('\n')) + + let fixtureNodeId = '' if (path.basename(testDirPath) === 'babel-loader-syntax-error') { - const nodeMajorVersion = process.version.split('.')[0].replace('v', ''); - fixtureNodeId = parseInt(nodeMajorVersion, 10) <= 11 ? '' : `.node-${nodeMajorVersion}`; + const nodeMajorVersion = process.version + .split('.')[0] + .replace('v', '') + fixtureNodeId = + parseInt(nodeMajorVersion, 10) <= 11 + ? '' + : `.node-${nodeMajorVersion}` } - const expectedWarningsPath = path.join(testDirPath, `warnings.webpack-${webpackMajorVersion}.txt`); - const expectedErrorsPath = path.join(testDirPath, `errors.webpack-${webpackMajorVersion}${fixtureNodeId}.txt`); - - if (!fs.existsSync(expectedWarningsPath) || !fs.existsSync(expectedErrorsPath)) { - fs.outputFileSync(expectedWarningsPath, warningsContent); - fs.outputFileSync(expectedErrorsPath, errorsContent); - - done(new Error('Expected files did not exist, yet. Created it. Have a look at them')); - return; + const expectedWarningsPath = path.join( + testDirPath, + `warnings.webpack-${webpackMajorVersion}.txt` + ) + const expectedErrorsPath = path.join( + testDirPath, + `errors.webpack-${webpackMajorVersion}${fixtureNodeId}.txt` + ) + + if ( + !fs.existsSync(expectedWarningsPath) || + !fs.existsSync(expectedErrorsPath) + ) { + fs.outputFileSync(expectedWarningsPath, warningsContent) + fs.outputFileSync(expectedErrorsPath, errorsContent) + + done( + new Error( + 'Expected files did not exist, yet. Created it. Have a look at them' + ) + ) + return } - const expectedWarningsContent = ensureConsistentCompare(fs.readFileSync(expectedWarningsPath, 'utf-8')); - const expectedErrorsContent = ensureConsistentCompare(fs.readFileSync(expectedErrorsPath, 'utf-8')); - - assert.strictEqual(warningsContent, expectedWarningsContent, 'Warnings should match'); - assert.strictEqual(errorsContent, expectedErrorsContent, 'Errors should match'); - - done(); - }); - }); - }); -}); + const expectedWarningsContent = ensureConsistentCompare( + fs.readFileSync(expectedWarningsPath, 'utf-8') + ) + const expectedErrorsContent = ensureConsistentCompare( + fs.readFileSync(expectedErrorsPath, 'utf-8') + ) + + assert.strictEqual( + warningsContent, + expectedWarningsContent, + 'Warnings should match' + ) + assert.strictEqual( + errorsContent, + expectedErrorsContent, + 'Errors should match' + ) + + done() + }) + }) + }) +}) diff --git a/test/unit/MochaWebpack.test.ts b/test/unit/MochaWebpack.test.ts index 26063f4..ae9750a 100644 --- a/test/unit/MochaWebpack.test.ts +++ b/test/unit/MochaWebpack.test.ts @@ -1,20 +1,20 @@ /* eslint-env node, mocha */ /* eslint-disable func-names, prefer-arrow-callback, max-len */ -import { assert } from "chai"; -import MochaWebpack from "../../src/MochaWebpack"; +import { assert } from 'chai' +import MochaWebpack from '../../src/MochaWebpack' -describe('MochaWebpack', function () { - it('should create a instance of MochaWebpack', function () { - assert.doesNotThrow(() => new MochaWebpack()); - const mochaWebpack = new MochaWebpack(); +describe('MochaWebpack', function() { + it('should create a instance of MochaWebpack', function() { + assert.doesNotThrow(() => new MochaWebpack()) + const mochaWebpack = new MochaWebpack() - assert.isNotNull(mochaWebpack); - }); + assert.isNotNull(mochaWebpack) + }) - it('has some default options', function () { - const mochaWebpack = new MochaWebpack(); - assert.isObject(mochaWebpack.options); + it('has some default options', function() { + const mochaWebpack = new MochaWebpack() + assert.isObject(mochaWebpack.options) const expected = { cwd: process.cwd(), @@ -35,285 +35,578 @@ describe('MochaWebpack', function () { clearTerminal: false, quiet: false, forbidOnly: false - }; - assert.deepEqual(mochaWebpack.options, expected); - }); - - it('has a list of entries', function () { - const mochaWebpack = new MochaWebpack(); - assert.isArray(mochaWebpack.entries); - assert.lengthOf(mochaWebpack.entries, 0); - }); - - it('has a list of includes', function () { - const mochaWebpack = new MochaWebpack(); - assert.isArray(mochaWebpack.includes); - assert.lengthOf(mochaWebpack.includes, 0); - }); - - - context('methods', function () { - beforeEach(function () { - this.mochaWebpack = new MochaWebpack(); - }); - - it('addEntry()', function () { - const oldEntries = this.mochaWebpack.entries; - const entry = './test.js'; - - const returnValue = this.mochaWebpack.addEntry(entry); - - assert.include(this.mochaWebpack.entries, entry, 'entry should be added'); - assert.notStrictEqual(this.mochaWebpack.entries, oldEntries, 'addEntry() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('addInclude()', function () { - const oldIncludes = this.mochaWebpack.includes; - const entry = './test.js'; - - const returnValue = this.mochaWebpack.addInclude(entry); - - assert.include(this.mochaWebpack.includes, entry, 'entry should be added'); - assert.notStrictEqual(this.mochaWebpack.includes, oldIncludes, 'addInclude() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('cwd()', function () { - const oldOptions = this.mochaWebpack.options; - const cwd = __dirname; - - const returnValue = this.mochaWebpack.cwd(cwd); - - assert.propertyVal(this.mochaWebpack.options, 'cwd', cwd, 'cwd should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'cwd() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('webpackConfig()', function () { - const oldOptions = this.mochaWebpack.options; + } + assert.deepEqual(mochaWebpack.options, expected) + }) + + it('has a list of entries', function() { + const mochaWebpack = new MochaWebpack() + assert.isArray(mochaWebpack.entries) + assert.lengthOf(mochaWebpack.entries, 0) + }) + + it('has a list of includes', function() { + const mochaWebpack = new MochaWebpack() + assert.isArray(mochaWebpack.includes) + assert.lengthOf(mochaWebpack.includes, 0) + }) + + context('methods', function() { + beforeEach(function() { + this.mochaWebpack = new MochaWebpack() + }) + + it('addEntry()', function() { + const oldEntries = this.mochaWebpack.entries + const entry = './test.js' + + const returnValue = this.mochaWebpack.addEntry(entry) + + assert.include(this.mochaWebpack.entries, entry, 'entry should be added') + assert.notStrictEqual( + this.mochaWebpack.entries, + oldEntries, + 'addEntry() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('addInclude()', function() { + const oldIncludes = this.mochaWebpack.includes + const entry = './test.js' + + const returnValue = this.mochaWebpack.addInclude(entry) + + assert.include(this.mochaWebpack.includes, entry, 'entry should be added') + assert.notStrictEqual( + this.mochaWebpack.includes, + oldIncludes, + 'addInclude() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('cwd()', function() { + const oldOptions = this.mochaWebpack.options + const cwd = __dirname + + const returnValue = this.mochaWebpack.cwd(cwd) + + assert.propertyVal( + this.mochaWebpack.options, + 'cwd', + cwd, + 'cwd should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'cwd() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('webpackConfig()', function() { + const oldOptions = this.mochaWebpack.options const webpackConfig = { loaders: [] - }; - - const returnValue = this.mochaWebpack.webpackConfig(webpackConfig); - - assert.propertyVal(this.mochaWebpack.options, 'webpackConfig', webpackConfig, 'webpackConfig should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'webpackConfig() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('bail()', function () { - const oldOptions = this.mochaWebpack.options; - const bail = true; - - const returnValue = this.mochaWebpack.bail(bail); - - assert.propertyVal(this.mochaWebpack.options, 'bail', bail, 'bail should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'bail() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('reporter()', function () { - const oldOptions = this.mochaWebpack.options; - const reporter = 'test'; + } + + const returnValue = this.mochaWebpack.webpackConfig(webpackConfig) + + assert.propertyVal( + this.mochaWebpack.options, + 'webpackConfig', + webpackConfig, + 'webpackConfig should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'webpackConfig() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('bail()', function() { + const oldOptions = this.mochaWebpack.options + const bail = true + + const returnValue = this.mochaWebpack.bail(bail) + + assert.propertyVal( + this.mochaWebpack.options, + 'bail', + bail, + 'bail should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'bail() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('reporter()', function() { + const oldOptions = this.mochaWebpack.options + const reporter = 'test' const reporterOptions = { foo: 'bar' - }; - - const returnValue = this.mochaWebpack.reporter(reporter, reporterOptions); - - assert.propertyVal(this.mochaWebpack.options, 'reporter', reporter, 'reporter should be changed'); - assert.propertyVal(this.mochaWebpack.options, 'reporterOptions', reporterOptions, 'reporterOptions should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'reporter() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('ui()', function () { - const oldOptions = this.mochaWebpack.options; - const ui = 'tdd'; - - const returnValue = this.mochaWebpack.ui(ui); - - assert.propertyVal(this.mochaWebpack.options, 'ui', ui, 'ui should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'reporter() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('fgrep()', function () { - const oldOptions = this.mochaWebpack.options; - const fgrep = 'fgrep'; - - const returnValue = this.mochaWebpack.fgrep(fgrep); - - assert.propertyVal(this.mochaWebpack.options, 'fgrep', fgrep, 'fgrep should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'fgrep() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('grep()', function () { - const oldOptions = this.mochaWebpack.options; - const grep = 'grep'; - - const returnValue = this.mochaWebpack.grep(grep); - - assert.propertyVal(this.mochaWebpack.options, 'grep', grep, 'grep should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'grep() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('invert()', function () { - const oldOptions = this.mochaWebpack.options; - - const returnValue = this.mochaWebpack.invert(); - - assert.propertyVal(this.mochaWebpack.options, 'invert', true, 'invert should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'invert() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('ignoreLeaks()', function () { - const oldOptions = this.mochaWebpack.options; - const ignoreLeaks = false; - - const returnValue = this.mochaWebpack.ignoreLeaks(ignoreLeaks); - - assert.propertyVal(this.mochaWebpack.options, 'ignoreLeaks', ignoreLeaks, 'ignoreLeaks should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'ignoreLeaks() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('fullStackTrace()', function () { - const oldOptions = this.mochaWebpack.options; - const fullStackTrace = true; - - const returnValue = this.mochaWebpack.fullStackTrace(fullStackTrace); - - assert.propertyVal(this.mochaWebpack.options, 'fullStackTrace', fullStackTrace, 'fullStackTrace should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'fullStackTrace() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('useColors()', function () { - const oldOptions = this.mochaWebpack.options; - const colors = false; - - const returnValue = this.mochaWebpack.useColors(colors); - - assert.propertyVal(this.mochaWebpack.options, 'colors', colors, 'colors should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'useColors() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('useInlineDiffs()', function () { - const oldOptions = this.mochaWebpack.options; - const useInlineDiffs = true; - - const returnValue = this.mochaWebpack.useInlineDiffs(useInlineDiffs); - - assert.propertyVal(this.mochaWebpack.options, 'useInlineDiffs', useInlineDiffs, 'useInlineDiffs should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'useInlineDiffs() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('timeout()', function () { - const oldOptions = this.mochaWebpack.options; - const timeout = 150; - - const returnValue = this.mochaWebpack.timeout(timeout); - - assert.propertyVal(this.mochaWebpack.options, 'timeout', timeout, 'timeout should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'timeout() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('retries()', function () { - const oldOptions = this.mochaWebpack.options; - const retries = 150; - - const returnValue = this.mochaWebpack.retries(retries); - - assert.propertyVal(this.mochaWebpack.options, 'retries', retries, 'retries should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'retries() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('slow()', function () { - const oldOptions = this.mochaWebpack.options; - const slow = 150; - - const returnValue = this.mochaWebpack.slow(slow); - - assert.propertyVal(this.mochaWebpack.options, 'slow', slow, 'slow should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'slow() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('asyncOnly()', function () { - const oldOptions = this.mochaWebpack.options; - - const returnValue = this.mochaWebpack.asyncOnly(); - - assert.propertyVal(this.mochaWebpack.options, 'asyncOnly', true, 'asyncOnly should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'asyncOnly() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('delay()', function () { - const oldOptions = this.mochaWebpack.options; - - const returnValue = this.mochaWebpack.delay(); - - assert.propertyVal(this.mochaWebpack.options, 'delay', true, 'delay should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'delay() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('interactive()', function () { - const oldOptions = this.mochaWebpack.options; - const oldValue = oldOptions.interactive; - const newValue = !oldValue; - - const returnValue = this.mochaWebpack.interactive(newValue); - - assert.propertyVal(this.mochaWebpack.options, 'interactive', newValue, 'interactive should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'interactive() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('clearTerminal()', function () { - const oldOptions = this.mochaWebpack.options; - const clearTerminal = false; - - const returnValue = this.mochaWebpack.clearTerminal(clearTerminal); - - assert.propertyVal(this.mochaWebpack.options, 'clearTerminal', clearTerminal, 'clearTerminal should be changed'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'clearTerminal() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('growl()', function () { - const oldOptions = this.mochaWebpack.options; - const oldValue = oldOptions.growl; - assert.isNotOk(oldValue, 'growl should be falsy'); - - const returnValue = this.mochaWebpack.growl(); - - assert.propertyVal(this.mochaWebpack.options, 'growl', true, 'growl should be changed to true'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'growl() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - - it('forbidOnly()', function () { - const oldOptions = this.mochaWebpack.options; - const oldValue = oldOptions.forbidOnly; - assert.isNotOk(oldValue, 'forbidOnly should be falsy'); - - const returnValue = this.mochaWebpack.forbidOnly(); - - assert.propertyVal(this.mochaWebpack.options, 'forbidOnly', true, 'forbidOnly should be changed to true'); - assert.notStrictEqual(this.mochaWebpack.options, oldOptions, 'forbidOnly() should not mutate'); - assert.strictEqual(returnValue, this.mochaWebpack, 'api should be chainable'); - }); - }); -}); + } + + const returnValue = this.mochaWebpack.reporter(reporter, reporterOptions) + + assert.propertyVal( + this.mochaWebpack.options, + 'reporter', + reporter, + 'reporter should be changed' + ) + assert.propertyVal( + this.mochaWebpack.options, + 'reporterOptions', + reporterOptions, + 'reporterOptions should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'reporter() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('ui()', function() { + const oldOptions = this.mochaWebpack.options + const ui = 'tdd' + + const returnValue = this.mochaWebpack.ui(ui) + + assert.propertyVal( + this.mochaWebpack.options, + 'ui', + ui, + 'ui should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'reporter() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('fgrep()', function() { + const oldOptions = this.mochaWebpack.options + const fgrep = 'fgrep' + + const returnValue = this.mochaWebpack.fgrep(fgrep) + + assert.propertyVal( + this.mochaWebpack.options, + 'fgrep', + fgrep, + 'fgrep should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'fgrep() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('grep()', function() { + const oldOptions = this.mochaWebpack.options + const grep = 'grep' + + const returnValue = this.mochaWebpack.grep(grep) + + assert.propertyVal( + this.mochaWebpack.options, + 'grep', + grep, + 'grep should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'grep() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('invert()', function() { + const oldOptions = this.mochaWebpack.options + + const returnValue = this.mochaWebpack.invert() + + assert.propertyVal( + this.mochaWebpack.options, + 'invert', + true, + 'invert should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'invert() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('ignoreLeaks()', function() { + const oldOptions = this.mochaWebpack.options + const ignoreLeaks = false + + const returnValue = this.mochaWebpack.ignoreLeaks(ignoreLeaks) + + assert.propertyVal( + this.mochaWebpack.options, + 'ignoreLeaks', + ignoreLeaks, + 'ignoreLeaks should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'ignoreLeaks() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('fullStackTrace()', function() { + const oldOptions = this.mochaWebpack.options + const fullStackTrace = true + + const returnValue = this.mochaWebpack.fullStackTrace(fullStackTrace) + + assert.propertyVal( + this.mochaWebpack.options, + 'fullStackTrace', + fullStackTrace, + 'fullStackTrace should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'fullStackTrace() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('useColors()', function() { + const oldOptions = this.mochaWebpack.options + const colors = false + + const returnValue = this.mochaWebpack.useColors(colors) + + assert.propertyVal( + this.mochaWebpack.options, + 'colors', + colors, + 'colors should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'useColors() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('useInlineDiffs()', function() { + const oldOptions = this.mochaWebpack.options + const useInlineDiffs = true + + const returnValue = this.mochaWebpack.useInlineDiffs(useInlineDiffs) + + assert.propertyVal( + this.mochaWebpack.options, + 'useInlineDiffs', + useInlineDiffs, + 'useInlineDiffs should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'useInlineDiffs() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('timeout()', function() { + const oldOptions = this.mochaWebpack.options + const timeout = 150 + + const returnValue = this.mochaWebpack.timeout(timeout) + + assert.propertyVal( + this.mochaWebpack.options, + 'timeout', + timeout, + 'timeout should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'timeout() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('retries()', function() { + const oldOptions = this.mochaWebpack.options + const retries = 150 + + const returnValue = this.mochaWebpack.retries(retries) + + assert.propertyVal( + this.mochaWebpack.options, + 'retries', + retries, + 'retries should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'retries() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('slow()', function() { + const oldOptions = this.mochaWebpack.options + const slow = 150 + + const returnValue = this.mochaWebpack.slow(slow) + + assert.propertyVal( + this.mochaWebpack.options, + 'slow', + slow, + 'slow should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'slow() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('asyncOnly()', function() { + const oldOptions = this.mochaWebpack.options + + const returnValue = this.mochaWebpack.asyncOnly() + + assert.propertyVal( + this.mochaWebpack.options, + 'asyncOnly', + true, + 'asyncOnly should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'asyncOnly() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('delay()', function() { + const oldOptions = this.mochaWebpack.options + + const returnValue = this.mochaWebpack.delay() + + assert.propertyVal( + this.mochaWebpack.options, + 'delay', + true, + 'delay should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'delay() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('interactive()', function() { + const oldOptions = this.mochaWebpack.options + const oldValue = oldOptions.interactive + const newValue = !oldValue + + const returnValue = this.mochaWebpack.interactive(newValue) + + assert.propertyVal( + this.mochaWebpack.options, + 'interactive', + newValue, + 'interactive should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'interactive() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('clearTerminal()', function() { + const oldOptions = this.mochaWebpack.options + const clearTerminal = false + + const returnValue = this.mochaWebpack.clearTerminal(clearTerminal) + + assert.propertyVal( + this.mochaWebpack.options, + 'clearTerminal', + clearTerminal, + 'clearTerminal should be changed' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'clearTerminal() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('growl()', function() { + const oldOptions = this.mochaWebpack.options + const oldValue = oldOptions.growl + assert.isNotOk(oldValue, 'growl should be falsy') + + const returnValue = this.mochaWebpack.growl() + + assert.propertyVal( + this.mochaWebpack.options, + 'growl', + true, + 'growl should be changed to true' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'growl() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + + it('forbidOnly()', function() { + const oldOptions = this.mochaWebpack.options + const oldValue = oldOptions.forbidOnly + assert.isNotOk(oldValue, 'forbidOnly should be falsy') + + const returnValue = this.mochaWebpack.forbidOnly() + + assert.propertyVal( + this.mochaWebpack.options, + 'forbidOnly', + true, + 'forbidOnly should be changed to true' + ) + assert.notStrictEqual( + this.mochaWebpack.options, + oldOptions, + 'forbidOnly() should not mutate' + ) + assert.strictEqual( + returnValue, + this.mochaWebpack, + 'api should be chainable' + ) + }) + }) +}) diff --git a/test/unit/cli/fixture/config/optsTestCases/default/expected.json b/test/unit/cli/fixture/config/optsTestCases/default/expected.json index 263278f..70b792b 100644 --- a/test/unit/cli/fixture/config/optsTestCases/default/expected.json +++ b/test/unit/cli/fixture/config/optsTestCases/default/expected.json @@ -2,7 +2,5 @@ "colors": true, "webpackConfig": "webpack.config-test.js", "glob": "*.test.js", - "files": [ - "test/**/.js" - ] + "files": ["test/**/.js"] } diff --git a/test/unit/cli/fixture/config/optsTestCases/quoted-double/expected.json b/test/unit/cli/fixture/config/optsTestCases/quoted-double/expected.json index 263278f..70b792b 100644 --- a/test/unit/cli/fixture/config/optsTestCases/quoted-double/expected.json +++ b/test/unit/cli/fixture/config/optsTestCases/quoted-double/expected.json @@ -2,7 +2,5 @@ "colors": true, "webpackConfig": "webpack.config-test.js", "glob": "*.test.js", - "files": [ - "test/**/.js" - ] + "files": ["test/**/.js"] } diff --git a/test/unit/cli/fixture/config/optsTestCases/quoted-single/expected.json b/test/unit/cli/fixture/config/optsTestCases/quoted-single/expected.json index 263278f..70b792b 100644 --- a/test/unit/cli/fixture/config/optsTestCases/quoted-single/expected.json +++ b/test/unit/cli/fixture/config/optsTestCases/quoted-single/expected.json @@ -2,7 +2,5 @@ "colors": true, "webpackConfig": "webpack.config-test.js", "glob": "*.test.js", - "files": [ - "test/**/.js" - ] + "files": ["test/**/.js"] } diff --git a/test/unit/cli/fixture/webpackConfig/webpack.config-ts.ts b/test/unit/cli/fixture/webpackConfig/webpack.config-ts.ts index c72a81b..b2fe3b0 100644 --- a/test/unit/cli/fixture/webpackConfig/webpack.config-ts.ts +++ b/test/unit/cli/fixture/webpackConfig/webpack.config-ts.ts @@ -1,11 +1,10 @@ - interface Config { - mode: string; - target: string; + mode: string + target: string } const config: Config = { mode: 'development', - target: 'node', -}; + target: 'node' +} export default config diff --git a/test/unit/cli/parseArgv.test.ts b/test/unit/cli/parseArgv.test.ts index d1de0a8..c738ee8 100644 --- a/test/unit/cli/parseArgv.test.ts +++ b/test/unit/cli/parseArgv.test.ts @@ -2,955 +2,975 @@ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import parseArgv from "../../../src/cli/parseArgv"; +import { assert } from 'chai' +import parseArgv from '../../../src/cli/parseArgv' -describe('parseArgv', function () { - beforeEach(function () { - this.parseArgv = parseArgv; - this.argv = ['src']; - }); +describe('parseArgv', function() { + beforeEach(function() { + this.parseArgv = parseArgv + this.argv = ['src'] + }) - context('duplicated arguments', function () { - it('should throw for non arrays', function () { + context('duplicated arguments', function() { + it('should throw for non arrays', function() { // given - const argv = ['--webpack-config', 'webpack-config.js', '--webpack-config', 'webpack-config2.js']; + const argv = [ + '--webpack-config', + 'webpack-config.js', + '--webpack-config', + 'webpack-config2.js' + ] // when const fn = () => { - this.parseArgv(argv); - }; + this.parseArgv(argv) + } // then - assert.throws(fn, /Duplicating arguments for /); - }); + assert.throws(fn, /Duplicating arguments for /) + }) - it('should not throw for arrays', function () { + it('should not throw for arrays', function() { // given - const argv = ['--require', 'test', '--require', 'test2']; + const argv = ['--require', 'test', '--require', 'test2'] // when const fn = () => { - this.parseArgv(argv); - }; + this.parseArgv(argv) + } // then - assert.doesNotThrow(fn); - }); - }); + assert.doesNotThrow(fn) + }) + }) - context('ignore default options', function () { - it('ignore default options when ignore=true', function () { - assert.deepEqual(this.parseArgv([], true), {}); - }); + context('ignore default options', function() { + it('ignore default options when ignore=true', function() { + assert.deepEqual(this.parseArgv([], true), {}) + }) - it('dont ignore default options when ignore=false', function () { - assert.notDeepEqual(this.parseArgv([], false), {}); - }); + it('dont ignore default options when ignore=false', function() { + assert.notDeepEqual(this.parseArgv([], false), {}) + }) - context('files must be parsed correctly', function () { - it('options without values & file when ignore=false', function () { - const argv = ['--recursive', 'test/bin/fixture']; + context('files must be parsed correctly', function() { + it('options without values & file when ignore=false', function() { + const argv = ['--recursive', 'test/bin/fixture'] - const parsed = this.parseArgv(argv, false); + const parsed = this.parseArgv(argv, false) - assert.property(parsed, 'files'); - assert.deepEqual(parsed.files, ['test/bin/fixture']); - }); + assert.property(parsed, 'files') + assert.deepEqual(parsed.files, ['test/bin/fixture']) + }) - it('options without values & file when ignore=true', function () { - const files = ['--recursive', 'test/bin/fixture']; + it('options without values & file when ignore=true', function() { + const files = ['--recursive', 'test/bin/fixture'] assert.deepEqual(this.parseArgv(files, true), { recursive: true, files: ['test/bin/fixture'] - }); - }); + }) + }) - it('options with values when ignore=true', function () { - const argv = ['--webpack-config', 'webpack-config.js']; + it('options with values when ignore=true', function() { + const argv = ['--webpack-config', 'webpack-config.js'] assert.deepEqual(this.parseArgv(argv, true), { webpackConfig: 'webpack-config.js' - }); - }); + }) + }) - it('options with values & file when ignore=true', function () { - const argv = ['--webpack-config', 'webpack-config.js', 'test/bin/fixture']; + it('options with values & file when ignore=true', function() { + const argv = [ + '--webpack-config', + 'webpack-config.js', + 'test/bin/fixture' + ] assert.deepEqual(this.parseArgv(argv, true), { webpackConfig: 'webpack-config.js', files: ['test/bin/fixture'] - }); - }); - }); - }); + }) + }) + }) + }) - context('non-option as files', function () { - it('uses "./test" as default', function () { + context('non-option as files', function() { + it('uses "./test" as default', function() { // given - const argv = []; + const argv = [] // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.property(parsedArgv, 'files'); - assert.deepEqual(parsedArgv.files, ['./test']); - }); + assert.property(parsedArgv, 'files') + assert.deepEqual(parsedArgv.files, ['./test']) + }) - it('parses non-options as files', function () { + it('parses non-options as files', function() { // given - const argv = ['./test']; + const argv = ['./test'] // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.property(parsedArgv, 'files'); - assert.deepEqual(parsedArgv.files, argv); - }); + assert.property(parsedArgv, 'files') + assert.deepEqual(parsedArgv.files, argv) + }) - it('parses non-options as files (multiple)', function () { + it('parses non-options as files (multiple)', function() { // given - const argv = ['./test', './test2']; + const argv = ['./test', './test2'] // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.property(parsedArgv, 'files'); - assert.deepEqual(parsedArgv.files, argv); - }); - }); - - context('options', function () { - context('async-only', function () { - it('uses false as default value', function () { + assert.property(parsedArgv, 'files') + assert.deepEqual(parsedArgv.files, argv) + }) + }) + + context('options', function() { + context('async-only', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'asyncOnly', false); - }); + assert.propertyVal(parsedArgv, 'asyncOnly', false) + }) for (const parameter of ['--async-only', '--A', '-A']) { - it(`'parses ${parameter}'`, function () { + it(`'parses ${parameter}'`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'asyncOnly', true); - }); + assert.propertyVal(parsedArgv, 'asyncOnly', true) + }) } - }); + }) - context('colors', function () { - it('uses undefined as default value', function () { + context('colors', function() { + it('uses undefined as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.notProperty(parsedArgv, 'colors'); - }); - + assert.notProperty(parsedArgv, 'colors') + }) for (const parameter of ['--colors', '--c', '-c']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'colors', true); - }); + assert.propertyVal(parsedArgv, 'colors', true) + }) } - - for (const parameter of ['--no-colors', '--colors=false', '--no-c', '--c=false']) { - it(`parses ${parameter}`, function () { + for (const parameter of [ + '--no-colors', + '--colors=false', + '--no-c', + '--c=false' + ]) { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'colors', false); - }); + assert.propertyVal(parsedArgv, 'colors', false) + }) } - }); + }) - context('growl', function () { - it('uses false as default value', function () { + context('growl', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'growl', false); - }); - + assert.propertyVal(parsedArgv, 'growl', false) + }) for (const parameter of ['--growl', '--G', '-G']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'growl', true); - }); + assert.propertyVal(parsedArgv, 'growl', true) + }) } - }); + }) - context('recursive', function () { - it('uses false as default value', function () { + context('recursive', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'recursive', false); - }); - + assert.propertyVal(parsedArgv, 'recursive', false) + }) for (const parameter of ['--recursive']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'recursive', true); - }); + assert.propertyVal(parsedArgv, 'recursive', true) + }) } - }); + }) - context('reporter-options', function () { - it('uses {} as default value', function () { + context('reporter-options', function() { + it('uses {} as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.property(parsedArgv, 'reporterOptions'); - assert.deepEqual(parsedArgv.reporterOptions, {}); - }); - - const parameters = [{ given: ['--reporter-options', 'foo=bar,quux'], expected: { foo: 'bar', quux: true } }, { given: ['--reporter-options', 'foo=bar,quux,bar=foo'], expected: { foo: 'bar', quux: true, bar: 'foo' } }, { given: ['--reporter-options', 'foo=bar,quux,bar=foo'], expected: { foo: 'bar', quux: true, bar: 'foo' } }, { given: ['--O', 'foo=bar'], expected: { foo: 'bar' } }, { given: ['-O', 'foo=bar'], expected: { foo: 'bar' } }]; + assert.property(parsedArgv, 'reporterOptions') + assert.deepEqual(parsedArgv.reporterOptions, {}) + }) + + const parameters = [ + { + given: ['--reporter-options', 'foo=bar,quux'], + expected: { foo: 'bar', quux: true } + }, + { + given: ['--reporter-options', 'foo=bar,quux,bar=foo'], + expected: { foo: 'bar', quux: true, bar: 'foo' } + }, + { + given: ['--reporter-options', 'foo=bar,quux,bar=foo'], + expected: { foo: 'bar', quux: true, bar: 'foo' } + }, + { given: ['--O', 'foo=bar'], expected: { foo: 'bar' } }, + { given: ['-O', 'foo=bar'], expected: { foo: 'bar' } } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.property(parsedArgv, 'reporterOptions'); - assert.deepEqual(parsedArgv.reporterOptions, parameter.expected); - }); + assert.property(parsedArgv, 'reporterOptions') + assert.deepEqual(parsedArgv.reporterOptions, parameter.expected) + }) } - }); + }) - context('reporter', function () { - it('uses "spec" as default value', function () { + context('reporter', function() { + it('uses "spec" as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'reporter', 'spec'); - }); + assert.propertyVal(parsedArgv, 'reporter', 'spec') + }) - const parameters = [{ given: ['--reporter', 'dot'], expected: 'dot' }, { given: ['--R', 'dot'], expected: 'dot' }, { given: ['-R', 'dot'], expected: 'dot' }]; + const parameters = [ + { given: ['--reporter', 'dot'], expected: 'dot' }, + { given: ['--R', 'dot'], expected: 'dot' }, + { given: ['-R', 'dot'], expected: 'dot' } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'reporter', parameter.expected); - }); + assert.propertyVal(parsedArgv, 'reporter', parameter.expected) + }) } - }); + }) - context('bail', function () { - it('uses false as default value', function () { + context('bail', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'bail', false); - }); - + assert.propertyVal(parsedArgv, 'bail', false) + }) for (const parameter of ['--bail', '--b', '-b']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'bail', true); - }); + assert.propertyVal(parsedArgv, 'bail', true) + }) } - }); + }) - context('grep', function () { - it('has no default value', function () { + context('grep', function() { + it('has no default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.notProperty(parsedArgv, 'grep'); - }); + assert.notProperty(parsedArgv, 'grep') + }) - - const parameters = [{ given: ['--grep', 'test'], expected: 'test' }, { given: ['--g', 'test'], expected: 'test' }, { given: ['-g', 'test'], expected: 'test' }]; + const parameters = [ + { given: ['--grep', 'test'], expected: 'test' }, + { given: ['--g', 'test'], expected: 'test' }, + { given: ['-g', 'test'], expected: 'test' } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'grep', parameter.expected); - }); + assert.propertyVal(parsedArgv, 'grep', parameter.expected) + }) } - }); + }) - context('fgrep', function () { - it('has no default value', function () { + context('fgrep', function() { + it('has no default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.notProperty(parsedArgv, 'fgrep'); - }); - + assert.notProperty(parsedArgv, 'fgrep') + }) - const parameters = [{ given: ['--fgrep', 'test'], expected: 'test' }, { given: ['--f', 'test'], expected: 'test' }, { given: ['-f', 'test'], expected: 'test' }]; + const parameters = [ + { given: ['--fgrep', 'test'], expected: 'test' }, + { given: ['--f', 'test'], expected: 'test' }, + { given: ['-f', 'test'], expected: 'test' } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'fgrep', parameter.expected); - }); + assert.propertyVal(parsedArgv, 'fgrep', parameter.expected) + }) } - }); + }) - context('invert', function () { - it('uses false as default value', function () { + context('invert', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'invert', false); - }); - + assert.propertyVal(parsedArgv, 'invert', false) + }) for (const parameter of ['--invert', '--i', '-i']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'invert', true); - }); + assert.propertyVal(parsedArgv, 'invert', true) + }) } - }); + }) - context('require', function () { - it('uses [] as default value', function () { + context('require', function() { + it('uses [] as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.property(parsedArgv, 'require'); - assert.deepEqual(parsedArgv.require, []); - }); - - - const parameters = [{ given: ['--require', 'test'], expected: ['test'] }, { given: ['--require', 'test', '--require', 'test2'], expected: ['test', 'test2'] }, { given: ['--r', 'test'], expected: ['test'] }, { given: ['-r', 'test'], expected: ['test'] }]; + assert.property(parsedArgv, 'require') + assert.deepEqual(parsedArgv.require, []) + }) + + const parameters = [ + { given: ['--require', 'test'], expected: ['test'] }, + { + given: ['--require', 'test', '--require', 'test2'], + expected: ['test', 'test2'] + }, + { given: ['--r', 'test'], expected: ['test'] }, + { given: ['-r', 'test'], expected: ['test'] } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.property(parsedArgv, 'require'); - assert.deepEqual(parsedArgv.require, parameter.expected); - }); + assert.property(parsedArgv, 'require') + assert.deepEqual(parsedArgv.require, parameter.expected) + }) } - }); + }) - context('include', function () { - it('uses [] as default value', function () { + context('include', function() { + it('uses [] as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.property(parsedArgv, 'include'); - assert.deepEqual(parsedArgv.include, []); - }); - - - const parameters = [{ given: ['--include', 'test'], expected: ['test'] }, { given: ['--include', 'test', '--include', 'test2'], expected: ['test', 'test2'] }]; + assert.property(parsedArgv, 'include') + assert.deepEqual(parsedArgv.include, []) + }) + + const parameters = [ + { given: ['--include', 'test'], expected: ['test'] }, + { + given: ['--include', 'test', '--include', 'test2'], + expected: ['test', 'test2'] + } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.property(parsedArgv, 'include'); - assert.deepEqual(parsedArgv.include, parameter.expected); - }); + assert.property(parsedArgv, 'include') + assert.deepEqual(parsedArgv.include, parameter.expected) + }) } - }); + }) - context('slow', function () { - it('uses 75 as default value', function () { + context('slow', function() { + it('uses 75 as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'slow', 75); - }); + assert.propertyVal(parsedArgv, 'slow', 75) + }) - - const parameters = [{ given: ['--slow', '1000'], expected: 1000 }, { given: ['--slow', '-1'], expected: -1 }, { given: ['--s', '1000'], expected: 1000 }, { given: ['-s', '1000'], expected: 1000 }, { given: ['-s', '-1'], expected: -1 }]; + const parameters = [ + { given: ['--slow', '1000'], expected: 1000 }, + { given: ['--slow', '-1'], expected: -1 }, + { given: ['--s', '1000'], expected: 1000 }, + { given: ['-s', '1000'], expected: 1000 }, + { given: ['-s', '-1'], expected: -1 } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'slow', parameter.expected); - }); + assert.propertyVal(parsedArgv, 'slow', parameter.expected) + }) } - }); + }) - context('timeout', function () { - it('uses 2000 as default value', function () { + context('timeout', function() { + it('uses 2000 as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'timeout', 2000); - }); - + assert.propertyVal(parsedArgv, 'timeout', 2000) + }) - const parameters = [{ given: ['--timeout', '1000'], expected: 1000 }, { given: ['--t', '1000'], expected: 1000 }, { given: ['-t', '1000'], expected: 1000 }]; + const parameters = [ + { given: ['--timeout', '1000'], expected: 1000 }, + { given: ['--t', '1000'], expected: 1000 }, + { given: ['-t', '1000'], expected: 1000 } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'timeout', parameter.expected); - }); + assert.propertyVal(parsedArgv, 'timeout', parameter.expected) + }) } - }); + }) - context('ui', function () { - it('uses "bdd" as default value', function () { + context('ui', function() { + it('uses "bdd" as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'ui', 'bdd'); - }); + assert.propertyVal(parsedArgv, 'ui', 'bdd') + }) - - const parameters = [{ given: ['--ui', 'tdd'], expected: 'tdd' }, { given: ['--u', 'tdd'], expected: 'tdd' }, { given: ['-u', 'tdd'], expected: 'tdd' }]; + const parameters = [ + { given: ['--ui', 'tdd'], expected: 'tdd' }, + { given: ['--u', 'tdd'], expected: 'tdd' }, + { given: ['-u', 'tdd'], expected: 'tdd' } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'ui', parameter.expected); - }); + assert.propertyVal(parsedArgv, 'ui', parameter.expected) + }) } - }); + }) - context('watch', function () { - it('uses false as default value', function () { + context('watch', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'watch', false); - }); - + assert.propertyVal(parsedArgv, 'watch', false) + }) for (const parameter of ['--watch', '--w', '-w']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'watch', true); - }); + assert.propertyVal(parsedArgv, 'watch', true) + }) } - }); + }) - context('check-leaks', function () { - it('uses false as default value', function () { + context('check-leaks', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'checkLeaks', false); - }); - + assert.propertyVal(parsedArgv, 'checkLeaks', false) + }) for (const parameter of ['--check-leaks']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'checkLeaks', true); - }); + assert.propertyVal(parsedArgv, 'checkLeaks', true) + }) } - }); + }) - context('full-trace', function () { - it('uses false as default value', function () { + context('full-trace', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'fullTrace', false); - }); - + assert.propertyVal(parsedArgv, 'fullTrace', false) + }) for (const parameter of ['--full-trace']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'fullTrace', true); - }); + assert.propertyVal(parsedArgv, 'fullTrace', true) + }) } - }); + }) - context('inline-diffs', function () { - it('uses false as default value', function () { + context('inline-diffs', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'inlineDiffs', false); - }); - + assert.propertyVal(parsedArgv, 'inlineDiffs', false) + }) for (const parameter of ['--inline-diffs']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'inlineDiffs', true); - }); + assert.propertyVal(parsedArgv, 'inlineDiffs', true) + }) } - }); + }) - context('exit', function () { - it('uses false as default value', function () { + context('exit', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'exit', false); - }); - + assert.propertyVal(parsedArgv, 'exit', false) + }) for (const parameter of ['--exit']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'exit', true); - }); + assert.propertyVal(parsedArgv, 'exit', true) + }) } - }); + }) - context('retries', function () { - it('has no default value', function () { + context('retries', function() { + it('has no default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.notProperty(parsedArgv, 'retries'); - }); + assert.notProperty(parsedArgv, 'retries') + }) - - const parameters = [{ given: ['--retries', '2'], expected: 2 }]; + const parameters = [{ given: ['--retries', '2'], expected: 2 }] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'retries', parameter.expected); - }); + assert.propertyVal(parsedArgv, 'retries', parameter.expected) + }) } - }); + }) - context('delay', function () { - it('uses false as default value', function () { + context('delay', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'delay', false); - }); - + assert.propertyVal(parsedArgv, 'delay', false) + }) for (const parameter of ['--delay']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'delay', true); - }); + assert.propertyVal(parsedArgv, 'delay', true) + }) } - }); + }) - context('webpack-config', function () { - it('has default value', function () { + context('webpack-config', function() { + it('has default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'webpackConfig', 'webpack.config.js'); - }); + assert.propertyVal(parsedArgv, 'webpackConfig', 'webpack.config.js') + }) - - const parameters = [{ given: ['--webpack-config', 'webpack-config.js'], expected: 'webpack-config.js' }]; + const parameters = [ + { + given: ['--webpack-config', 'webpack-config.js'], + expected: 'webpack-config.js' + } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'webpackConfig', parameter.expected); - }); + assert.propertyVal(parsedArgv, 'webpackConfig', parameter.expected) + }) } - }); + }) - context('webpack-env', function () { - it('has no default value', function () { + context('webpack-env', function() { + it('has no default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.notProperty(parsedArgv, 'webpackEnv'); - }); - - const parameters = [{ given: ['--webpack-env', 'production'], expected: 'production' }, { given: ['--webpack-env.env', 'production'], expected: { env: 'production' } }, { given: ['--webpack-env.anotherEnv', 'test'], expected: { anotherEnv: 'test' } }, { - given: ['--webpack-env.env', 'production', '--webpack-env.anotherEnv', 'test'], - expected: { env: 'production', anotherEnv: 'test' } - }]; + assert.notProperty(parsedArgv, 'webpackEnv') + }) + + const parameters = [ + { given: ['--webpack-env', 'production'], expected: 'production' }, + { + given: ['--webpack-env.env', 'production'], + expected: { env: 'production' } + }, + { + given: ['--webpack-env.anotherEnv', 'test'], + expected: { anotherEnv: 'test' } + }, + { + given: [ + '--webpack-env.env', + 'production', + '--webpack-env.anotherEnv', + 'test' + ], + expected: { env: 'production', anotherEnv: 'test' } + } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.deepPropertyVal(parsedArgv, 'webpackEnv', parameter.expected); - }); + assert.deepPropertyVal(parsedArgv, 'webpackEnv', parameter.expected) + }) } - }); + }) - context('opts', function () { - it('has no default value', function () { + context('opts', function() { + it('has no default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.notProperty(parsedArgv, 'opts'); - }); + assert.notProperty(parsedArgv, 'opts') + }) - - const parameters = [{ given: ['--opts', 'path/to/other.opts'], expected: 'path/to/other.opts' }]; + const parameters = [ + { + given: ['--opts', 'path/to/other.opts'], + expected: 'path/to/other.opts' + } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'opts', parameter.expected); - }); + assert.propertyVal(parsedArgv, 'opts', parameter.expected) + }) } - }); + }) - context('mode', function () { - it('has no default value', function () { + context('mode', function() { + it('has no default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.notProperty(parsedArgv, 'mode'); - }); - + assert.notProperty(parsedArgv, 'mode') + }) - const parameters = [{ given: ['--mode', 'development'], expected: 'development' }, { given: ['--mode', 'production'], expected: 'production' }]; + const parameters = [ + { given: ['--mode', 'development'], expected: 'development' }, + { given: ['--mode', 'production'], expected: 'production' } + ] for (const parameter of parameters) { - it(`parses ${parameter.given.join(' ')}`, function () { + it(`parses ${parameter.given.join(' ')}`, function() { // given - const argv = this.argv.concat(parameter.given); + const argv = this.argv.concat(parameter.given) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'mode', parameter.expected); - }); + assert.propertyVal(parsedArgv, 'mode', parameter.expected) + }) } - }); + }) - context('forbid-only', function () { - it('uses false as default value', function () { + context('forbid-only', function() { + it('uses false as default value', function() { // given - const { - argv - } = this; + const { argv } = this // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'forbidOnly', false); - }); - + assert.propertyVal(parsedArgv, 'forbidOnly', false) + }) for (const parameter of ['--forbid-only']) { - it(`parses ${parameter}`, function () { + it(`parses ${parameter}`, function() { // given - const argv = this.argv.concat([parameter]); + const argv = this.argv.concat([parameter]) // when - const parsedArgv = this.parseArgv(argv); + const parsedArgv = this.parseArgv(argv) // then - assert.propertyVal(parsedArgv, 'forbidOnly', true); - }); + assert.propertyVal(parsedArgv, 'forbidOnly', true) + }) } - }); - }); -}); + }) + }) +}) diff --git a/test/unit/cli/parseConfig.test.ts b/test/unit/cli/parseConfig.test.ts index 70ba8f7..3fe4142 100644 --- a/test/unit/cli/parseConfig.test.ts +++ b/test/unit/cli/parseConfig.test.ts @@ -2,48 +2,53 @@ /* eslint-disable func-names, prefer-arrow-callback */ -import path from "path"; -import fs from "fs-extra"; -import { assert } from "chai"; -import parseConfig from "../../../src/cli/parseConfig"; - -const optsTestCasesPath = path.join(__dirname, 'fixture', 'config', 'optsTestCases'); -const optsTestCases = fs.readdirSync(optsTestCasesPath); - -describe('parseConfig', function () { - it('returns empty object when default config file is missing', function () { - assert.deepEqual(parseConfig(), {}); - }); - - it('throws an error when explicitly-specified default config file is missing', function () { +import path from 'path' +import fs from 'fs-extra' +import { assert } from 'chai' +import parseConfig from '../../../src/cli/parseConfig' + +const optsTestCasesPath = path.join( + __dirname, + 'fixture', + 'config', + 'optsTestCases' +) +const optsTestCases = fs.readdirSync(optsTestCasesPath) + +describe('parseConfig', function() { + it('returns empty object when default config file is missing', function() { + assert.deepEqual(parseConfig(), {}) + }) + + it('throws an error when explicitly-specified default config file is missing', function() { const fn = () => { - parseConfig('mochapack.opts'); - }; + parseConfig('mochapack.opts') + } // then - assert.throws(fn, /Options file 'mochapack.opts' not found/); - }); + assert.throws(fn, /Options file 'mochapack.opts' not found/) + }) - it('throws an error when specified config file is missing', function () { + it('throws an error when specified config file is missing', function() { const fn = () => { - parseConfig('missing-config.opts'); - }; + parseConfig('missing-config.opts') + } // then - assert.throws(fn, /Options file 'missing-config.opts' not found/); - }); + assert.throws(fn, /Options file 'missing-config.opts' not found/) + }) optsTestCases.forEach(testDirName => { - const testDirPath = path.join(optsTestCasesPath, testDirName); - const optsFilePath = path.join(testDirPath, 'mochapack.opts'); - const expectedResultsPath = path.join(testDirPath, 'expected.json'); + const testDirPath = path.join(optsTestCasesPath, testDirName) + const optsFilePath = path.join(testDirPath, 'mochapack.opts') + const expectedResultsPath = path.join(testDirPath, 'expected.json') - it(`parses '${testDirName}/mochapack.opts' and returns options`, function () { + it(`parses '${testDirName}/mochapack.opts' and returns options`, function() { // eslint-disable-next-line global-require, import/no-dynamic-require - const expectedResult = require(expectedResultsPath); - const parsedOptions = parseConfig(optsFilePath); + const expectedResult = require(expectedResultsPath) + const parsedOptions = parseConfig(optsFilePath) - assert.deepEqual(parsedOptions, expectedResult); - }); - }); -}); + assert.deepEqual(parsedOptions, expectedResult) + }) + }) +}) diff --git a/test/unit/cli/requireWebpackConfig.test.ts b/test/unit/cli/requireWebpackConfig.test.ts index a99fd2d..086d0a5 100644 --- a/test/unit/cli/requireWebpackConfig.test.ts +++ b/test/unit/cli/requireWebpackConfig.test.ts @@ -1,64 +1,88 @@ /* eslint-env node, mocha */ -import path from "path"; -import { assert } from "chai"; -import { rejects } from "assert"; -import requireWebpackConfig from "../../../src/cli/requireWebpackConfig"; +import path from 'path' +import { assert } from 'chai' +import { rejects } from 'assert' +import requireWebpackConfig from '../../../src/cli/requireWebpackConfig' describe('requireWebpackConfig', () => { - const getConfigPath = (extension, suffix = 'config-test') => path.join(__dirname, 'fixture', 'webpackConfig', `webpack.${suffix}${extension}`); + const getConfigPath = (extension, suffix = 'config-test') => + path.join( + __dirname, + 'fixture', + 'webpackConfig', + `webpack.${suffix}${extension}` + ) - const expectedConfigPath = path.join(__dirname, 'fixture', 'webpackConfig', 'expected.json'); - const expectedConfig = require(expectedConfigPath); // eslint-disable-line global-require, import/no-dynamic-require + const expectedConfigPath = path.join( + __dirname, + 'fixture', + 'webpackConfig', + 'expected.json' + ) + const expectedConfig = require(expectedConfigPath) // eslint-disable-line global-require, import/no-dynamic-require it('requires plain JavaScript Webpack config file', async () => { - const configPath = getConfigPath('.js'); - assert.deepEqual((await requireWebpackConfig(configPath)), expectedConfig); - }); - - (process.platform === 'win32' ? it.skip : it)('requires symlinked config file', async () => { - const configPath = getConfigPath('.js', 'config-symlink'); - assert.deepEqual((await requireWebpackConfig(configPath)), expectedConfig); - }); + const configPath = getConfigPath('.js') + assert.deepEqual(await requireWebpackConfig(configPath), expectedConfig) + }) + ;(process.platform === 'win32' ? it.skip : it)( + 'requires symlinked config file', + async () => { + const configPath = getConfigPath('.js', 'config-symlink') + assert.deepEqual(await requireWebpackConfig(configPath), expectedConfig) + } + ) it('requires Babel Webpack config file', async () => { - const configPath = getConfigPath('.babel.js'); - assert.deepEqual((await requireWebpackConfig(configPath)), expectedConfig); - }); + const configPath = getConfigPath('.babel.js') + assert.deepEqual(await requireWebpackConfig(configPath), expectedConfig) + }) it('requires CoffeeScript Webpack config file', async () => { - const configPath = getConfigPath('.coffee'); - assert.deepEqual((await requireWebpackConfig(configPath)), expectedConfig); - }); + const configPath = getConfigPath('.coffee') + assert.deepEqual(await requireWebpackConfig(configPath), expectedConfig) + }) it('requires CoffeeScript Webpack config file with config.js', async () => { - const configPath = getConfigPath('.js', 'config'); - assert.deepEqual((await requireWebpackConfig(configPath)), expectedConfig); - }); + const configPath = getConfigPath('.js', 'config') + assert.deepEqual(await requireWebpackConfig(configPath), expectedConfig) + }) it('supports config that exports a function', async () => { - const configPath = getConfigPath('.js', 'config-function'); - assert.deepEqual((await requireWebpackConfig(configPath, false, 'test')), expectedConfig); - }); + const configPath = getConfigPath('.js', 'config-function') + assert.deepEqual( + await requireWebpackConfig(configPath, false, 'test'), + expectedConfig + ) + }) it('supports config that exports a Promise', async () => { - const configPath = getConfigPath('.js', 'config-promise'); - assert.deepEqual((await requireWebpackConfig(configPath, false, 'test')), expectedConfig); - }); + const configPath = getConfigPath('.js', 'config-promise') + assert.deepEqual( + await requireWebpackConfig(configPath, false, 'test'), + expectedConfig + ) + }) it('throws error when multi compiler config is given', async () => { - const configPath = getConfigPath('.js', 'config-multi'); - const error = 'Passing multiple configs as an Array is not supported. Please provide a single config instead.'; - await rejects(() => requireWebpackConfig(configPath, true), { message: error }); - }); + const configPath = getConfigPath('.js', 'config-multi') + const error = + 'Passing multiple configs as an Array is not supported. Please provide a single config instead.' + await rejects(() => requireWebpackConfig(configPath, true), { + message: error + }) + }) it('throws error when not found when required', async () => { - const configPath = getConfigPath('.js', 'config-xxx'); - await rejects(() => requireWebpackConfig(configPath, true), { message: `Webpack config could not be found: ${configPath}` }); - }); + const configPath = getConfigPath('.js', 'config-xxx') + await rejects(() => requireWebpackConfig(configPath, true), { + message: `Webpack config could not be found: ${configPath}` + }) + }) it('return empty config when not found and not required', async () => { - const configPath = getConfigPath('.xxx', 'config-xxx'); - assert.deepEqual((await requireWebpackConfig(configPath)), {}); - }); -}); + const configPath = getConfigPath('.xxx', 'config-xxx') + assert.deepEqual(await requireWebpackConfig(configPath), {}) + }) +}) diff --git a/test/unit/createMochaWebpack.test.ts b/test/unit/createMochaWebpack.test.ts index 4d37751..00947a4 100644 --- a/test/unit/createMochaWebpack.test.ts +++ b/test/unit/createMochaWebpack.test.ts @@ -1,16 +1,16 @@ /* eslint-env node, mocha */ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import MochaWebpack from "../../src/MochaWebpack"; -import { createMochaWebpack } from "../../src/createMochaWebpack"; +import { assert } from 'chai' +import MochaWebpack from '../../src/MochaWebpack' +import createMochaWebpack from '../../src/createMochaWebpack' -describe('createMochaWebpack', function () { - it('should create a instance of MochaWebpack', function () { - assert.doesNotThrow(() => createMochaWebpack()); - const mochaWebpack = createMochaWebpack(); +describe('createMochaWebpack', function() { + it('should create a instance of MochaWebpack', function() { + assert.doesNotThrow(() => createMochaWebpack()) + const mochaWebpack = createMochaWebpack() - assert.isNotNull(mochaWebpack); - assert.instanceOf(mochaWebpack, MochaWebpack); - }); -}); + assert.isNotNull(mochaWebpack) + assert.instanceOf(mochaWebpack, MochaWebpack) + }) +}) diff --git a/test/unit/runner/configureMocha.test.ts b/test/unit/runner/configureMocha.test.ts index 58474b3..24f4779 100644 --- a/test/unit/runner/configureMocha.test.ts +++ b/test/unit/runner/configureMocha.test.ts @@ -1,15 +1,14 @@ /* eslint-env node, mocha */ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import { sandbox } from "sinon"; -import Mocha from "mocha"; +import { assert } from 'chai' +import { sandbox } from 'sinon' +import Mocha from 'mocha' -import configureMocha from "../../../src/runner/configureMocha"; +import configureMocha from '../../../src/runner/configureMocha' - -describe('configureMocha', function () { - beforeEach(function () { +describe('configureMocha', function() { + beforeEach(function() { this.options = { bail: false, reporter: 'spec', @@ -24,97 +23,111 @@ describe('configureMocha', function () { asyncOnly: false, delay: false, forbidOnly: true - }; - this.sandbox = sandbox.create(); - this.spyReporter = this.sandbox.spy(Mocha.prototype, 'reporter'); - this.spyUseColors = this.sandbox.spy(Mocha.prototype, 'useColors'); - this.spyUseInlineDiffs = this.sandbox.spy(Mocha.prototype, 'useInlineDiffs'); - this.spyEnableTimeouts = this.sandbox.spy(Mocha.prototype, 'enableTimeouts'); - this.spyGrep = this.sandbox.spy(Mocha.prototype, 'grep'); - this.spyGrowl = this.sandbox.spy(Mocha.prototype, 'growl'); - this.spyForbidOnly = this.sandbox.spy(Mocha.prototype, 'forbidOnly'); - }); - - afterEach(function () { - this.sandbox.restore(); - }); - - it('should create a instance of Mocha', function () { - const mocha = configureMocha(this.options); - assert.instanceOf(mocha, Mocha, 'configureMocha should return a instance of Mocha'); - }); - - it('should call reporter()', function () { + } + this.sandbox = sandbox.create() + this.spyReporter = this.sandbox.spy(Mocha.prototype, 'reporter') + this.spyUseColors = this.sandbox.spy(Mocha.prototype, 'useColors') + this.spyUseInlineDiffs = this.sandbox.spy(Mocha.prototype, 'useInlineDiffs') + this.spyEnableTimeouts = this.sandbox.spy(Mocha.prototype, 'enableTimeouts') + this.spyGrep = this.sandbox.spy(Mocha.prototype, 'grep') + this.spyGrowl = this.sandbox.spy(Mocha.prototype, 'growl') + this.spyForbidOnly = this.sandbox.spy(Mocha.prototype, 'forbidOnly') + }) + + afterEach(function() { + this.sandbox.restore() + }) + + it('should create a instance of Mocha', function() { + const mocha = configureMocha(this.options) + assert.instanceOf( + mocha, + Mocha, + 'configureMocha should return a instance of Mocha' + ) + }) + + it('should call reporter()', function() { configureMocha({ ...this.options - }); + }) - const reporter = Mocha.reporters[this.options.reporter]; + const reporter = Mocha.reporters[this.options.reporter] - assert.isTrue(this.spyReporter.called, 'reporter() should be called'); - assert.isTrue(this.spyReporter.calledWith(reporter, this.options.reporterOptions)); - }); + assert.isTrue(this.spyReporter.called, 'reporter() should be called') + assert.isTrue( + this.spyReporter.calledWith(reporter, this.options.reporterOptions) + ) + }) - it('should call useColors()', function () { + it('should call useColors()', function() { configureMocha({ ...this.options - }); + }) - assert.isTrue(this.spyUseColors.called, 'useColors() should be called'); - assert.isTrue(this.spyUseColors.calledWith(this.options.colors)); - }); + assert.isTrue(this.spyUseColors.called, 'useColors() should be called') + assert.isTrue(this.spyUseColors.calledWith(this.options.colors)) + }) - it('should call useInlineDiffs()', function () { + it('should call useInlineDiffs()', function() { configureMocha({ ...this.options - }); - - assert.isTrue(this.spyUseInlineDiffs.called, 'useInlineDiffs() should be called'); - assert.isTrue(this.spyUseInlineDiffs.calledWith(this.options.useInlineDiffs)); - }); - - it('should call enableTimeouts()', function () { + }) + + assert.isTrue( + this.spyUseInlineDiffs.called, + 'useInlineDiffs() should be called' + ) + assert.isTrue( + this.spyUseInlineDiffs.calledWith(this.options.useInlineDiffs) + ) + }) + + it('should call enableTimeouts()', function() { configureMocha({ ...this.options, timeout: 0 - }); + }) - assert.isTrue(this.spyEnableTimeouts.called, 'enableTimeouts() should be called'); - assert.isTrue(this.spyEnableTimeouts.calledWith(false)); - }); + assert.isTrue( + this.spyEnableTimeouts.called, + 'enableTimeouts() should be called' + ) + assert.isTrue(this.spyEnableTimeouts.calledWith(false)) + }) - it('should call grep()', function () { + it('should call grep()', function() { configureMocha({ ...this.options, grep: 'dddd', fgrep: 'dddd' - }); + }) - assert.isTrue(this.spyGrep.called, 'grep() should be called'); - }); + assert.isTrue(this.spyGrep.called, 'grep() should be called') + }) - it('should set growl', function () { + it('should set growl', function() { configureMocha({ ...this.options, growl: undefined - }); + }) - assert.isFalse(this.spyGrowl.called, 'growl() should not be called'); + assert.isFalse(this.spyGrowl.called, 'growl() should not be called') configureMocha({ ...this.options, growl: true - }); + }) - assert.isTrue(this.spyGrowl.called, 'growl() should be called'); - }); + assert.isTrue(this.spyGrowl.called, 'growl() should be called') + }) - it('should call forbidOnly()', function () { + it('should call forbidOnly()', function() { configureMocha({ ...this.options, timeout: 0 - }); + }) - assert.isTrue(this.spyForbidOnly.called, 'spyForbidOnly() should be called'); - }); -}); + assert.isTrue(this.spyForbidOnly.called, 'spyForbidOnly() should be called') + }) +}) diff --git a/test/unit/runner/loadReporter.test.ts b/test/unit/runner/loadReporter.test.ts index 14add99..962c95c 100644 --- a/test/unit/runner/loadReporter.test.ts +++ b/test/unit/runner/loadReporter.test.ts @@ -1,56 +1,83 @@ /* eslint-env node, mocha */ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import spec from "mocha/lib/reporters/spec"; -import progress from "mocha/lib/reporters/progress"; - -import customMochaReporter from "../../fixture/customMochaReporter"; -import loadReporter from "../../../src/runner/loadReporter"; - -const customMochaReporterPath = require.resolve('../../fixture/customMochaReporter'); - -describe('loadReporter', function () { - it('should allow to use reporter by function', function () { - const reporter = loadReporter(spec); - assert.strictEqual(reporter, spec, 'should equal reporter'); - }); - - it('should load built-in reporter', function () { - const reporter = loadReporter('spec'); - assert.strictEqual(reporter, spec, 'should equal built-in reporter'); - }); - - it('should load reporter from node_modules', function () { - const reporter = loadReporter('mocha/lib/reporters/progress'); - assert.strictEqual(reporter, progress, 'should equal node_module reporter'); - }); - - it('should load reporter relative from real cwd (1)', function () { - const reporter = loadReporter('./test/fixture/customMochaReporter', process.cwd()); - assert.strictEqual(reporter, customMochaReporter, 'should equal custom reporter'); - }); - - it('should load reporter relative from real cwd (2)', function () { - const reporter = loadReporter('test/fixture/customMochaReporter', process.cwd()); - assert.strictEqual(reporter, customMochaReporter, 'should equal custom reporter'); - }); - - it('should load reporter with relative path from custom cwd', function () { - const reporter = loadReporter('../../fixture/customMochaReporter', __dirname); - assert.strictEqual(reporter, customMochaReporter, 'should equal custom reporter'); - }); - - it('should load reporter with absolute path', function () { - const reporter = loadReporter(customMochaReporterPath, process.cwd()); - assert.strictEqual(reporter, customMochaReporter, 'should equal custom reporter'); - }); - - it('throws error when not found', function () { +import { assert } from 'chai' +import spec from 'mocha/lib/reporters/spec' +import progress from 'mocha/lib/reporters/progress' + +import customMochaReporter from '../../fixture/customMochaReporter' +import loadReporter from '../../../src/runner/loadReporter' + +const customMochaReporterPath = require.resolve( + '../../fixture/customMochaReporter' +) + +describe('loadReporter', function() { + it('should allow to use reporter by function', function() { + const reporter = loadReporter(spec) + assert.strictEqual(reporter, spec, 'should equal reporter') + }) + + it('should load built-in reporter', function() { + const reporter = loadReporter('spec') + assert.strictEqual(reporter, spec, 'should equal built-in reporter') + }) + + it('should load reporter from node_modules', function() { + const reporter = loadReporter('mocha/lib/reporters/progress') + assert.strictEqual(reporter, progress, 'should equal node_module reporter') + }) + + it('should load reporter relative from real cwd (1)', function() { + const reporter = loadReporter( + './test/fixture/customMochaReporter', + process.cwd() + ) + assert.strictEqual( + reporter, + customMochaReporter, + 'should equal custom reporter' + ) + }) + + it('should load reporter relative from real cwd (2)', function() { + const reporter = loadReporter( + 'test/fixture/customMochaReporter', + process.cwd() + ) + assert.strictEqual( + reporter, + customMochaReporter, + 'should equal custom reporter' + ) + }) + + it('should load reporter with relative path from custom cwd', function() { + const reporter = loadReporter( + '../../fixture/customMochaReporter', + __dirname + ) + assert.strictEqual( + reporter, + customMochaReporter, + 'should equal custom reporter' + ) + }) + + it('should load reporter with absolute path', function() { + const reporter = loadReporter(customMochaReporterPath, process.cwd()) + assert.strictEqual( + reporter, + customMochaReporter, + 'should equal custom reporter' + ) + }) + + it('throws error when not found', function() { const load = () => { - loadReporter('xxx/xxxx/xxxx/test.js', process.cwd()); - }; + loadReporter('xxx/xxxx/xxxx/test.js', process.cwd()) + } - assert.throws(load, /Cannot find module/); - }); -}); + assert.throws(load, /Cannot find module/) + }) +}) diff --git a/test/unit/runner/loadUI.test.ts b/test/unit/runner/loadUI.test.ts index d97c2fb..751bf60 100644 --- a/test/unit/runner/loadUI.test.ts +++ b/test/unit/runner/loadUI.test.ts @@ -1,48 +1,66 @@ /* eslint-env node, mocha */ /* eslint-disable func-names, prefer-arrow-callback */ -import path from "path"; -import { assert } from "chai"; -import loadUI from "../../../src/runner/loadUI"; - -const customMochaReporterPath = require.resolve('../../fixture/customMochaReporter.js'); - -describe('loadUI', function () { - it('should load built-in interface', function () { - const ui = loadUI('tdd'); - assert.strictEqual(ui, 'tdd', 'should equal built-in ui'); - }); - - it('should load interface from node_modules', function () { - const ui = loadUI('mocha/lib/interfaces/tdd'); - assert.strictEqual(ui, require.resolve('mocha/lib/interfaces/tdd'), 'should equal node_module ui'); - }); - - it('should load interface relative from real cwd (1)', function () { - const ui = loadUI('./test/fixture/customMochaReporter', process.cwd()); - assert.strictEqual(ui, path.join(process.cwd(), './test/fixture/customMochaReporter.js'), 'should equal custom ui'); - }); - - it('should load interface relative from real cwd (2)', function () { - const ui = loadUI('test/fixture/customMochaReporter', process.cwd()); - assert.strictEqual(ui, path.join(process.cwd(), 'test/fixture/customMochaReporter.js'), 'should equal custom ui'); - }); - - it('should load interface with relative path from custom cwd', function () { - const ui = loadUI('../../fixture/customMochaReporter', __dirname); - assert.strictEqual(ui, path.join(__dirname, '../../fixture/customMochaReporter.js'), 'should equal custom ui'); - }); - - it('should load interface with absolute path', function () { - const ui = loadUI(customMochaReporterPath, process.cwd()); - assert.strictEqual(ui, customMochaReporterPath, 'should equal custom ui'); - }); - - it('throws error when not found', function () { +import path from 'path' +import { assert } from 'chai' +import loadUI from '../../../src/runner/loadUI' + +const customMochaReporterPath = require.resolve( + '../../fixture/customMochaReporter.js' +) + +describe('loadUI', function() { + it('should load built-in interface', function() { + const ui = loadUI('tdd') + assert.strictEqual(ui, 'tdd', 'should equal built-in ui') + }) + + it('should load interface from node_modules', function() { + const ui = loadUI('mocha/lib/interfaces/tdd') + assert.strictEqual( + ui, + require.resolve('mocha/lib/interfaces/tdd'), + 'should equal node_module ui' + ) + }) + + it('should load interface relative from real cwd (1)', function() { + const ui = loadUI('./test/fixture/customMochaReporter', process.cwd()) + assert.strictEqual( + ui, + path.join(process.cwd(), './test/fixture/customMochaReporter.js'), + 'should equal custom ui' + ) + }) + + it('should load interface relative from real cwd (2)', function() { + const ui = loadUI('test/fixture/customMochaReporter', process.cwd()) + assert.strictEqual( + ui, + path.join(process.cwd(), 'test/fixture/customMochaReporter.js'), + 'should equal custom ui' + ) + }) + + it('should load interface with relative path from custom cwd', function() { + const ui = loadUI('../../fixture/customMochaReporter', __dirname) + assert.strictEqual( + ui, + path.join(__dirname, '../../fixture/customMochaReporter.js'), + 'should equal custom ui' + ) + }) + + it('should load interface with absolute path', function() { + const ui = loadUI(customMochaReporterPath, process.cwd()) + assert.strictEqual(ui, customMochaReporterPath, 'should equal custom ui') + }) + + it('throws error when not found', function() { const load = () => { - loadUI('xxx/xxxx/xxxx/test.js', process.cwd()); - }; + loadUI('xxx/xxxx/xxxx/test.js', process.cwd()) + } - assert.throws(load, /Cannot find module/); - }); -}); + assert.throws(load, /Cannot find module/) + }) +}) diff --git a/test/unit/util/glob.test.ts b/test/unit/util/glob.test.ts index 64b30de..27b660d 100644 --- a/test/unit/util/glob.test.ts +++ b/test/unit/util/glob.test.ts @@ -1,100 +1,106 @@ /* eslint-env node, mocha */ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import { ensureGlob, extensionsToGlob } from "../../../src/util/glob"; - -describe('glob', function () { - context('ensureGlob', function () { - it('allows to pass in file paths', function () { - const path = 'test/file/test.js'; - const expected = path; - - const result = ensureGlob(path); - assert.strictEqual(result, expected); - }); - - it('allows to pass in globs', function () { - const path = 'test/file/**/*.test'; - const expected = path; - - const result = ensureGlob(path); - assert.strictEqual(result, expected); - }); - - it('transforms directories to glob non-recursive', function () { - const path = 'test/file/'; - const expected = 'test/file/*.js'; - - const result = ensureGlob(path); - assert.strictEqual(result, expected); - }); - - it('transforms directories to glob recursive', function () { - const path = 'test/file/'; - const expected = 'test/file/**/*.js'; - - const result = ensureGlob(path, true); - assert.strictEqual(result, expected); - }); - - it('transforms directories to glob non-recursive with custom file pattern', function () { - const path = 'test/file/'; - const expected = 'test/file/*.{js,coffee,ts}'; - - const result = ensureGlob(path, false, '*.{js,coffee,ts}'); - assert.strictEqual(result, expected); - }); - - it('transforms directories to glob recursive with custom file pattern', function () { - const path = 'test/file/'; - const expected = 'test/file/**/*.{js,coffee,ts}'; - - const result = ensureGlob(path, true, '*.{js,coffee,ts}'); - assert.strictEqual(result, expected); - }); - - it('throws an error when transforming directory to glob and an invalid file pattern is given', function () { - const path = 'test/file/'; - const errorNonGlob = /is not a valid glob pattern/; - const errorNonFilePattern = /must be a file pattern like/; - - assert.doesNotThrow(() => ensureGlob(path, true, '*.js')); - assert.doesNotThrow(() => ensureGlob(path, true, '*.{js,coffee,ts}')); - assert.throws(() => ensureGlob(path, true, 'd'), errorNonGlob); - assert.throws(() => ensureGlob(path, true, '**/*.js'), errorNonFilePattern); - assert.throws(() => ensureGlob(path, true, 'test/*.js'), errorNonFilePattern); - assert.doesNotThrow(() => ensureGlob(path, true, '*.js')); - }); - }); - - context('extensionsToGlob', function () { - it('handles ["", ".js", ".coffee"]', function () { - const given = ['', '.js', '.coffee']; - const expected = '*{.js,.coffee}'; - const result = extensionsToGlob(given); - assert.strictEqual(result, expected); - }); - - it('handles ["", ".js"]', function () { - const given = ['', '.js']; - const expected = '*.js'; - const result = extensionsToGlob(given); - assert.strictEqual(result, expected); - }); - - it('handles [""] - js fallback', function () { - const given = ['']; - const expected = '*.js'; - const result = extensionsToGlob(given); - assert.strictEqual(result, expected); - }); - - it('handles [] - js fallback', function () { - const given = []; - const expected = '*.js'; - const result = extensionsToGlob(given); - assert.strictEqual(result, expected); - }); - }); -}); +import { assert } from 'chai' +import { ensureGlob, extensionsToGlob } from '../../../src/util/glob' + +describe('glob', function() { + context('ensureGlob', function() { + it('allows to pass in file paths', function() { + const path = 'test/file/test.js' + const expected = path + + const result = ensureGlob(path) + assert.strictEqual(result, expected) + }) + + it('allows to pass in globs', function() { + const path = 'test/file/**/*.test' + const expected = path + + const result = ensureGlob(path) + assert.strictEqual(result, expected) + }) + + it('transforms directories to glob non-recursive', function() { + const path = 'test/file/' + const expected = 'test/file/*.js' + + const result = ensureGlob(path) + assert.strictEqual(result, expected) + }) + + it('transforms directories to glob recursive', function() { + const path = 'test/file/' + const expected = 'test/file/**/*.js' + + const result = ensureGlob(path, true) + assert.strictEqual(result, expected) + }) + + it('transforms directories to glob non-recursive with custom file pattern', function() { + const path = 'test/file/' + const expected = 'test/file/*.{js,coffee,ts}' + + const result = ensureGlob(path, false, '*.{js,coffee,ts}') + assert.strictEqual(result, expected) + }) + + it('transforms directories to glob recursive with custom file pattern', function() { + const path = 'test/file/' + const expected = 'test/file/**/*.{js,coffee,ts}' + + const result = ensureGlob(path, true, '*.{js,coffee,ts}') + assert.strictEqual(result, expected) + }) + + it('throws an error when transforming directory to glob and an invalid file pattern is given', function() { + const path = 'test/file/' + const errorNonGlob = /is not a valid glob pattern/ + const errorNonFilePattern = /must be a file pattern like/ + + assert.doesNotThrow(() => ensureGlob(path, true, '*.js')) + assert.doesNotThrow(() => ensureGlob(path, true, '*.{js,coffee,ts}')) + assert.throws(() => ensureGlob(path, true, 'd'), errorNonGlob) + assert.throws( + () => ensureGlob(path, true, '**/*.js'), + errorNonFilePattern + ) + assert.throws( + () => ensureGlob(path, true, 'test/*.js'), + errorNonFilePattern + ) + assert.doesNotThrow(() => ensureGlob(path, true, '*.js')) + }) + }) + + context('extensionsToGlob', function() { + it('handles ["", ".js", ".coffee"]', function() { + const given = ['', '.js', '.coffee'] + const expected = '*{.js,.coffee}' + const result = extensionsToGlob(given) + assert.strictEqual(result, expected) + }) + + it('handles ["", ".js"]', function() { + const given = ['', '.js'] + const expected = '*.js' + const result = extensionsToGlob(given) + assert.strictEqual(result, expected) + }) + + it('handles [""] - js fallback', function() { + const given = [''] + const expected = '*.js' + const result = extensionsToGlob(given) + assert.strictEqual(result, expected) + }) + + it('handles [] - js fallback', function() { + const given = [] + const expected = '*.js' + const result = extensionsToGlob(given) + assert.strictEqual(result, expected) + }) + }) +}) diff --git a/test/unit/util/registerRequireHook.test.ts b/test/unit/util/registerRequireHook.test.ts index 4a68b02..0291120 100644 --- a/test/unit/util/registerRequireHook.test.ts +++ b/test/unit/util/registerRequireHook.test.ts @@ -1,43 +1,41 @@ /* eslint-env node, mocha */ /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from "chai"; -import registerRequireHook from "../../../src/util/registerRequireHook"; -import fakemodule from "./fixture/fakeModule"; +import { assert } from 'chai' +import registerRequireHook from '../../../src/util/registerRequireHook' +import fakemodule from './fixture/fakeModule' -const fakeModulePath = require.resolve('./fixture/fakeModule'); +const fakeModulePath = require.resolve('./fixture/fakeModule') -describe('registerRequireHook', function () { - beforeEach(function () { - delete require.cache[fakeModulePath]; - }); +describe('registerRequireHook', function() { + beforeEach(function() { + delete require.cache[fakeModulePath] + }) - it('requires from disk', function () { - const result = require(fakeModulePath); // eslint-disable-line - assert.equal(result, fakemodule); - }); + it('requires from disk', function() { + const result = require(fakeModulePath) // eslint-disable-line + assert.equal(result, fakemodule) + }) - it('requires from memory', function () { + it('requires from memory', function() { const dispose = registerRequireHook('.js', (filePath, requireCaller) => { if (filePath === fakeModulePath) { - const { - filename - } = requireCaller; - assert.equal(filename, __filename); - return { path: filePath, source: 'module.exports = "from-memory";' }; + const { filename } = requireCaller + assert.equal(filename, __filename) + return { path: filePath, source: 'module.exports = "from-memory";' } } - return { path: null, source: null }; - }); + return { path: null, source: null } + }) // module should be read from memory - const resultMemory = require(fakeModulePath); // eslint-disable-line - assert.notEqual(resultMemory, fakemodule); + const resultMemory = require(fakeModulePath) // eslint-disable-line + assert.notEqual(resultMemory, fakemodule) // unregister memory require handler - dispose(); + dispose() // module should be read from disk - const resultDisk = require(fakeModulePath); // eslint-disable-line - assert.equal(resultDisk, fakemodule); - }); -}); + const resultDisk = require(fakeModulePath) // eslint-disable-line + assert.equal(resultDisk, fakemodule) + }) +}) diff --git a/tsconfig.json b/tsconfig.json index f58fb60..062ffe6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,13 +7,8 @@ "moduleResolution": "node", "outDir": "lib", "resolveJsonModule": true, - "sourceMap": true, + "sourceMap": true }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules", - "**/*.test.ts" - ] + "include": ["src/**/*"], + "exclude": ["node_modules", "**/*.test.*"] } diff --git a/tsconfig.lint.json b/tsconfig.lint.json new file mode 100644 index 0000000..40d4697 --- /dev/null +++ b/tsconfig.lint.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "allowJs": true + }, + "include": ["bin/**/*", "src/**/*", "test/**/*"], + "exclude": ["node_modules"] +} diff --git a/yarn.lock b/yarn.lock index 43a5d01..ae0d8d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -836,6 +836,16 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/chai@^4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.7.tgz#1c8c25cbf6e59ffa7d6b9652c78e547d9a41692d" + integrity sha512-luq8meHGYwvky0O7u0eQZdA7B4Wd9owUCqvbw2m3XCrCU8mplYOujMBbvyS547AxJkC+pGnd0Cm15eNxEUNU8g== + +"@types/eslint-visitor-keys@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" + integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== + "@types/events@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" @@ -850,6 +860,11 @@ "@types/minimatch" "*" "@types/node" "*" +"@types/json-schema@^7.0.3": + version "7.0.3" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" + integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -865,6 +880,11 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== +"@types/mocha@^5.2.7": + version "5.2.7" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" + integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== + "@types/node@*": version "12.6.9" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.9.tgz#ffeee23afdc19ab16e979338e7b536fdebbbaeaf" @@ -918,6 +938,49 @@ "@types/webpack-sources" "*" source-map "^0.6.0" +"@typescript-eslint/eslint-plugin@^2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.11.0.tgz#4477c33491ccf0a9a3f4a30ef84978fa0ea0cad2" + integrity sha512-G2HHA1vpMN0EEbUuWubiCCfd0R3a30BB+UdvnFkxwZIxYEGOrWEXDv8tBFO9f44CWc47Xv9lLM3VSn4ORLI2bA== + dependencies: + "@typescript-eslint/experimental-utils" "2.11.0" + eslint-utils "^1.4.3" + functional-red-black-tree "^1.0.1" + regexpp "^3.0.0" + tsutils "^3.17.1" + +"@typescript-eslint/experimental-utils@2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.11.0.tgz#cef18e6b122706c65248a5d8984a9779ed1e52ac" + integrity sha512-YxcA/y0ZJaCc/fB/MClhcDxHI0nOBB7v2/WxBju2cOTanX7jO9ttQq6Fy4yW9UaY5bPd9xL3cun3lDVqk67sPQ== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.11.0" + eslint-scope "^5.0.0" + +"@typescript-eslint/parser@^2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.11.0.tgz#cdcc3be73ee31cbef089af5ff97ccaa380ef6e8b" + integrity sha512-DyGXeqhb3moMioEFZIHIp7oXBBh7dEfPTzGrlyP0Mi9ScCra4SWEGs3kPd18mG7Sy9Wy8z88zmrw5tSGL6r/6A== + dependencies: + "@types/eslint-visitor-keys" "^1.0.0" + "@typescript-eslint/experimental-utils" "2.11.0" + "@typescript-eslint/typescript-estree" "2.11.0" + eslint-visitor-keys "^1.1.0" + +"@typescript-eslint/typescript-estree@2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.11.0.tgz#21ada6504274cd1644855926312c798fc697e9fb" + integrity sha512-HGY4+d4MagO6cKMcKfIKaTMxcAv7dEVnji2Zi+vi5VV8uWAM631KjAB5GxFcexMYrwKT0EekRiiGK1/Sd7VFGA== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash.unescape "4.0.1" + semver "^6.3.0" + tsutils "^3.17.1" + "@webassemblyjs/ast@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" @@ -1092,28 +1155,21 @@ abbrev@~1.0.9: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s= - dependencies: - acorn "^3.0.4" - -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= - -acorn@^5.5.0: - version "5.7.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" - integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== +acorn-jsx@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384" + integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw== acorn@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.1.tgz#3ed8422d6dec09e6121cc7a843ca86a330a86b51" integrity sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q== +acorn@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" + integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== + agent-base@4, agent-base@^4.1.0, agent-base@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" @@ -1141,11 +1197,6 @@ ajv-errors@^1.0.0: resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== -ajv-keywords@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" - integrity sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I= - ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" @@ -1159,17 +1210,7 @@ ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.2.3, ajv@^5.3.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - -ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5: version "6.10.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== @@ -1441,6 +1482,11 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + async-each@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" @@ -1502,7 +1548,7 @@ aws4@^1.2.1, aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== -babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: +babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= @@ -2072,13 +2118,6 @@ caller-callsite@^2.0.0: dependencies: callsites "^2.0.0" -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= - dependencies: - callsites "^0.2.0" - caller-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" @@ -2086,16 +2125,16 @@ caller-path@^2.0.0: dependencies: caller-callsite "^2.0.0" -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= - callsites@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" @@ -2281,11 +2320,6 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== - class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -2480,7 +2514,7 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.5.0, concat-stream@^1.5.2, concat-stream@^1.6.0: +concat-stream@^1.5.0, concat-stream@^1.5.2: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -2668,7 +2702,7 @@ cross-spawn@^4: lru-cache "^4.0.1" which "^1.2.9" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: +cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= @@ -2814,7 +2848,7 @@ debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: dependencies: ms "2.0.0" -debug@^4.1.0, debug@^4.1.1: +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -3028,10 +3062,10 @@ doctrine@1.5.0: esutils "^2.0.2" isarray "^1.0.0" -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== dependencies: esutils "^2.0.2" @@ -3269,6 +3303,13 @@ eslint-config-airbnb-base@12.1.0: dependencies: eslint-restricted-globals "^0.1.1" +eslint-config-prettier@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.7.0.tgz#9a876952e12df2b284adbd3440994bf1f39dfbb9" + integrity sha512-FamQVKM3jjUVwhG4hEMnbtsq7xOIDm+SY5iBPfR8gKsJoAB2IQnNF+bk1+8Fy44Nq7PPJaLvkRxILYdJWoguKQ== + dependencies: + get-stdin "^6.0.0" + eslint-import-resolver-node@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" @@ -3315,14 +3356,6 @@ eslint-scope@3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^3.7.1: - version "3.7.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" - integrity sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -3331,74 +3364,94 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== -eslint@4.19.1: - version "4.19.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" - integrity sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ== +eslint-visitor-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + +eslint@^6.7.2: + version "6.7.2" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.7.2.tgz#c17707ca4ad7b2d8af986a33feba71e18a9fecd1" + integrity sha512-qMlSWJaCSxDFr8fBPvJM9kJwbazrhNcBU3+DszDW1OlEwKBBRWsJc7NJFelvwQpanHCR14cOLD41x8Eqvo3Nng== dependencies: - ajv "^5.3.0" - babel-code-frame "^6.22.0" + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" chalk "^2.1.0" - concat-stream "^1.6.0" - cross-spawn "^5.1.0" - debug "^3.1.0" - doctrine "^2.1.0" - eslint-scope "^3.7.1" - eslint-visitor-keys "^1.0.0" - espree "^3.5.4" - esquery "^1.0.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.3" + eslint-visitor-keys "^1.1.0" + espree "^6.1.2" + esquery "^1.0.1" esutils "^2.0.2" - file-entry-cache "^2.0.0" + file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.0.1" - ignore "^3.3.3" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-resolvable "^1.0.0" - js-yaml "^3.9.1" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" + lodash "^4.17.14" + minimatch "^3.0.4" mkdirp "^0.5.1" natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - pluralize "^7.0.0" + optionator "^0.8.3" progress "^2.0.0" - regexpp "^1.0.1" - require-uncached "^1.0.3" - semver "^5.3.0" - strip-ansi "^4.0.0" - strip-json-comments "~2.0.1" - table "4.0.2" - text-table "~0.2.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" esm@^3.2.25: version "3.2.25" resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== -espree@^3.5.4: - version "3.5.4" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" - integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A== +espree@^6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.2.tgz#6c272650932b4f91c3714e5e7b5f5e2ecf47262d" + integrity sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA== dependencies: - acorn "^5.5.0" - acorn-jsx "^3.0.0" + acorn "^7.1.0" + acorn-jsx "^5.1.0" + eslint-visitor-keys "^1.1.0" esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.0: +esquery@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== @@ -3559,11 +3612,6 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= - fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -3586,7 +3634,7 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= -fast-levenshtein@~2.0.4: +fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= @@ -3625,13 +3673,12 @@ figures@^3.0.0: dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E= +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" + flat-cache "^2.0.1" filename-regex@^2.0.0: version "2.0.1" @@ -3732,15 +3779,14 @@ find-up@^4.0.0: locate-path "^5.0.0" path-exists "^4.0.0" -flat-cache@^1.2.1: - version "1.3.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f" - integrity sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg== +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== dependencies: - circular-json "^0.3.1" - graceful-fs "^4.1.2" - rimraf "~2.6.2" - write "^0.2.1" + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" flat@^4.1.0: version "4.1.0" @@ -3749,6 +3795,11 @@ flat@^4.1.0: dependencies: is-buffer "~2.0.3" +flatted@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" + integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + flush-write-stream@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" @@ -4042,6 +4093,11 @@ get-stdin@^4.0.1: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= +get-stdin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" + integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== + get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -4204,6 +4260,18 @@ glob@7.1.4, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glo once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@~7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" @@ -4223,11 +4291,18 @@ global-dirs@^0.1.0, global-dirs@^0.1.1: dependencies: ini "^1.3.4" -globals@^11.0.1, globals@^11.1.0: +globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globals@^12.1.0: + version "12.3.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13" + integrity sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw== + dependencies: + type-fest "^0.8.1" + globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -4631,10 +4706,10 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" -ignore@^3.3.3: - version "3.3.10" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== ignore@^5.1.1: version "5.1.2" @@ -4649,6 +4724,14 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" +import-fresh@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" @@ -4747,7 +4830,7 @@ init-package-json@~1.9.4: validate-npm-package-license "^3.0.1" validate-npm-package-name "^3.0.0" -inquirer@^3.0.6, inquirer@^3.3.0: +inquirer@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== @@ -5142,11 +5225,6 @@ is-regex@^1.0.4: dependencies: has "^1.0.1" -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== - is-retry-allowed@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" @@ -5335,7 +5413,7 @@ js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= -js-yaml@3.13.1, js-yaml@>=3.13.0, js-yaml@^3.13.1, js-yaml@^3.9.1: +js-yaml@3.13.1, js-yaml@>=3.13.0, js-yaml@^3.13.1: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -5373,11 +5451,6 @@ json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-bet resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -5774,6 +5847,11 @@ lodash.tail@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ= +lodash.unescape@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" + integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= + lodash.union@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" @@ -7153,17 +7231,17 @@ optimist@0.6.1, optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= +optionator@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== dependencies: deep-is "~0.1.3" - fast-levenshtein "~2.0.4" + fast-levenshtein "~2.0.6" levn "~0.3.0" prelude-ls "~1.1.2" type-check "~0.3.2" - wordwrap "~1.0.0" + word-wrap "~1.2.3" os-browserify@^0.3.0: version "0.3.0" @@ -7370,6 +7448,13 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-asn1@^5.0.0: version "5.1.4" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc" @@ -7595,11 +7680,6 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" -pluralize@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== - posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -7681,6 +7761,11 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= +prettier@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== + prismjs@^1.15.0: version "1.17.1" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.17.1.tgz#e669fcbd4cdd873c35102881c33b14d0d68519be" @@ -8170,10 +8255,15 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpp@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" - integrity sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw== +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +regexpp@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e" + integrity sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g== regexpu-core@^4.6.0: version "4.6.0" @@ -8359,19 +8449,6 @@ require-package-name@^2.0.1: resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9" integrity sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk= -require-uncached@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= - resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" @@ -8432,7 +8509,7 @@ reusify@^1.0.0: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@~2.6.1, rimraf@~2.6.2: +rimraf@2, rimraf@2.6.3, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@~2.6.1: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -8729,11 +8806,13 @@ slice-ansi@0.0.4: resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU= -slice-ansi@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" - integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: @@ -9142,6 +9221,11 @@ strip-json-comments@2.0.1, strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +strip-json-comments@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" + integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== + strip-outer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" @@ -9205,17 +9289,15 @@ symbol-observable@^1.1.0, symbol-observable@^1.2.0: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== -table@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" - integrity sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA== +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== dependencies: - ajv "^5.2.3" - ajv-keywords "^2.1.0" - chalk "^2.1.0" - lodash "^4.17.4" - slice-ansi "1.0.0" - string-width "^2.1.1" + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" tapable@^1.0.0, tapable@^1.1.3: version "1.1.3" @@ -9327,7 +9409,7 @@ test-exclude@^5.2.3: read-pkg-up "^4.0.0" require-main-filename "^2.0.0" -text-table@~0.2.0: +text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= @@ -9527,11 +9609,18 @@ tsconfig-paths@^3.5.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.9.0: +tslib@^1.8.1, tslib@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== +tsutils@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + dependencies: + tslib "^1.8.1" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -9576,6 +9665,11 @@ type-fest@^0.6.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -9811,6 +9905,11 @@ uuid@~3.1.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" integrity sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g== +v8-compile-cache@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" + integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== + validate-npm-package-license@^3.0.1, validate-npm-package-license@~3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -9938,16 +10037,16 @@ widest-line@^2.0.0: dependencies: string-width "^2.1.1" +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - worker-farm@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" @@ -10041,10 +10140,10 @@ write-file-webpack-plugin@^4.2.0: moment "^2.22.1" write-file-atomic "^2.3.0" -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== dependencies: mkdirp "^0.5.1"