2017-02-02 19:56:41 +08:00
|
|
|
/* globals describe, it */
|
2017-01-18 16:03:37 +08:00
|
|
|
"use strict";
|
2013-01-31 01:49:25 +08:00
|
|
|
|
2017-01-18 16:03:37 +08:00
|
|
|
const should = require("should");
|
|
|
|
const path = require("path");
|
2017-06-24 04:30:30 +08:00
|
|
|
const sinon = require("sinon");
|
2013-01-31 01:49:25 +08:00
|
|
|
|
2017-01-18 16:03:37 +08:00
|
|
|
const webpack = require("../");
|
|
|
|
const WebpackOptionsDefaulter = require("../lib/WebpackOptionsDefaulter");
|
2017-06-24 07:12:37 +08:00
|
|
|
const Compiler = require("../lib/Compiler");
|
2017-01-18 16:03:37 +08:00
|
|
|
|
|
|
|
describe("Compiler", () => {
|
2013-01-31 01:49:25 +08:00
|
|
|
function compile(entry, options, callback) {
|
2017-01-18 16:03:37 +08:00
|
|
|
const noOutputPath = !options.output || !options.output.path;
|
2013-01-31 01:49:25 +08:00
|
|
|
new WebpackOptionsDefaulter().process(options);
|
|
|
|
options.entry = entry;
|
|
|
|
options.context = path.join(__dirname, "fixtures");
|
2017-02-02 19:36:15 +08:00
|
|
|
if(noOutputPath) options.output.path = "/";
|
2013-01-31 01:49:25 +08:00
|
|
|
options.output.pathinfo = true;
|
2017-01-18 16:03:37 +08:00
|
|
|
const logs = {
|
2015-01-05 21:13:11 +08:00
|
|
|
mkdirp: [],
|
|
|
|
writeFile: [],
|
|
|
|
};
|
2013-01-31 01:49:25 +08:00
|
|
|
|
2017-01-18 16:03:37 +08:00
|
|
|
const c = webpack(options);
|
|
|
|
const files = {};
|
2013-01-31 01:49:25 +08:00
|
|
|
c.outputFileSystem = {
|
2017-02-09 19:28:26 +08:00
|
|
|
join: function() {
|
2017-02-09 19:57:09 +08:00
|
|
|
return [].join.call(arguments, "/").replace(/\/+/g, "/");
|
2017-02-09 19:28:26 +08:00
|
|
|
},
|
2013-01-31 01:49:25 +08:00
|
|
|
mkdirp: function(path, callback) {
|
2015-01-05 21:13:11 +08:00
|
|
|
logs.mkdirp.push(path);
|
2013-01-31 01:49:25 +08:00
|
|
|
callback();
|
|
|
|
},
|
|
|
|
writeFile: function(name, content, callback) {
|
2015-01-05 21:13:11 +08:00
|
|
|
logs.writeFile.push(name, content);
|
2013-01-31 01:49:25 +08:00
|
|
|
files[name] = content.toString("utf-8");
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
};
|
2017-01-18 16:03:37 +08:00
|
|
|
c.plugin("compilation", (compilation) => compilation.bail = true);
|
|
|
|
c.run((err, stats) => {
|
2013-01-31 01:49:25 +08:00
|
|
|
if(err) throw err;
|
2013-10-16 14:57:37 +08:00
|
|
|
should.strictEqual(typeof stats, "object");
|
2017-01-18 16:03:37 +08:00
|
|
|
const compilation = stats.compilation;
|
2013-01-31 01:49:25 +08:00
|
|
|
stats = stats.toJson({
|
|
|
|
modules: true,
|
|
|
|
reasons: true
|
|
|
|
});
|
2013-10-16 14:57:37 +08:00
|
|
|
should.strictEqual(typeof stats, "object");
|
2013-01-31 01:49:25 +08:00
|
|
|
stats.should.have.property("errors");
|
2017-01-02 08:44:24 +08:00
|
|
|
Array.isArray(stats.errors).should.be.ok();
|
2013-01-31 01:49:25 +08:00
|
|
|
if(stats.errors.length > 0) {
|
|
|
|
stats.errors[0].should.be.instanceOf(Error);
|
|
|
|
throw stats.errors[0];
|
|
|
|
}
|
2015-01-05 21:13:11 +08:00
|
|
|
stats.logs = logs;
|
2016-12-14 19:03:24 +08:00
|
|
|
callback(stats, files, compilation);
|
2013-01-31 01:49:25 +08:00
|
|
|
});
|
|
|
|
}
|
2015-01-05 21:13:11 +08:00
|
|
|
|
2017-01-18 16:03:37 +08:00
|
|
|
it("should compile a single file to deep output", (done) => {
|
2015-01-05 21:13:11 +08:00
|
|
|
compile("./c", {
|
|
|
|
output: {
|
2017-02-02 19:56:41 +08:00
|
|
|
path: "/what",
|
2017-02-09 19:28:26 +08:00
|
|
|
filename: "the/hell.js",
|
2015-01-05 21:13:11 +08:00
|
|
|
}
|
2017-01-18 16:03:37 +08:00
|
|
|
}, (stats, files) => {
|
2015-01-05 21:13:11 +08:00
|
|
|
stats.logs.mkdirp.should.eql([
|
2017-02-02 19:56:41 +08:00
|
|
|
"/what",
|
2017-02-09 19:28:26 +08:00
|
|
|
"/what/the",
|
2015-01-05 21:13:11 +08:00
|
|
|
]);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2017-02-02 19:36:15 +08:00
|
|
|
|
2017-03-01 01:26:49 +08:00
|
|
|
it("should compile a single file", (done) => {
|
2017-01-18 16:03:37 +08:00
|
|
|
compile("./c", {}, (stats, files) => {
|
2017-02-02 19:36:15 +08:00
|
|
|
files.should.have.property("/main.js").have.type("string");
|
|
|
|
Object.keys(files).should.be.eql(["/main.js"]);
|
2017-03-01 01:23:24 +08:00
|
|
|
const bundle = files["/main.js"];
|
2014-07-28 02:39:22 +08:00
|
|
|
bundle.should.containEql("function __webpack_require__(");
|
2017-06-01 21:42:57 +08:00
|
|
|
bundle.should.containEql("__webpack_require__(/*! ./a */ 1);");
|
2014-07-28 02:39:22 +08:00
|
|
|
bundle.should.containEql("./c.js");
|
|
|
|
bundle.should.containEql("./a.js");
|
|
|
|
bundle.should.containEql("This is a");
|
|
|
|
bundle.should.containEql("This is c");
|
|
|
|
bundle.should.not.containEql("2: function(");
|
|
|
|
bundle.should.not.containEql("window");
|
|
|
|
bundle.should.not.containEql("jsonp");
|
|
|
|
bundle.should.not.containEql("fixtures");
|
2013-01-31 01:49:25 +08:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2017-02-02 19:36:15 +08:00
|
|
|
|
2017-03-01 01:26:49 +08:00
|
|
|
it("should compile a complex file", (done) => {
|
2017-01-18 16:03:37 +08:00
|
|
|
compile("./main1", {}, (stats, files) => {
|
2017-02-02 19:36:15 +08:00
|
|
|
files.should.have.property("/main.js").have.type("string");
|
|
|
|
Object.keys(files).should.be.eql(["/main.js"]);
|
2017-03-01 01:23:24 +08:00
|
|
|
const bundle = files["/main.js"];
|
2014-07-28 02:39:22 +08:00
|
|
|
bundle.should.containEql("function __webpack_require__(");
|
|
|
|
bundle.should.containEql("__webpack_require__(/*! ./a */");
|
|
|
|
bundle.should.containEql("./main1.js");
|
|
|
|
bundle.should.containEql("./a.js");
|
|
|
|
bundle.should.containEql("./b.js");
|
2017-01-18 05:26:38 +08:00
|
|
|
bundle.should.containEql("./node_modules/m1/a.js");
|
2014-07-28 02:39:22 +08:00
|
|
|
bundle.should.containEql("This is a");
|
|
|
|
bundle.should.containEql("This is b");
|
|
|
|
bundle.should.containEql("This is m1/a");
|
|
|
|
bundle.should.not.containEql("4: function(");
|
|
|
|
bundle.should.not.containEql("window");
|
|
|
|
bundle.should.not.containEql("jsonp");
|
|
|
|
bundle.should.not.containEql("fixtures");
|
2013-01-31 01:49:25 +08:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2017-02-02 19:36:15 +08:00
|
|
|
|
2017-03-01 01:26:49 +08:00
|
|
|
it("should compile a file with transitive dependencies", (done) => {
|
2017-01-18 16:03:37 +08:00
|
|
|
compile("./abc", {}, (stats, files) => {
|
2017-02-02 19:36:15 +08:00
|
|
|
files.should.have.property("/main.js").have.type("string");
|
|
|
|
Object.keys(files).should.be.eql(["/main.js"]);
|
2017-03-01 01:23:24 +08:00
|
|
|
const bundle = files["/main.js"];
|
2014-07-28 02:39:22 +08:00
|
|
|
bundle.should.containEql("function __webpack_require__(");
|
|
|
|
bundle.should.containEql("__webpack_require__(/*! ./a */");
|
|
|
|
bundle.should.containEql("__webpack_require__(/*! ./b */");
|
|
|
|
bundle.should.containEql("__webpack_require__(/*! ./c */");
|
|
|
|
bundle.should.containEql("./abc.js");
|
|
|
|
bundle.should.containEql("./a.js");
|
|
|
|
bundle.should.containEql("./b.js");
|
|
|
|
bundle.should.containEql("./c.js");
|
|
|
|
bundle.should.containEql("This is a");
|
|
|
|
bundle.should.containEql("This is b");
|
|
|
|
bundle.should.containEql("This is c");
|
|
|
|
bundle.should.not.containEql("4: function(");
|
|
|
|
bundle.should.not.containEql("window");
|
|
|
|
bundle.should.not.containEql("jsonp");
|
|
|
|
bundle.should.not.containEql("fixtures");
|
2013-01-31 01:49:25 +08:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2017-02-02 19:36:15 +08:00
|
|
|
|
2017-03-01 01:26:49 +08:00
|
|
|
it("should compile a file with multiple chunks", (done) => {
|
2017-01-18 16:03:37 +08:00
|
|
|
compile("./chunks", {}, (stats, files) => {
|
2013-01-31 01:49:25 +08:00
|
|
|
stats.chunks.length.should.be.eql(2);
|
2017-02-02 19:36:15 +08:00
|
|
|
files.should.have.property("/main.js").have.type("string");
|
|
|
|
files.should.have.property("/0.js").have.type("string");
|
|
|
|
Object.keys(files).should.be.eql(["/0.js", "/main.js"]);
|
2017-03-01 01:23:24 +08:00
|
|
|
const bundle = files["/main.js"];
|
|
|
|
const chunk = files["/0.js"];
|
2014-07-28 02:39:22 +08:00
|
|
|
bundle.should.containEql("function __webpack_require__(");
|
|
|
|
bundle.should.containEql("__webpack_require__(/*! ./b */");
|
|
|
|
chunk.should.not.containEql("__webpack_require__(/* ./b */");
|
|
|
|
bundle.should.containEql("./chunks.js");
|
|
|
|
chunk.should.containEql("./a.js");
|
|
|
|
chunk.should.containEql("./b.js");
|
|
|
|
chunk.should.containEql("This is a");
|
|
|
|
bundle.should.not.containEql("This is a");
|
|
|
|
chunk.should.containEql("This is b");
|
|
|
|
bundle.should.not.containEql("This is b");
|
|
|
|
bundle.should.not.containEql("4: function(");
|
|
|
|
bundle.should.not.containEql("fixtures");
|
|
|
|
chunk.should.not.containEql("fixtures");
|
|
|
|
bundle.should.containEql("webpackJsonp");
|
2017-04-23 00:59:15 +08:00
|
|
|
chunk.should.containEql("window[\"webpackJsonp\"] || []).push");
|
2013-01-31 01:49:25 +08:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2017-06-24 07:12:37 +08:00
|
|
|
describe("constructor", () => {
|
|
|
|
let compiler;
|
|
|
|
beforeEach(() => {
|
|
|
|
compiler = webpack({
|
|
|
|
entry: "./c",
|
|
|
|
context: path.join(__dirname, "fixtures"),
|
|
|
|
output: {
|
|
|
|
path: "/",
|
|
|
|
pathinfo: true,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe("parser", () => {
|
|
|
|
describe("apply", () => {
|
|
|
|
it("invokes sets a 'compilation' plugin", (done) => {
|
|
|
|
compiler.plugin = sinon.spy();
|
|
|
|
compiler.parser.apply();
|
|
|
|
compiler.plugin.callCount.should.be.exactly(1);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2017-06-24 04:30:30 +08:00
|
|
|
describe("methods", () => {
|
|
|
|
let compiler;
|
|
|
|
beforeEach(() => {
|
|
|
|
compiler = webpack({
|
|
|
|
entry: "./c",
|
|
|
|
context: path.join(__dirname, "fixtures"),
|
|
|
|
output: {
|
|
|
|
path: "/",
|
|
|
|
pathinfo: true,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe("purgeInputFileSystem", () => {
|
|
|
|
it("invokes purge() if inputFileSystem.purge", (done) => {
|
|
|
|
const mockPurge = sinon.spy();
|
|
|
|
compiler.inputFileSystem = {
|
|
|
|
purge: mockPurge,
|
|
|
|
};
|
|
|
|
compiler.purgeInputFileSystem();
|
|
|
|
mockPurge.callCount.should.be.exactly(1);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
it("does NOT invoke purge() if !inputFileSystem.purge", (done) => {
|
|
|
|
const mockPurge = sinon.spy();
|
|
|
|
compiler.inputFileSystem = null;
|
|
|
|
compiler.purgeInputFileSystem();
|
|
|
|
mockPurge.callCount.should.be.exactly(0);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe("isChild", () => {
|
|
|
|
it("returns booleanized this.parentCompilation", (done) => {
|
|
|
|
compiler.parentCompilation = "stringyStringString";
|
|
|
|
const response1 = compiler.isChild();
|
|
|
|
response1.should.be.exactly(true);
|
|
|
|
|
|
|
|
compiler.parentCompilation = 123456789;
|
|
|
|
const response2 = compiler.isChild();
|
|
|
|
response2.should.be.exactly(true);
|
|
|
|
|
2017-06-24 04:45:59 +08:00
|
|
|
compiler.parentCompilation = {
|
|
|
|
what: "I belong to an object"
|
|
|
|
};
|
2017-06-24 04:30:30 +08:00
|
|
|
const response3 = compiler.isChild();
|
|
|
|
response3.should.be.exactly(true);
|
|
|
|
|
|
|
|
compiler.parentCompilation = ["Array", 123, true, null, [], () => {}];
|
|
|
|
const response4 = compiler.isChild();
|
|
|
|
response4.should.be.exactly(true);
|
|
|
|
|
|
|
|
compiler.parentCompilation = false;
|
|
|
|
const response5 = compiler.isChild();
|
|
|
|
response5.should.be.exactly(false);
|
|
|
|
|
|
|
|
compiler.parentCompilation = 0;
|
|
|
|
const response6 = compiler.isChild();
|
|
|
|
response6.should.be.exactly(false);
|
|
|
|
|
|
|
|
compiler.parentCompilation = null;
|
|
|
|
const response7 = compiler.isChild();
|
|
|
|
response7.should.be.exactly(false);
|
|
|
|
|
|
|
|
compiler.parentCompilation = "";
|
|
|
|
const response8 = compiler.isChild();
|
|
|
|
response8.should.be.exactly(false);
|
|
|
|
|
|
|
|
compiler.parentCompilation = NaN;
|
|
|
|
const response9 = compiler.isChild();
|
|
|
|
response9.should.be.exactly(false);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe("Watching", () => {
|
|
|
|
let compiler;
|
|
|
|
beforeEach(() => {
|
|
|
|
compiler = webpack({
|
|
|
|
entry: "./c",
|
|
|
|
context: path.join(__dirname, "fixtures"),
|
|
|
|
output: {
|
|
|
|
path: "/",
|
|
|
|
pathinfo: true,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2017-07-06 21:06:13 +08:00
|
|
|
describe("static method", () => {
|
|
|
|
it("should have an method, Watching", (done) => {
|
|
|
|
const actual = new Compiler.Watching(compiler, 1000, err => err);
|
|
|
|
actual.running.should.be.exactly(true);
|
|
|
|
actual.constructor.name.should.be.exactly("Watching");
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2017-06-24 04:30:30 +08:00
|
|
|
describe("constructor", () => {
|
|
|
|
it("constructs Watching.watchOptions correctly when passed a number, string, or object for watchOptions", (done) => {
|
|
|
|
const Watching1 = compiler.watch(1000, err => err);
|
2017-06-24 04:45:59 +08:00
|
|
|
const Watching2 = compiler.watch({
|
|
|
|
aggregateTimeout: 1000
|
|
|
|
}, err => err);
|
2017-06-24 04:30:30 +08:00
|
|
|
const Watching3 = compiler.watch("I am a string", err => err);
|
|
|
|
Watching1.watchOptions.aggregateTimeout.should.equal(Watching2.watchOptions.aggregateTimeout);
|
|
|
|
Watching3.watchOptions.aggregateTimeout.should.equal(200);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
it("invokes compiler.readRecords", (done) => {
|
|
|
|
compiler.readRecords = sinon.spy();
|
|
|
|
compiler.watch(1000, err => err);
|
|
|
|
compiler.readRecords.callCount.should.be.exactly(1);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe("_done", () => {
|
|
|
|
it("invokes this.handler and turns this.running boolean to false when passed an error", (done) => {
|
|
|
|
const mockHandler = sinon.spy();
|
|
|
|
const Watching1 = compiler.watch(1000, mockHandler);
|
|
|
|
Watching1.running.should.be.exactly(true);
|
|
|
|
Watching1._done(Watching1.handler, false);
|
|
|
|
mockHandler.callCount.should.be.exactly(1);
|
|
|
|
Watching1.running.should.be.exactly(false);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe("invalidate", () => {
|
|
|
|
it("pauses this.watcher and sets this.watcher to null if this.watcher is true", (done) => {
|
|
|
|
const mockPause = sinon.spy();
|
|
|
|
const Watching1 = compiler.watch(1000, err => err);
|
2017-06-24 04:45:59 +08:00
|
|
|
Watching1.watcher = {
|
|
|
|
pause: mockPause
|
|
|
|
};
|
2017-06-24 04:30:30 +08:00
|
|
|
Watching1.invalidate();
|
|
|
|
mockPause.callCount.should.be.exactly(1);
|
|
|
|
should(Watching1.watcher).be.exactly(null);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
it("sets this.invalid to true if this.running is true, else this.invalid = false", (done) => {
|
|
|
|
const Watching1 = compiler.watch(1000, err => err);
|
|
|
|
Watching1.invalid = false;
|
|
|
|
const response = Watching1.invalidate();
|
|
|
|
Watching1.invalid.should.be.exactly(true);
|
|
|
|
response.should.be.exactly(false);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
it("invokes this._go() if !this.running", (done) => {
|
|
|
|
const Watching1 = compiler.watch(1000, err => err);
|
|
|
|
Watching1.running = false;
|
|
|
|
Watching1._go = sinon.spy();
|
|
|
|
Watching1.invalidate();
|
|
|
|
Watching1._go.callCount.should.be.exactly(1);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-01-05 21:13:11 +08:00
|
|
|
});
|