UNPKG

nwb

Version:

A toolkit for React, Preact & Inferno apps, React libraries and other npm modules for the web, with no configuration (until you need it)

263 lines (218 loc) 7.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processPluginConfig = processPluginConfig; exports.findPlugin = findPlugin; exports.getKarmaPluginConfig = getKarmaPluginConfig; exports.default = createKarmaConfig; var _path = _interopRequireDefault(require("path")); var _webpackMerge = _interopRequireDefault(require("webpack-merge")); var _createWebpackConfig = _interopRequireDefault(require("./createWebpackConfig")); var _debug = _interopRequireDefault(require("./debug")); var _errors = require("./errors"); var _utils = require("./utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // The following defaults are combined into a single extglob-style pattern to // avoid generating "pattern ... does not match any file" warnings. // Exclude top-level test dirs and __tests__ dirs under src/ from code coverage // by default. const DEFAULT_EXCLUDE_FROM_COVERAGE = ['test/', 'tests/', 'src/**/__tests__/']; // Not every file in a test directory is a test and tests may also be co-located // with the code they test, so determine test files by suffix. const DEFAULT_TEST_FILES = ['+(src|test?(s))/**/*+(.spec|.test).js']; /** * Browser, framework and reporter config can be passed as strings or as plugin * objects. This handles figuring out which names and plugins have been provided * and automatically extracting the first browser/framework/reporter name from a * plugin object. */ function processPluginConfig(configs) { let names = []; let plugins = []; configs.forEach(config => { if ((0, _utils.typeOf)(config) === 'string') { names.push(config); } else { names.push(Object.keys(config)[0].split(':').pop()); plugins.push(config); } }); return [names, plugins]; } /** * Finds a karma plugin with the given type:name id. If a plugin object contains * multiple plugins (e.g. karma-chai-plugins), only the first will be checked. */ function findPlugin(plugins, findId) { for (let i = 0, l = plugins.length; i < l; i++) { if ((0, _utils.typeOf)(plugins[i]) !== 'object') { continue; } if (Object.keys(plugins[i])[0] === findId) { return plugins[i]; } } return null; } /** * Handles creation of Karma config based on Karma plugins. */ function getKarmaPluginConfig({ codeCoverage = false, userConfig = {} } = {}) { let browsers = ['PhantomJS']; let frameworks = ['mocha']; let plugins = [require('karma-sourcemap-loader'), require('karma-webpack')]; // Default reporter if the user configure their own frameworks let reporters = ['dots']; // Browsers, frameworks and reporters can be configured as a list containing // names of bundled plugins, or plugin objects. if (userConfig.browsers) { let [browserNames, browserPlugins] = processPluginConfig(userConfig.browsers); browsers = browserNames; plugins = plugins.concat(browserPlugins); } if (userConfig.frameworks) { let [frameworkNames, frameworkPlugins] = processPluginConfig(userConfig.frameworks); frameworks = frameworkNames; plugins = plugins.concat(frameworkPlugins); } else { // Use the Mocha reporter by default if the user didn't configure frameworks reporters = ['mocha']; } if (userConfig.reporters) { let [reporterNames, reporterPlugins] = processPluginConfig(userConfig.reporters); reporters = reporterNames; plugins = plugins.concat(reporterPlugins); } // Plugins can be provided as a list of imported plugin objects if (userConfig.plugins) { plugins = plugins.concat(userConfig.plugins); } // Ensure nwb's version of plugins get loaded if they're going to be used and = // haven't been provided by the user. if (frameworks.indexOf('mocha') !== -1 && !findPlugin(plugins, 'framework:mocha')) { plugins.push(require('karma-mocha')); } if (reporters.indexOf('mocha') !== -1 && !findPlugin(plugins, 'reporter:mocha')) { plugins.push(require('karma-mocha-reporter')); } if (browsers.indexOf('PhantomJS') !== -1 && !findPlugin(plugins, 'launcher:PhantomJS')) { plugins.push(require('karma-phantomjs-launcher')); } if (browsers.some(function matchChrom(b) { return /Chrom/.test(b); }) && !findPlugin(plugins, 'launcher:Chrome')) { plugins.push(require('karma-chrome-launcher')); } if (codeCoverage) { plugins.push(require('karma-coverage')); reporters.push('coverage'); } return { browsers, frameworks, plugins, reporters }; } function createKarmaConfig(args, buildConfig, pluginConfig, userConfig) { let isCi = process.env.CI || process.env.CONTINUOUS_INTEGRATION; let codeCoverage = isCi || !!args.coverage; let userKarma = userConfig.karma || {}; let { browsers, frameworks, plugins, reporters } = getKarmaPluginConfig({ codeCoverage, userConfig: userKarma }); let { excludeFromCoverage = DEFAULT_EXCLUDE_FROM_COVERAGE } = userKarma; let testFiles = userKarma.testFiles || DEFAULT_TEST_FILES; // Polyfill by default for browsers which lack features (hello PhantomJS) let files = [require.resolve('@babel/polyfill/dist/polyfill.js')]; let preprocessors = {}; if (userKarma.testContext) { files.push(userKarma.testContext); preprocessors[userKarma.testContext] = ['webpack', 'sourcemap']; } else { testFiles.forEach(testGlob => { files.push(testGlob); preprocessors[testGlob] = ['webpack', 'sourcemap']; }); } // Tweak Babel config for code coverage when necessary buildConfig = { ...buildConfig }; if (!buildConfig.babel) { buildConfig.babel = {}; } if (codeCoverage) { let exclude = ['node_modules/', ...excludeFromCoverage, ...testFiles]; if (userKarma.testContext) { exclude.push(userKarma.testContext); } buildConfig.babel.plugins = [[require.resolve('babel-plugin-istanbul'), { exclude }]]; } let karmaConfig = { browsers, coverageReporter: { dir: _path.default.resolve('coverage'), reporters: [{ type: 'html', subdir: 'html' }, { type: 'lcovonly', subdir: '.' }, { type: 'text-summary' }] }, files, frameworks, mochaReporter: { showDiff: true }, plugins, preprocessors, reporters, singleRun: isCi || !args.server, webpack: (0, _createWebpackConfig.default)((0, _webpackMerge.default)(buildConfig, { devtool: 'cheap-module-inline-source-map', node: { fs: 'empty' }, plugins: { status: { quiet: true } }, resolve: { alias: { expect: _path.default.dirname(require.resolve('expect/package')), src: _path.default.resolve('src') } }, server: { hot: false } }), pluginConfig, userConfig), webpackMiddleware: { logLevel: 'silent' } }; // Any extra user Karma config is merged into the generated config to give // them even more control. if (userKarma.extra) { karmaConfig = (0, _webpackMerge.default)(karmaConfig, userKarma.extra); } // Finally, give the user a chance to do whatever they want with the generated // config. if ((0, _utils.typeOf)(userKarma.config) === 'function') { karmaConfig = userKarma.config(karmaConfig); if (!karmaConfig) { throw new _errors.UserError(`karma.config() in ${userConfig.path} didn't return anything - it must return the Karma config object.`); } } (0, _debug.default)('karma config: %s', (0, _utils.deepToString)(karmaConfig)); return karmaConfig; }