webpack/test/TestCases.test.js

340 lines
8.0 KiB
JavaScript

/* global describe, it*/
"use strict";
require("should");
const path = require("path");
const fs = require("fs");
const vm = require("vm");
const mkdirp = require("mkdirp");
const Test = require("mocha/lib/test");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const checkArrayExpectation = require("./checkArrayExpectation");
const Stats = require("../lib/Stats");
const webpack = require("../lib/webpack");
const uglifyJsForTesting = new UglifyJsPlugin({
cache: false,
parallel: false,
sourceMap: true
});
const DEFAULT_OPTIMIZATIONS = {
removeAvailableModules: true,
removeEmptyChunks: true,
mergeDuplicateChunks: true,
flagIncludedChunks: true,
occurrenceOrder: true,
sideEffects: true,
providedExports: true,
usedExports: true,
noEmitOnErrors: false,
concatenateModules: false,
namedModules: false,
minimizer: [uglifyJsForTesting]
};
const NO_EMIT_ON_ERRORS_OPTIMIZATIONS = {
noEmitOnErrors: false,
minimizer: [uglifyJsForTesting]
};
describe("TestCases", () => {
const casesPath = path.join(__dirname, "cases");
let categories = fs.readdirSync(casesPath);
categories = categories.map(cat => {
return {
name: cat,
tests: fs
.readdirSync(path.join(casesPath, cat))
.filter(folder => folder.indexOf("_") < 0)
};
});
[
{
name: "normal"
},
{
name: "production",
mode: "production"
},
{
name: "development",
mode: "development",
devtool: "none"
},
{
name: "hot",
plugins: [new webpack.HotModuleReplacementPlugin()]
},
{
name: "hot-multi-step",
plugins: [
new webpack.HotModuleReplacementPlugin({
multiStep: true
})
]
},
{
name: "devtool-eval",
devtool: "eval"
},
{
name: "devtool-eval-named-modules",
devtool: "eval",
plugins: [new webpack.NamedModulesPlugin()]
},
{
name: "devtool-eval-source-map",
devtool: "#eval-source-map"
},
{
name: "devtool-inline-source-map",
devtool: "inline-source-map"
},
{
name: "devtool-source-map",
devtool: "#@source-map"
},
{
name: "devtool-cheap-inline-source-map",
devtool: "cheap-inline-source-map"
},
{
name: "devtool-cheap-eval-source-map",
devtool: "cheap-eval-source-map"
},
{
name: "devtool-cheap-eval-module-source-map",
devtool: "cheap-eval-module-source-map"
},
{
name: "devtool-cheap-source-map",
devtool: "cheap-source-map"
},
{
name: "minimized-source-map",
mode: "production",
devtool: "eval-cheap-module-source-map",
minimize: true
},
{
name: "minimized-hashed-modules",
mode: "production",
minimize: true,
plugins: [new webpack.HashedModuleIdsPlugin()]
},
{
name: "all-combined",
mode: "production",
devtool: "#@source-map",
minimize: true,
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.NamedChunksPlugin()
]
}
].forEach(config => {
describe(config.name, () => {
categories.forEach(category => {
describe(category.name, function() {
this.timeout(30000);
category.tests
.filter(test => {
const testDirectory = path.join(casesPath, category.name, test);
const filterPath = path.join(testDirectory, "test.filter.js");
if (fs.existsSync(filterPath) && !require(filterPath)(config)) {
describe.skip(test, () => it("filtered"));
return false;
}
return true;
})
.forEach(testName => {
const suite = describe(testName, () => {});
it(testName + " should compile", done => {
const testDirectory = path.join(
casesPath,
category.name,
testName
);
const outputDirectory = path.join(
__dirname,
"js",
config.name,
category.name,
testName
);
const options = {
context: casesPath,
entry: "./" + category.name + "/" + testName + "/index",
target: "async-node",
devtool: config.devtool,
mode: config.mode || "none",
optimization: config.mode
? NO_EMIT_ON_ERRORS_OPTIMIZATIONS
: Object.assign(
{},
config.optimization,
DEFAULT_OPTIMIZATIONS
),
performance: {
hints: false
},
output: {
pathinfo: true,
path: outputDirectory,
filename: "bundle.js"
},
resolve: {
modules: ["web_modules", "node_modules"],
mainFields: [
"webpack",
"browser",
"web",
"browserify",
["jam", "main"],
"main"
],
aliasFields: ["browser"],
extensions: [
".mjs",
".webpack.js",
".web.js",
".js",
".json"
],
concord: true
},
resolveLoader: {
modules: [
"web_loaders",
"web_modules",
"node_loaders",
"node_modules"
],
mainFields: [
"webpackLoader",
"webLoader",
"loader",
"main"
],
extensions: [
".webpack-loader.js",
".web-loader.js",
".loader.js",
".js"
]
},
module: {
rules: [
{
test: /\.coffee$/,
loader: "coffee-loader"
},
{
test: /\.jade$/,
loader: "jade-loader"
}
]
},
plugins: (config.plugins || []).concat(function() {
this.hooks.compilation.tap("TestCasesTest", compilation => {
[
"optimize",
"optimizeModulesBasic",
"optimizeChunksBasic",
"afterOptimizeTree",
"afterOptimizeAssets"
].forEach(hook => {
compilation.hooks[hook].tap("TestCasesTest", () =>
compilation.checkConstraints()
);
});
});
})
};
webpack(options, (err, stats) => {
if (err) return done(err);
const statOptions = Stats.presetToOptions("verbose");
statOptions.colors = false;
mkdirp.sync(outputDirectory);
fs.writeFileSync(
path.join(outputDirectory, "stats.txt"),
stats.toString(statOptions),
"utf-8"
);
const jsonStats = stats.toJson({
errorDetails: true
});
if (
checkArrayExpectation(
testDirectory,
jsonStats,
"error",
"Error",
done
)
)
return;
if (
checkArrayExpectation(
testDirectory,
jsonStats,
"warning",
"Warning",
done
)
)
return;
let exportedTest = 0;
function _it(title, fn) {
const test = new Test(title, fn);
suite.addTest(test);
exportedTest++;
// WORKAROUND for a v8 bug
// Error objects retrain all scopes in the stacktrace
test._trace = test._trace.message;
return test;
}
function _require(module) {
if (module.substr(0, 2) === "./") {
const p = path.join(outputDirectory, module);
const fn = vm.runInThisContext(
"(function(require, module, exports, __dirname, it) {" +
fs.readFileSync(p, "utf-8") +
"\n})",
p
);
const m = {
exports: {},
webpackTestSuiteModule: true
};
fn.call(
m.exports,
_require,
m,
m.exports,
outputDirectory,
_it
);
return m.exports;
} else return require(module);
}
_require.webpackTestSuiteRequire = true;
_require("./bundle.js");
if (exportedTest === 0)
return done(new Error("No tests exported by test case"));
done();
});
});
});
});
});
});
});
});