diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 192d686e..6616426d 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -58,7 +58,6 @@ jobs:
node-10-canary:
node_version: ^10.13.0
webpack_version: next
- continue_on_error: true
steps:
- task: NodeTool@0
inputs:
@@ -115,7 +114,6 @@ jobs:
node-10-canary:
node_version: ^10.13.0
webpack_version: next
- continue_on_error: true
steps:
- task: NodeTool@0
inputs:
@@ -172,7 +170,6 @@ jobs:
node-10-canary:
node_version: ^10.13.0
webpack_version: next
- continue_on_error: true
steps:
- script: 'git config --global core.autocrlf input'
displayName: 'Config git core.autocrlf'
diff --git a/package-lock.json b/package-lock.json
index 657c4a1b..1ebd2489 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1486,9 +1486,9 @@
"dev": true
},
"@types/node": {
- "version": "12.12.18",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.18.tgz",
- "integrity": "sha512-DBkZuIMFuAfjJHiunyRc+aNvmXYNwV1IPMgGKGlwCp6zh6MKrVtmvjSWK/axWcD25KJffkXgkfvFra8ndenXAw==",
+ "version": "12.12.19",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.19.tgz",
+ "integrity": "sha512-OXw80IpKyLeuZ5a8r2XCxVNnRAtS3lRDHBleSUQmbgu3C6eKqRsz7/5XNBU0EvK0RTVfotvYFgvRwwe2jeoiKw==",
"dev": true
},
"@types/normalize-package-data": {
@@ -3901,8 +3901,9 @@
}
},
"css-loader": {
- "version": "github:webpack-contrib/css-loader#63a74b2ccbec74c8e019e66465018c74378b95ad",
- "from": "github:webpack-contrib/css-loader#master",
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.0.tgz",
+ "integrity": "sha512-JornYo4RAXl1Mzt0lOSVPmArzAMV3rGY2VuwtaDc732WTWjdwTaeS19nCGWMcSCf305Q396lhhDAJEWWM0SgPQ==",
"dev": true,
"requires": {
"camelcase": "^5.3.1",
diff --git a/package.json b/package.json
index 5ff361ac..aad58a03 100644
--- a/package.json
+++ b/package.json
@@ -41,7 +41,7 @@
"dist"
],
"peerDependencies": {
- "webpack": "^4.0.0"
+ "webpack": "^4.0.0 || ^5.0.0"
},
"dependencies": {
"loader-utils": "^1.2.3",
@@ -58,7 +58,7 @@
"babel-jest": "^24.9.0",
"commitlint-azure-pipelines-cli": "^1.0.2",
"cross-env": "^6.0.3",
- "css-loader": "webpack-contrib/css-loader#master",
+ "css-loader": "^3.4.0",
"del": "^5.1.0",
"del-cli": "^3.0.0",
"es-check": "^5.1.0",
diff --git a/test/__snapshots__/loader.test.js.snap b/test/__snapshots__/loader.test.js.snap
index 57a784ae..3011264f 100644
--- a/test/__snapshots__/loader.test.js.snap
+++ b/test/__snapshots__/loader.test.js.snap
@@ -314,6 +314,54 @@ exports[`loader should work when ref is negative when the "injectType" option is
exports[`loader should work when ref is negative when the "injectType" option is "lazyStyleTag": warnings 1`] = `Array []`;
+exports[`loader should work when the "injectType" option is "lazySingletonStyleTag" and CommonJS module syntax used: DOM 1`] = `
+"
+ style-loader test
+
+
+
+ Body
+
+
+
+
+"
+`;
+
+exports[`loader should work when the "injectType" option is "lazySingletonStyleTag" and CommonJS module syntax used: errors 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "lazySingletonStyleTag" and CommonJS module syntax used: warnings 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "lazySingletonStyleTag" and ES module syntax used: DOM 1`] = `
+"
+ style-loader test
+
+
+
+ Body
+
+
+
+
+"
+`;
+
+exports[`loader should work when the "injectType" option is "lazySingletonStyleTag" and ES module syntax used: errors 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "lazySingletonStyleTag" and ES module syntax used: warnings 1`] = `Array []`;
+
exports[`loader should work when the "injectType" option is "lazySingletonStyleTag": DOM 1`] = `
"
style-loader test
@@ -338,6 +386,54 @@ exports[`loader should work when the "injectType" option is "lazySingletonStyleT
exports[`loader should work when the "injectType" option is "lazySingletonStyleTag": warnings 1`] = `Array []`;
+exports[`loader should work when the "injectType" option is "lazyStyleTag" and CommonJS module syntax used: DOM 1`] = `
+"
+ style-loader test
+
+
+
+ Body
+
+
+
+
+"
+`;
+
+exports[`loader should work when the "injectType" option is "lazyStyleTag" and CommonJS module syntax used: errors 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "lazyStyleTag" and CommonJS module syntax used: warnings 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "lazyStyleTag" and ES module syntax used: DOM 1`] = `
+"
+ style-loader test
+
+
+
+ Body
+
+
+
+
+"
+`;
+
+exports[`loader should work when the "injectType" option is "lazyStyleTag" and ES module syntax used: errors 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "lazyStyleTag" and ES module syntax used: warnings 1`] = `Array []`;
+
exports[`loader should work when the "injectType" option is "lazyStyleTag": DOM 1`] = `
"
style-loader test
@@ -362,7 +458,7 @@ exports[`loader should work when the "injectType" option is "lazyStyleTag": erro
exports[`loader should work when the "injectType" option is "lazyStyleTag": warnings 1`] = `Array []`;
-exports[`loader should work when the "injectType" option is "linkTag" and "file-loader" uses CommonJS module syntax: DOM 1`] = `
+exports[`loader should work when the "injectType" option is "linkTag" and CommonJS module syntax used: DOM 1`] = `
"
style-loader test
@@ -376,11 +472,11 @@ exports[`loader should work when the "injectType" option is "linkTag" and "file-
"
`;
-exports[`loader should work when the "injectType" option is "linkTag" and "file-loader" uses CommonJS module syntax: errors 1`] = `Array []`;
+exports[`loader should work when the "injectType" option is "linkTag" and CommonJS module syntax used: errors 1`] = `Array []`;
-exports[`loader should work when the "injectType" option is "linkTag" and "file-loader" uses CommonJS module syntax: warnings 1`] = `Array []`;
+exports[`loader should work when the "injectType" option is "linkTag" and CommonJS module syntax used: warnings 1`] = `Array []`;
-exports[`loader should work when the "injectType" option is "linkTag" and "file-loader" uses ES module syntax: DOM 1`] = `
+exports[`loader should work when the "injectType" option is "linkTag" and ES module syntax used: DOM 1`] = `
"
style-loader test
@@ -394,9 +490,9 @@ exports[`loader should work when the "injectType" option is "linkTag" and "file-
"
`;
-exports[`loader should work when the "injectType" option is "linkTag" and "file-loader" uses ES module syntax: errors 1`] = `Array []`;
+exports[`loader should work when the "injectType" option is "linkTag" and ES module syntax used: errors 1`] = `Array []`;
-exports[`loader should work when the "injectType" option is "linkTag" and "file-loader" uses ES module syntax: warnings 1`] = `Array []`;
+exports[`loader should work when the "injectType" option is "linkTag" and ES module syntax used: warnings 1`] = `Array []`;
exports[`loader should work when the "injectType" option is "linkTag": DOM 1`] = `
"
@@ -416,6 +512,54 @@ exports[`loader should work when the "injectType" option is "linkTag": errors 1`
exports[`loader should work when the "injectType" option is "linkTag": warnings 1`] = `Array []`;
+exports[`loader should work when the "injectType" option is "singletonStyleTag" and CommonJS module syntax used: DOM 1`] = `
+"
+ style-loader test
+
+
+
+ Body
+
+
+
+
+"
+`;
+
+exports[`loader should work when the "injectType" option is "singletonStyleTag" and CommonJS module syntax used: errors 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "singletonStyleTag" and CommonJS module syntax used: warnings 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "singletonStyleTag" and ES module syntax used: DOM 1`] = `
+"
+ style-loader test
+
+
+
+ Body
+
+
+
+
+"
+`;
+
+exports[`loader should work when the "injectType" option is "singletonStyleTag" and ES module syntax used: errors 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "singletonStyleTag" and ES module syntax used: warnings 1`] = `Array []`;
+
exports[`loader should work when the "injectType" option is "singletonStyleTag": DOM 1`] = `
"
style-loader test
@@ -440,6 +584,54 @@ exports[`loader should work when the "injectType" option is "singletonStyleTag":
exports[`loader should work when the "injectType" option is "singletonStyleTag": warnings 1`] = `Array []`;
+exports[`loader should work when the "injectType" option is "styleTag" and CommonJS module syntax used: DOM 1`] = `
+"
+ style-loader test
+
+
+
+ Body
+
+
+
+
+"
+`;
+
+exports[`loader should work when the "injectType" option is "styleTag" and CommonJS module syntax used: errors 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "styleTag" and CommonJS module syntax used: warnings 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "styleTag" and ES module syntax used: DOM 1`] = `
+"
+ style-loader test
+
+
+
+ Body
+
+
+
+
+"
+`;
+
+exports[`loader should work when the "injectType" option is "styleTag" and ES module syntax used: errors 1`] = `Array []`;
+
+exports[`loader should work when the "injectType" option is "styleTag" and ES module syntax used: warnings 1`] = `Array []`;
+
exports[`loader should work when the "injectType" option is "styleTag": DOM 1`] = `
"
style-loader test
diff --git a/test/__snapshots__/validate-options.test.js.snap b/test/__snapshots__/validate-options.test.js.snap
index bb8d5a10..749d3d72 100644
--- a/test/__snapshots__/validate-options.test.js.snap
+++ b/test/__snapshots__/validate-options.test.js.snap
@@ -1,20 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`validate options 1`] = `
-"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
- - options.injectType should be one of these:
- \\"styleTag\\" | \\"singletonStyleTag\\" | \\"lazyStyleTag\\" | \\"lazySingletonStyleTag\\" | \\"linkTag\\"
- -> Allows to setup how styles will be injected into DOM (https://github.com/webpack-contrib/style-loader#injecttype)."
-`;
-
-exports[`validate options 2`] = `
+exports[`validate options should throw an error on the "attributes" option with "true" value 1`] = `
"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
- options.attributes should be an object:
object { … }
-> Adds custom attributes to tag (https://github.com/webpack-contrib/style-loader#attributes)."
`;
-exports[`validate options 3`] = `
+exports[`validate options should throw an error on the "injectType" option with "unknown" value 1`] = `
+"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
+ - options.injectType should be one of these:
+ \\"styleTag\\" | \\"singletonStyleTag\\" | \\"lazyStyleTag\\" | \\"lazySingletonStyleTag\\" | \\"linkTag\\"
+ -> Allows to setup how styles will be injected into DOM (https://github.com/webpack-contrib/style-loader#injecttype)."
+`;
+
+exports[`validate options should throw an error on the "insert" option with "true" value 1`] = `
"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
- options.insert should be one of these:
string | function
@@ -24,7 +24,49 @@ exports[`validate options 3`] = `
* options.insert should be an instance of function."
`;
-exports[`validate options 4`] = `
+exports[`validate options should throw an error on the "unknown" option with "/test/" value 1`] = `
+"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
+ - options has an unknown property 'unknown'. These properties are valid:
+ object { injectType?, attributes?, insert?, base? }"
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "[]" value 1`] = `
+"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
+ - options has an unknown property 'unknown'. These properties are valid:
+ object { injectType?, attributes?, insert?, base? }"
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "{"foo":"bar"}" value 1`] = `
+"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
+ - options has an unknown property 'unknown'. These properties are valid:
+ object { injectType?, attributes?, insert?, base? }"
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "{}" value 1`] = `
+"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
+ - options has an unknown property 'unknown'. These properties are valid:
+ object { injectType?, attributes?, insert?, base? }"
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "1" value 1`] = `
+"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
+ - options has an unknown property 'unknown'. These properties are valid:
+ object { injectType?, attributes?, insert?, base? }"
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "false" value 1`] = `
+"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
+ - options has an unknown property 'unknown'. These properties are valid:
+ object { injectType?, attributes?, insert?, base? }"
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "test" value 1`] = `
+"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
+ - options has an unknown property 'unknown'. These properties are valid:
+ object { injectType?, attributes?, insert?, base? }"
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "true" value 1`] = `
"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
- options has an unknown property 'unknown'. These properties are valid:
object { injectType?, attributes?, insert?, base? }"
diff --git a/test/attributes-option.test.js b/test/attributes-option.test.js
index 65228082..2868190a 100644
--- a/test/attributes-option.test.js
+++ b/test/attributes-option.test.js
@@ -1,4 +1,11 @@
-import { compile, getTestId, runTestInJsdom } from './helpers';
+import {
+ compile,
+ getCompiler,
+ getEntryByInjectType,
+ getErrors,
+ getWarnings,
+ runInJsDom,
+} from './helpers/index';
describe('attributes option', () => {
const injectTypes = [
@@ -13,58 +20,53 @@ describe('attributes option', () => {
it(`should add attributes to tag when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('simple.js', injectType);
- const stats = await compile(testId, {
- loader: {
- options: {
- injectType,
- attributes: {
- type: 'text/css',
- foo: 'bar',
- 'data-id': 'style-tag-id',
- },
- },
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(entry, {
+ injectType,
+ attributes: {
+ type: 'text/css',
+ foo: 'bar',
+ 'data-id': 'style-tag-id',
},
});
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should add nonce attribute when "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('nonce-require.js', injectType);
- const stats = await compile(testId, {
- loader: { options: { injectType } },
- });
+ const entry = getEntryByInjectType('nonce-require.js', injectType);
+ const compiler = getCompiler(entry, { injectType });
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should add nonce attribute when "injectType" option is "${injectType}" #2`, async () => {
expect.assertions(3);
- const testId = getTestId('nonce-import.js', injectType);
- const stats = await compile(testId, {
- loader: { options: { injectType } },
- });
+ const entry = getEntryByInjectType('nonce-import.js', injectType);
+ const compiler = getCompiler(entry, { injectType });
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
});
});
diff --git a/test/base-option.test.js b/test/base-option.test.js
index ac5d1967..f76e9a2a 100644
--- a/test/base-option.test.js
+++ b/test/base-option.test.js
@@ -1,24 +1,23 @@
-import compile from './helpers/compiler';
-import runTestInJsdom from './helpers/runTestInJsdom';
+import {
+ compile,
+ getCompiler,
+ getErrors,
+ getWarnings,
+ runInJsDom,
+} from './helpers/index';
describe('base option', () => {
it('should work', async () => {
expect.assertions(3);
- const testId = './simple.js';
- const stats = await compile(testId, {
- loader: {
- options: {
- base: 1000,
- },
- },
- });
+ const compiler = getCompiler('./simple.js', { base: 1000 });
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
});
diff --git a/test/helpers/compile.js b/test/helpers/compile.js
new file mode 100644
index 00000000..066873ab
--- /dev/null
+++ b/test/helpers/compile.js
@@ -0,0 +1,11 @@
+export default (compiler) => {
+ return new Promise((resolve, reject) => {
+ compiler.run((error, stats) => {
+ if (error) {
+ return reject(error);
+ }
+
+ return resolve(stats);
+ });
+ });
+};
diff --git a/test/helpers/compiler.js b/test/helpers/compiler.js
deleted file mode 100644
index 0f6ae6e2..00000000
--- a/test/helpers/compiler.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/* eslint-disable
- import/order,
- multiline-ternary,
- no-param-reassign,
-*/
-import del from 'del';
-import path from 'path';
-import webpack from 'webpack';
-import { createFsFromVolume, Volume } from 'memfs';
-
-const module = (config) => {
- const shouldUseFileLoader =
- config.loader &&
- config.loader.options &&
- config.loader.options.injectType === 'linkTag';
-
- return {
- rules: config.rules
- ? config.rules
- : [
- {
- test: (config.loader && config.loader.test) || /\.css$/i,
- use: [
- {
- loader: path.join(__dirname, '../../src'),
- options: (config.loader && config.loader.options) || {},
- },
- shouldUseFileLoader
- ? {
- loader: 'file-loader',
- options:
- (config.fileLoader && config.fileLoader.options) || {},
- }
- : {
- loader: 'css-loader',
- options:
- (config.cssLoader && config.cssLoader.options) || {},
- },
- ],
- },
- ],
- };
-};
-
-const plugins = (config) => [].concat(config.plugins || []);
-
-const output = (config) => {
- return {
- path: path.resolve(
- __dirname,
- `../outputs/${config.output ? config.output : ''}`
- ),
- filename: '[name].bundle.js',
- };
-};
-
-export default function(fixture, config = {}, options = {}) {
- // webpack Config
- config = {
- mode: config.mode || 'development',
- devtool: config.devtool || false,
- context: path.resolve(__dirname, '..', 'fixtures'),
- entry: `./${fixture}`,
- output: output(config),
- module: module(config),
- plugins: plugins(config),
- optimization: {
- runtimeChunk: false,
- },
- };
- // Compiler Options
- options = Object.assign({ output: false }, options);
-
- if (options.output) {
- del.sync(config.output.path);
- }
-
- const compiler = webpack(config);
-
- if (!options.output) {
- const outputFileSystem = createFsFromVolume(new Volume());
- // Todo remove when we drop webpack@4 support
- outputFileSystem.join = path.join.bind(path);
-
- compiler.outputFileSystem = outputFileSystem;
- }
-
- return new Promise((resolve, reject) =>
- compiler.run((err, stats) => {
- if (err) {
- return reject(err);
- }
-
- return resolve(stats);
- })
- );
-}
diff --git a/test/helpers/execute.js b/test/helpers/execute.js
new file mode 100644
index 00000000..866001ae
--- /dev/null
+++ b/test/helpers/execute.js
@@ -0,0 +1,22 @@
+import Module from 'module';
+import path from 'path';
+
+const parentModule = module;
+
+export default (code) => {
+ const resource = 'test.js';
+ const module = new Module(resource, parentModule);
+ // eslint-disable-next-line no-underscore-dangle
+ module.paths = Module._nodeModulePaths(
+ path.resolve(__dirname, '../fixtures')
+ );
+ module.filename = resource;
+
+ // eslint-disable-next-line no-underscore-dangle
+ module._compile(
+ `let __export__;${code};module.exports = __export__;`,
+ resource
+ );
+
+ return module.exports;
+};
diff --git a/test/helpers/getCompiler.js b/test/helpers/getCompiler.js
new file mode 100644
index 00000000..12622781
--- /dev/null
+++ b/test/helpers/getCompiler.js
@@ -0,0 +1,50 @@
+import path from 'path';
+
+import webpack from 'webpack';
+import { createFsFromVolume, Volume } from 'memfs';
+
+export default (fixture, loaderOptions = {}, config = {}) => {
+ const fullConfig = {
+ mode: 'development',
+ devtool: config.devtool || false,
+ context: path.resolve(__dirname, '../fixtures'),
+ entry: path.resolve(__dirname, '../fixtures', fixture),
+ output: {
+ path: path.resolve(__dirname, '../outputs'),
+ filename: '[name].bundle.js',
+ chunkFilename: '[name].chunk.js',
+ },
+ module: {
+ rules: [
+ {
+ test: /\.css$/i,
+ use: [
+ {
+ loader: path.resolve(__dirname, '../../src'),
+ options: loaderOptions || {},
+ },
+ loaderOptions &&
+ loaderOptions.injectType &&
+ loaderOptions.injectType === 'linkTag'
+ ? { loader: 'file-loader' }
+ : { loader: 'css-loader' },
+ ],
+ },
+ ],
+ },
+ plugins: [],
+ ...config,
+ };
+
+ const compiler = webpack(fullConfig);
+
+ if (!config.outputFileSystem) {
+ const outputFileSystem = createFsFromVolume(new Volume());
+ // Todo remove when we drop webpack@4 support
+ outputFileSystem.join = path.join.bind(path);
+
+ compiler.outputFileSystem = outputFileSystem;
+ }
+
+ return compiler;
+};
diff --git a/test/helpers/getTestId.js b/test/helpers/getEntryByInjectType.js
similarity index 58%
rename from test/helpers/getTestId.js
rename to test/helpers/getEntryByInjectType.js
index 7f6489a3..18639195 100644
--- a/test/helpers/getTestId.js
+++ b/test/helpers/getEntryByInjectType.js
@@ -1,7 +1,7 @@
-function getTestId(testId, injectType) {
+function getEntryByInjectType(testId, injectType) {
const isLazy = injectType && injectType.toLowerCase().includes('lazy');
return `./${isLazy ? 'lazy-' : ''}${testId}`;
}
-export default getTestId;
+export default getEntryByInjectType;
diff --git a/test/helpers/getErrors.js b/test/helpers/getErrors.js
new file mode 100644
index 00000000..716fbbb4
--- /dev/null
+++ b/test/helpers/getErrors.js
@@ -0,0 +1,5 @@
+import normalizeErrors from './normalizeErrors';
+
+export default (stats) => {
+ return normalizeErrors(stats.compilation.errors);
+};
diff --git a/test/helpers/getWarnings.js b/test/helpers/getWarnings.js
new file mode 100644
index 00000000..c8a09d6d
--- /dev/null
+++ b/test/helpers/getWarnings.js
@@ -0,0 +1,5 @@
+import normalizeErrors from './normalizeErrors';
+
+export default (stats) => {
+ return normalizeErrors(stats.compilation.warnings);
+};
diff --git a/test/helpers/index.js b/test/helpers/index.js
index 6b078c24..8c65bc60 100644
--- a/test/helpers/index.js
+++ b/test/helpers/index.js
@@ -1,5 +1,23 @@
-import compile from './compiler';
-import getTestId from './getTestId';
-import runTestInJsdom from './runTestInJsdom';
+import compile from './compile';
+import execute from './execute';
+import getCompiler from './getCompiler';
+import getEntryByInjectType from './getEntryByInjectType';
+import getErrors from './getErrors';
+import getWarnings from './getWarnings';
+import normalizeErrors from './normalizeErrors';
+import readAsset from './readAsset';
+import readsAssets from './readAssets';
+import runInJsDom from './runInJsDom';
-export { compile, getTestId, runTestInJsdom };
+export {
+ compile,
+ execute,
+ getCompiler,
+ getEntryByInjectType,
+ getErrors,
+ getWarnings,
+ normalizeErrors,
+ readAsset,
+ readsAssets,
+ runInJsDom,
+};
diff --git a/test/helpers/normalizeErrors.js b/test/helpers/normalizeErrors.js
new file mode 100644
index 00000000..d540ed76
--- /dev/null
+++ b/test/helpers/normalizeErrors.js
@@ -0,0 +1,25 @@
+function removeCWD(str) {
+ const isWin = process.platform === 'win32';
+ let cwd = process.cwd();
+
+ if (isWin) {
+ // eslint-disable-next-line no-param-reassign
+ str = str.replace(/\\/g, '/');
+ // eslint-disable-next-line no-param-reassign
+ cwd = cwd.replace(/\\/g, '/');
+ }
+
+ return str.replace(new RegExp(cwd, 'g'), '');
+}
+
+export default (errors) => {
+ return errors.map((error) =>
+ removeCWD(
+ error
+ .toString()
+ .split('\n')
+ .slice(0, 2)
+ .join('\n')
+ )
+ );
+};
diff --git a/test/helpers/readAsset.js b/test/helpers/readAsset.js
new file mode 100644
index 00000000..8f4699f0
--- /dev/null
+++ b/test/helpers/readAsset.js
@@ -0,0 +1,23 @@
+import path from 'path';
+
+export default (asset, compiler, stats) => {
+ const usedFs = compiler.outputFileSystem;
+ const outputPath = stats.compilation.outputOptions.path;
+
+ let data = '';
+ let targetFile = asset;
+
+ const queryStringIdx = targetFile.indexOf('?');
+
+ if (queryStringIdx >= 0) {
+ targetFile = targetFile.substr(0, queryStringIdx);
+ }
+
+ try {
+ data = usedFs.readFileSync(path.join(outputPath, targetFile)).toString();
+ } catch (error) {
+ data = error.toString();
+ }
+
+ return data;
+};
diff --git a/test/helpers/readAssets.js b/test/helpers/readAssets.js
new file mode 100644
index 00000000..a2fb7837
--- /dev/null
+++ b/test/helpers/readAssets.js
@@ -0,0 +1,11 @@
+import readAsset from './readAsset';
+
+export default function readAssets(compiler, stats) {
+ const assets = {};
+
+ Object.keys(stats.compilation.assets).forEach((asset) => {
+ assets[asset] = readAsset(asset, compiler, stats);
+ });
+
+ return assets;
+}
diff --git a/test/helpers/runTestInJsdom.js b/test/helpers/runInJsDom.js
similarity index 76%
rename from test/helpers/runTestInJsdom.js
rename to test/helpers/runInJsDom.js
index 8b5faa06..088751fb 100644
--- a/test/helpers/runTestInJsdom.js
+++ b/test/helpers/runInJsDom.js
@@ -1,7 +1,9 @@
-const jsdom = require('jsdom');
+import jsdom from 'jsdom';
-function runTestInJsdom(stats, testFn) {
- const bundle = stats.compilation.assets['main.bundle.js'].source();
+import { readAsset } from './index';
+
+function runInJsDom(assetName, compiler, stats, testFn) {
+ const bundle = readAsset(assetName, compiler, stats);
const virtualConsole = new jsdom.VirtualConsole();
virtualConsole.sendTo(console);
@@ -39,4 +41,4 @@ function runTestInJsdom(stats, testFn) {
}
}
-export default runTestInJsdom;
+export default runInJsDom;
diff --git a/test/injectType-option.test.js b/test/injectType-option.test.js
index 7e6daa1a..26cec3df 100644
--- a/test/injectType-option.test.js
+++ b/test/injectType-option.test.js
@@ -1,6 +1,13 @@
/* eslint-env browser */
-import { compile, getTestId, runTestInJsdom } from './helpers';
+import {
+ compile,
+ getCompiler,
+ getEntryByInjectType,
+ getErrors,
+ getWarnings,
+ runInJsDom,
+} from './helpers/index';
describe('injectType option', () => {
const injectTypes = [
@@ -15,17 +22,16 @@ describe('injectType option', () => {
it(`should work when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('simple.js', injectType);
- const stats = await compile(testId, {
- loader: { options: { injectType } },
- });
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(entry, { injectType });
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
});
});
diff --git a/test/insert-option.test.js b/test/insert-option.test.js
index c2f94f7f..7692ba86 100644
--- a/test/insert-option.test.js
+++ b/test/insert-option.test.js
@@ -1,5 +1,12 @@
/* eslint-env browser */
-import { compile, getTestId, runTestInJsdom } from './helpers';
+import {
+ compile,
+ getCompiler,
+ getEntryByInjectType,
+ getErrors,
+ getWarnings,
+ runInJsDom,
+} from './helpers/index';
describe('insert option', () => {
const injectTypes = [
@@ -14,61 +21,57 @@ describe('insert option', () => {
it(`should insert styles into "head" bottom when not specified and when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('simple.js', injectType);
- const stats = await compile(testId, {
- loader: { options: { injectType } },
- });
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(entry, { injectType });
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should insert styles into "body" bottom when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('simple.js', injectType);
- const stats = await compile(testId, {
- loader: { options: { injectType, insert: 'body' } },
- });
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(entry, { injectType, insert: 'body' });
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should insert styles into "div.target" bottom when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('simple.js', injectType);
- const stats = await compile(testId, {
- loader: { options: { injectType, insert: 'div.target' } },
- });
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(entry, { injectType, insert: 'div.target' });
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should insert styles into "iframe.iframeTarget" bottom when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(4);
const selector = 'iframe.iframeTarget';
- const testId = getTestId('simple.js', injectType);
- const stats = await compile(testId, {
- loader: { options: { injectType, insert: selector } },
- });
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(entry, { injectType, insert: selector });
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(
dom.window.document.querySelector(selector).contentDocument.head
.innerHTML
@@ -76,106 +79,97 @@ describe('insert option', () => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should insert styles into runtime created element bottom when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('element.js', injectType);
- const stats = await compile(testId, {
- loader: {
- options: {
- injectType,
- insert: (element) =>
- document.querySelector('#test-shadow').appendChild(element),
- },
- },
+ const entry = getEntryByInjectType('element.js', injectType);
+ const compiler = getCompiler(entry, {
+ injectType,
+ insert: (element) =>
+ document.querySelector('#test-shadow').appendChild(element),
});
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should insert styles into "head" top when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('simple.js', injectType);
- const stats = await compile(testId, {
- loader: {
- options: {
- injectType,
- insert: (element) => {
- const parent = document.querySelector('head');
- const lastInsertedElement =
- // eslint-disable-next-line no-underscore-dangle
- window._lastElementInsertedByStyleLoader;
-
- if (!lastInsertedElement) {
- parent.insertBefore(element, parent.firstChild);
- } else if (lastInsertedElement.nextSibling) {
- parent.insertBefore(element, lastInsertedElement.nextSibling);
- } else {
- parent.appendChild(element);
- }
-
- // eslint-disable-next-line no-underscore-dangle
- window._lastElementInsertedByStyleLoader = element;
- },
- },
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(entry, {
+ injectType,
+ insert: (element) => {
+ const parent = document.querySelector('head');
+ const lastInsertedElement =
+ // eslint-disable-next-line no-underscore-dangle
+ window._lastElementInsertedByStyleLoader;
+
+ if (!lastInsertedElement) {
+ parent.insertBefore(element, parent.firstChild);
+ } else if (lastInsertedElement.nextSibling) {
+ parent.insertBefore(element, lastInsertedElement.nextSibling);
+ } else {
+ parent.appendChild(element);
+ }
+
+ // eslint-disable-next-line no-underscore-dangle
+ window._lastElementInsertedByStyleLoader = element;
},
});
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should insert styles into before "#existing-style" id when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('simple.js', injectType);
- const stats = await compile(testId, {
- loader: {
- options: {
- injectType,
- insert: (element) => {
- const parent = document.querySelector('head');
- const target = document.querySelector('#existing-style');
-
- const lastInsertedElement =
- // eslint-disable-next-line no-underscore-dangle
- window._lastElementInsertedByStyleLoader;
-
- if (!lastInsertedElement) {
- parent.insertBefore(element, target);
- } else if (lastInsertedElement.nextSibling) {
- parent.insertBefore(element, lastInsertedElement.nextSibling);
- } else {
- parent.appendChild(element);
- }
-
- // eslint-disable-next-line no-underscore-dangle
- window._lastElementInsertedByStyleLoader = element;
- },
- },
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(entry, {
+ injectType,
+ insert: (element) => {
+ const parent = document.querySelector('head');
+ const target = document.querySelector('#existing-style');
+
+ const lastInsertedElement =
+ // eslint-disable-next-line no-underscore-dangle
+ window._lastElementInsertedByStyleLoader;
+
+ if (!lastInsertedElement) {
+ parent.insertBefore(element, target);
+ } else if (lastInsertedElement.nextSibling) {
+ parent.insertBefore(element, lastInsertedElement.nextSibling);
+ } else {
+ parent.appendChild(element);
+ }
+
+ // eslint-disable-next-line no-underscore-dangle
+ window._lastElementInsertedByStyleLoader = element;
},
});
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
});
});
diff --git a/test/loader.test.js b/test/loader.test.js
index 1ebcd394..ccac85a2 100644
--- a/test/loader.test.js
+++ b/test/loader.test.js
@@ -1,8 +1,18 @@
/* eslint-env browser */
+import path from 'path';
+
import webpack from 'webpack';
-import { compile, getTestId, runTestInJsdom } from './helpers';
+import {
+ compile,
+ getCompiler,
+ getEntryByInjectType,
+ getErrors,
+ getWarnings,
+ readAsset,
+ runInJsDom,
+} from './helpers/index';
describe('loader', () => {
const injectTypes = [
@@ -14,217 +24,284 @@ describe('loader', () => {
];
it('should work', async () => {
- const testId = './simple.js';
- const stats = await compile(testId);
-
- runTestInJsdom(stats, (dom) => {
- expect(dom.serialize()).toMatchSnapshot('DOM');
- });
-
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
- });
-
- it('should work when the "injectType" option is "linkTag" and "file-loader" uses ES module syntax', async () => {
- const testId = './simple.js';
- const stats = await compile(testId, {
- loader: { options: { injectType: 'linkTag' } },
- fileLoader: { options: { esModule: true } },
- });
-
- runTestInJsdom(stats, (dom) => {
- expect(dom.serialize()).toMatchSnapshot('DOM');
- });
+ const compiler = getCompiler('./simple.js');
+ const stats = await compile(compiler);
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
- });
-
- it('should work when the "injectType" option is "linkTag" and "file-loader" uses CommonJS module syntax', async () => {
- const testId = './simple.js';
- const stats = await compile(testId, {
- loader: { options: { injectType: 'linkTag' } },
- fileLoader: { options: { esModule: false } },
- });
-
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
injectTypes.forEach((injectType) => {
it(`should work when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('simple.js', injectType);
- const stats = await compile(testId, {
- loader: { options: { injectType } },
- });
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(entry, { injectType });
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should work with css modules when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('css-modules.js', injectType);
- const stats = await compile(testId, {
- loader: { options: { injectType } },
- cssLoader: {
- options: {
- modules: { localIdentName: '[name]-[local]_[hash:base64:7]' },
+ const entry = getEntryByInjectType('css-modules.js', injectType);
+ const compiler = getCompiler(
+ entry,
+ {},
+ {
+ module: {
+ rules: [
+ {
+ test: /\.css$/i,
+ use: [
+ {
+ loader: path.resolve(__dirname, '../src'),
+ options: { injectType },
+ },
+ injectType === 'linkTag'
+ ? { loader: 'file-loader' }
+ : {
+ loader: 'css-loader',
+ options: {
+ modules: {
+ localIdentName: '[name]-[local]_[hash:base64:7]',
+ },
+ },
+ },
+ ],
+ },
+ ],
},
- },
- });
+ }
+ );
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should not inject hmr code without HotModuleReplacementPlugin when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(4);
- const testId = './hot.js';
- const stats = await compile(testId, {
- loader: { options: { injectType } },
- });
+ const compiler = getCompiler('./hot.js', { injectType });
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.window.hotApi).not.toBeDefined();
});
- const bundleSource = stats.compilation.assets['main.bundle.js'].source();
+ const bundleSource = readAsset('main.bundle.js', compiler, stats);
expect(bundleSource).not.toMatch(/module\.hot\.accept/);
-
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should inject hmr code with HotModuleReplacementPlugin when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(4);
- const testId = './hot.js';
- const stats = await compile(testId, {
- plugins: [new webpack.HotModuleReplacementPlugin()],
- loader: { options: { injectType } },
- });
+ const compiler = getCompiler(
+ './hot.js',
+ { injectType },
+ { plugins: [new webpack.HotModuleReplacementPlugin()] }
+ );
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.window.hotApi).toBeDefined();
});
- const bundleSource = stats.compilation.assets['main.bundle.js'].source();
+ const bundleSource = readAsset('main.bundle.js', compiler, stats);
expect(bundleSource).toMatch(/module\.hot\.accept/);
-
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
it(`should not generate source maps when previous loader don't emit them when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('simple.js', injectType);
- const stats = await compile(testId, {
- devtool: 'source-map',
- loader: { options: { injectType } },
- });
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(
+ entry,
+ { injectType },
+ {
+ devtool: 'source-map',
+ module: {
+ rules: [
+ {
+ test: /\.css$/i,
+ use: [
+ {
+ loader: path.resolve(__dirname, '../src'),
+ options: { injectType },
+ },
+ injectType === 'linkTag'
+ ? { loader: 'file-loader' }
+ : {
+ loader: 'css-loader',
+ options: { sourceMap: false },
+ },
+ ],
+ },
+ ],
+ },
+ }
+ );
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
// `linkTag` doesn't generate source maps, original source should contains them
it(`should generate source maps when previous loader emit them when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = getTestId('simple.js', injectType);
- const stats = await compile(testId, {
- devtool: 'source-map',
- loader: { options: { injectType } },
- cssLoader: { options: { sourceMap: true } },
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(
+ entry,
+ { injectType },
+ {
+ devtool: 'source-map',
+ module: {
+ rules: [
+ {
+ test: /\.css$/i,
+ use: [
+ {
+ loader: path.resolve(__dirname, '../src'),
+ options: { injectType },
+ },
+ injectType === 'linkTag'
+ ? { loader: 'file-loader' }
+ : {
+ loader: 'css-loader',
+ options: { sourceMap: true },
+ },
+ ],
+ },
+ ],
+ },
+ }
+ );
+ const stats = await compile(compiler);
+
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
+ expect(dom.serialize()).toMatchSnapshot('DOM');
});
- runTestInJsdom(stats, (dom) => {
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ });
+
+ it(`should work when the "injectType" option is "${injectType}" and ES module syntax used`, async () => {
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(
+ entry,
+ { injectType },
+ {
+ module: {
+ rules: [
+ {
+ test: /\.css$/i,
+ use: [
+ {
+ loader: path.resolve(__dirname, '../src'),
+ options: { injectType },
+ },
+ injectType === 'linkTag'
+ ? { loader: 'file-loader' }
+ : {
+ loader: 'css-loader',
+ options: { esModule: true },
+ },
+ ],
+ },
+ ],
+ },
+ }
+ );
+ const stats = await compile(compiler);
+
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
- // Uncomment after `css-loader` release the `esModule` option
- // if (
- // [
- // 'styleTag',
- // 'singletonStyleTag',
- // 'lazyStyleTag',
- // 'lazySingletonStyleTag',
- // ].includes(injectType)
- // ) {
- // it(`should work when the "injectType" option is "${injectType}" and "css-loader" uses ES module syntax`, async () => {
- // const testId = getTestId('simple.js', injectType);
- // const stats = await compile(testId, {
- // loader: { options: { injectType } },
- // cssLoader: { options: { esModule: true } },
- // });
- //
- // runTestInJsdom(stats, (dom) => {
- // expect(dom.serialize()).toMatchSnapshot('DOM');
- // });
- //
- // expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- // expect(stats.compilation.errors).toMatchSnapshot('errors');
- // });
- //
- // it(`should work when the "injectType" option is "${injectType}" and "css-loader" uses CommonJS module syntax`, async () => {
- // const testId = getTestId('simple.js', injectType);
- // const stats = await compile(testId, {
- // loader: { options: { injectType } },
- // cssLoader: { options: { esModule: true } },
- // });
- //
- // runTestInJsdom(stats, (dom) => {
- // expect(dom.serialize()).toMatchSnapshot('DOM');
- // });
- //
- // expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- // expect(stats.compilation.errors).toMatchSnapshot('errors');
- // });
- // }
+ it(`should work when the "injectType" option is "${injectType}" and CommonJS module syntax used`, async () => {
+ const entry = getEntryByInjectType('simple.js', injectType);
+ const compiler = getCompiler(
+ entry,
+ { injectType },
+ {
+ module: {
+ rules: [
+ {
+ test: /\.css$/i,
+ use: [
+ {
+ loader: path.resolve(__dirname, '../src'),
+ options: { injectType },
+ },
+ injectType === 'linkTag'
+ ? { loader: 'file-loader' }
+ : {
+ loader: 'css-loader',
+ options: { esModule: false },
+ },
+ ],
+ },
+ ],
+ },
+ }
+ );
+ const stats = await compile(compiler);
+
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
+ expect(dom.serialize()).toMatchSnapshot('DOM');
+ });
+
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ });
if (['lazyStyleTag', 'lazySingletonStyleTag'].includes(injectType)) {
it(`should work when ref is negative when the "injectType" option is "${injectType}"`, async () => {
expect.assertions(3);
- const testId = './lazy-negative-refs.js';
- const stats = await compile(testId, {
- loader: { options: { injectType } },
+ const compiler = getCompiler('./lazy-negative-refs.js', {
+ injectType,
});
+ const stats = await compile(compiler);
- runTestInJsdom(stats, (dom) => {
+ runInJsDom('main.bundle.js', compiler, stats, (dom) => {
expect(dom.serialize()).toMatchSnapshot('DOM');
});
- expect(stats.compilation.warnings).toMatchSnapshot('warnings');
- expect(stats.compilation.errors).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ expect(getErrors(stats)).toMatchSnapshot('errors');
});
}
});
diff --git a/test/validate-options.test.js b/test/validate-options.test.js
index a15732ea..940cb836 100644
--- a/test/validate-options.test.js
+++ b/test/validate-options.test.js
@@ -1,46 +1,74 @@
-import loader from '../src/index';
-
-it('validate options', () => {
- const validate = (options) =>
- loader.pitch.call(
- Object.assign(
- {},
- {
- query: options,
- loaders: [],
- remainingRequest: 'file.css',
- currentRequest: 'file.css',
- async: () => (error) => {
- if (error) {
- throw error;
- }
- },
+import { getCompiler, compile } from './helpers';
+
+describe('validate options', () => {
+ const tests = {
+ injectType: {
+ success: [
+ 'styleTag',
+ 'singletonStyleTag',
+ 'lazyStyleTag',
+ 'lazySingletonStyleTag',
+ 'linkTag',
+ ],
+ failure: ['unknown'],
+ },
+ attributes: {
+ success: [{}, { id: 'id' }],
+ failure: [true],
+ },
+ insert: {
+ success: ['selector', () => {}],
+ failure: [true],
+ },
+ unknown: {
+ success: [],
+ failure: [1, true, false, 'test', /test/, [], {}, { foo: 'bar' }],
+ },
+ };
+
+ function stringifyValue(value) {
+ if (
+ Array.isArray(value) ||
+ (value && typeof value === 'object' && value.constructor === Object)
+ ) {
+ return JSON.stringify(value);
+ }
+
+ return value;
+ }
+
+ async function createTestCase(key, value, type) {
+ it(`should ${
+ type === 'success' ? 'successfully validate' : 'throw an error on'
+ } the "${key}" option with "${stringifyValue(value)}" value`, async () => {
+ const compiler = getCompiler('simple.js', { [key]: value });
+
+ let stats;
+
+ try {
+ stats = await compile(compiler);
+ } finally {
+ if (type === 'success') {
+ expect(stats.hasErrors()).toBe(false);
+ } else if (type === 'failure') {
+ const {
+ compilation: { errors },
+ } = stats;
+
+ expect(errors).toHaveLength(2);
+ expect(() => {
+ throw new Error(errors[0].error.message);
+ }).toThrowErrorMatchingSnapshot();
}
- ),
- 'file.css'
- );
-
- expect(() => validate({ injectType: 'styleTag' })).not.toThrow();
- expect(() => validate({ injectType: 'singletonStyleTag' })).not.toThrow();
- expect(() => validate({ injectType: 'lazyStyleTag' })).not.toThrow();
- expect(() => validate({ injectType: 'lazySingletonStyleTag' })).not.toThrow();
- expect(() => validate({ injectType: 'linkTag' })).not.toThrow();
- expect(() =>
- validate({ injectType: 'unknown' })
- ).toThrowErrorMatchingSnapshot();
-
- expect(() => validate({ attributes: {} })).not.toThrow();
- expect(() => validate({ attributes: { id: 'id' } })).not.toThrow();
- expect(() => validate({ attributes: true })).toThrowErrorMatchingSnapshot();
-
- expect(() =>
- validate({
- // eslint-disable-next-line no-undef
- insert: (element) => document.querySelector('#root').appendChild(element),
- })
- ).not.toThrow();
- expect(() => validate({ insert: 'test' })).not.toThrow();
- expect(() => validate({ insert: true })).toThrowErrorMatchingSnapshot();
-
- expect(() => validate({ unknown: 'unknown' })).toThrowErrorMatchingSnapshot();
+ }
+ });
+ }
+
+ for (const [key, values] of Object.entries(tests)) {
+ for (const type of Object.keys(values)) {
+ for (const value of values[type]) {
+ createTestCase(key, value, type);
+ }
+ }
+ }
});