diff --git a/.eslintrc b/.eslintrc index b851edc92b..9547a7446f 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,11 @@ "extends": ["webpack", "prettier"], "globals": { "document": true, - "window": true + "window": true, + "self": true, + "WorkerGlobalScope": true, + "__resourceQuery": true, + "__webpack_dev_server_client__": true }, "parserOptions": { "sourceType": "script", diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8977de369e..d0fdf318cd 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -47,9 +47,6 @@ jobs: node-8: node_version: ^8.9.0 webpack_version: latest - node-6: - node_version: ^6.9.0 - webpack_version: latest steps: - task: NodeTool@0 inputs: @@ -98,9 +95,6 @@ jobs: node-8: node_version: ^8.9.0 webpack_version: latest - node-6: - node_version: ^6.9.0 - webpack_version: latest steps: - task: NodeTool@0 inputs: @@ -149,9 +143,6 @@ jobs: node-8: node_version: ^8.9.0 webpack_version: latest - node-6: - node_version: ^6.9.0 - webpack_version: latest steps: - script: 'git config --global core.autocrlf input' displayName: 'Config git core.autocrlf' diff --git a/bin/webpack-dev-server.js b/bin/webpack-dev-server.js index 286cad93b9..224a69d978 100755 --- a/bin/webpack-dev-server.js +++ b/bin/webpack-dev-server.js @@ -4,8 +4,6 @@ /* eslint-disable no-shadow, no-console */ -const fs = require('fs'); -const net = require('net'); const debug = require('debug')('webpack-dev-server'); const importLocal = require('import-local'); const yargs = require('yargs'); @@ -116,42 +114,10 @@ function startDevServer(config, options) { } if (options.socket) { - server.listeningApp.on('error', (e) => { - if (e.code === 'EADDRINUSE') { - const clientSocket = new net.Socket(); - - clientSocket.on('error', (err) => { - if (err.code === 'ECONNREFUSED') { - // No other server listening on this socket so it can be safely removed - fs.unlinkSync(options.socket); - - server.listen(options.socket, options.host, (error) => { - if (error) { - throw error; - } - }); - } - }); - - clientSocket.connect({ path: options.socket }, () => { - throw new Error('This socket is already used'); - }); - } - }); - server.listen(options.socket, options.host, (err) => { if (err) { throw err; } - - // chmod 666 (rw rw rw) - const READ_WRITE = 438; - - fs.chmod(options.socket, READ_WRITE, (err) => { - if (err) { - throw err; - } - }); }); } else { server.listen(options.port, options.host, (err) => { diff --git a/client-src/.eslintrc b/client-src/.eslintrc new file mode 100644 index 0000000000..bd14a19ef2 --- /dev/null +++ b/client-src/.eslintrc @@ -0,0 +1,5 @@ +{ + "parserOptions": { + "sourceType": "module" + } +} diff --git a/client-src/clients/BaseClient.js b/client-src/clients/BaseClient.js index 1dfa65911b..7c47b70e2a 100644 --- a/client-src/clients/BaseClient.js +++ b/client-src/clients/BaseClient.js @@ -1,5 +1,3 @@ -'use strict'; - /* eslint-disable no-unused-vars */ diff --git a/client-src/clients/SockJSClient.js b/client-src/clients/SockJSClient.js index 193c571d26..9a1fd729fa 100644 --- a/client-src/clients/SockJSClient.js +++ b/client-src/clients/SockJSClient.js @@ -1,5 +1,3 @@ -'use strict'; - /* eslint-disable no-unused-vars */ diff --git a/client-src/clients/WebsocketClient.js b/client-src/clients/WebsocketClient.js index 0089f6faed..9785bb5517 100644 --- a/client-src/clients/WebsocketClient.js +++ b/client-src/clients/WebsocketClient.js @@ -1,5 +1,3 @@ -'use strict'; - /* global WebSocket */ /* eslint-disable diff --git a/client-src/default/index.js b/client-src/default/index.js index dede6f0763..df7432b5ea 100644 --- a/client-src/default/index.js +++ b/client-src/default/index.js @@ -1,14 +1,14 @@ -'use strict'; - -/* global __resourceQuery WorkerGlobalScope self */ /* eslint prefer-destructuring: off */ -const stripAnsi = require('strip-ansi'); -const socket = require('./socket'); -const overlay = require('./overlay'); -const { log, setLogLevel } = require('./utils/log'); -const sendMessage = require('./utils/sendMessage'); -const reloadApp = require('./utils/reloadApp'); -const createSocketUrl = require('./utils/createSocketUrl'); +import stripAnsi from 'strip-ansi'; +import socket from './socket'; +import { + clear as clearOverlay, + showMessage as showMessageOverlay, +} from './overlay'; +import { log, setLogLevel } from './utils/log'; +import sendMessage from './utils/sendMessage'; +import reloadApp from './utils/reloadApp'; +import createSocketUrl from './utils/createSocketUrl'; const status = { isUnloading: false, @@ -47,7 +47,7 @@ const onSocketMessage = { log.info('[WDS] App updated. Recompiling...'); // fixes #1042. overlay doesn't clear if errors are fixed but warnings remain. if (options.useWarningOverlay || options.useErrorOverlay) { - overlay.clear(); + clearOverlay(); } sendMessage('Invalid'); }, @@ -57,7 +57,7 @@ const onSocketMessage = { 'still-ok': function stillOk() { log.info('[WDS] Nothing changed.'); if (options.useWarningOverlay || options.useErrorOverlay) { - overlay.clear(); + clearOverlay(); } sendMessage('StillOk'); }, @@ -93,7 +93,7 @@ const onSocketMessage = { ok() { sendMessage('Ok'); if (options.useWarningOverlay || options.useErrorOverlay) { - overlay.clear(); + clearOverlay(); } if (options.initial) { return (options.initial = false); @@ -112,7 +112,7 @@ const onSocketMessage = { log.warn(strippedWarnings[i]); } if (options.useWarningOverlay) { - overlay.showMessage(warnings); + showMessageOverlay(warnings); } if (options.initial) { @@ -128,7 +128,7 @@ const onSocketMessage = { log.error(strippedErrors[i]); } if (options.useErrorOverlay) { - overlay.showMessage(errors); + showMessageOverlay(errors); } options.initial = false; }, diff --git a/client-src/default/overlay.js b/client-src/default/overlay.js index a1bb6cef2b..f73cb29578 100644 --- a/client-src/default/overlay.js +++ b/client-src/default/overlay.js @@ -1,12 +1,10 @@ -'use strict'; - // The error overlay is inspired (and mostly copied) from Create React App (https://github.com/facebookincubator/create-react-app) // They, in turn, got inspired by webpack-hot-middleware (https://github.com/glenjamin/webpack-hot-middleware). -const ansiHTML = require('ansi-html'); -const { AllHtmlEntities } = require('html-entities'); +import ansiHTML from 'ansi-html'; +import { AllHtmlEntities as Entities } from 'html-entities'; -const entities = new AllHtmlEntities(); +const entities = new Entities(); const colors = { reset: ['transparent', 'transparent'], black: '181818', @@ -95,8 +93,8 @@ function ensureOverlayDivExists(onOverlayDivReady) { document.body.appendChild(overlayIframe); } -// Successful compilation. -function clear() { +// successful compilation. +export function clear() { if (!overlayDiv) { // It is not there in the first place. return; @@ -110,7 +108,7 @@ function clear() { } // Compilation with errors (e.g. syntax error or missing modules). -function showMessage(messages) { +export function showMessage(messages) { ensureOverlayDivExists((div) => { // Make it look similar to our terminal. div.innerHTML = `= 0 ? this.publicHost.substr(0, idxPublic) : this.publicHost; + idxPublic >= 0 + ? this.options.public.substr(0, idxPublic) + : this.options.public; if (hostname === publicHostname) { return true; diff --git a/lib/options.json b/lib/options.json index 217ee5a631..87319af51c 100644 --- a/lib/options.json +++ b/lib/options.json @@ -37,16 +37,7 @@ ] }, "clientLogLevel": { - "enum": [ - "info", - "warn", - "error", - "debug", - "trace", - "silent", - "none", - "warning" - ] + "enum": ["info", "warn", "error", "debug", "trace", "silent"] }, "compress": { "type": "boolean" @@ -377,6 +368,9 @@ } ] }, + "stdin": { + "type": "boolean" + }, "useLocalIp": { "type": "boolean" }, @@ -408,7 +402,7 @@ "bonjour": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverbonjour)", "ca": "should be {String|Buffer}", "cert": "should be {String|Buffer}", - "clientLogLevel": "should be {String} and equal to one of the allowed values\n\n [ 'none', 'silent', 'info', 'debug', 'trace', 'error', 'warning', 'warn' ]\n\n (https://webpack.js.org/configuration/dev-server/#devserverclientloglevel)", + "clientLogLevel": "should be {String} and equal to one of the allowed values\n\n [ 'silent', 'info', 'debug', 'trace', 'error', 'warn' ]\n\n (https://webpack.js.org/configuration/dev-server/#devserverclientloglevel)", "compress": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devservercompress)", "contentBase": "should be {Number|String|Array} (https://webpack.js.org/configuration/dev-server/#devservercontentbase)", "disableHostCheck": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverdisablehostcheck)", @@ -459,6 +453,7 @@ "staticOptions": "should be {Object} (https://webpack.js.org/configuration/dev-server/#devserverstaticoptions)", "stats": "should be {Object|Boolean} (https://webpack.js.org/configuration/dev-server/#devserverstats-)", "transportMode": "should be {String|Object} (https://webpack.js.org/configuration/dev-server/#devservertransportmode)", + "stdin": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverstdin)", "useLocalIp": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserveruselocalip)", "warn": "should be {Function}", "watchContentBase": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverwatchcontentbase)", diff --git a/lib/utils/createConfig.js b/lib/utils/createConfig.js index 0211561235..b5e7eedc68 100644 --- a/lib/utils/createConfig.js +++ b/lib/utils/createConfig.js @@ -1,21 +1,16 @@ 'use strict'; -const path = require('path'); -const isAbsoluteUrl = require('is-absolute-url'); const defaultTo = require('./defaultTo'); function createConfig(config, argv, { port }) { const firstWpOpt = Array.isArray(config) ? config[0] : config; const options = firstWpOpt.devServer || {}; - // This updates both config and firstWpOpt - firstWpOpt.mode = defaultTo(firstWpOpt.mode, 'development'); - if (argv.bonjour) { options.bonjour = true; } - if (argv.host && (argv.host !== 'localhost' || !options.host)) { + if (argv.host) { options.host = argv.host; } @@ -59,90 +54,26 @@ function createConfig(config, argv, { port }) { options.overlay = argv.overlay; } - if (!options.publicPath) { - // eslint-disable-next-line - options.publicPath = - (firstWpOpt.output && firstWpOpt.output.publicPath) || ''; - - if ( - !isAbsoluteUrl(String(options.publicPath)) && - options.publicPath[0] !== '/' - ) { - options.publicPath = `/${options.publicPath}`; - } - } - - if (!options.filename && firstWpOpt.output && firstWpOpt.output.filename) { - options.filename = firstWpOpt.output && firstWpOpt.output.filename; - } - - if (!options.watchOptions && firstWpOpt.watchOptions) { - options.watchOptions = firstWpOpt.watchOptions; - } - if (argv.stdin) { - process.stdin.on('end', () => { - // eslint-disable-next-line no-process-exit - process.exit(0); - }); - - process.stdin.resume(); + options.stdin = true; } - // TODO https://github.com/webpack/webpack-dev-server/issues/616 (v4) - // We should prefer CLI arg under config, now we always prefer `hot` from `devServer` - if (!options.hot) { - options.hot = argv.hot; + if (argv.hot) { + options.hot = true; } - // TODO https://github.com/webpack/webpack-dev-server/issues/616 (v4) - // We should prefer CLI arg under config, now we always prefer `hotOnly` from `devServer` - if (!options.hotOnly) { - options.hotOnly = argv.hotOnly; + if (argv.hotOnly) { + options.hotOnly = true; } - // TODO https://github.com/webpack/webpack-dev-server/issues/616 (v4) - // We should prefer CLI arg under config, now we always prefer `clientLogLevel` from `devServer` - if (!options.clientLogLevel && argv.clientLogLevel) { + if (argv.clientLogLevel) { options.clientLogLevel = argv.clientLogLevel; } - if (argv.contentBase) { - options.contentBase = argv.contentBase; - - if (Array.isArray(options.contentBase)) { - options.contentBase = options.contentBase.map((p) => path.resolve(p)); - } else if (/^[0-9]$/.test(options.contentBase)) { - options.contentBase = +options.contentBase; - } else if (!isAbsoluteUrl(String(options.contentBase))) { - options.contentBase = path.resolve(options.contentBase); - } - } - // It is possible to disable the contentBase by using - // `--no-content-base`, which results in arg["content-base"] = false - else if (argv.contentBase === false) { - options.contentBase = false; - } - if (argv.watchContentBase) { options.watchContentBase = true; } - if (!options.stats) { - options.stats = defaultTo(firstWpOpt.stats, { - cached: false, - cachedAssets: false, - }); - } - - if ( - typeof options.stats === 'object' && - typeof options.stats.colors === 'undefined' && - argv.color - ) { - options.stats = Object.assign({}, options.stats, { colors: argv.color }); - } - if (argv.lazy) { options.lazy = true; } @@ -202,16 +133,12 @@ function createConfig(config, argv, { port }) { } if (argv.openPage) { - options.open = true; options.openPage = argv.openPage; } - if (typeof argv.open !== 'undefined') { - options.open = argv.open !== '' ? argv.open : true; - } - - if (options.open && !options.openPage) { - options.openPage = ''; + // eslint-disable-next-line no-undefined + if (argv.open !== undefined) { + options.open = argv.open; } if (argv.useLocalIp) { diff --git a/lib/utils/handleStdin.js b/lib/utils/handleStdin.js new file mode 100644 index 0000000000..c26431300c --- /dev/null +++ b/lib/utils/handleStdin.js @@ -0,0 +1,16 @@ +'use strict'; + +function handleStdin(options) { + if (options.stdin) { + // listening for this event only once makes testing easier, + // since it prevents event listeners from hanging open + process.stdin.once('end', () => { + // eslint-disable-next-line no-process-exit + process.exit(0); + }); + + process.stdin.resume(); + } +} + +module.exports = handleStdin; diff --git a/lib/utils/normalizeOptions.js b/lib/utils/normalizeOptions.js index 885f365687..466fb670be 100644 --- a/lib/utils/normalizeOptions.js +++ b/lib/utils/normalizeOptions.js @@ -4,7 +4,129 @@ no-undefined */ +const path = require('path'); +const isAbsoluteUrl = require('is-absolute-url'); +const supportsColor = require('supports-color').stdout; +const defaultTo = require('./defaultTo'); + function normalizeOptions(compiler, options) { + const firstWpOpt = compiler.compilers + ? compiler.compilers[0].options + : compiler.options; + + // defaultTo only returns the second parameter if the first is null or undefined + firstWpOpt.mode = defaultTo(firstWpOpt.mode, 'development'); + + const devServerOptions = firstWpOpt.devServer || {}; + + // webpackOptions.devServer has the lowest priority here. + // This is a breaking change for CLI, but a desired one. + + // For the API, it did not use webpackOptions.devServer in previous versions. + // With these changes, API users, optimally, should do 1 of 3 things: + // 1. Put all config in webpackOptions.devServer, then call: new Server(compiler, {}); + // 2. Put all config in webpackOptions.devServer, then call: new Server(compiler, webpackOptions.devServer); + // 3. Put no config in webpackOptions.devServer, then call: new Server(compiler, options); + + // These are the recommended usage practices, + // because it will cause no collision between webpackOptions.devServer and normal options + + // not using Object.assign because we want the current options object to remain, + // but populate it with data from devServer if it does not already exist + Object.keys(devServerOptions).forEach((key) => { + if (options[key] === undefined) { + options[key] = devServerOptions[key]; + } + }); + + if (!options.publicPath) { + options.publicPath = + (firstWpOpt.output && firstWpOpt.output.publicPath) || ''; + } + + // moving this block out of the above (!options.publicPath) if statement + // is a minor breaking change, but I think will make for better UX all around + if ( + !isAbsoluteUrl(String(options.publicPath)) && + options.publicPath[0] !== '/' + ) { + options.publicPath = `/${options.publicPath}`; + } + + if (!options.filename && firstWpOpt.output && firstWpOpt.output.filename) { + options.filename = firstWpOpt.output && firstWpOpt.output.filename; + } + + if (!options.watchOptions && firstWpOpt.watchOptions) { + options.watchOptions = firstWpOpt.watchOptions; + } + + // resolve paths if this is an array + if (Array.isArray(options.contentBase)) { + options.contentBase = options.contentBase.map((p) => { + if (isAbsoluteUrl(p)) { + return p; + } + + return path.resolve(p); + }); + // string that should be a number + // TODO: remove ability to make contentBase a number + } else if ( + typeof options.contentBase === 'string' && + /^[0-9]$/.test(options.contentBase) + ) { + options.contentBase = +options.contentBase; + // resolve path if it is not absolute + } else if ( + typeof options.contentBase === 'string' && + !isAbsoluteUrl(options.contentBase) + ) { + options.contentBase = path.resolve(options.contentBase); + } + + if (!options.stats) { + options.stats = defaultTo(firstWpOpt.stats, { + cached: false, + cachedAssets: false, + }); + } + + // the fallback for the color value is whether or not the user's console + // supports color, so usually true (supportsColor is an object but we just want a boolean) + let colors = !!supportsColor; + if ( + typeof firstWpOpt.stats === 'object' && + firstWpOpt.stats.colors !== undefined + ) { + // firstWpOpt.stats.colors could be an object but we just want a boolean + colors = !!firstWpOpt.stats.colors; + } + + if (typeof options.stats === 'object' && options.stats.colors === undefined) { + options.stats = Object.assign({}, options.stats, { colors }); + } + + if (options.openPage) { + options.open = true; + } + + if (options.open !== undefined) { + options.open = options.open !== '' ? options.open : true; + } + + if (options.open && !options.openPage) { + options.openPage = ''; + } + + // options that default to true: + if (options.liveReload === undefined) { + options.liveReload = true; + } + if (options.inline === undefined) { + options.inline = true; + } + // Setup default value options.contentBase = options.contentBase !== undefined ? options.contentBase : process.cwd(); diff --git a/lib/utils/runOpen.js b/lib/utils/runOpen.js index a2757ab919..7f0b814ffe 100644 --- a/lib/utils/runOpen.js +++ b/lib/utils/runOpen.js @@ -1,6 +1,6 @@ 'use strict'; -const open = require('opn'); +const open = require('open'); const isAbsoluteUrl = require('is-absolute-url'); function runOpen(uri, options, log) { diff --git a/lib/utils/startUnixSocket.js b/lib/utils/startUnixSocket.js new file mode 100644 index 0000000000..9bf850c2ec --- /dev/null +++ b/lib/utils/startUnixSocket.js @@ -0,0 +1,62 @@ +'use strict'; + +const fs = require('fs'); +const net = require('net'); +const { promisify } = require('util'); + +const accessAsync = promisify(fs.access); + +async function startUnixSocket(listeningApp, socket, cb) { + const chmodSocket = (done) => { + // chmod 666 (rw rw rw) - octal + const READ_WRITE = 438; + fs.chmod(socket, READ_WRITE, done); + }; + + const startSocket = () => { + listeningApp.on('error', (err) => { + cb(err); + }); + + // 511 is the default value for the server.listen backlog parameter + // https://nodejs.org/api/net.html#net_server_listen + listeningApp.listen(socket, 511, (err) => { + if (err) { + cb(err); + } else { + chmodSocket(cb); + } + }); + }; + + try { + await accessAsync(socket, fs.constants.F_OK); + } catch (e) { + // file does not exist + startSocket(); + return; + } + + // file exists + + const clientSocket = new net.Socket(); + + clientSocket.on('error', (err) => { + if (err.code === 'ECONNREFUSED' || err.code === 'ENOTSOCK') { + // No other server listening on this socket so it can be safely removed + fs.unlinkSync(socket); + + startSocket(); + } + }); + + clientSocket.connect({ path: socket }, () => { + // if a client socket successfully connects to the given socket path, + // it means that the socket is in use + const err = new Error('This socket is already used'); + clientSocket.destroy(); + cb(err); + }); +} + +module.exports = startUnixSocket; diff --git a/package-lock.json b/package-lock.json index b85b554cfe..7f143226c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,58 @@ "output-file-sync": "^2.0.0", "slash": "^2.0.0", "source-map": "^0.5.0" + }, + "dependencies": { + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "optional": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + } } }, "@babel/code-frame": { @@ -1408,6 +1460,66 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "jest-changed-files": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + } + }, + "jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" + } + }, "jest-get-type": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", @@ -1434,6 +1546,21 @@ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, "pretty-format": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", @@ -1743,7 +1870,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.1.tgz", "integrity": "sha512-NT/skIZjgotDSiXs0WqYhgcuBKhUMgfekCmCGtkUAiLqZdOnrdjmZr9wRl3ll64J9NF79uZ4fk16Dx0yMc/Xbg==", - "dev": true, "requires": { "@nodelib/fs.stat": "2.0.1", "run-parallel": "^1.1.9" @@ -1752,14 +1878,12 @@ "@nodelib/fs.stat": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.1.tgz", - "integrity": "sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw==", - "dev": true + "integrity": "sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw==" }, "@nodelib/fs.walk": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.2.tgz", "integrity": "sha512-J/DR3+W12uCzAJkw7niXDcqcKBg6+5G5Q/ZpThpGNzAUz70eOR6RV4XnnSN01qHZiVl0eavoxJsBypQoKsV2QQ==", - "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.1", "fastq": "^1.6.0" @@ -1871,6 +1995,11 @@ "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", "dev": true }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, "@types/semver": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.0.1.tgz", @@ -2219,6 +2348,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, "requires": { "micromatch": "^3.1.4", "normalize-path": "^2.1.1" @@ -2228,6 +2358,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" } @@ -2319,6 +2450,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, "requires": { "array-uniq": "^1.0.1" } @@ -2326,7 +2458,8 @@ "array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true }, "array-unique": { "version": "0.3.2", @@ -2424,7 +2557,8 @@ "async-each": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true }, "async-limiter": { "version": "1.0.0", @@ -2654,9 +2788,9 @@ "dev": true }, "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==" }, "bluebird": { "version": "3.5.5", @@ -3082,22 +3216,72 @@ "dev": true }, "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.0.2.tgz", + "integrity": "sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA==", "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", + "anymatch": "^3.0.1", + "braces": "^3.0.2", + "fsevents": "^2.0.6", + "glob-parent": "^5.0.0", + "is-binary-path": "^2.1.0", + "is-glob": "^4.0.1", "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "readdirp": "^3.1.1" + }, + "dependencies": { + "anymatch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.0.tgz", + "integrity": "sha512-Ozz7l4ixzI7Oxj2+cw+p0tVUt27BpaJ+1+q1TCeANWxHpvyn2+Un+YamBdfKu0uh8xLodGhoa1v7595NhKDAuA==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz", + "integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==", + "optional": true + }, + "glob-parent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + } } }, "chownr": { @@ -3316,6 +3500,47 @@ "dev": true, "requires": { "execa": "^1.0.0" + }, + "dependencies": { + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + } } }, "commondir": { @@ -4388,6 +4613,43 @@ "requires": { "execa": "^1.0.0", "ip-regex": "^2.1.0" + }, + "dependencies": { + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "^2.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + } } }, "define-properties": { @@ -4437,16 +4699,25 @@ } }, "del": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", - "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-5.0.0.tgz", + "integrity": "sha512-TfU3nUY0WDIhN18eq+pgpbLY9AfL5RfiE9czKaTSolc6aK7qASXfDErvYgjV1UqCR4sNXDoxO0/idPmhDUt2Sg==", "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", + "globby": "^10.0.0", "is-path-cwd": "^2.0.0", "is-path-in-cwd": "^2.0.0", "p-map": "^2.0.0", - "pify": "^4.0.1" + "rimraf": "^2.6.3" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } } }, "delayed-stream": { @@ -5290,17 +5561,43 @@ "dev": true }, "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/execa/-/execa-2.0.3.tgz", + "integrity": "sha512-iM124nlyGSrXmuyZF1EMe83ESY2chIYVyDRZKgmcDynid2Q2v/+GuE7gNMl6Sy9Niwf4MC0DDxagOxeMPjuLsw==", + "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "^6.0.5", + "get-stream": "^5.0.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^3.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + } } }, "exit": { @@ -5591,7 +5888,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.0.4.tgz", "integrity": "sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg==", - "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.1", "@nodelib/fs.walk": "^1.2.1", @@ -5605,7 +5901,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -5614,7 +5909,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -5623,7 +5917,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -5631,14 +5924,12 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.0.5" @@ -5648,7 +5939,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } @@ -5676,7 +5966,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", - "dev": true, "requires": { "reusify": "^1.0.0" } @@ -5732,12 +6021,12 @@ } }, "file-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", - "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.0.0.tgz", + "integrity": "sha512-roAbL6IdSGczwfXxhMi6Zq+jD4IfUpL0jWHD7fvmjdOVb7xBfdRUHe4LpBgO23VtVK5AW1OlWZo0p34Jvx3iWg==", "dev": true, "requires": { - "loader-utils": "^1.0.2", + "loader-utils": "^1.2.2", "schema-utils": "^1.0.0" } }, @@ -5976,6 +6265,7 @@ "version": "1.2.9", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, "optional": true, "requires": { "nan": "^2.12.1", @@ -5985,21 +6275,25 @@ "abbrev": { "version": "1.1.1", "bundled": true, + "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", "bundled": true, + "dev": true, "optional": true }, "aproba": { "version": "1.2.0", "bundled": true, + "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", "bundled": true, + "dev": true, "optional": true, "requires": { "delegates": "^1.0.0", @@ -6009,11 +6303,13 @@ "balanced-match": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "dev": true, "optional": true, "requires": { "balanced-match": "^1.0.0", @@ -6023,31 +6319,37 @@ "chownr": { "version": "1.1.1", "bundled": true, + "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", "bundled": true, + "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, + "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, + "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "debug": { "version": "4.1.1", "bundled": true, + "dev": true, "optional": true, "requires": { "ms": "^2.1.1" @@ -6056,21 +6358,25 @@ "deep-extend": { "version": "0.6.0", "bundled": true, + "dev": true, "optional": true }, "delegates": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", "bundled": true, + "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", "bundled": true, + "dev": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -6079,11 +6385,13 @@ "fs.realpath": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "gauge": { "version": "2.7.4", "bundled": true, + "dev": true, "optional": true, "requires": { "aproba": "^1.0.3", @@ -6099,6 +6407,7 @@ "glob": { "version": "7.1.3", "bundled": true, + "dev": true, "optional": true, "requires": { "fs.realpath": "^1.0.0", @@ -6112,11 +6421,13 @@ "has-unicode": { "version": "2.0.1", "bundled": true, + "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.24", "bundled": true, + "dev": true, "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -6125,6 +6436,7 @@ "ignore-walk": { "version": "3.0.1", "bundled": true, + "dev": true, "optional": true, "requires": { "minimatch": "^3.0.4" @@ -6133,6 +6445,7 @@ "inflight": { "version": "1.0.6", "bundled": true, + "dev": true, "optional": true, "requires": { "once": "^1.3.0", @@ -6142,16 +6455,19 @@ "inherits": { "version": "2.0.3", "bundled": true, + "dev": true, "optional": true }, "ini": { "version": "1.3.5", "bundled": true, + "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true, "requires": { "number-is-nan": "^1.0.0" @@ -6160,11 +6476,13 @@ "isarray": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", "bundled": true, + "dev": true, "optional": true, "requires": { "brace-expansion": "^1.1.7" @@ -6173,11 +6491,13 @@ "minimist": { "version": "0.0.8", "bundled": true, + "dev": true, "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "dev": true, "optional": true, "requires": { "safe-buffer": "^5.1.2", @@ -6187,6 +6507,7 @@ "minizlib": { "version": "1.2.1", "bundled": true, + "dev": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -6195,6 +6516,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "dev": true, "optional": true, "requires": { "minimist": "0.0.8" @@ -6203,11 +6525,13 @@ "ms": { "version": "2.1.1", "bundled": true, + "dev": true, "optional": true }, "needle": { "version": "2.3.0", "bundled": true, + "dev": true, "optional": true, "requires": { "debug": "^4.1.0", @@ -6218,6 +6542,7 @@ "node-pre-gyp": { "version": "0.12.0", "bundled": true, + "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", @@ -6235,6 +6560,7 @@ "nopt": { "version": "4.0.1", "bundled": true, + "dev": true, "optional": true, "requires": { "abbrev": "1", @@ -6244,11 +6570,13 @@ "npm-bundled": { "version": "1.0.6", "bundled": true, + "dev": true, "optional": true }, "npm-packlist": { "version": "1.4.1", "bundled": true, + "dev": true, "optional": true, "requires": { "ignore-walk": "^3.0.1", @@ -6258,6 +6586,7 @@ "npmlog": { "version": "4.1.2", "bundled": true, + "dev": true, "optional": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -6269,16 +6598,19 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, + "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", "bundled": true, + "dev": true, "optional": true }, "once": { "version": "1.4.0", "bundled": true, + "dev": true, "optional": true, "requires": { "wrappy": "1" @@ -6287,16 +6619,19 @@ "os-homedir": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "osenv": { "version": "0.1.5", "bundled": true, + "dev": true, "optional": true, "requires": { "os-homedir": "^1.0.0", @@ -6306,16 +6641,19 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, + "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", "bundled": true, + "dev": true, "optional": true }, "rc": { "version": "1.2.8", "bundled": true, + "dev": true, "optional": true, "requires": { "deep-extend": "^0.6.0", @@ -6327,6 +6665,7 @@ "minimist": { "version": "1.2.0", "bundled": true, + "dev": true, "optional": true } } @@ -6334,6 +6673,7 @@ "readable-stream": { "version": "2.3.6", "bundled": true, + "dev": true, "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -6348,6 +6688,7 @@ "rimraf": { "version": "2.6.3", "bundled": true, + "dev": true, "optional": true, "requires": { "glob": "^7.1.3" @@ -6356,36 +6697,43 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, + "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", "bundled": true, + "dev": true, "optional": true }, "sax": { "version": "1.2.4", "bundled": true, + "dev": true, "optional": true }, "semver": { "version": "5.7.0", "bundled": true, + "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", "bundled": true, + "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", "bundled": true, + "dev": true, "optional": true }, "string-width": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true, "requires": { "code-point-at": "^1.0.0", @@ -6396,6 +6744,7 @@ "string_decoder": { "version": "1.1.1", "bundled": true, + "dev": true, "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -6404,6 +6753,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "dev": true, "optional": true, "requires": { "ansi-regex": "^2.0.0" @@ -6412,11 +6762,13 @@ "strip-json-comments": { "version": "2.0.1", "bundled": true, + "dev": true, "optional": true }, "tar": { "version": "4.4.8", "bundled": true, + "dev": true, "optional": true, "requires": { "chownr": "^1.1.1", @@ -6431,11 +6783,13 @@ "util-deprecate": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "wide-align": { "version": "1.1.3", "bundled": true, + "dev": true, "optional": true, "requires": { "string-width": "^1.0.2 || 2" @@ -6444,11 +6798,13 @@ "wrappy": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, + "dev": true, "optional": true } } @@ -6672,9 +7028,10 @@ "dev": true }, "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, "requires": { "pump": "^3.0.0" } @@ -6810,6 +7167,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, "requires": { "is-glob": "^3.1.0", "path-dirname": "^1.0.0" @@ -6819,6 +7177,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, "requires": { "is-extglob": "^2.1.0" } @@ -6876,28 +7235,55 @@ "dev": true }, "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" }, "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "ignore": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.2.tgz", + "integrity": "sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" } } }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true }, "growly": { "version": "1.3.0", @@ -6967,7 +7353,8 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "has-symbols": { "version": "1.0.0", @@ -7291,6 +7678,21 @@ "slash": "^3.0.0" }, "dependencies": { + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -7301,6 +7703,15 @@ "path-exists": "^4.0.0" } }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -7310,6 +7721,21 @@ "p-locate": "^4.1.0" } }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, "p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", @@ -7433,12 +7859,52 @@ } }, "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + } } }, "imurmurhash": { @@ -7597,11 +8063,11 @@ "dev": true }, "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "^2.0.0" } }, "is-buffer": { @@ -7911,6 +8377,17 @@ "istanbul-lib-coverage": "^2.0.5", "make-dir": "^2.1.0", "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "istanbul-lib-source-maps": { @@ -7962,26 +8439,6 @@ "jest-cli": "^24.9.0" }, "dependencies": { - "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@types/yargs": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.2.tgz", - "integrity": "sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", @@ -8005,6 +8462,16 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, "jest-cli": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", @@ -8026,42 +8493,29 @@ "yargs": "^13.3.0" } }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", - "dev": true - }, - "jest-validate": { + "jest-config": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", "dev": true, "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", + "babel-jest": "^24.9.0", "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" } }, "require-main-filename": { @@ -8070,6 +8524,15 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -8103,154 +8566,30 @@ }, "yargs": { "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "jest-changed-files": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", - "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "execa": "^1.0.0", - "throat": "^4.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@types/yargs": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.2.tgz", - "integrity": "sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", - "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^24.9.0", - "@jest/types": "^24.9.0", - "babel-jest": "^24.9.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^24.9.0", - "jest-environment-node": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "micromatch": "^3.1.10", - "pretty-format": "^24.9.0", - "realpath-native": "^1.1.0" - }, - "dependencies": { - "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@types/yargs": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.2.tgz", - "integrity": "sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", - "dev": true - }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", "dev": true, "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" } }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", "dev": true, "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } @@ -8902,6 +9241,31 @@ "requires": { "@types/yargs-parser": "*" } + }, + "jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" + } } } }, @@ -8979,6 +9343,31 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" + } + }, "jest-get-type": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", @@ -9264,6 +9653,17 @@ "requires": { "merge-stream": "^2.0.0", "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "jquery": { @@ -10193,10 +10593,9 @@ "dev": true }, "merge2": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.4.tgz", - "integrity": "sha512-FYE8xI+6pjFOhokZu0We3S5NKCirLbCzSh2Usf3qEyr4X8U+0jNg9P8RZ4qz+V2UoECLVwSyzU3LxXBaLGtD3A==", - "dev": true + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", + "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==" }, "methods": { "version": "1.1.2", @@ -10395,6 +10794,7 @@ "version": "2.14.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, "optional": true }, "nanomatch": { @@ -10583,11 +10983,20 @@ } }, "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", + "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", + "dev": true, "requires": { - "path-key": "^2.0.0" + "path-key": "^3.0.0" + }, + "dependencies": { + "path-key": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", + "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==", + "dev": true + } } }, "nth-check": { @@ -10625,7 +11034,8 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "object-copy": { "version": "0.1.0", @@ -10754,20 +11164,20 @@ } } }, + "open": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.3.0.tgz", + "integrity": "sha512-6AHdrJxPvAXIowO/aIaeHZ8CeMdDf7qCyRNq8NwJpinmCdXhz+NZR7ie1Too94lpciCDsG+qHGO9Mt0svA4OqA==", + "requires": { + "is-wsl": "^1.1.0" + } + }, "opencollective-postinstall": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", "dev": true }, - "opn": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", - "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", - "requires": { - "is-wsl": "^1.1.0" - } - }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -10822,6 +11232,43 @@ "execa": "^1.0.0", "lcid": "^2.0.0", "mem": "^4.0.0" + }, + "dependencies": { + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "^2.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + } } }, "os-tmpdir": { @@ -10856,9 +11303,10 @@ } }, "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", + "dev": true }, "p-is-promise": { "version": "2.1.0", @@ -10893,10 +11341,11 @@ "dev": true }, "p-retry": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", - "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.1.0.tgz", + "integrity": "sha512-oepllyG9gX1qH4Sm20YAKxg1GA7L7puhvGnTfimi31P07zSIj7SDV6YtuAx9nbJF51DES+2CIIRkXs8GKqWJxA==", "requires": { + "@types/retry": "^0.12.0", "retry": "^0.12.0" } }, @@ -11001,7 +11450,8 @@ "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true }, "path-exists": { "version": "3.0.0", @@ -11079,8 +11529,7 @@ "picomatch": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", - "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", - "dev": true + "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==" }, "pidtree": { "version": "0.3.0", @@ -11091,17 +11540,20 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, "requires": { "pinkie": "^2.0.0" } @@ -11119,6 +11571,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, "requires": { "find-up": "^3.0.0" } @@ -11179,6 +11632,15 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, @@ -11437,6 +11899,15 @@ "requires": { "glob": "^7.1.3" } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } } } }, @@ -11602,13 +12073,11 @@ } }, "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.1.2.tgz", + "integrity": "sha512-8rhl0xs2cxfVsqzreYCvs8EwBfn/DhVdqtoLmw19uI3SC5avYX9teCurlErfpPXGmYtMHReGaP2RsLnFvz/lnw==", "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "picomatch": "^2.0.4" } }, "realpath-native": { @@ -11747,7 +12216,8 @@ "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true }, "renderkid": { "version": "2.0.3", @@ -11878,11 +12348,18 @@ } }, "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "requires": { - "resolve-from": "^3.0.0" + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } } }, "resolve-dir": { @@ -11911,7 +12388,8 @@ "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true }, "resolve-global": { "version": "1.0.0", @@ -11950,8 +12428,7 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, "rimraf": { "version": "3.0.0", @@ -11996,8 +12473,7 @@ "run-parallel": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" }, "run-queue": { "version": "1.0.3", @@ -12052,11 +12528,50 @@ "walker": "~1.0.5" }, "dependencies": { + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true } } }, @@ -13098,11 +13613,18 @@ } }, "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.0.0.tgz", + "integrity": "sha512-WRt32iTpYEZWYOpcetGm0NPeSvaebccx7hhS/5M6sAiqnhedtFCHFxkjzZlJvFNCPowiKSFGiZk5USQDFy83vQ==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + } } }, "symbol-observable": { @@ -13629,9 +14151,10 @@ } }, "upath": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", - "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true }, "upper-case": { "version": "1.1.3", @@ -13669,21 +14192,49 @@ } }, "url-loader": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", - "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-2.1.0.tgz", + "integrity": "sha512-kVrp/8VfEm5fUt+fl2E0FQyrpmOYgMEkBsv8+UDP1wFhszECq5JyGF33I7cajlVY90zRZ6MyfgKXngLvHYZX8A==", "dev": true, "requires": { - "loader-utils": "^1.1.0", - "mime": "^2.0.3", - "schema-utils": "^1.0.0" + "loader-utils": "^1.2.3", + "mime": "^2.4.4", + "schema-utils": "^2.0.0" }, "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, "mime": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.3.tgz", - "integrity": "sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", "dev": true + }, + "schema-utils": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.2.0.tgz", + "integrity": "sha512-5EwsCNhfFTZvUreQhx/4vVQpJ/lnCAkgoIHLhSpp4ZirE+4hzFvdJi0FMub6hxbFVBJYSpeVVmon+2e7uEGRrA==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } } } }, @@ -13806,6 +14357,54 @@ "chokidar": "^2.0.2", "graceful-fs": "^4.1.2", "neo-async": "^2.5.0" + }, + "dependencies": { + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + } } }, "wbuf": { @@ -13931,12 +14530,31 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -13957,6 +14575,15 @@ "ansi-regex": "^4.1.0" } }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, "v8-compile-cache": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", @@ -14174,11 +14801,11 @@ } }, "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.1.2.tgz", + "integrity": "sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg==", "requires": { - "async-limiter": "~1.0.0" + "async-limiter": "^1.0.0" } }, "xml": { diff --git a/package.json b/package.json index acc642de21..ea094b14c3 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "client" ], "engines": { - "node": ">= 6.11.5" + "node": ">= 8.9.0" }, "scripts": { "lint:prettier": "prettier \"{**/*,*}.{js,json,md,yml,css}\" --list-different", @@ -38,22 +38,22 @@ "dependencies": { "ansi-html": "0.0.7", "bonjour": "^3.5.0", - "chokidar": "^2.1.8", + "chokidar": "^3.0.1", "compression": "^1.7.4", "connect-history-api-fallback": "^1.6.0", "debug": "^4.1.1", - "del": "^4.1.1", + "del": "^5.0.0", "express": "^4.17.1", "html-entities": "^1.2.1", "http-proxy-middleware": "^0.19.1", - "import-local": "^2.0.0", + "import-local": "^3.0.2", "internal-ip": "^4.3.0", "ip": "^1.1.5", "is-absolute-url": "^3.0.1", "killable": "^1.0.1", "loglevel": "^1.6.4", - "opn": "^5.5.0", - "p-retry": "^3.0.1", + "open": "^6.2.0", + "p-retry": "^4.1.0", "portfinder": "^1.0.24", "schema-utils": "^1.0.0", "selfsigned": "^1.10.6", @@ -63,11 +63,11 @@ "sockjs-client": "1.4.0", "spdy": "^4.0.1", "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", + "supports-color": "^7.0.0", "url": "^0.11.0", "webpack-dev-middleware": "^3.7.1", "webpack-log": "^2.0.0", - "ws": "^6.2.1", + "ws": "^7.1.1", "yargs": "12.0.5" }, "devDependencies": { @@ -87,8 +87,8 @@ "eslint-config-prettier": "^6.1.0", "eslint-config-webpack": "^1.2.5", "eslint-plugin-import": "^2.18.2", - "execa": "^1.0.0", - "file-loader": "^3.0.1", + "execa": "^2.0.3", + "file-loader": "^4.0.0", "html-loader": "^0.5.5", "html-webpack-plugin": "^3.2.0", "husky": "^3.0.5", @@ -109,7 +109,7 @@ "supertest": "^4.0.2", "tcp-port-used": "^1.0.1", "typescript": "^3.6.2", - "url-loader": "^1.1.2", + "url-loader": "^2.1.0", "webpack": "^4.39.3", "webpack-cli": "^3.3.8" }, diff --git a/test/cli/cli.test.js b/test/cli/cli.test.js index 372a21afef..72a5443ad6 100644 --- a/test/cli/cli.test.js +++ b/test/cli/cli.test.js @@ -1,9 +1,15 @@ +/** + * @jest-environment node + */ + 'use strict'; -const { unlink } = require('fs'); const { join, resolve } = require('path'); const execa = require('execa'); +const { unlinkAsync } = require('../helpers/fs'); const testBin = require('../helpers/test-bin'); +const timer = require('../helpers/timer'); +const { skipTestOnWindows } = require('../helpers/conditional-test'); const httpsCertificateDirectory = resolve( __dirname, @@ -15,134 +21,131 @@ const keyPath = resolve(httpsCertificateDirectory, 'server.key'); const certPath = resolve(httpsCertificateDirectory, 'server.crt'); describe('CLI', () => { - it('--progress', (done) => { - testBin('--progress') - .then((output) => { - expect(output.code).toEqual(0); - expect(output.stderr.includes('0% compiling')).toBe(true); - // should not profile - expect( - output.stderr.includes('ms after chunk modules optimization') - ).toBe(false); - done(); - }) - .catch(done); + it('--progress', async () => { + const { exitCode, stderr } = await testBin('--progress'); + expect(exitCode).toEqual(0); + expect(stderr.includes('0% compiling')).toBe(true); }); - it('--progress --profile', (done) => { - testBin('--progress --profile') - .then((output) => { - expect(output.code).toEqual(0); - // should profile - expect(output.stderr.includes('after chunk modules optimization')).toBe( - true - ); - done(); - }) - .catch(done); + it('--progress --profile', async () => { + const { exitCode, stderr } = await testBin('--progress --profile'); + expect(exitCode).toEqual(0); + // should profile + expect(stderr.includes('after chunk modules optimization')).toBe(true); }); - it('--bonjour', (done) => { - testBin('--bonjour') - .then((output) => { - expect(output.code).toEqual(0); - expect(output.stdout.includes('Bonjour')).toBe(true); - done(); - }) - .catch(done); + it('--bonjour', async () => { + const { exitCode, stdout } = await testBin('--bonjour'); + expect(exitCode).toEqual(0); + expect(stdout.includes('Bonjour')).toBe(true); }); - it('--https', (done) => { - testBin('--https') - .then((output) => { - expect(output.code).toEqual(0); - expect(output.stdout.includes('Project is running at')).toBe(true); - done(); - }) - .catch(done); + it('--https', async () => { + const { exitCode, stdout } = await testBin('--https'); + expect(exitCode).toEqual(0); + expect(stdout.includes('Project is running at')).toBe(true); }); - it('--https --cacert --pfx --key --cert --pfx-passphrase', (done) => { - testBin( + it('--https --cacert --pfx --key --cert --pfx-passphrase', async () => { + const { exitCode, stdout } = await testBin( `--https --cacert ${caPath} --pfx ${pfxPath} --key ${keyPath} --cert ${certPath} --pfx-passphrase webpack-dev-server` - ) - .then((output) => { - expect(output.code).toEqual(0); - expect(output.stdout.includes('Project is running at')).toBe(true); - done(); - }) - .catch(done); + ); + expect(exitCode).toEqual(0); + expect(stdout.includes('Project is running at')).toBe(true); }); - it('--sockPath', (done) => { - testBin('--sockPath /mysockPath') - .then((output) => { - expect( - /http:\/\/localhost:[0-9]+&sockPath=\/mysockPath/.test(output.stdout) - ).toEqual(true); - done(); - }) - .catch(done); + it('--sockPath', async () => { + const { stdout } = await testBin('--sockPath /mysockPath'); + expect( + /http:\/\/localhost:[0-9]+&sockPath=\/mysockPath/.test(stdout) + ).toEqual(true); }); - it('unspecified port', (done) => { - testBin('') - .then((output) => { - expect(/http:\/\/localhost:[0-9]+/.test(output.stdout)).toEqual(true); - done(); - }) - .catch(done); + it('unspecified port', async () => { + const { stdout } = await testBin(''); + expect(/http:\/\/localhost:[0-9]+/.test(stdout)).toEqual(true); }); - it('--color', (done) => { - testBin('--color') - .then((output) => { - // https://github.com/webpack/webpack-dev-server/blob/master/lib/utils/colors.js - expect( - output.stdout.includes('\u001b[39m \u001b[90mï½¢wdsï½£\u001b[39m:') - ).toEqual(true); - done(); - }) - .catch(done); + it('--color', async () => { + const { stdout } = await testBin('--color'); + // https://github.com/webpack/webpack-dev-server/blob/master/lib/utils/colors.js + expect(stdout.includes('\u001b[39m \u001b[90mï½¢wdsï½£\u001b[39m:')).toBe(true); }); - // The Unix socket to listen to (instead of a host). - it('--socket', (done) => { - const socketPath = join('.', 'webpack.sock'); - - testBin(`--socket ${socketPath}`) - .then((output) => { - expect(output.code).toEqual(0); - - if (process.platform === 'win32') { - done(); - } else { - expect(output.stdout.includes(socketPath)).toBe(true); - - unlink(socketPath, () => { - done(); - }); - } - }) - .catch(done); + describe('Unix socket', () => { + if (skipTestOnWindows('Unix sockets are not supported on Windows')) { + return; + } + + // The Unix socket to listen to (instead of a host). + it('--socket', async () => { + const socketPath = join('.', 'webpack.sock'); + + const { exitCode, stdout } = await testBin(`--socket ${socketPath}`); + expect(exitCode).toEqual(0); + + if (process.platform !== 'win32') { + expect(stdout.includes(socketPath)).toBe(true); + + await unlinkAsync(socketPath); + } + }); }); - it('should accept the promise function of webpack.config.js', (done) => { - testBin( - false, - resolve(__dirname, '../fixtures/promise-config/webpack.config.js') - ) - .then((output) => { - expect(output.code).toEqual(0); - done(); - }) - .catch((err) => { - // for windows - expect(err.stdout.includes('Compiled successfully.')).toEqual(true); - done(); - }); + it('without --stdin, with stdin "end" event should time out', async (done) => { + const configPath = resolve( + __dirname, + '../fixtures/simple-config/webpack.config.js' + ); + const childProcess = testBin(false, configPath, true); + + childProcess.once('exit', () => { + expect(childProcess.killed).toBeTruthy(); + done(); + }); + + await timer(500); + // this is meant to confirm that it does not have any effect on the running process + // since options.stdin is not enabled + childProcess.stdin.emit('end'); + childProcess.stdin.pause(); + + await timer(500); + + childProcess.kill(); + }); + + it('--stdin, with "end" event should exit without time out', async () => { + const configPath = resolve( + __dirname, + '../fixtures/simple-config/webpack.config.js' + ); + const childProcess = testBin('--stdin', configPath); + + await timer(500); + + childProcess.stdin.emit('end'); + childProcess.stdin.pause(); + + const { exitCode, timedOut, killed } = await childProcess; + expect(exitCode).toEqual(0); + expect(timedOut).toBeFalsy(); + expect(killed).toBeFalsy(); + }); + + it('should accept the promise function of webpack.config.js', async () => { + try { + const { exitCode } = await testBin( + false, + resolve(__dirname, '../fixtures/promise-config/webpack.config.js') + ); + expect(exitCode).toEqual(0); + } catch (err) { + expect(err.stdout.includes('Compiled successfully.')).toBe(true); + } }); + // TODO: hiroppy it('should exit the process when SIGINT is detected', (done) => { const cliPath = resolve(__dirname, '../../bin/webpack-dev-server.js'); const examplePath = resolve(__dirname, '../../examples/cli/public'); diff --git a/test/client/clients/SockJSClient.test.js b/test/client/clients/SockJSClient.test.js index d6c1ec4745..02009a4512 100644 --- a/test/client/clients/SockJSClient.test.js +++ b/test/client/clients/SockJSClient.test.js @@ -4,6 +4,7 @@ const http = require('http'); const express = require('express'); const sockjs = require('sockjs'); const SockJSClient = require('../../../client-src/clients/SockJSClient'); +const timer = require('../../helpers/timer'); const port = require('../../ports-map').sockJSClient; describe('SockJSClient', () => { @@ -32,13 +33,12 @@ describe('SockJSClient', () => { }); describe('client', () => { - it('should open, receive message, and close', (done) => { - socketServer.on('connection', (connection) => { + it('should open, receive message, and close', async () => { + socketServer.on('connection', async (connection) => { connection.write('hello world'); - setTimeout(() => { - connection.close(); - }, 1000); + await timer(1000); + connection.close(); }); const client = new SockJSClient(`http://localhost:${port}/sockjs-node`); @@ -54,16 +54,13 @@ describe('SockJSClient', () => { data.push(msg); }); - setTimeout(() => { - expect(data).toMatchSnapshot(); - done(); - }, 3000); + await timer(3000); + + expect(data).toMatchSnapshot(); }); }); afterAll((done) => { - listeningApp.close(() => { - done(); - }); + listeningApp.close(done); }); }); diff --git a/test/client/index.test.js b/test/client/index.test.js index 72eb8a63cd..20d99df19f 100644 --- a/test/client/index.test.js +++ b/test/client/index.test.js @@ -3,7 +3,6 @@ /* eslint-disable no-undefined */ -/* global self */ describe('index', () => { let log; diff --git a/test/client/socket-helper.test.js b/test/client/socket-helper.test.js index a40007aa49..b8074cebd5 100644 --- a/test/client/socket-helper.test.js +++ b/test/client/socket-helper.test.js @@ -8,7 +8,7 @@ describe('socket', () => { it('should default to SockJSClient when no __webpack_dev_server_client__ set', () => { jest.mock('../../client/clients/SockJSClient'); - const socket = require('../../client/socket'); + const { default: socket } = require('../../client/socket'); const SockJSClient = require('../../client/clients/SockJSClient'); const mockHandler = jest.fn(); @@ -36,7 +36,7 @@ describe('socket', () => { it('should use __webpack_dev_server_client__ when set', () => { jest.mock('../../client/clients/SockJSClient'); - const socket = require('../../client/socket'); + const { default: socket } = require('../../client/socket'); global.__webpack_dev_server_client__ = require('../../client/clients/SockJSClient'); const mockHandler = jest.fn(); diff --git a/test/client/utils/__snapshots__/log.test.js.snap b/test/client/utils/__snapshots__/log.test.js.snap index a62894e923..8f120617a2 100644 --- a/test/client/utils/__snapshots__/log.test.js.snap +++ b/test/client/utils/__snapshots__/log.test.js.snap @@ -19,8 +19,5 @@ Array [ Array [ "trace", ], - Array [ - "warn", - ], ] `; diff --git a/test/client/utils/createSocketUrl.test.js b/test/client/utils/createSocketUrl.test.js index 09a4cd6adc..b521242c76 100644 --- a/test/client/utils/createSocketUrl.test.js +++ b/test/client/utils/createSocketUrl.test.js @@ -21,7 +21,10 @@ describe('createSocketUrl', () => { () => () => url ); - const createSocketUrl = require('../../../client-src/default/utils/createSocketUrl'); + const { + default: createSocketUrl, + // eslint-disable-next-line global-require + } = require('../../../client-src/default/utils/createSocketUrl'); test(`should return the url when __resourceQuery is ${url}`, () => { expect(createSocketUrl(url)).toMatchSnapshot(); diff --git a/test/client/utils/getCurrentScriptSource.test.js b/test/client/utils/getCurrentScriptSource.test.js index 8fb953b1f3..b6c4f4d017 100644 --- a/test/client/utils/getCurrentScriptSource.test.js +++ b/test/client/utils/getCurrentScriptSource.test.js @@ -1,6 +1,8 @@ 'use strict'; -const getCurrentScriptSource = require('../../../client-src/default/utils/getCurrentScriptSource'); +const { + default: getCurrentScriptSource, +} = require('../../../client-src/default/utils/getCurrentScriptSource'); describe('getCurrentScriptSource', () => { afterEach(() => { diff --git a/test/client/utils/log.test.js b/test/client/utils/log.test.js index f1f857ae70..3165a5353d 100644 --- a/test/client/utils/log.test.js +++ b/test/client/utils/log.test.js @@ -33,7 +33,7 @@ describe('log', () => { }); test('should set log level via setLogLevel', () => { - ['info', 'warn', 'error', 'debug', 'trace', 'warning'].forEach((level) => { + ['info', 'warn', 'error', 'debug', 'trace'].forEach((level) => { setLogLevel(level); }); @@ -42,14 +42,12 @@ describe('log', () => { ).toMatchSnapshot(); }); - test('should set none and silent via setLogLevel', () => { - ['none', 'silent'].forEach((level) => { - setLogLevel(level); - }); + test('should set silent via setLogLevel', () => { + setLogLevel('silent'); expect( logMock.getLogger.mock.results[0].value.disableAll.mock.results - ).toHaveLength(2); + ).toHaveLength(1); }); test('should output exception log when the level is unknown', () => { diff --git a/test/client/utils/reloadApp.test.js b/test/client/utils/reloadApp.test.js index f2b39859db..84b346769b 100644 --- a/test/client/utils/reloadApp.test.js +++ b/test/client/utils/reloadApp.test.js @@ -1,7 +1,5 @@ 'use strict'; -/* global self */ - describe('reloadApp', () => { let reloadApp; let log; @@ -23,7 +21,8 @@ describe('reloadApp', () => { }; }); - reloadApp = require('../../../client-src/default/utils/reloadApp'); + // eslint-disable-next-line global-require + reloadApp = require('../../../client-src/default/utils/reloadApp').default; }); afterEach(() => { diff --git a/test/client/utils/sendMessage.test.js b/test/client/utils/sendMessage.test.js index a60f2548bc..e13b7b49c8 100644 --- a/test/client/utils/sendMessage.test.js +++ b/test/client/utils/sendMessage.test.js @@ -1,8 +1,8 @@ 'use strict'; -/* global self */ - -const sendMessage = require('../../../client-src/default/utils/sendMessage'); +const { + default: sendMessage, +} = require('../../../client-src/default/utils/sendMessage'); describe('sendMessage', () => { afterEach(() => { diff --git a/test/e2e/ClientOptions.test.js b/test/e2e/ClientOptions.test.js index c1cd2fffe9..1d7f4aa6e8 100644 --- a/test/e2e/ClientOptions.test.js +++ b/test/e2e/ClientOptions.test.js @@ -50,19 +50,18 @@ describe('Client code', () => { }); afterAll((done) => { - proxy.close(() => { - done(); - }); - }); - - it('responds with a 200 on proxy port', (done) => { - const req = request(`http://localhost:${port2}`); - req.get('/sockjs-node').expect(200, 'Welcome to SockJS!\n', done); + proxy.close(done); }); - it('responds with a 200 on non-proxy port', (done) => { - const req = request(`http://localhost:${port1}`); - req.get('/sockjs-node').expect(200, 'Welcome to SockJS!\n', done); + it('responds with a 200', async () => { + { + const req = request(`http://localhost:${port2}`); + await req.get('/sockjs-node').expect(200, 'Welcome to SockJS!\n'); + } + { + const req = request(`http://localhost:${port1}`); + await req.get('/sockjs-node').expect(200, 'Welcome to SockJS!\n'); + } }); it('requests websocket through the proxy with proper port number', (done) => { @@ -296,47 +295,34 @@ describe('Client console.log', () => { }, ]; - cases.forEach(({ title, options }) => { - it(title, (done) => { + for (const { title, options } of cases) { + it(title, async () => { const res = []; const testOptions = Object.assign({}, baseOptions, options); - // TODO: use async/await when Node.js v6 support is dropped - Promise.resolve() - .then(() => { - return new Promise((resolve) => { - testServer.startAwaitingCompilation(config, testOptions, resolve); - }); - }) - .then(() => { - // make sure the previous Promise is not passing along strange arguments to runBrowser - return runBrowser(); - }) - .then(({ page, browser }) => { - return new Promise((resolve) => { - page.goto(`http://localhost:${port2}/main`); - page.on('console', ({ _text }) => { - res.push(_text); - }); - // wait for load before closing the browser - page.waitForNavigation({ waitUntil: 'load' }).then(() => { - page.waitFor(beforeBrowserCloseDelay).then(() => { - browser.close().then(() => { - resolve(); - }); - }); - }); - }); - }) - .then(() => { - return new Promise((resolve) => { - testServer.close(resolve); - }); - }) - .then(() => { - expect(res).toMatchSnapshot(); - done(); - }); + // TODO: refactor(hiroppy) + await new Promise((resolve) => { + testServer.startAwaitingCompilation(config, testOptions, resolve); + }); + + const { page, browser } = await runBrowser(); + + page.goto(`http://localhost:${port2}/main`); + page.on('console', ({ _text }) => { + res.push(_text); + }); + + // wait for load before closing the browser + await page.waitForNavigation({ waitUntil: 'load' }); + await page.waitFor(beforeBrowserCloseDelay); + await browser.close(); + + expect(res).toMatchSnapshot(); + + // TODO: refactor(hiroppy) + await new Promise((resolve) => { + testServer.close(resolve); + }); }); - }); + } }); diff --git a/test/helpers/fs.js b/test/helpers/fs.js new file mode 100644 index 0000000000..d715846748 --- /dev/null +++ b/test/helpers/fs.js @@ -0,0 +1,15 @@ +// we'll delete this file when Node8 is not supported. +// because we can use fs.promise + +'use strict'; + +const { promisify } = require('util'); +const { writeFile, unlink } = require('fs'); + +const unlinkAsync = promisify(unlink); +const writeAsync = promisify(writeFile); + +module.exports = { + unlinkAsync, + writeAsync, +}; diff --git a/test/helpers/run-browser.js b/test/helpers/run-browser.js index 74f63652c3..688b847db3 100644 --- a/test/helpers/run-browser.js +++ b/test/helpers/run-browser.js @@ -3,7 +3,7 @@ const puppeteer = require('puppeteer'); const { puppeteerArgs } = require('./puppeteer-constants'); -function runBrowser(config) { +async function runBrowser(config) { const options = { viewport: { width: 500, @@ -13,27 +13,16 @@ function runBrowser(config) { ...config, }; - return new Promise((resolve, reject) => { - let page; - let browser; - - puppeteer - .launch({ - headless: true, - // args come from: https://github.com/alixaxel/chrome-aws-lambda/blob/master/source/index.js - args: puppeteerArgs, - }) - .then((launchedBrowser) => { - browser = launchedBrowser; - return browser.newPage(); - }) - .then((newPage) => { - page = newPage; - page.emulate(options); - resolve({ page, browser }); - }) - .catch(reject); + const launchedBrowser = await puppeteer.launch({ + headless: true, + // args come from: https://github.com/alixaxel/chrome-aws-lambda/blob/master/source/index.js + args: puppeteerArgs, }); + const browser = launchedBrowser; + const page = await browser.newPage(); + page.emulate(options); + + return { page, browser }; } module.exports = runBrowser; diff --git a/test/helpers/test-bin.js b/test/helpers/test-bin.js index 25e3af020a..39f38f0b16 100644 --- a/test/helpers/test-bin.js +++ b/test/helpers/test-bin.js @@ -1,6 +1,7 @@ 'use strict'; const path = require('path'); +const { spawn } = require('child_process'); const execa = require('execa'); const webpackDevServerPath = path.resolve( @@ -12,9 +13,12 @@ const basicConfigPath = path.resolve( '../fixtures/cli/webpack.config.js' ); -function testBin(testArgs, configPath) { +function testBin(testArgs, configPath, useSpawn) { const cwd = process.cwd(); - const env = process.env.NODE_ENV; + const env = { + NODE_ENV: process.env.NODE_ENV, + PATH: process.env.PATH, + }; if (!configPath) { configPath = basicConfigPath; @@ -28,7 +32,16 @@ function testBin(testArgs, configPath) { const args = [webpackDevServerPath, '--config', configPath].concat(testArgs); - return execa('node', args, { cwd, env, timeout: 10000 }); + const opts = { cwd, env, timeout: 10000 }; + let execLib = execa; + // use Node's spawn as a workaround for execa issues + // https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options + if (useSpawn) { + execLib = spawn; + delete opts.timeout; + } + + return execLib('node', args, opts); } module.exports = testBin; diff --git a/test/helpers/test-server.js b/test/helpers/test-server.js index f9284c4fca..85de3777f7 100644 --- a/test/helpers/test-server.js +++ b/test/helpers/test-server.js @@ -40,9 +40,19 @@ function startFullSetup(config, options, done) { server = new Server(compiler, options); - const port = Object.prototype.hasOwnProperty.call(options, 'port') - ? options.port - : 8080; + // originally the fallback default was 8080, but it should be + // undefined so that the server.listen method can choose it for us, + // and thus prevent port mapping collision between tests + let port; + if (Object.prototype.hasOwnProperty.call(options, 'port')) { + port = options.port; + } else if (Object.prototype.hasOwnProperty.call(options, 'socket')) { + port = options.socket; + } else { + // TODO: remove this when findPort is implemented in the server.listen method + port = 8080; + } + const host = Object.prototype.hasOwnProperty.call(options, 'host') ? options.host : 'localhost'; @@ -65,10 +75,12 @@ function startFullSetup(config, options, done) { function startAwaitingCompilationFullSetup(config, options, done) { let readyCount = 0; - const ready = () => { + let err; + const ready = (e) => { + err = e instanceof Error || (typeof e === 'object' && e.code) ? e : err; readyCount += 1; if (readyCount === 2) { - done(); + done(err); } }; diff --git a/test/helpers/test-unix-socket.js b/test/helpers/test-unix-socket.js new file mode 100644 index 0000000000..d2c504b62f --- /dev/null +++ b/test/helpers/test-unix-socket.js @@ -0,0 +1,30 @@ +'use strict'; + +const http = require('http'); + +const TestUnixSocket = class TestUnixSocket { + constructor() { + this.server = http.createServer(); + this.sockets = new Set(); + this.server.on('connection', (socket) => { + this.sockets.add(socket); + socket.on('close', () => { + this.sockets.delete(socket); + }); + }); + } + + close(done) { + if (this.server.listening) { + // get rid of connected sockets + for (const socket of this.sockets.values()) { + socket.destroy(); + } + this.server.close(done); + } else { + done(); + } + } +}; + +module.exports = TestUnixSocket; diff --git a/test/helpers/timer.js b/test/helpers/timer.js new file mode 100644 index 0000000000..0608301ec8 --- /dev/null +++ b/test/helpers/timer.js @@ -0,0 +1,11 @@ +'use strict'; + +function timer(t) { + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, t); + }); +} + +module.exports = timer; diff --git a/test/integration/MultiCompiler.test.js b/test/integration/MultiCompiler.test.js index 5d9cc9c15b..d35fe9ba78 100644 --- a/test/integration/MultiCompiler.test.js +++ b/test/integration/MultiCompiler.test.js @@ -17,10 +17,10 @@ describe('multi compiler', () => { afterAll(testServer.close); // TODO: this is a very basic test, optimally it should test multiple configs etc. - it('should handle GET request to bundle', (done) => { - req + it('should handle GET request to bundle', async () => { + await req .get('/main.js') .expect('Content-Type', 'application/javascript; charset=UTF-8') - .expect(200, done); + .expect(200); }); }); diff --git a/test/integration/UniversalCompiler.test.js b/test/integration/UniversalCompiler.test.js index 81225c3ad1..3ae2c3bd7a 100644 --- a/test/integration/UniversalCompiler.test.js +++ b/test/integration/UniversalCompiler.test.js @@ -16,35 +16,33 @@ describe('universal compiler', () => { afterAll(testServer.close); - it('client bundle should have the inlined the client runtime', (done) => { - req + it('client bundle should have the inlined the client runtime', async () => { + const { res, err } = await req .get('/client.js') .expect('Content-Type', 'application/javascript; charset=UTF-8') - .expect(200) - .end((err, res) => { - if (err) { - return done(err); - } - expect(res.text).toContain('Hello from the client'); - expect(res.text).toContain('sockjs-client'); - done(); - }); + .expect(200); + + if (err) { + throw err; + } + + expect(res.text).toContain('Hello from the client'); + expect(res.text).toContain('sockjs-client'); }); - it('server bundle should NOT have the inlined the client runtime', (done) => { + it('server bundle should NOT have the inlined the client runtime', async () => { // we wouldn't normally request a server bundle // but we'll do it here to check the contents - req + const { res, err } = await req .get('/server.js') .expect('Content-Type', 'application/javascript; charset=UTF-8') - .expect(200) - .end((err, res) => { - if (err) { - return done(err); - } - expect(res.text).toContain('Hello from the server'); - expect(res.text).not.toContain('sockjs-client'); - done(); - }); + .expect(200); + + if (err) { + throw err; + } + + expect(res.text).toContain('Hello from the server'); + expect(res.text).not.toContain('sockjs-client'); }); }); diff --git a/test/options.test.js b/test/options.test.js index 409dc07bec..8f41f4b65f 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -26,82 +26,14 @@ describe('options', () => { const properties = Object.keys(options.properties); const messages = Object.keys(options.errorMessage.properties); - expect(properties.length).toEqual(messages.length); + expect(properties).toEqual(messages); const res = properties.every((name) => messages.includes(name)); expect(res).toEqual(true); }); - describe('validation', () => { - let server; - - afterAll((done) => { - if (server) { - server.close(() => { - done(); - }); - } - }); - - function validateOption(propertyName, cases) { - const successCount = cases.success.length; - const testCases = []; - - for (const key of Object.keys(cases)) { - testCases.push(...cases[key]); - } - - let current = 0; - - return testCases.reduce((p, value) => { - let compiler = webpack(config); - - return p - .then(() => { - const opts = - Object.prototype.toString.call(value) === '[object Object]' && - Object.keys(value).length !== 0 - ? value - : { - [propertyName]: value, - }; - - server = new Server(compiler, opts); - }) - .then(() => { - if (current < successCount) { - expect(true).toBeTruthy(); - } else { - expect(false).toBeTruthy(); - } - }) - .catch((err) => { - if (current >= successCount) { - expect(err).toBeInstanceOf(ValidationError); - } else { - expect(false).toBeTruthy(); - } - }) - .then(() => { - return new Promise((resolve) => { - if (server) { - server.close(() => { - compiler = null; - server = null; - resolve(); - }); - } else { - resolve(); - } - }); - }) - .then(() => { - current += 1; - }); - }, Promise.resolve()); - } - + { const memfs = createFsFromVolume(new Volume()); // We need to patch memfs // https://github.com/webpack/webpack-dev-middleware#fs @@ -133,19 +65,8 @@ describe('options', () => { failure: [false], }, clientLogLevel: { - success: [ - 'silent', - 'info', - 'error', - 'warn', - 'trace', - 'debug', - // deprecated - 'none', - // deprecated - 'warning', - ], - failure: ['whoops!'], + success: ['silent', 'info', 'error', 'warn', 'trace', 'debug'], + failure: ['whoops!', 'none', 'warning'], }, compress: { success: [true], @@ -454,6 +375,10 @@ describe('options', () => { }, ], }, + stdin: { + success: [false], + failure: [''], + }, useLocalIp: { success: [false], failure: [''], @@ -476,10 +401,58 @@ describe('options', () => { }, }; - Object.keys(cases).forEach((key) => { - it(key, () => { - return validateOption(key, cases[key]); + for (const [key, values] of Object.entries(cases)) { + it(`should validate "${key}" option`, async () => { + const compiler = webpack(config); + const { success, failure } = values; + + for (const sample of success) { + let server; + + try { + server = new Server(compiler, createOptions(key, sample)); + expect(true).toBeTruthy(); + } catch (e) { + expect(false).toBeTruthy(); + } + + // eslint-disable-next-line no-await-in-loop + await closeServer(server); + } + + for (const sample of failure) { + let server; + + try { + server = new Server(compiler, createOptions(key, sample)); + expect(false).toBeTruthy(); + } catch (e) { + expect(e).toBeInstanceOf(ValidationError); + } + + // eslint-disable-next-line no-await-in-loop + await closeServer(server); + } }); + } + } + + function createOptions(key, value) { + return Object.prototype.toString.call(value) === '[object Object]' && + Object.keys(value).length !== 0 + ? value + : { + [key]: value, + }; + } + + async function closeServer(server) { + await new Promise((resolve) => { + if (server) { + server.close(resolve); + } else { + resolve(); + } }); - }); + } }); diff --git a/test/ports-map.js b/test/ports-map.js index ac73aaa142..07ebee36a0 100644 --- a/test/ports-map.js +++ b/test/ports-map.js @@ -43,14 +43,13 @@ const portsList = { 'progress-option': 1, 'profile-option': 1, Iframe: 1, + 'stdin-option': 1, }; let startPort = 8089; const ports = {}; -Object.keys(portsList).forEach((key) => { - const value = portsList[key]; - +Object.entries(portsList).forEach(([key, value]) => { ports[key] = value === 1 ? (startPort += 1) diff --git a/test/server/__snapshots__/transportMode-option.test.js.snap b/test/server/__snapshots__/transportMode-option.test.js.snap index 0a07287ada..baf012714c 100644 --- a/test/server/__snapshots__/transportMode-option.test.js.snap +++ b/test/server/__snapshots__/transportMode-option.test.js.snap @@ -87,7 +87,7 @@ Array [ Object { "foo": "bar", }, - "{\\"type\\":\\"liveReload\\"}", + "{\\"type\\":\\"liveReload\\",\\"data\\":true}", ] `; diff --git a/test/server/after-option.test.js b/test/server/after-option.test.js index b9d57616d0..07e7fd5545 100644 --- a/test/server/after-option.test.js +++ b/test/server/after-option.test.js @@ -39,13 +39,12 @@ describe('after option', () => { afterAll(testServer.close); - it('should handle after route', () => { - return req + it('should handle after route', async () => { + const res = await req .get('/after/some/path') .expect('Content-Type', 'text/html; charset=utf-8') - .expect(200) - .then((response) => { - expect(response.text).toBe('after'); - }); + .expect(200); + + expect(res.text).toBe('after'); }); }); diff --git a/test/server/before-option.test.js b/test/server/before-option.test.js index 3da0ecfd54..4e831133c2 100644 --- a/test/server/before-option.test.js +++ b/test/server/before-option.test.js @@ -39,13 +39,12 @@ describe('before option', () => { afterAll(testServer.close); - it('should handle before route', () => { - return req + it('should handle before route', async () => { + const res = await req .get('/before/some/path') .expect('Content-Type', 'text/html; charset=utf-8') - .expect(200) - .then((response) => { - expect(response.text).toBe('before'); - }); + .expect(200); + + expect(res.text).toBe('before'); }); }); diff --git a/test/server/compress-option.test.js b/test/server/compress-option.test.js index 0a04d1466f..644d40356f 100644 --- a/test/server/compress-option.test.js +++ b/test/server/compress-option.test.js @@ -22,15 +22,15 @@ describe('compress option', () => { afterAll(testServer.close); - it('request to bundle file', (done) => { - req + it('request to bundle file', async () => { + await req .get('/main.js') .expect((res) => { if (res.header['content-encoding']) { throw new Error('Expected `content-encoding` header is undefined.'); } }) - .expect(200, done); + .expect(200); }); }); @@ -49,11 +49,11 @@ describe('compress option', () => { afterAll(testServer.close); - it('request to bundle file', (done) => { - req + it('request to bundle file', async () => { + await req .get('/main.js') .expect('Content-Encoding', 'gzip') - .expect(200, done); + .expect(200); }); }); @@ -72,15 +72,15 @@ describe('compress option', () => { afterAll(testServer.close); - it('request to bundle file', (done) => { - req + it('request to bundle file', async () => { + await req .get('/main.js') .expect((res) => { if (res.header['content-encoding']) { throw new Error('Expected `content-encoding` header is undefined.'); } }) - .expect(200, done); + .expect(200); }); }); }); diff --git a/test/server/contentBase-option.test.js b/test/server/contentBase-option.test.js index 13acc53165..acaa46da02 100644 --- a/test/server/contentBase-option.test.js +++ b/test/server/contentBase-option.test.js @@ -37,19 +37,17 @@ describe('contentBase option', () => { }); afterAll((done) => { - testServer.close(() => { - done(); - }); + testServer.close(done); fs.truncateSync(nestedFile); }); - it('Request to index', (done) => { - req.get('/').expect(200, /Heyo/, done); + it('Request to index', async () => { + await req.get('/').expect(200, /Heyo/); }); - it('Request to other file', (done) => { - req.get('/other.html').expect(200, /Other html/, done); + it('Request to other file', async () => { + await req.get('/other.html').expect(200, /Other html/); }); it('Watches folder recursively', (done) => { @@ -108,12 +106,12 @@ describe('contentBase option', () => { }); }); - it("shouldn't list the files inside the assets folder (404)", (done) => { - req.get('/assets/').expect(404, done); + it("shouldn't list the files inside the assets folder (404)", async () => { + await req.get('/assets/').expect(404); }); - it('should show Heyo. because bar has index.html inside it (200)', (done) => { - req.get('/bar/').expect(200, /Heyo/, done); + it('should show Heyo. because bar has index.html inside it (200)', async () => { + await req.get('/bar/').expect(200, /Heyo/); }); }); @@ -133,17 +131,15 @@ describe('contentBase option', () => { }); afterAll((done) => { - testServer.close(() => { - done(); - }); + testServer.close(done); }); - it('should list the files inside the assets folder (200)', (done) => { - req.get('/assets/').expect(200, done); + it('should list the files inside the assets folder (200)', async () => { + await req.get('/assets/').expect(200); }); - it('should show Heyo. because bar has index.html inside it (200)', (done) => { - req.get('/bar/').expect(200, /Heyo/, done); + it('should show Heyo. because bar has index.html inside it (200)', async () => { + await req.get('/bar/').expect(200, /Heyo/); }); }); @@ -162,17 +158,15 @@ describe('contentBase option', () => { }); afterAll((done) => { - testServer.close(() => { - done(); - }); + testServer.close(done); }); - it('should list the files inside the assets folder (200)', (done) => { - req.get('/assets/').expect(200, done); + it('should list the files inside the assets folder (200)', async () => { + await req.get('/assets/').expect(200); }); - it('should show Heyo. because bar has index.html inside it (200)', (done) => { - req.get('/bar/').expect(200, /Heyo/, done); + it('should show Heyo. because bar has index.html inside it (200)', async () => { + await req.get('/bar/').expect(200, /Heyo/); }); }); @@ -190,17 +184,15 @@ describe('contentBase option', () => { }); afterAll((done) => { - testServer.close(() => { - done(); - }); + testServer.close(done); }); - it('Request to first directory', (done) => { - req.get('/').expect(200, /Heyo/, done); + it('Request to first directory', async () => { + await req.get('/').expect(200, /Heyo/); }); - it('Request to second directory', (done) => { - req.get('/foo.html').expect(200, /Foo!/, done); + it('Request to second directory', async () => { + await req.get('/foo.html').expect(200, /Foo!/); }); }); @@ -218,16 +210,14 @@ describe('contentBase option', () => { }); afterAll((done) => { - testServer.close(() => { - done(); - }); + testServer.close(done); }); - it('Request to page', (done) => { - req + it('Request to page', async () => { + await req .get('/other.html') .expect('Location', '//localhost:9099999/other.html') - .expect(302, done); + .expect(302); }); }); @@ -245,25 +235,23 @@ describe('contentBase option', () => { }); afterAll((done) => { - testServer.close(() => { - done(); - }); + testServer.close(done); }); - it('Request to page', (done) => { - req + it('Request to page', async () => { + await req .get('/foo.html') // TODO: hmm, two slashes seems to be a bug? .expect('Location', 'http://example.com//foo.html') - .expect(302, done); + .expect(302); }); - it('Request to page with search params', (done) => { - req + it('Request to page with search params', async () => { + await req .get('/foo.html?space=ship') // TODO: hmm, two slashes seems to be a bug? .expect('Location', 'http://example.com//foo.html?space=ship') - .expect(302, done); + .expect(302); }); }); @@ -357,18 +345,16 @@ describe('contentBase option', () => { beforeAll((done) => { jest.spyOn(process, 'cwd').mockImplementation(() => contentBasePublic); - server = testServer.start(config, {}, done); + server = testServer.start(config, { port }, done); req = request(server.app); }); afterAll((done) => { - testServer.close(() => { - done(); - }); + testServer.close(done); }); - it('Request to page', (done) => { - req.get('/other.html').expect(200, done); + it('Request to page', async () => { + await req.get('/other.html').expect(200); }); }); @@ -390,13 +376,11 @@ describe('contentBase option', () => { }); afterAll((done) => { - testServer.close(() => { - done(); - }); + testServer.close(done); }); - it('Request to page', (done) => { - req.get('/other.html').expect(404, done); + it('Request to page', async () => { + await req.get('/other.html').expect(404); }); }); @@ -414,13 +398,11 @@ describe('contentBase option', () => { }); afterAll((done) => { - testServer.close(() => { - done(); - }); + testServer.close(done); }); - it('Request foo.wasm', (done) => { - req.get('/foo.wasm').expect('Content-Type', 'application/wasm', done); + it('Request foo.wasm', async () => { + await req.get('/foo.wasm').expect('Content-Type', 'application/wasm'); }); }); }); diff --git a/test/server/headers-option.test.js b/test/server/headers-option.test.js index 1f3f7ad6fa..1891fe01a2 100644 --- a/test/server/headers-option.test.js +++ b/test/server/headers-option.test.js @@ -24,11 +24,11 @@ describe('headers option', () => { afterAll(testServer.close); - it('GET request with headers', (done) => { - req + it('GET request with headers', async () => { + await req .get('/main') .expect('X-Foo', '1') - .expect(200, done); + .expect(200); }); }); @@ -47,17 +47,18 @@ describe('headers option', () => { afterAll(testServer.close); - it('GET request with headers as an array', (done) => { + it('GET request with headers as an array', async () => { // https://github.com/webpack/webpack-dev-server/pull/1650#discussion_r254217027 const expected = ['v7', 'v8', 'v9'].includes( process.version.split('.')[0] ) ? 'key1=value1,key2=value2' : 'key1=value1, key2=value2'; - req + + await req .get('/main') .expect('X-Bar', expected) - .expect(200, done); + .expect(200); }); }); }); diff --git a/test/server/historyApiFallback-option.test.js b/test/server/historyApiFallback-option.test.js index cc600e7a4a..460e9441fd 100644 --- a/test/server/historyApiFallback-option.test.js +++ b/test/server/historyApiFallback-option.test.js @@ -50,11 +50,11 @@ describe('historyApiFallback option', () => { req = request(server.app); }); - it('request to directory', (done) => { - req + it('request to directory', async () => { + await req .get('/foo') .accept('html') - .expect(200, /Foobar/, done); + .expect(200, /Foobar/); }); }); @@ -77,18 +77,18 @@ describe('historyApiFallback option', () => { req = request(server.app); }); - it('historyApiFallback should take preference above directory index', (done) => { - req + it('historyApiFallback should take preference above directory index', async () => { + await req .get('/') .accept('html') - .expect(200, /Foobar/, done); + .expect(200, /Foobar/); }); - it('request to directory', (done) => { - req + it('request to directory', async () => { + await req .get('/foo') .accept('html') - .expect(200, /Foobar/, done); + .expect(200, /Foobar/); }); it('contentBase file should take preference above historyApiFallback', (done) => { @@ -124,11 +124,11 @@ describe('historyApiFallback option', () => { req = request(server.app); }); - it('historyApiFallback should work and ignore static content', (done) => { - req + it('historyApiFallback should work and ignore static content', async () => { + await req .get('/index.html') .accept('html') - .expect(200, /In-memory file/, done); + .expect(200, /In-memory file/); }); }); @@ -160,25 +160,25 @@ describe('historyApiFallback option', () => { req = request(server.app); }); - it('historyApiFallback respect rewrites for index', (done) => { - req + it('historyApiFallback respect rewrites for index', async () => { + await req .get('/') .accept('html') - .expect(200, /Foobar/, done); + .expect(200, /Foobar/); }); - it('historyApiFallback respect rewrites and shows index for unknown urls', (done) => { - req + it('historyApiFallback respect rewrites and shows index for unknown urls', async () => { + await req .get('/acme') .accept('html') - .expect(200, /Foobar/, done); + .expect(200, /Foobar/); }); - it('historyApiFallback respect any other specified rewrites', (done) => { - req + it('historyApiFallback respect any other specified rewrites', async () => { + await req .get('/other') .accept('html') - .expect(200, /Other file/, done); + .expect(200, /Other file/); }); }); @@ -199,11 +199,11 @@ describe('historyApiFallback option', () => { req = request(server.app); }); - it('should take precedence over contentBase files', (done) => { - req + it('should take precedence over contentBase files', async () => { + await req .get('/foo') .accept('html') - .expect(200, /In-memory file/, done); + .expect(200, /In-memory file/); }); }); }); diff --git a/test/server/host-option.test.js b/test/server/host-option.test.js index 009379062a..667caabd9f 100644 --- a/test/server/host-option.test.js +++ b/test/server/host-option.test.js @@ -50,8 +50,8 @@ describe('host option', () => { expect(address.port).toBe(port); }); - it('Request to index', (done) => { - req.get('/').expect(200, done); + it('Request to index', async () => { + await req.get('/').expect(200); }); afterAll(testServer.close); @@ -77,8 +77,8 @@ describe('host option', () => { expect(address.port).toBe(port); }); - it('Request to index', (done) => { - req.get('/').expect(200, done); + it('Request to index', async () => { + await req.get('/').expect(200); }); afterAll(testServer.close); @@ -104,8 +104,8 @@ describe('host option', () => { expect(address.port).toBe(port); }); - it('Request to index', (done) => { - req.get('/').expect(200, done); + it('Request to index', async () => { + await req.get('/').expect(200); }); afterAll(testServer.close); @@ -131,8 +131,8 @@ describe('host option', () => { expect(address.port).toBe(port); }); - it('Request to index', (done) => { - req.get('/').expect(200, done); + it('Request to index', async () => { + await req.get('/').expect(200); }); afterAll(testServer.close); @@ -158,8 +158,8 @@ describe('host option', () => { expect(address.port).toBe(port); }); - it('Request to index', (done) => { - req.get('/').expect(200, done); + it('Request to index', async () => { + await req.get('/').expect(200); }); afterAll(testServer.close); diff --git a/test/server/hot-option.test.js b/test/server/hot-option.test.js index 979bbad12c..e79679ff4b 100644 --- a/test/server/hot-option.test.js +++ b/test/server/hot-option.test.js @@ -26,8 +26,8 @@ describe('hot option', () => { afterAll(testServer.close); - it('should include hot script in the bundle', (done) => { - req.get('/main.js').expect(200, /webpack\/hot\/dev-server\.js/, done); + it('should include hot script in the bundle', async () => { + await req.get('/main.js').expect(200, /webpack\/hot\/dev-server\.js/); }); }); @@ -51,8 +51,8 @@ describe('hot option', () => { afterAll(testServer.close); - it('should include hot script in the bundle', (done) => { - req.get('/main.js').expect(200, /webpack\/hot\/dev-server\.js/, done); + it('should include hot script in the bundle', async () => { + await req.get('/main.js').expect(200, /webpack\/hot\/dev-server\.js/); }); }); @@ -72,14 +72,10 @@ describe('hot option', () => { afterAll(testServer.close); - it('should NOT include hot script in the bundle', (done) => { - req - .get('/main.js') - .expect(200) - .then(({ text }) => { - expect(text).not.toMatch(/webpack\/hot\/dev-server\.js/); - done(); - }); + it('should NOT include hot script in the bundle', async () => { + const { text } = await req.get('/main.js').expect(200); + + expect(text).not.toMatch(/webpack\/hot\/dev-server\.js/); }); }); diff --git a/test/server/hotOnly-option.test.js b/test/server/hotOnly-option.test.js index e601325fd3..61cba1eb88 100644 --- a/test/server/hotOnly-option.test.js +++ b/test/server/hotOnly-option.test.js @@ -25,10 +25,10 @@ describe('hotOnly options', () => { afterAll(testServer.close); - it('should include hotOnly script in the bundle', (done) => { - req + it('should include hotOnly script in the bundle', async () => { + await req .get('/main.js') - .expect(200, /webpack\/hot\/only-dev-server\.js/, done); + .expect(200, /webpack\/hot\/only-dev-server\.js/); }); }); diff --git a/test/server/http2-option.test.js b/test/server/http2-option.test.js index 4cf4cd9934..aff171d6fa 100644 --- a/test/server/http2-option.test.js +++ b/test/server/http2-option.test.js @@ -107,14 +107,10 @@ describe('http2 option', () => { req = request(server.app); }); - it('Request to index', (done) => { - req - .get('/') - .expect(200, /Heyo/) - .then(({ res }) => { - expect(res.httpVersion).not.toEqual('2.0'); - done(); - }); + it('Request to index', async () => { + const { res } = await req.get('/').expect(200, /Heyo/); + + expect(res.httpVersion).not.toEqual('2.0'); }); afterAll(testServer.close); diff --git a/test/server/https-option.test.js b/test/server/https-option.test.js index 719875a000..2c569ea5df 100644 --- a/test/server/https-option.test.js +++ b/test/server/https-option.test.js @@ -35,8 +35,8 @@ describe('https option', () => { req = request(server.app); }); - it('Request to index', (done) => { - req.get('/').expect(200, /Heyo/, done); + it('Request to index', async () => { + await req.get('/').expect(200, /Heyo/); }); afterAll(() => { @@ -70,8 +70,8 @@ describe('https option', () => { req = request(server.app); }); - it('Request to index', (done) => { - req.get('/').expect(200, /Heyo/, done); + it('Request to index', async () => { + await req.get('/').expect(200, /Heyo/); }); }); @@ -124,8 +124,8 @@ describe('https option', () => { req = request(server.app); }); - it('Request to index', (done) => { - req.get('/').expect(200, /Heyo/, done); + it('Request to index', async () => { + await req.get('/').expect(200, /Heyo/); }); afterAll(testServer.close); @@ -160,8 +160,8 @@ describe('https option', () => { req = request(server.app); }); - it('Request to index', (done) => { - req.get('/').expect(200, /Heyo/, done); + it('Request to index', async () => { + await req.get('/').expect(200, /Heyo/); }); }); diff --git a/test/server/inline-option.test.js b/test/server/inline-option.test.js index 78344621e6..7fc37ad994 100644 --- a/test/server/inline-option.test.js +++ b/test/server/inline-option.test.js @@ -26,10 +26,10 @@ describe('inline option', () => { afterAll(testServer.close); - it('should include inline client script in the bundle', (done) => { + it('should include inline client script in the bundle', async () => { const url = new RegExp(`client/index.js\\?http://0.0.0.0:${port}`); - req.get('/main.js').expect(200, url, done); + await req.get('/main.js').expect(200, url); }); }); @@ -76,14 +76,10 @@ describe('inline option', () => { afterAll(testServer.close); - it('should NOT include inline client script in the bundle', (done) => { - req - .get('/main.js') - .expect(200) - .then(({ text }) => { - expect(text.includes(`client/index.js?http://0.0.0.0:${port}`)); - done(); - }); + it('should NOT include inline client script in the bundle', async () => { + const { text } = await req.get('/main.js').expect(200); + + expect(text.includes(`client/index.js?http://0.0.0.0:${port}`)); }); }); }); diff --git a/test/server/mimeTypes-option.test.js b/test/server/mimeTypes-option.test.js index 662007dadd..5f2fef5e7a 100644 --- a/test/server/mimeTypes-option.test.js +++ b/test/server/mimeTypes-option.test.js @@ -54,11 +54,11 @@ describe('mimeTypes option', () => { afterAll(testServer.close); - it('request to bundle file with modified mime type', (done) => { - req + it('request to bundle file with modified mime type', async () => { + await req .get('/main.js') .expect('Content-Type', /application\/octet-stream/) - .expect(200, done); + .expect(200); }); }); }); diff --git a/test/server/onListening-option.test.js b/test/server/onListening-option.test.js index d6d66b1565..2d8b86dc3e 100644 --- a/test/server/onListening-option.test.js +++ b/test/server/onListening-option.test.js @@ -1,32 +1,71 @@ 'use strict'; +const { unlink } = require('fs'); +const { join } = require('path'); const testServer = require('../helpers/test-server'); const config = require('../fixtures/simple-config/webpack.config'); const port = require('../ports-map')['onListening-option']; +const { skipTestOnWindows } = require('../helpers/conditional-test'); describe('onListening option', () => { - let onListeningIsRunning = false; - - beforeAll((done) => { - testServer.start( - config, - { - onListening: (devServer) => { - if (!devServer) { - throw new Error('webpack-dev-server is not defined'); - } - - onListeningIsRunning = true; + describe('with host and port', () => { + let onListeningIsRunning = false; + + beforeAll((done) => { + testServer.start( + config, + { + onListening: (devServer) => { + if (!devServer) { + throw new Error('webpack-dev-server is not defined'); + } + + onListeningIsRunning = true; + }, + port, }, - port, - }, - done - ); + done + ); + }); + + afterAll(testServer.close); + + it('should run onListening callback', () => { + expect(onListeningIsRunning).toBe(true); + }); }); - afterAll(testServer.close); + describe('with Unix socket', () => { + if (skipTestOnWindows('Unix sockets are not supported on Windows')) { + return; + } + + const socketPath = join('.', 'onListening.webpack.sock'); + let onListeningIsRunning = false; + + beforeAll((done) => { + testServer.start( + config, + { + onListening: (devServer) => { + if (!devServer) { + throw new Error('webpack-dev-server is not defined'); + } + + onListeningIsRunning = true; + }, + socket: socketPath, + }, + done + ); + }); + + afterAll(testServer.close); + + it('should run onListening callback', (done) => { + expect(onListeningIsRunning).toBe(true); - it('should runs onListening callback', () => { - expect(onListeningIsRunning).toBe(true); + unlink(socketPath, done); + }); }); }); diff --git a/test/server/open-option.test.js b/test/server/open-option.test.js index 9eeb8d3cd8..01f7d88b8a 100644 --- a/test/server/open-option.test.js +++ b/test/server/open-option.test.js @@ -1,9 +1,9 @@ 'use strict'; -jest.mock('opn'); +jest.mock('open'); const webpack = require('webpack'); -const open = require('opn'); +const open = require('open'); const Server = require('../../lib/Server'); const config = require('../fixtures/simple-config/webpack.config'); const port = require('../ports-map')['open-option']; diff --git a/test/server/port-option.test.js b/test/server/port-option.test.js index ff7488de80..d9fd6c2391 100644 --- a/test/server/port-option.test.js +++ b/test/server/port-option.test.js @@ -23,8 +23,8 @@ describe('port', () => { expect(address.port).toBeDefined(); }); - it('Request to index', (done) => { - req.get('/').expect(200, done); + it('Request to index', async () => { + await req.get('/').expect(200); }); afterAll(testServer.close); @@ -51,8 +51,8 @@ describe('port', () => { expect(address.port).toBeDefined(); }); - it('Request to index', (done) => { - req.get('/').expect(200, done); + it('Request to index', async () => { + await req.get('/').expect(200); }); afterAll(testServer.close); @@ -78,8 +78,8 @@ describe('port', () => { expect(address.port).toBeDefined(); }); - it('Request to index', (done) => { - req.get('/').expect(200, done); + it('Request to index', async () => { + await req.get('/').expect(200); }); afterAll(testServer.close); @@ -104,8 +104,8 @@ describe('port', () => { expect(address.port).toBe(33333); }); - it('Request to index', (done) => { - req.get('/').expect(200, done); + it('Request to index', async () => { + await req.get('/').expect(200); }); afterAll(testServer.close); @@ -130,8 +130,8 @@ describe('port', () => { expect(address.port).toBe(33333); }); - it('Request to index', (done) => { - req.get('/').expect(200, done); + it('Request to index', async () => { + await req.get('/').expect(200); }); afterAll(testServer.close); diff --git a/test/server/proxy-option.test.js b/test/server/proxy-option.test.js index 6f21967248..21917d9ab8 100644 --- a/test/server/proxy-option.test.js +++ b/test/server/proxy-option.test.js @@ -108,32 +108,32 @@ describe('proxy option', () => { }); describe('target', () => { - it('respects a proxy option when a request path is matched', (done) => { - req.get('/proxy1').expect(200, 'from proxy1', done); + it('respects a proxy option when a request path is matched', async () => { + await req.get('/proxy1').expect(200, 'from proxy1'); }); }); describe('pathRewrite', () => { - it('respects a pathRewrite option', (done) => { - req.get('/api/proxy2').expect(200, 'from proxy2', done); + it('respects a pathRewrite option', async () => { + await req.get('/api/proxy2').expect(200, 'from proxy2'); }); }); describe('bypass', () => { - it('can rewrite a request path', (done) => { - req.get('/foo/bar.html').expect(200, /Hello/, done); + it('can rewrite a request path', async () => { + await req.get('/foo/bar.html').expect(200, /Hello/); }); - it('can rewrite a request path regardless of the target defined a bypass option', (done) => { - req.get('/baz/hoge.html').expect(200, /Hello/, done); + it('can rewrite a request path regardless of the target defined a bypass option', async () => { + await req.get('/baz/hoge.html').expect(200, /Hello/); }); - it('should pass through a proxy when a bypass function returns null', (done) => { - req.get('/foo.js').expect(200, /Hey/, done); + it('should pass through a proxy when a bypass function returns null', async () => { + await req.get('/foo.js').expect(200, /Hey/); }); - it('should not pass through a proxy when a bypass function returns false', (done) => { - req.get('/proxyfalse').expect(404, done); + it('should not pass through a proxy when a bypass function returns false', async () => { + await req.get('/proxyfalse').expect(404); }); }); }); @@ -164,8 +164,8 @@ describe('proxy option', () => { }); }); - it('respects a proxy option', (done) => { - req.get('/proxy1').expect(200, 'from proxy1', done); + it('respects a proxy option', async () => { + await req.get('/proxy1').expect(200, 'from proxy1'); }); }); @@ -195,12 +195,12 @@ describe('proxy option', () => { }); }); - it('respects a proxy option', (done) => { - req.get('/proxy1').expect(200, 'from proxy1', done); + it('respects a proxy option', async () => { + await req.get('/proxy1').expect(200, 'from proxy1'); }); - it('respects a proxy option of function', (done) => { - req.get('/api/proxy2').expect(200, 'from proxy2', done); + it('respects a proxy option of function', async () => { + await req.get('/api/proxy2').expect(200, 'from proxy2'); }); }); @@ -243,12 +243,12 @@ describe('proxy option', () => { }); }); - it('respects proxy1 option', (done) => { - req.get('/proxy1').expect(200, 'from proxy', done); + it('respects proxy1 option', async () => { + await req.get('/proxy1').expect(200, 'from proxy'); }); - it('respects proxy2 option', (done) => { - req.get('/proxy2').expect(200, 'from proxy', done); + it('respects proxy2 option', async () => { + await req.get('/proxy2').expect(200, 'from proxy'); }); }); @@ -366,36 +366,35 @@ describe('proxy option', () => { }); }); - it('GET method', (done) => { - req.get('/get').expect(200, 'GET method from proxy', done); + it('GET method', async () => { + await req.get('/get').expect(200, 'GET method from proxy'); }); it('HEAD method', (done) => { req.head('/head').expect(200, done); }); - it('POST method (application/x-www-form-urlencoded)', (done) => { - req + it('POST method (application/x-www-form-urlencoded)', async () => { + await req .post('/post-x-www-form-urlencoded') .send('id=1') - .expect(200, 'POST method from proxy (id: 1)', done); + .expect(200, 'POST method from proxy (id: 1)'); }); - it('POST method (application/json)', (done) => { - req + it('POST method (application/json)', async () => { + await req .post('/post-application-json') .send({ id: '1' }) .set('Accept', 'application/json') .expect('Content-Type', /json/) .expect( 200, - JSON.stringify({ answer: 'POST method from proxy (id: 1)' }), - done + JSON.stringify({ answer: 'POST method from proxy (id: 1)' }) ); }); - it('DELETE method', (done) => { - req.delete('/delete').expect(200, 'DELETE method from proxy', done); + it('DELETE method', async () => { + await req.delete('/delete').expect(200, 'DELETE method from proxy'); }); }); }); diff --git a/test/server/servers/SockJSServer.test.js b/test/server/servers/SockJSServer.test.js index 48c535e98e..14aaf04d73 100644 --- a/test/server/servers/SockJSServer.test.js +++ b/test/server/servers/SockJSServer.test.js @@ -4,6 +4,7 @@ const http = require('http'); const express = require('express'); const SockJS = require('sockjs-client/dist/sockjs'); const SockJSServer = require('../../../lib/servers/SockJSServer'); +const timer = require('../../helpers/timer'); const port = require('../../ports-map').SockJSServer; describe('SockJSServer', () => { @@ -32,18 +33,19 @@ describe('SockJSServer', () => { }); describe('server', () => { - it('should recieve connection, send message, and close client', (done) => { + it('should recieve connection, send message, and close client', async () => { const data = []; - let headers; - socketServer.onConnection((connection, h) => { + + socketServer.onConnection(async (connection, h) => { headers = h; data.push('open'); socketServer.send(connection, 'hello world'); - setTimeout(() => { - // the server closes the connection with the client - socketServer.close(connection); - }, 1000); + + await timer(1000); + + // the server closes the connection with the client + socketServer.close(connection); }); const client = new SockJS(`http://localhost:${port}/sockjs-node`); @@ -56,14 +58,13 @@ describe('SockJSServer', () => { data.push('close'); }; - setTimeout(() => { - expect(headers.host).toMatchSnapshot(); - expect(data).toMatchSnapshot(); - done(); - }, 3000); + await timer(3000); + + expect(headers.host).toMatchSnapshot(); + expect(data).toMatchSnapshot(); }); - it('should receive client close event', (done) => { + it('should receive client close event', async () => { let receivedClientClose = false; socketServer.onConnection((connection) => { socketServer.onConnectionClose(connection, () => { @@ -74,15 +75,14 @@ describe('SockJSServer', () => { // eslint-disable-next-line new-cap const client = new SockJS(`http://localhost:${port}/sockjs-node`); - setTimeout(() => { - // the client closes itself, the server does not close it - client.close(); - }, 1000); + await timer(1000); + + // the client closes itself, the server does not close it + client.close(); + + await timer(3000); - setTimeout(() => { - expect(receivedClientClose).toBeTruthy(); - done(); - }, 3000); + expect(receivedClientClose).toBeTruthy(); }); it('should not throw an exception when connection is null', () => { diff --git a/test/server/sockPath-option.test.js b/test/server/sockPath-option.test.js index b6840228b5..860e3818be 100644 --- a/test/server/sockPath-option.test.js +++ b/test/server/sockPath-option.test.js @@ -25,8 +25,8 @@ describe('sockPath options', () => { expect(!!server.sockPath.match(/\/[a-z0-9\-/]+[^/]$/)).toBeTruthy(); }); - it('responds with a 200', (done) => { - req.get('/sockjs-node').expect(200, done); + it('responds with a 200', async () => { + await req.get('/sockjs-node').expect(200); }); }); @@ -49,8 +49,8 @@ describe('sockPath options', () => { expect(server.sockPath).toEqual(path); }); - it('responds with a 200 second', (done) => { - req.get(path).expect(200, done); + it('responds with a 200 second', async () => { + await req.get(path).expect(200); }); }); }); diff --git a/test/server/socket-option.test.js b/test/server/socket-option.test.js new file mode 100644 index 0000000000..a933097bb1 --- /dev/null +++ b/test/server/socket-option.test.js @@ -0,0 +1,149 @@ +'use strict'; + +const net = require('net'); +const fs = require('fs'); +const path = require('path'); +const webpack = require('webpack'); +const testServer = require('../helpers/test-server'); +const TestUnixSocket = require('../helpers/test-unix-socket'); +const { skipTestOnWindows } = require('../helpers/conditional-test'); +const config = require('../fixtures/simple-config/webpack.config'); +const Server = require('../../lib/Server'); + +describe('socket', () => { + const socketPath = path.join('.', 'socket-option.webpack.sock'); + let server = null; + + describe('path to a non-existent file', () => { + let err; + beforeAll((done) => { + server = testServer.start( + config, + { + socket: socketPath, + }, + (e) => { + err = e; + done(); + } + ); + }); + + it('should work as Unix socket or error on windows', (done) => { + if (process.platform === 'win32') { + expect(err.code).toEqual('EACCES'); + done(); + } else { + const clientSocket = new net.Socket(); + clientSocket.connect({ path: socketPath }, () => { + // this means the connection was made successfully + expect(true).toBeTruthy(); + done(); + }); + } + }); + + afterAll((done) => { + testServer.close(() => { + fs.unlink(socketPath, done); + }); + }); + }); + + describe('path to existent, unused file', () => { + if (skipTestOnWindows('Unix sockets are not supported on Windows')) { + return; + } + + beforeAll((done) => { + fs.writeFileSync(socketPath, ''); + server = testServer.start( + config, + { + socket: socketPath, + }, + done + ); + }); + + it('should work as Unix socket', (done) => { + const clientSocket = new net.Socket(); + clientSocket.connect({ path: socketPath }, () => { + // this means the connection was made successfully + expect(true).toBeTruthy(); + done(); + }); + }); + + afterAll((done) => { + testServer.close(() => { + fs.unlink(socketPath, done); + }); + }); + }); + + describe('path to existent file with listening server', () => { + if (skipTestOnWindows('Unix sockets are not supported on Windows')) { + return; + } + + let testUnixSocket; + beforeAll((done) => { + testUnixSocket = new TestUnixSocket(); + testUnixSocket.server.listen(socketPath, 511, () => { + done(); + }); + }); + + it('should throw already used error', (done) => { + server = testServer.start( + config, + { + socket: socketPath, + }, + (err) => { + expect(err).not.toBeNull(); + expect(err).not.toBeUndefined(); + expect(err.message).toEqual('This socket is already used'); + server.close(done); + } + ); + }); + + afterAll((done) => { + testUnixSocket.close(() => { + fs.unlink(socketPath, done); + }); + }); + }); + + describe('path to existent, unused file', () => { + let devServer; + const options = { + socket: socketPath, + }; + beforeAll(() => { + fs.writeFileSync(socketPath, ''); + }); + + // this test is significant because previously the callback was called + // twice if a file at the given socket path already existed, but + // could be removed + it('should only call server.listen callback once', (done) => { + const compiler = webpack(config); + + devServer = new Server(compiler, options); + const onListen = jest.fn(); + // eslint-disable-next-line no-undefined + devServer.listen(options.socket, undefined, onListen); + setTimeout(() => { + expect(onListen).toBeCalledTimes(1); + done(); + }, 10000); + }); + + afterAll((done) => { + devServer.close(done); + }); + }); +}); diff --git a/test/server/stats-option.test.js b/test/server/stats-option.test.js index dc89702cc8..f6db78dcc3 100644 --- a/test/server/stats-option.test.js +++ b/test/server/stats-option.test.js @@ -6,7 +6,7 @@ const config = require('../fixtures/simple-config/webpack.config'); const port = require('../ports-map')['stats-option']; describe('stats option', () => { - it(`should works with difference stats values (contains 'hash', 'assets', 'warnings' and 'errors')`, () => { + it(`should works with difference stats values (contains 'hash', 'assets', 'warnings' and 'errors')`, async () => { const allStats = [ {}, // eslint-disable-next-line no-undefined @@ -18,23 +18,22 @@ describe('stats option', () => { }, ]; - return allStats.reduce((p, stats) => { - return p.then(() => { - return new Promise((resolve) => { - const compiler = webpack(config); - const server = new Server(compiler, { stats, port, quiet: true }); + for (const stats of allStats) { + const compiler = webpack(config); + const server = new Server(compiler, { stats, port, quiet: true }); - compiler.hooks.done.tap('webpack-dev-server', (s) => { - expect(Object.keys(server.getStats(s))).toMatchSnapshot(); + // eslint-disable-next-line no-await-in-loop + await new Promise((resolve) => { + compiler.hooks.done.tap('webpack-dev-server', (s) => { + expect(Object.keys(server.getStats(s))).toMatchSnapshot(); - server.close(resolve); - }); - - compiler.run(() => {}); - server.listen(port, 'localhost'); + server.close(resolve); }); + + compiler.run(() => {}); + server.listen(port, 'localhost'); }); - }, Promise.resolve()); + } }); it('should respect warningsFilter', (done) => { diff --git a/test/server/stdin-option.test.js b/test/server/stdin-option.test.js new file mode 100644 index 0000000000..da742ffff8 --- /dev/null +++ b/test/server/stdin-option.test.js @@ -0,0 +1,62 @@ +'use strict'; + +const config = require('../fixtures/simple-config/webpack.config'); +const testServer = require('../helpers/test-server'); +const timer = require('../helpers/timer'); +const port = require('../ports-map')['stdin-option']; + +describe('stdin', () => { + // eslint-disable-next-line no-unused-vars + let server; + let exitSpy; + + beforeAll(() => { + exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {}); + }); + + afterEach((done) => { + server = null; + exitSpy.mockReset(); + process.stdin.removeAllListeners('end'); + testServer.close(done); + }); + + describe('enabled', () => { + beforeAll((done) => { + server = testServer.start( + config, + { + port, + stdin: true, + }, + done + ); + }); + + it('should exit process', async () => { + process.stdin.emit('end'); + await timer(1000); + process.stdin.pause(); + expect(exitSpy.mock.calls[0]).toEqual([0]); + }); + }); + + describe('disabled (default)', () => { + beforeAll((done) => { + server = testServer.start( + config, + { + port, + }, + done + ); + }); + + it('should not exit process', async () => { + process.stdin.emit('end'); + await timer(1000); + process.stdin.pause(); + expect(exitSpy.mock.calls.length).toEqual(0); + }); + }); +}); diff --git a/test/server/utils/__snapshots__/createConfig.test.js.snap b/test/server/utils/__snapshots__/createConfig.test.js.snap index 585d74105c..b95e10e224 100644 --- a/test/server/utils/__snapshots__/createConfig.test.js.snap +++ b/test/server/utils/__snapshots__/createConfig.test.js.snap @@ -7,14 +7,8 @@ Object { "host2.com", ], "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -25,14 +19,8 @@ Object { "host2.com", ], "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -40,14 +28,8 @@ exports[`createConfig bonjour option (devServer config) 1`] = ` Object { "bonjour": true, "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -55,14 +37,8 @@ exports[`createConfig bonjour option 1`] = ` Object { "bonjour": true, "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -70,15 +46,9 @@ exports[`createConfig cacert option (in devServer config) 1`] = ` Object { "ca": "/path/to/ca.pem", "hot": true, - "hotOnly": false, "https": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -86,15 +56,9 @@ exports[`createConfig cacert option 1`] = ` Object { "ca": "/path/to/ca.pem", "hot": true, - "hotOnly": false, "https": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -102,15 +66,9 @@ exports[`createConfig cert option (in devServer config) 1`] = ` Object { "cert": "/path/to/server.crt", "hot": true, - "hotOnly": false, "https": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -118,15 +76,9 @@ exports[`createConfig cert option 1`] = ` Object { "cert": "/path/to/server.crt", "hot": true, - "hotOnly": false, "https": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -134,14 +86,8 @@ exports[`createConfig clientLogLevel option (in devServer config) 1`] = ` Object { "clientLogLevel": "none", "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -149,14 +95,8 @@ exports[`createConfig clientLogLevel option 1`] = ` Object { "clientLogLevel": "none", "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -164,14 +104,8 @@ exports[`createConfig compress option (in devServer config) 1`] = ` Object { "compress": true, "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -179,77 +113,8 @@ exports[`createConfig compress option 1`] = ` Object { "compress": true, "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig contentBase option (array) 1`] = ` -Object { - "contentBase": Array [ - "assets", - "static", - ], - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig contentBase option (boolean) 1`] = ` -Object { - "contentBase": false, - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig contentBase option (string) (in devServer config) 1`] = ` -Object { - "contentBase": "assets", - "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig contentBase option (string) 1`] = ` -Object { - "contentBase": "assets", - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -257,14 +122,8 @@ exports[`createConfig disableHostCheck option (in devServer config) 1`] = ` Object { "disableHostCheck": true, "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -272,59 +131,8 @@ exports[`createConfig disableHostCheck option 1`] = ` Object { "disableHostCheck": true, "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig filename option (in devServer config) 1`] = ` -Object { - "filename": "[name]-dev-server-bundle.js", - "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig filename option (in output config) 1`] = ` -Object { - "filename": "[name]-output-bundle.js", - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig filename option (in webpack config) 1`] = ` -Object { - "filename": "[name]-bundle.js", - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -332,14 +140,8 @@ exports[`createConfig historyApiFallback option (in devServer config) 1`] = ` Object { "historyApiFallback": true, "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -347,14 +149,8 @@ exports[`createConfig historyApiFallback option 1`] = ` Object { "historyApiFallback": true, "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -362,14 +158,8 @@ exports[`createConfig host option (devServer config) 1`] = ` Object { "host": "example.dev", "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -377,28 +167,16 @@ exports[`createConfig host option (localhost) 1`] = ` Object { "host": "localhost", "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig host option (null) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -406,28 +184,16 @@ exports[`createConfig host option (specify for CLI and devServer config) 1`] = ` Object { "host": "other.dev", "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig host option (undefined) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -435,42 +201,8 @@ exports[`createConfig host option 1`] = ` Object { "host": "example.dev", "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig hot option (in devServer config) 1`] = ` -Object { - "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig hot option 1`] = ` -Object { - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -480,11 +212,6 @@ Object { "hotOnly": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; @@ -494,230 +221,140 @@ Object { "hotOnly": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig http2 option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "http2": true, "https": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig http2 option 1`] = ` Object { "hot": true, - "hotOnly": false, "http2": true, "https": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig https option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "https": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig https option (in devServer config) 2`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "pfxPassphrase": "passphrase", "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig https option 1`] = ` Object { "hot": true, - "hotOnly": false, "https": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig info option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig info option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig inline option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "inline": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig inline option 1`] = ` Object { "hot": true, - "hotOnly": false, "inline": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig key option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "https": true, "key": "/path/to/server.key", "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig key option 1`] = ` Object { "hot": true, - "hotOnly": false, "https": true, "key": "/path/to/server.key", "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig lazy option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "lazy": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig lazy option 1`] = ` Object { "hot": true, - "hotOnly": false, "lazy": true, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig liveReload option 1`] = ` Object { "hot": true, - "hotOnly": false, "liveReload": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig mimeTypes option - with force 1`] = ` Object { "hot": true, - "hotOnly": false, "mimeTypes": Object { "force": true, "typeMap": Object { @@ -728,18 +365,12 @@ Object { }, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig mimeTypes option 1`] = ` Object { "hot": true, - "hotOnly": false, "mimeTypes": Object { "text/html": Array [ "phtml", @@ -747,555 +378,272 @@ Object { }, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig onListening option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "onListening": [Function], "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig open option (boolean) (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "open": true, - "openPage": "", "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig open option (boolean) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "open": true, - "openPage": "", "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig open option (browser) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "open": "Google Chrome", - "openPage": "", "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig openPage option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "open": true, "openPage": "/different/page", "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig openPage option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, - "open": true, "openPage": "/different/page", "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig overlay option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "overlay": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig overlay option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "overlay": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig pfx option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "https": true, "noInfo": true, "pfx": "/path/to/file.pfx", "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig pfx option 1`] = ` Object { "hot": true, - "hotOnly": false, "https": true, "noInfo": true, "pfx": "/path/to/file.pfx", "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig pfxPassphrase option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "pfxPassphrase": "passphrase", "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig port option (difference) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 7070, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig port option (same) (null) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": null, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig port option (same) (string) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": "9090", - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig port option (same) (undefined) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": undefined, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig port option (same) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 9090, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig profile option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, "profile": "profile", - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig progress option (devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, "progress": true, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig progress option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, "progress": true, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig public option (devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, "public": true, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig public option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, "public": true, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig publicPath option (not specify) 1`] = ` -Object { - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig publicPath option (path in devServer option) 1`] = ` -Object { - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/assets/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig publicPath option (path in output option) 1`] = ` -Object { - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/assets/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig publicPath option (path without starting slash in output option) 1`] = ` -Object { - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/assets/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig publicPath option (url in devServer option) 1`] = ` -Object { - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "http://localhost:8080/assets/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig publicPath option (url in output option) 1`] = ` -Object { - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "http://localhost:8080/assets/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig quiet option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", "quiet": true, - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig quiet option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", "quiet": true, - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig simple 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig sockHost option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", "sockHost": true, - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig sockPath option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", "sockPath": "path", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig sockPort option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", "sockPort": "port", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig socket option (devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", "socket": "socket", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, } `; exports[`createConfig socket option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", "socket": "socket", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, -} -`; - -exports[`createConfig stats option (colors) 1`] = ` -Object { - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "colors": true, - "errors": true, - }, } `; exports[`createConfig stats option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", "stats": "errors-only", } `; @@ -1309,7 +657,7 @@ Object { "filename": "_filename", "historyApiFallback": "_historyApiFallback", "host": "_foo", - "hot": "_hot", + "hot": true, "hotOnly": "_hotOnly", "https": "_https", "inline": "_inline", @@ -1324,9 +672,6 @@ Object { "publicPath": "_publicPath", "quiet": "_quiet", "socket": "_socket", - "stats": Object { - "assetsSort": "size", - }, "useLocalIp": "_useLocalIp", "watchContentBase": "_watchContentBase", } @@ -1342,7 +687,7 @@ Object { "filename": "_filename", "historyApiFallback": "_historyApiFallback", "host": "_foo", - "hot": "_hot", + "hot": true, "hotOnly": "_hotOnly", "https": "_https", "inline": "_inline", @@ -1357,14 +702,10 @@ Object { "publicPath": "_publicPath", "quiet": "_quiet", "socket": "_socket", - "stats": Object { - "assetsSort": "size", - }, "useLocalIp": "_useLocalIp", "watchContentBase": "_watchContentBase", }, "entry": "./app.js", - "mode": "development", "stats": Object { "assetsSort": "size", }, @@ -1374,14 +715,8 @@ Object { exports[`createConfig useLocalIp option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, "useLocalIp": true, } `; @@ -1389,14 +724,8 @@ Object { exports[`createConfig useLocalIp option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, "useLocalIp": true, } `; @@ -1404,14 +733,8 @@ Object { exports[`createConfig watchContentBase option (in devServer config) 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, "watchContentBase": true, } `; @@ -1419,48 +742,8 @@ Object { exports[`createConfig watchContentBase option 1`] = ` Object { "hot": true, - "hotOnly": false, "noInfo": true, "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, "watchContentBase": true, } `; - -exports[`createConfig watchOptions option (in devServer config) 1`] = ` -Object { - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, - "watchOptions": Object { - "poll": true, - }, -} -`; - -exports[`createConfig watchOptions option (in output config) 1`] = ` -Object { - "hot": true, - "hotOnly": false, - "noInfo": true, - "port": 8080, - "publicPath": "/", - "stats": Object { - "cached": false, - "cachedAssets": false, - }, - "watchOptions": Object { - "poll": true, - }, -} -`; diff --git a/test/server/utils/__snapshots__/normalizeOptions.test.js.snap b/test/server/utils/__snapshots__/normalizeOptions.test.js.snap index 5741d85d9a..5561d85c86 100644 --- a/test/server/utils/__snapshots__/normalizeOptions.test.js.snap +++ b/test/server/utils/__snapshots__/normalizeOptions.test.js.snap @@ -1,11 +1,839 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`normalizeOptions contentBase array should set correct options 1`] = ` +exports[`normalizeOptions absolute options.publicPath (multi compiler) should set correct options 1`] = ` Object { - "contentBase": Array [ - "/path/to/dist1", - "/path/to/dist2", - ], + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "http://localhost:8080/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions absolute options.publicPath should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "http://localhost:8080/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions bad relative options.publicPath (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions bad relative options.publicPath should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.devServer (multi compiler) should set correct options 1`] = ` +Object { + "clientLogLevel": "silent", + "filename": "[name].js", + "hot": true, + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.devServer should set correct options 1`] = ` +Object { + "clientLogLevel": "silent", + "filename": "[name].js", + "hot": true, + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.devServer.stats (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.devServer.stats overrides compiler options.stats (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.devServer.stats overrides compiler options.stats should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.devServer.stats should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.stats (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": "none", + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.stats should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": "none", + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.stats.colors does not override options.stats.colors (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": true, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.stats.colors does not override options.stats.colors should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": true, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.stats.colors used (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": true, + "colors": false, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler options.stats.colors used should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": true, + "colors": false, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler stats (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "colors": true, + "errors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler stats should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "colors": true, + "errors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions compiler watchOptions (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object { + "poll": true, + }, +} +`; + +exports[`normalizeOptions compiler watchOptions should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object { + "poll": true, + }, +} +`; + +exports[`normalizeOptions complex compiler options.devServer (multi compiler) should set correct options 1`] = ` +Object { + "clientLogLevel": "_clientLogLevel", + "compress": "_compress", + "disableHostCheck": "_disableHostCheck", + "filename": "_filename", + "historyApiFallback": "_historyApiFallback", + "host": "_foo", + "hot": "_hot", + "hotOnly": "_hotOnly", + "https": "_https", + "inline": "_inline", + "lazy": "_lazy", + "liveReload": true, + "noInfo": "_noInfo", + "open": true, + "openPage": "_openPage", + "pfxPassphrase": "_pfxPassphrase", + "port": "_port", + "progress": "_progress", + "public": "_public", + "publicPath": "/_publicPath", + "quiet": "_quiet", + "socket": "_socket", + "stats": Object { + "assetsSort": "size", + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "useLocalIp": "_useLocalIp", + "watchContentBase": "_watchContentBase", + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions complex compiler options.devServer should set correct options 1`] = ` +Object { + "clientLogLevel": "_clientLogLevel", + "compress": "_compress", + "disableHostCheck": "_disableHostCheck", + "filename": "_filename", + "historyApiFallback": "_historyApiFallback", + "host": "_foo", + "hot": "_hot", + "hotOnly": "_hotOnly", + "https": "_https", + "inline": "_inline", + "lazy": "_lazy", + "liveReload": true, + "noInfo": "_noInfo", + "open": true, + "openPage": "_openPage", + "pfxPassphrase": "_pfxPassphrase", + "port": "_port", + "progress": "_progress", + "public": "_public", + "publicPath": "/_publicPath", + "quiet": "_quiet", + "socket": "_socket", + "stats": Object { + "assetsSort": "size", + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "useLocalIp": "_useLocalIp", + "watchContentBase": "_watchContentBase", + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions contentBase (array) should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions contentBase (boolean) should set correct options 1`] = ` +Object { + "contentBase": false, + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions contentBase (string) should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions existing options.filename, existing compiler filename (multi compiler) should set correct options 1`] = ` +Object { + "filename": "devserver-bundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions existing options.filename, existing compiler filename should set correct options 1`] = ` +Object { + "filename": "devserver-bundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions existing options.filename, no compiler filename should set correct options 1`] = ` +Object { + "filename": "devserver-bundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.filename, existing compiler filename (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.filename, existing compiler filename (multi compiler) should set correct options 2`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.filename, existing compiler filename should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.filename, existing compiler filename should set correct options 2`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.filename, no compiler filename should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.filename, no compiler filename should set correct options 2`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.publicPath, / compiler publicPath (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.publicPath, / compiler publicPath should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.publicPath, absolute url compiler publicPath (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "http://localhost:8080/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.publicPath, absolute url compiler publicPath should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "http://localhost:8080/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.publicPath, bad relative compiler publicPath (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.publicPath, bad relative compiler publicPath should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.publicPath, no compiler publicPath should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions no options.publicPath, relative compiler publicPath (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, "transportMode": Object { "client": "sockjs", "server": "sockjs", @@ -14,9 +842,17 @@ Object { } `; -exports[`normalizeOptions contentBase string should set correct options 1`] = ` +exports[`normalizeOptions no options.publicPath, relative compiler publicPath should set correct options 1`] = ` Object { - "contentBase": "/path/to/dist", + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, "transportMode": Object { "client": "sockjs", "server": "sockjs", @@ -25,8 +861,473 @@ Object { } `; -exports[`normalizeOptions no options should set correct options 1`] = ` +exports[`normalizeOptions normal options override compiler options.devServer (multi compiler) should set correct options 1`] = ` +Object { + "clientLogLevel": "debug", + "filename": "[name].js", + "hot": false, + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions normal options override compiler options.devServer should set correct options 1`] = ` +Object { + "clientLogLevel": "debug", + "filename": "[name].js", + "hot": false, + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.clientLogLevel overrides compiler options.devServer.clientLogLevel (multi compiler) should set correct options 1`] = ` +Object { + "clientLogLevel": "debug", + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.clientLogLevel overrides compiler options.devServer.clientLogLevel should set correct options 1`] = ` +Object { + "clientLogLevel": "debug", + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.host localhost overrides compiler options.devServer.host (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "host": "localhost", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.host localhost overrides compiler options.devServer.host should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "host": "localhost", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.host should set correct options 1`] = ` +Object { + "filename": "[name].js", + "host": "0.0.0.0", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.hot overrides compiler options.devServer.hot (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "hot": false, + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.hot overrides compiler options.devServer.hot should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "hot": false, + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.hotOnly overrides compiler options.devServer.hotOnly (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "hotOnly": false, + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.hotOnly overrides compiler options.devServer.hotOnly should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "hotOnly": false, + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.inline should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": false, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.liveReload should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": false, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.open (boolean) should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "open": true, + "openPage": "", + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.open (empty string) should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "open": true, + "openPage": "", + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.open (string) should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "open": "Google Chrome", + "openPage": "", + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.openPage, no options.open should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "open": true, + "openPage": "/different/page", + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.openPage, options.open should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "open": true, + "openPage": "/different/page", + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.stats overrides compiler options.devServer.stats (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": true, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.stats overrides compiler options.devServer.stats should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": true, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.stats should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": "errors-only", + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions options.watchOptions should set correct options 1`] = ` +Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object { + "poll": true, + }, +} +`; + +exports[`normalizeOptions relative options.publicPath (multi compiler) should set correct options 1`] = ` +Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, + "transportMode": Object { + "client": "sockjs", + "server": "sockjs", + }, + "watchOptions": Object {}, +} +`; + +exports[`normalizeOptions relative options.publicPath should set correct options 1`] = ` Object { + "filename": "mybundle.js", + "inline": true, + "liveReload": true, + "publicPath": "/assets/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, "transportMode": Object { "client": "sockjs", "server": "sockjs", @@ -37,6 +1338,15 @@ Object { exports[`normalizeOptions transportMode custom client path should set correct options 1`] = ` Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, "transportMode": Object { "client": "/path/to/custom/client/", "server": "sockjs", @@ -47,6 +1357,15 @@ Object { exports[`normalizeOptions transportMode custom server class should set correct options 1`] = ` Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, "transportMode": Object { "client": "sockjs", "server": [Function], @@ -57,6 +1376,15 @@ Object { exports[`normalizeOptions transportMode custom server path should set correct options 1`] = ` Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, "transportMode": Object { "client": "sockjs", "server": "/path/to/custom/server/", @@ -67,6 +1395,15 @@ Object { exports[`normalizeOptions transportMode sockjs string should set correct options 1`] = ` Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, "transportMode": Object { "client": "sockjs", "server": "sockjs", @@ -77,6 +1414,15 @@ Object { exports[`normalizeOptions transportMode ws object should set correct options 1`] = ` Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, "transportMode": Object { "client": "ws", "server": "ws", @@ -87,6 +1433,15 @@ Object { exports[`normalizeOptions transportMode ws string should set correct options 1`] = ` Object { + "filename": "[name].js", + "inline": true, + "liveReload": true, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + "colors": true, + }, "transportMode": Object { "client": "ws", "server": "ws", @@ -94,15 +1449,3 @@ Object { "watchOptions": Object {}, } `; - -exports[`normalizeOptions watchOptions should set correct options 1`] = ` -Object { - "transportMode": Object { - "client": "sockjs", - "server": "sockjs", - }, - "watchOptions": Object { - "poll": true, - }, -} -`; diff --git a/test/server/utils/addEntries.test.js b/test/server/utils/addEntries.test.js index 1bc6a6cef6..c124c7c36c 100644 --- a/test/server/utils/addEntries.test.js +++ b/test/server/utils/addEntries.test.js @@ -17,7 +17,7 @@ describe('addEntries util', () => { expect(webpackOptions.entry.length).toEqual(2); expect( - normalize(webpackOptions.entry[0]).indexOf('client/index.js?') !== -1 + normalize(webpackOptions.entry[0]).includes('client/index.js?') ).toBeTruthy(); expect(normalize(webpackOptions.entry[1])).toEqual('./foo.js'); }); @@ -33,7 +33,7 @@ describe('addEntries util', () => { expect(webpackOptions.entry.length).toEqual(3); expect( - normalize(webpackOptions.entry[0]).indexOf('client/index.js?') !== -1 + normalize(webpackOptions.entry[0]).includes('client/index.js?') ).toBeTruthy(); expect(webpackOptions.entry[1]).toEqual('./foo.js'); expect(webpackOptions.entry[2]).toEqual('./bar.js'); @@ -54,7 +54,7 @@ describe('addEntries util', () => { expect(webpackOptions.entry.foo.length).toEqual(2); expect( - normalize(webpackOptions.entry.foo[0]).indexOf('client/index.js?') !== -1 + normalize(webpackOptions.entry.foo[0]).includes('client/index.js?') ).toBeTruthy(); expect(webpackOptions.entry.foo[1]).toEqual('./foo.js'); expect(webpackOptions.entry.bar[1]).toEqual('./bar.js'); @@ -70,7 +70,7 @@ describe('addEntries util', () => { expect(webpackOptions.entry[1]).toEqual('./src'); }); - it('should preserves dynamic entry points', (done) => { + it('should preserves dynamic entry points', async () => { let i = 0; const webpackOptions = { // simulate dynamic entry @@ -85,22 +85,21 @@ describe('addEntries util', () => { expect(typeof webpackOptions.entry).toEqual('function'); - webpackOptions - .entry() - .then((entryFirstRun) => - webpackOptions.entry().then((entrySecondRun) => { - expect(entryFirstRun.length).toEqual(2); - expect(entryFirstRun[1]).toEqual('./src-1.js'); - - expect(entrySecondRun.length).toEqual(2); - expect(entrySecondRun[1]).toEqual('./src-2.js'); - done(); - }) - ) - .catch(done); + { + const entry = await webpackOptions.entry(); + + expect(entry.length).toEqual(2); + expect(entry[1]).toEqual('./src-1.js'); + } + { + const entry = await webpackOptions.entry(); + + expect(entry.length).toEqual(2); + expect(entry[1]).toEqual('./src-2.js'); + } }); - it('should preserves asynchronous dynamic entry points', (done) => { + it('should preserves asynchronous dynamic entry points', async () => { let i = 0; const webpackOptions = { // simulate async dynamic entry @@ -117,19 +116,18 @@ describe('addEntries util', () => { expect(typeof webpackOptions.entry).toEqual('function'); - webpackOptions - .entry() - .then((entryFirstRun) => - webpackOptions.entry().then((entrySecondRun) => { - expect(entryFirstRun.length).toEqual(2); - expect(entryFirstRun[1]).toEqual('./src-1.js'); - - expect(entrySecondRun.length).toEqual(2); - expect(entrySecondRun[1]).toEqual('./src-2.js'); - done(); - }) - ) - .catch(done); + { + const entry = await webpackOptions.entry(); + + expect(entry.length).toEqual(2); + expect(entry[1]).toEqual('./src-1.js'); + } + { + const entry = await webpackOptions.entry(); + + expect(entry.length).toEqual(2); + expect(entry[1]).toEqual('./src-2.js'); + } }); it("should prepends webpack's hot reload client script", () => { @@ -312,7 +310,7 @@ describe('addEntries util', () => { if (expectInline) { expect( - normalize(webpackOptions.entry[0]).indexOf('client/index.js?') !== -1 + normalize(webpackOptions.entry[0]).includes('client/index.js?') ).toBeTruthy(); } @@ -344,7 +342,7 @@ describe('addEntries util', () => { if (expectInline) { expect( - normalize(webpackOptions.entry[0]).indexOf('client/index.js?') !== -1 + normalize(webpackOptions.entry[0]).includes('client/index.js?') ).toBeTruthy(); } @@ -400,7 +398,7 @@ describe('addEntries util', () => { expect(webWebpackOptions.entry.length).toEqual(2); expect( - normalize(webWebpackOptions.entry[0]).indexOf('client/index.js?') !== -1 + normalize(webWebpackOptions.entry[0]).includes('client/index.js?') ).toBeTruthy(); expect(normalize(webWebpackOptions.entry[1])).toEqual('./foo.js'); diff --git a/test/server/utils/createConfig.test.js b/test/server/utils/createConfig.test.js index 685941ef56..cc9342419a 100644 --- a/test/server/utils/createConfig.test.js +++ b/test/server/utils/createConfig.test.js @@ -1,6 +1,5 @@ 'use strict'; -const path = require('path'); const createConfig = require('../../../lib/utils/createConfig'); const webpackConfig = require('./../../fixtures/schema/webpack.config.simple'); const webpackConfigNoStats = require('./../../fixtures/schema/webpack.config.no-dev-stats'); @@ -210,154 +209,6 @@ describe('createConfig', () => { expect(config).toMatchSnapshot(); }); - it('publicPath option (not specify)', () => { - const config = createConfig(webpackConfig, argv, { port: 8080 }); - - expect(config).toMatchSnapshot(); - }); - - it('publicPath option (path in devServer option)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - devServer: { publicPath: '/assets/' }, - }), - argv, - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('publicPath option (url in devServer option)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - devServer: { publicPath: 'http://localhost:8080/assets/' }, - }), - argv, - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('publicPath option (url in output option)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - output: { publicPath: 'http://localhost:8080/assets/' }, - }), - argv, - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('publicPath option (path in output option)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - output: { publicPath: '/assets/' }, - }), - argv, - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('publicPath option (path without starting slash in output option)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - output: { publicPath: 'assets/' }, - }), - argv, - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('filename option (in webpack config)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - output: { filename: '[name]-bundle.js' }, - }), - argv, - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('filename option (in output config)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - output: { filename: '[name]-output-bundle.js' }, - }), - argv, - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('filename option (in devServer config)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - devServer: { filename: '[name]-dev-server-bundle.js' }, - }), - argv, - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('watchOptions option (in output config)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - watchOptions: { poll: true }, - }), - argv, - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('watchOptions option (in devServer config)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - devServer: { watchOptions: { poll: true } }, - }), - argv, - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('hot option', () => { - const config = createConfig( - webpackConfig, - Object.assign({}, argv, { hot: true }), - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('hot option (in devServer config)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - devServer: { hot: true }, - }), - argv, - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - it('hotOnly option', () => { const config = createConfig( webpackConfig, @@ -402,56 +253,6 @@ describe('createConfig', () => { expect(config).toMatchSnapshot(); }); - it('contentBase option (string)', () => { - const config = createConfig( - webpackConfig, - Object.assign({}, argv, { contentBase: 'assets' }), - { port: 8080 } - ); - - config.contentBase = path.relative(process.cwd(), config.contentBase); - - expect(config).toMatchSnapshot(); - }); - - it('contentBase option (array)', () => { - const config = createConfig( - webpackConfig, - Object.assign({}, argv, { contentBase: ['assets', 'static'] }), - { port: 8080 } - ); - - config.contentBase = config.contentBase.map((item) => - path.relative(process.cwd(), item) - ); - - expect(config).toMatchSnapshot(); - }); - - it('contentBase option (boolean)', () => { - const config = createConfig( - webpackConfig, - Object.assign({}, argv, { contentBase: false }), - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - - it('contentBase option (string) (in devServer config)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - devServer: { contentBase: 'assets' }, - }), - argv, - { port: 8080 } - ); - - config.contentBase = path.relative(process.cwd(), config.contentBase); - - expect(config).toMatchSnapshot(); - }); - it('watchContentBase option', () => { const config = createConfig( webpackConfig, @@ -486,18 +287,6 @@ describe('createConfig', () => { expect(config).toMatchSnapshot(); }); - it('stats option (colors)', () => { - const config = createConfig( - Object.assign({}, webpackConfig, { - devServer: { stats: { errors: true } }, - }), - Object.assign({}, argv, { color: true }), - { port: 8080 } - ); - - expect(config).toMatchSnapshot(); - }); - it('lazy option', () => { const config = createConfig( webpackConfig, diff --git a/test/server/utils/findPort.test.js b/test/server/utils/findPort.test.js index 8914807a6e..cabfc832e0 100644 --- a/test/server/utils/findPort.test.js +++ b/test/server/utils/findPort.test.js @@ -7,106 +7,109 @@ const findPort = require('../../../lib/utils/findPort'); describe('findPort', () => { let dummyServers = []; - afterEach(() => { + afterEach(async () => { delete process.env.DEFAULT_PORT_RETRY; - return dummyServers - .reduce((p, server) => { - return p.then(() => { - return new Promise((resolve) => { - server.close(resolve); - }); - }); - }, Promise.resolve()) - .then(() => { - dummyServers = []; + async function close(server) { + return new Promise((resolve) => { + server.close(resolve); }); + } + + for (const server of dummyServers) { + // eslint-disable-next-line no-await-in-loop + await close(server); + } + + dummyServers = []; }); - function createDummyServers(n) { - return (Array.isArray(n) ? n : [...new Array(n)]).reduce((p, _, i) => { - return p.then(() => { - return new Promise((resolve) => { - const server = http.createServer(); - dummyServers.push(server); - server.listen(8080 + i, resolve); - }); + async function createDummyServers(n) { + async function create(i) { + return new Promise((resolve) => { + const server = http.createServer(); + dummyServers.push(server); + server.listen(8080 + i, resolve); }); - }, Promise.resolve()); + } + + const samples = [...new Array(n)].map((_, i) => i); + + for (const i of samples) { + // eslint-disable-next-line no-await-in-loop + await create(i); + } } - it('should returns the port when the port is specified', () => { + it('should returns the port when the port is specified', async () => { process.env.DEFAULT_PORT_RETRY = 5; - return findPort(8082).then((port) => { - expect(port).toEqual(8082); - }); + const port = await findPort(8082); + expect(port).toEqual(8082); }); - it.only('should returns the port when the port is null', () => { + it.only('should returns the port when the port is null', async () => { const retryCount = 2; process.env.DEFAULT_PORT_RETRY = 2; - return createDummyServers(retryCount) - .then(() => findPort(null)) - .then((port) => { - expect(port).toEqual(8080 + retryCount); - }); + await createDummyServers(retryCount); + + const port = await findPort(null); + + expect(port).toEqual(8080 + retryCount); }); - it('should returns the port when the port is undefined', () => { + it('should returns the port when the port is undefined', async () => { const retryCount = 2; process.env.DEFAULT_PORT_RETRY = 2; - return ( - createDummyServers(retryCount) - // eslint-disable-next-line no-undefined - .then(() => findPort(undefined)) - .then((port) => { - expect(port).toEqual(8080 + retryCount); - }) - ); + await createDummyServers(retryCount); + + // eslint-disable-next-line no-undefined + const port = findPort(undefined); + + expect(port).toEqual(8080 + retryCount); }); - it('should retry finding the port for up to defaultPortRetry times (number)', () => { + it('should retry finding the port for up to defaultPortRetry times (number)', async () => { const retryCount = 3; process.env.DEFAULT_PORT_RETRY = retryCount; - return createDummyServers(retryCount) - .then(() => findPort()) - .then((port) => { - expect(port).toEqual(8080 + retryCount); - }); + await createDummyServers(retryCount); + + const port = await findPort(); + + expect(port).toEqual(8080 + retryCount); }); - it('should retry finding the port for up to defaultPortRetry times (string)', () => { + it('should retry finding the port for up to defaultPortRetry times (string)', async () => { const retryCount = 3; process.env.DEFAULT_PORT_RETRY = `${retryCount}`; - return createDummyServers(retryCount) - .then(() => findPort()) - .then((port) => { - expect(port).toEqual(8080 + retryCount); - }); + await createDummyServers(retryCount); + + const port = await findPort(); + + expect(port).toEqual(8080 + retryCount); }); - it('should retry finding the port when serial ports are busy', () => { + it('should retry finding the port when serial ports are busy', async () => { const busyPorts = [8080, 8081, 8082, 8083]; process.env.DEFAULT_PORT_RETRY = 3; - return createDummyServers(busyPorts) - .then(() => findPort()) - .then((port) => { - expect(port).toEqual(8080 + busyPorts.length); - }); + await createDummyServers(busyPorts); + + const port = await findPort(); + + expect(port).toEqual(8080 + busyPorts.length); }); - it("should throws the error when the port isn't found", () => { + it("should throws the error when the port isn't found", async () => { expect.assertions(1); const spy = jest @@ -119,12 +122,14 @@ describe('findPort', () => { process.env.DEFAULT_PORT_RETRY = 0; - return createDummyServers(retryCount) - .then(() => findPort()) - .catch((err) => { - expect(err.message).toMatchSnapshot(); + await createDummyServers(retryCount); - spy.mockRestore(); - }); + try { + await findPort(); + } catch (err) { + expect(err.message).toMatchSnapshot(); + } + + spy.mockRestore(); }); }); diff --git a/test/server/utils/handleStdin.test.js b/test/server/utils/handleStdin.test.js new file mode 100644 index 0000000000..5d44e0dc06 --- /dev/null +++ b/test/server/utils/handleStdin.test.js @@ -0,0 +1,41 @@ +'use strict'; + +const timer = require('../../helpers/timer'); +const handleStdin = require('../../../lib/utils/handleStdin'); + +describe('handleStdin', () => { + let exitSpy; + + beforeAll(() => { + exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {}); + }); + + afterEach(() => { + process.stdin.removeAllListeners('end'); + exitSpy.mockReset(); + }); + + describe('enabled', () => { + it('should exit process', async () => { + handleStdin({ + stdin: true, + }); + process.stdin.emit('end'); + + await timer(1000); + process.stdin.pause(); + expect(exitSpy.mock.calls[0]).toEqual([0]); + }); + }); + + describe('disabled (default)', () => { + it('should not exit process', async () => { + handleStdin({}); + process.stdin.emit('end'); + + await timer(1000); + process.stdin.pause(); + expect(exitSpy.mock.calls.length).toEqual(0); + }); + }); +}); diff --git a/test/server/utils/normalizeOptions.test.js b/test/server/utils/normalizeOptions.test.js index 1490b36088..d3c27bc5fb 100644 --- a/test/server/utils/normalizeOptions.test.js +++ b/test/server/utils/normalizeOptions.test.js @@ -1,9 +1,17 @@ 'use strict'; +const path = require('path'); const webpack = require('webpack'); -const normalizeOptions = require('../../../lib/utils/normalizeOptions'); +const multiWebpackConfig = require('../../fixtures/multi-compiler-config/webpack.config'); +const simpleWebpackConfig = require('../../fixtures/simple-config/webpack.config'); +const webpackConfigNoStats = require('../../fixtures/schema/webpack.config.no-dev-stats'); describe('normalizeOptions', () => { + jest.setMock('supports-color', { + stdout: true, + }); + const normalizeOptions = require('../../../lib/utils/normalizeOptions'); + const cases = [ { title: 'no options', @@ -11,32 +19,85 @@ describe('normalizeOptions', () => { options: {}, optionsResults: null, }, + + // compiler's options.devServer works + + { + title: 'compiler options.devServer', + webpackConfig: { + devServer: { + hot: true, + clientLogLevel: 'silent', + }, + }, + multiCompiler: false, + options: {}, + optionsResults: null, + }, + + { + title: 'complex compiler options.devServer', + webpackConfig: webpackConfigNoStats, + multiCompiler: false, + options: {}, + optionsResults: { + contentBase: path.resolve('_contentBase'), + }, + }, + + // normal options override compiler's options.devServer + { - title: 'contentBase string', + title: 'normal options override compiler options.devServer', + webpackConfig: { + devServer: { + hot: true, + clientLogLevel: 'silent', + }, + }, multiCompiler: false, options: { - contentBase: '/path/to/dist', + hot: false, + clientLogLevel: 'debug', }, optionsResults: null, }, + + // contentBase { - title: 'contentBase array', + title: 'contentBase (string)', multiCompiler: false, options: { - contentBase: ['/path/to/dist1', '/path/to/dist2'], + contentBase: 'path/to/dist', + }, + optionsResults: { + contentBase: path.resolve('path/to/dist'), }, - optionsResults: null, }, { - title: 'watchOptions', + title: 'contentBase (array)', multiCompiler: false, options: { - watchOptions: { - poll: true, - }, + contentBase: ['path/to/dist1', 'path/to/dist2'], + }, + optionsResults: { + contentBase: [ + path.resolve('path/to/dist1'), + path.resolve('path/to/dist2'), + ], + }, + }, + { + title: 'contentBase (boolean)', + multiCompiler: false, + options: { + contentBase: false, }, optionsResults: null, }, + + // watchOptions + { title: 'transportMode sockjs string', multiCompiler: false, @@ -94,37 +155,505 @@ describe('normalizeOptions', () => { }, optionsResults: null, }, + + { + title: 'no options.filename, no compiler filename', + webpackConfig: null, + multiCompiler: false, + options: {}, + optionsResults: null, + }, + { + title: 'no options.filename, existing compiler filename', + webpackConfig: { + output: { + filename: 'mybundle.js', + }, + }, + multiCompiler: false, + options: {}, + optionsResults: null, + }, + { + title: 'options.watchOptions', + webpackConfig: null, + multiCompiler: false, + options: { + watchOptions: { + poll: true, + }, + }, + optionsResults: null, + }, + { + title: 'compiler watchOptions', + webpackConfig: { + watchOptions: { + poll: true, + }, + }, + multiCompiler: false, + options: {}, + optionsResults: null, + }, + + // filename + + { + title: 'no options.filename, no compiler filename', + webpackConfig: null, + multiCompiler: false, + options: {}, + optionsResults: null, + }, + { + title: 'no options.filename, existing compiler filename', + webpackConfig: { + output: { + filename: 'mybundle.js', + }, + }, + multiCompiler: false, + options: {}, + optionsResults: null, + }, + { + title: 'existing options.filename, no compiler filename', + webpackConfig: null, + multiCompiler: false, + options: { + filename: 'devserver-bundle.js', + }, + optionsResults: null, + }, + { + title: 'existing options.filename, existing compiler filename', + webpackConfig: { + output: { + filename: 'mybundle.js', + }, + }, + multiCompiler: false, + options: { + filename: 'devserver-bundle.js', + }, + optionsResults: null, + }, + + // publicPath + + { + title: 'no options.publicPath, no compiler publicPath', + webpackConfig: null, + multiCompiler: false, + options: {}, + }, + { + title: 'no options.publicPath, relative compiler publicPath', + webpackConfig: { + output: { + publicPath: '/assets/', + }, + }, + multiCompiler: false, + options: {}, + }, + { + title: 'no options.publicPath, bad relative compiler publicPath', + webpackConfig: { + output: { + publicPath: 'assets/', + }, + }, + multiCompiler: false, + options: {}, + }, + { + title: 'no options.publicPath, / compiler publicPath', + webpackConfig: { + output: { + publicPath: '/', + }, + }, + multiCompiler: false, + options: {}, + }, + { + title: 'no options.publicPath, absolute url compiler publicPath', + webpackConfig: { + output: { + publicPath: 'http://localhost:8080/assets/', + }, + }, + multiCompiler: false, + options: {}, + }, + { + title: 'relative options.publicPath', + webpackConfig: { + output: { + publicPath: '/', + }, + }, + multiCompiler: false, + options: { + publicPath: '/assets/', + }, + }, + { + title: 'bad relative options.publicPath', + webpackConfig: { + output: { + publicPath: '/', + }, + }, + multiCompiler: false, + options: { + publicPath: 'assets/', + }, + }, + { + title: 'absolute options.publicPath', + webpackConfig: { + output: { + publicPath: '/', + }, + }, + multiCompiler: false, + options: { + publicPath: 'http://localhost:8080/assets/', + }, + }, + + // stats + + { + title: 'options.stats', + webpackConfig: null, + multiCompiler: false, + options: { + stats: 'errors-only', + }, + }, + { + title: 'compiler stats', + webpackConfig: { + stats: { errors: true }, + }, + multiCompiler: false, + options: {}, + }, + + // inline + + { + title: 'options.inline', + webpackConfig: null, + multiCompiler: false, + options: { + inline: false, + }, + }, + + // liveReload + + { + title: 'options.liveReload', + webpackConfig: null, + multiCompiler: false, + options: { + liveReload: false, + }, + }, + + // open/openPage + + { + title: 'options.open (boolean)', + webpackConfig: null, + multiCompiler: false, + options: { + open: true, + }, + }, + { + title: 'options.open (string)', + webpackConfig: null, + multiCompiler: false, + options: { + open: 'Google Chrome', + }, + }, + { + title: 'options.open (empty string)', + webpackConfig: null, + multiCompiler: false, + options: { + open: '', + }, + }, + { + title: 'options.openPage, no options.open', + webpackConfig: null, + multiCompiler: false, + options: { + openPage: '/different/page', + }, + }, + { + title: 'options.openPage, options.open', + webpackConfig: null, + multiCompiler: false, + options: { + open: true, + openPage: '/different/page', + }, + }, + + // host + + // this test is here because previously devServer.host would override CLI host option + // only if CLI's options.host was localhost. Since we want a firm stance that + // normal/CLI options always override the compiler's devServer options, this is no + // longer the case. + { + title: 'options.host localhost overrides compiler options.devServer.host', + webpackConfig: { + devServer: { + host: '0.0.0.0', + }, + }, + multiCompiler: false, + options: { + host: 'localhost', + }, + optionsResults: null, + }, + { + title: 'options.host', + webpackConfig: null, + multiCompiler: false, + options: { + host: '0.0.0.0', + }, + optionsResults: null, + }, + + { + title: 'options.hot overrides compiler options.devServer.hot', + webpackConfig: { + devServer: { + hot: true, + }, + }, + multiCompiler: false, + options: { + hot: false, + }, + optionsResults: null, + }, + + { + title: 'options.hotOnly overrides compiler options.devServer.hotOnly', + webpackConfig: { + devServer: { + hotOnly: true, + }, + }, + multiCompiler: false, + options: { + hotOnly: false, + }, + optionsResults: null, + }, + + { + title: + 'options.clientLogLevel overrides compiler options.devServer.clientLogLevel', + webpackConfig: { + devServer: { + clientLogLevel: 'silent', + }, + }, + multiCompiler: false, + options: { + clientLogLevel: 'debug', + }, + optionsResults: null, + }, + + { + title: 'compiler options.devServer.stats', + webpackConfig: { + devServer: { + stats: { + colors: true, + }, + }, + }, + multiCompiler: false, + options: {}, + optionsResults: null, + }, + { + title: 'options.stats overrides compiler options.devServer.stats', + webpackConfig: { + devServer: { + // this stats object should not be used + stats: { + colors: true, + }, + }, + }, + multiCompiler: false, + options: { + stats: { + cached: true, + }, + }, + optionsResults: null, + }, + { + title: + 'compiler options.devServer.stats overrides compiler options.stats', + webpackConfig: { + devServer: { + stats: { + colors: true, + }, + }, + // this stats object should not be used for the dev server + stats: 'none', + }, + multiCompiler: false, + options: {}, + optionsResults: null, + }, + { + title: 'compiler options.stats', + webpackConfig: { + stats: 'none', + }, + multiCompiler: false, + options: {}, + optionsResults: null, + }, + + { + title: + 'compiler options.stats.colors does not override options.stats.colors', + webpackConfig: { + stats: { + // colors for the dev server will be true, because the main options object + // explicitly sets colors to true below + colors: false, + }, + }, + multiCompiler: false, + options: { + stats: { + colors: true, + cached: true, + }, + }, + optionsResults: null, + }, + { + title: 'compiler options.stats.colors used', + webpackConfig: { + stats: { + // colors for the dev server will be false, because the main options object + // does not set colors below + colors: false, + }, + }, + multiCompiler: false, + options: { + stats: { + cached: true, + }, + }, + optionsResults: null, + }, ]; cases.forEach((data) => { - describe(data.title, () => { - let compiler; - beforeAll(() => { - let webpackConfig; - if (data.multiCompiler) { - webpackConfig = require('../../fixtures/multi-compiler-config/webpack.config'); - } else { - webpackConfig = require('../../fixtures/simple-config/webpack.config'); - } + let repeatWithMultiCompiler = false; + if (data.webpackConfig) { + repeatWithMultiCompiler = true; + } + + const useMultiCompiler = [false]; + + if (repeatWithMultiCompiler) { + useMultiCompiler.push(true); + } + + useMultiCompiler.forEach((multi) => { + data.multiCompiler = multi; + describe( + data.title + (data.multiCompiler ? ' (multi compiler)' : ''), + () => { + let compiler; + beforeAll(() => { + // this will merge webpack configs through a depth of one layer of objects, + // specifically so that the webpack config output object can be merged + const mergeConfigs = (baseConfig, config) => { + Object.keys(config).forEach((key1) => { + if (typeof config[key1] === 'object') { + Object.keys(config[key1]).forEach((key2) => { + if (!baseConfig[key1]) { + baseConfig[key1] = {}; + } + baseConfig[key1][key2] = config[key1][key2]; + }); + } else { + baseConfig[key1] = config[key1]; + } + }); + }; + + let webpackConfig; + if (data.multiCompiler) { + webpackConfig = [Object.assign({}, multiWebpackConfig[0])]; + } else { + webpackConfig = Object.assign({}, simpleWebpackConfig); + } + + if (data.webpackConfig) { + mergeConfigs( + data.multiCompiler ? webpackConfig[0] : webpackConfig, + data.webpackConfig + ); + } + + compiler = webpack(webpackConfig); + }); + + it('should set correct options', () => { + const optionsClone = Object.assign({}, data.options); + const originalContentBase = optionsClone.contentBase; + normalizeOptions(compiler, optionsClone); + if (data.optionsResults) { + Object.keys(data.optionsResults).forEach((key) => { + expect(optionsClone[key]).toEqual(data.optionsResults[key]); + delete optionsClone[key]; + }); + } - compiler = webpack(webpackConfig); - }); - - it('should set correct options', () => { - const originalContentBase = data.options.contentBase; - normalizeOptions(compiler, data.options); - if (data.optionsResults) { - expect(data.options).toEqual(data.optionsResults); - } else { - if (data.options.contentBase !== originalContentBase) { - // we don't want this in the snapshot, because it is - // the current working directory - expect(data.options.contentBase).toEqual(process.cwd()); - delete data.options.contentBase; - } - expect(data.options).toMatchSnapshot(); + if ( + optionsClone.contentBase && + optionsClone.contentBase !== originalContentBase + ) { + // we don't want this in the snapshot, because it is + // the current working directory + expect(optionsClone.contentBase).toEqual(process.cwd()); + delete optionsClone.contentBase; + } + expect(optionsClone).toMatchSnapshot(); + }); } - }); + ); }); }); }); diff --git a/test/server/utils/routes.test.js b/test/server/utils/routes.test.js index acc94eb8eb..f4b5030e3d 100644 --- a/test/server/utils/routes.test.js +++ b/test/server/utils/routes.test.js @@ -16,112 +16,106 @@ describe('routes util', () => { afterAll(testServer.close); - it('should handles GET request to live bundle', (done) => { - req.get('/__webpack_dev_server__/live.bundle.js').then(({ res }) => { - expect(res.headers['content-type']).toEqual('application/javascript'); - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles GET request to live bundle', async () => { + const { headers, statusCode } = await req.get( + '/__webpack_dev_server__/live.bundle.js' + ); + + expect(headers['content-type']).toEqual('application/javascript'); + expect(statusCode).toEqual(200); }); - it('should handles HEAD request to live bundle', (done) => { - req.head('/__webpack_dev_server__/live.bundle.js').then(({ res }) => { - expect(res.headers['content-type']).toEqual('application/javascript'); - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles HEAD request to live bundle', async () => { + const { headers, statusCode } = await req.head( + '/__webpack_dev_server__/live.bundle.js' + ); + + expect(headers['content-type']).toEqual('application/javascript'); + expect(statusCode).toEqual(200); }); - it('should handles GET request to sockjs bundle', (done) => { - req.get('/__webpack_dev_server__/sockjs.bundle.js').then(({ res }) => { - expect(res.headers['content-type']).toEqual('application/javascript'); - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles GET request to sockjs bundle', async () => { + const { headers, statusCode } = await req.get( + '/__webpack_dev_server__/sockjs.bundle.js' + ); + + expect(headers['content-type']).toEqual('application/javascript'); + expect(statusCode).toEqual(200); }); - it('should handles HEAD request to sockjs bundle', (done) => { - req.head('/__webpack_dev_server__/sockjs.bundle.js').then(({ res }) => { - expect(res.headers['content-type']).toEqual('application/javascript'); - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles HEAD request to sockjs bundle', async () => { + const { headers, statusCode } = await req.head( + '/__webpack_dev_server__/sockjs.bundle.js' + ); + + expect(headers['content-type']).toEqual('application/javascript'); + expect(statusCode).toEqual(200); }); - it('should handles GET request to inline bundle', (done) => { - req.get('/webpack-dev-server.js').then(({ res }) => { - expect(res.headers['content-type']).toEqual('application/javascript'); - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles GET request to inline bundle', async () => { + const { headers, statusCode } = await req.get('/webpack-dev-server.js'); + + expect(headers['content-type']).toEqual('application/javascript'); + expect(statusCode).toEqual(200); }); - it('should handles HEAD request to inline bundle', (done) => { - req.head('/webpack-dev-server.js').then(({ res }) => { - expect(res.headers['content-type']).toEqual('application/javascript'); - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles HEAD request to inline bundle', async () => { + const { headers, statusCode } = await req.head('/webpack-dev-server.js'); + + expect(headers['content-type']).toEqual('application/javascript'); + expect(statusCode).toEqual(200); }); - it('should handles GET request to live html', (done) => { - req.get('/webpack-dev-server/').then(({ res }) => { - expect(res.headers['content-type']).toEqual('text/html'); - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles GET request to live html', async () => { + const { headers, statusCode } = await req.get('/webpack-dev-server/'); + + expect(headers['content-type']).toEqual('text/html'); + expect(statusCode).toEqual(200); }); - it('should handles HEAD request to live html', (done) => { - req.head('/webpack-dev-server/').then(({ res }) => { - expect(res.headers['content-type']).toEqual('text/html'); - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles HEAD request to live html', async () => { + const { headers, statusCode } = await req.head('/webpack-dev-server/'); + + expect(headers['content-type']).toEqual('text/html'); + expect(statusCode).toEqual(200); }); - it('should handles GET request to directory index', (done) => { - req.get('/webpack-dev-server').then(({ res }) => { - expect(res.headers['content-type']).toEqual('text/html'); - expect(res.statusCode).toEqual(200); - expect(res.text).toMatchSnapshot(); - done(); - }); + it('should handles GET request to directory index', async () => { + const { headers, statusCode, text } = await req.get('/webpack-dev-server'); + + expect(headers['content-type']).toEqual('text/html'); + expect(statusCode).toEqual(200); + expect(text).toMatchSnapshot(); }); - it('should handles HEAD request to directory index', (done) => { - req.head('/webpack-dev-server').then(({ res }) => { - expect(res.headers['content-type']).toEqual('text/html'); - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles HEAD request to directory index', async () => { + const { headers, statusCode } = await req.head('/webpack-dev-server'); + + expect(headers['content-type']).toEqual('text/html'); + expect(statusCode).toEqual(200); }); - it('should handles GET request to magic html', (done) => { - req.get('/main').then(({ res }) => { - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles GET request to magic html', async () => { + const { statusCode } = await req.get('/main'); + + expect(statusCode).toEqual(200); }); - it('should handles HEAD request to magic html', (done) => { - req.head('/main').then(({ res }) => { - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles HEAD request to magic html', async () => { + const { statusCode } = await req.head('/main'); + + expect(statusCode).toEqual(200); }); - it('should handles GET request to main chunk', (done) => { - req.get('/main.js').then(({ res }) => { - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles GET request to main chunk', async () => { + const { statusCode } = await req.get('/main.js'); + + expect(statusCode).toEqual(200); }); - it('should handles HEAD request to main chunk', (done) => { - req.head('/main.js').then(({ res }) => { - expect(res.statusCode).toEqual(200); - done(); - }); + it('should handles HEAD request to main chunk', async () => { + const { statusCode } = await req.head('/main.js'); + + expect(statusCode).toEqual(200); }); }); diff --git a/test/server/utils/runOpen.test.js b/test/server/utils/runOpen.test.js index e6fa3b155a..1ae6b092d1 100644 --- a/test/server/utils/runOpen.test.js +++ b/test/server/utils/runOpen.test.js @@ -1,23 +1,24 @@ 'use strict'; -const opn = require('opn'); +const open = require('open'); const runOpen = require('../../../lib/utils/runOpen'); -jest.mock('opn'); +jest.mock('open'); describe('runOpen util', () => { afterEach(() => { - opn.mockClear(); + open.mockClear(); }); describe('should open browser', () => { beforeEach(() => { - opn.mockImplementation(() => Promise.resolve()); + open.mockImplementation(() => Promise.resolve()); }); - it('on specify URL', () => { - return runOpen('https://example.com', {}, console).then(() => { - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + it('on specify URL', async () => { + await runOpen('https://example.com', {}, console); + + expect(open.mock.calls[0]).toMatchInlineSnapshot(` Array [ "https://example.com", Object { @@ -25,16 +26,16 @@ describe('runOpen util', () => { }, ] `); - }); }); - it('on specify URL with page', () => { - return runOpen( + it('on specify URL with page', async () => { + await runOpen( 'https://example.com', { openPage: '/index.html' }, console - ).then(() => { - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + ); + + expect(open.mock.calls[0]).toMatchInlineSnapshot(` Array [ "https://example.com/index.html", Object { @@ -42,16 +43,12 @@ describe('runOpen util', () => { }, ] `); - }); }); - it('on specify URL in Google Chrome', () => { - return runOpen( - 'https://example.com', - { open: 'Google Chrome' }, - console - ).then(() => { - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + it('on specify URL in Google Chrome', async () => { + await runOpen('https://example.com', { open: 'Google Chrome' }, console); + + expect(open.mock.calls[0]).toMatchInlineSnapshot(` Array [ "https://example.com", Object { @@ -60,16 +57,16 @@ describe('runOpen util', () => { }, ] `); - }); }); - it('on specify URL with page in Google Chrome ', () => { - return runOpen( + it('on specify URL with page in Google Chrome ', async () => { + await runOpen( 'https://example.com', { open: 'Google Chrome', openPage: '/index.html' }, console - ).then(() => { - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + ); + + expect(open.mock.calls[0]).toMatchInlineSnapshot(` Array [ "https://example.com/index.html", Object { @@ -78,16 +75,17 @@ describe('runOpen util', () => { }, ] `); - }); }); + }); - it('on specify absolute https URL with page in Google Chrome ', () => { - return runOpen( - 'https://example.com', - { open: 'Google Chrome', openPage: 'https://example2.com' }, - console - ).then(() => { - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + it('on specify absolute https URL with page in Google Chrome ', async () => { + await runOpen( + 'https://example.com', + { open: 'Google Chrome', openPage: 'https://example2.com' }, + console + ); + + expect(open.mock.calls[0]).toMatchInlineSnapshot(` Array [ "https://example2.com", Object { @@ -96,16 +94,16 @@ describe('runOpen util', () => { }, ] `); - }); - }); + }); - it('on specify absolute http URL with page in Google Chrome ', () => { - return runOpen( - 'https://example.com', - { open: 'Google Chrome', openPage: 'http://example2.com' }, - console - ).then(() => { - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + it('on specify absolute http URL with page in Google Chrome ', async () => { + runOpen( + 'https://example.com', + { open: 'Google Chrome', openPage: 'http://example2.com' }, + console + ); + + expect(open.mock.calls[0]).toMatchInlineSnapshot(` Array [ "http://example2.com", Object { @@ -114,27 +112,26 @@ describe('runOpen util', () => { }, ] `); - }); - }); }); describe('should not open browser', () => { const logMock = { warn: jest.fn() }; beforeEach(() => { - opn.mockImplementation(() => Promise.reject()); + open.mockImplementation(() => Promise.reject()); }); afterEach(() => { logMock.warn.mockClear(); }); - it('on specify URL and log error', () => { - return runOpen('https://example.com', {}, logMock).then(() => { - expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open browser. If you are running in a headless environment, please do not use the --open flag"` - ); - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + it('on specify URL and log error', async () => { + await runOpen('https://example.com', {}, logMock); + + expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( + `"Unable to open browser. If you are running in a headless environment, please do not use the --open flag"` + ); + expect(open.mock.calls[0]).toMatchInlineSnapshot(` Array [ "https://example.com", Object { @@ -142,19 +139,19 @@ describe('runOpen util', () => { }, ] `); - }); }); - it('on specify URL with page and log error', () => { - return runOpen( + it('on specify URL with page and log error', async () => { + await runOpen( 'https://example.com', { openPage: '/index.html' }, logMock - ).then(() => { - expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open browser. If you are running in a headless environment, please do not use the --open flag"` - ); - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + ); + + expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( + `"Unable to open browser. If you are running in a headless environment, please do not use the --open flag"` + ); + expect(open.mock.calls[0]).toMatchInlineSnapshot(` Array [ "https://example.com/index.html", Object { @@ -162,19 +159,15 @@ describe('runOpen util', () => { }, ] `); - }); }); - it('on specify URL in Google Chrome and log error', () => { - return runOpen( - 'https://example.com', - { open: 'Google Chrome' }, - logMock - ).then(() => { - expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open browser: Google Chrome. If you are running in a headless environment, please do not use the --open flag"` - ); - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + it('on specify URL in Google Chrome and log error', async () => { + await runOpen('https://example.com', { open: 'Google Chrome' }, logMock); + + expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( + `"Unable to open browser: Google Chrome. If you are running in a headless environment, please do not use the --open flag"` + ); + expect(open.mock.calls[0]).toMatchInlineSnapshot(` Array [ "https://example.com", Object { @@ -183,19 +176,19 @@ describe('runOpen util', () => { }, ] `); - }); }); - it('on specify URL with page in Google Chrome and log error ', () => { - return runOpen( + it('on specify URL with page in Google Chrome and log error ', async () => { + await runOpen( 'https://example.com', { open: 'Google Chrome', openPage: '/index.html' }, logMock - ).then(() => { - expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open browser: Google Chrome. If you are running in a headless environment, please do not use the --open flag"` - ); - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + ); + + expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( + `"Unable to open browser: Google Chrome. If you are running in a headless environment, please do not use the --open flag"` + ); + expect(open.mock.calls[0]).toMatchInlineSnapshot(` Array [ "https://example.com/index.html", Object { @@ -204,7 +197,6 @@ describe('runOpen util', () => { }, ] `); - }); }); }); }); diff --git a/test/server/utils/startUnixSocket.test.js b/test/server/utils/startUnixSocket.test.js new file mode 100644 index 0000000000..e0ab7b899a --- /dev/null +++ b/test/server/utils/startUnixSocket.test.js @@ -0,0 +1,124 @@ +'use strict'; + +const net = require('net'); +const fs = require('fs'); +const path = require('path'); +const TestUnixSocket = require('../../helpers/test-unix-socket'); +const { skipTestOnWindows } = require('../../helpers/conditional-test'); +const startUnixSocket = require('../../../lib/utils/startUnixSocket'); + +describe('startUnixSocket', () => { + const socketPath = path.join('.', 'startUnixSocket.webpack.sock'); + let testUnixSocket = null; + + describe('path to a non-existent file', () => { + let err; + beforeAll((done) => { + testUnixSocket = new TestUnixSocket(); + startUnixSocket(testUnixSocket.server, socketPath, (e) => { + err = e; + done(); + }); + }); + + it('should work as Unix socket or error on windows', (done) => { + if (process.platform === 'win32') { + expect(err.code).toEqual('EACCES'); + done(); + } else { + const clientSocket = new net.Socket(); + clientSocket.connect({ path: socketPath }, () => { + // this means the connection was made successfully + expect(true).toBeTruthy(); + done(); + }); + } + }); + + afterAll((done) => { + testUnixSocket.close(() => { + fs.unlink(socketPath, done); + }); + }); + }); + + describe('path to existent, unused file', () => { + if (skipTestOnWindows('Unix sockets are not supported on Windows')) { + return; + } + + beforeAll((done) => { + fs.writeFileSync(socketPath, ''); + testUnixSocket = new TestUnixSocket(); + startUnixSocket(testUnixSocket.server, socketPath, done); + }); + + it('should work as Unix socket', (done) => { + const clientSocket = new net.Socket(); + clientSocket.connect({ path: socketPath }, () => { + // this means the connection was made successfully + expect(true).toBeTruthy(); + done(); + }); + }); + + afterAll((done) => { + testUnixSocket.close(() => { + fs.unlink(socketPath, done); + }); + }); + }); + + describe('path to existent file with listening server', () => { + if (skipTestOnWindows('Unix sockets are not supported on Windows')) { + return; + } + + let dummyUnixSocket; + beforeAll((done) => { + dummyUnixSocket = new TestUnixSocket(); + dummyUnixSocket.server.listen(socketPath, 511, () => { + done(); + }); + }); + + it('should throw already used error', (done) => { + testUnixSocket = new TestUnixSocket(); + startUnixSocket(testUnixSocket.server, socketPath, (err) => { + expect(err).not.toBeNull(); + expect(err).not.toBeUndefined(); + expect(err.message).toEqual('This socket is already used'); + testUnixSocket.close(done); + }); + }); + + afterAll((done) => { + dummyUnixSocket.close(() => { + fs.unlink(socketPath, done); + }); + }); + }); + + describe('path to existent, unused file', () => { + beforeAll(() => { + fs.writeFileSync(socketPath, ''); + testUnixSocket = new TestUnixSocket(); + }); + + // this test is significant because previously the callback was called + // twice if a file at the given socket path already existed, but + // could be removed + it('should only call server.listen callback once', (done) => { + const userCallback = jest.fn(); + startUnixSocket(testUnixSocket.server, socketPath, userCallback); + setTimeout(() => { + expect(userCallback).toBeCalledTimes(1); + done(); + }, 3000); + }); + + afterAll((done) => { + testUnixSocket.close(done); + }); + }); +});