/* globals describe, it, beforeEach, afterEach */ "use strict"; const sinon = require("sinon"); const NormalModule = require("../lib/NormalModule"); const NullDependency = require("../lib/dependencies/NullDependency"); const SourceMapSource = require("webpack-sources").SourceMapSource; const OriginalSource = require("webpack-sources").OriginalSource; const RawSource = require("webpack-sources").RawSource; describe("NormalModule", () => { let normalModule; let request; let userRequest; let rawRequest; let loaders; let resource; let parser; beforeEach(() => { request = "some/request"; userRequest = "some/userRequest"; rawRequest = "some/rawRequest"; loaders = []; resource = "some/resource"; parser = { parse() {} }; normalModule = new NormalModule( "javascript/auto", request, userRequest, rawRequest, loaders, resource, parser ); normalModule.buildInfo = { cacheable: true }; }); describe("#identifier", () => { it("returns an identifier for this module", () => { expect(normalModule.identifier()).toBe(request); }); it("returns an identifier from toString", () => { normalModule.debugId = 1000; expect(normalModule.toString()).toBe("Module[1000]"); normalModule.id = 1; expect(normalModule.toString()).toBe("Module[1]"); }); }); describe("#readableIdentifier", () => { it("calls the given requestShortener with the user request", () => { const spy = sinon.spy(); normalModule.readableIdentifier({ shorten: spy }); expect(spy.callCount).toBe(1); expect(spy.args[0][0]).toBe(userRequest); }); }); describe("#libIdent", () => { it("contextifies the userRequest of the module", () => { expect(normalModule.libIdent({ context: "some/context" })).toBe("../userRequest"); }); describe("given a userRequest containing loaders", () => { beforeEach(() => { userRequest = "some/userRequest!some/other/userRequest!some/thing/is/off/here"; normalModule = new NormalModule( "javascript/auto", request, userRequest, rawRequest, loaders, resource, parser ); }); it("contextifies every path in the userRequest", () => { expect(normalModule.libIdent({ context: "some/context" })).toBe("../userRequest!../other/userRequest!../thing/is/off/here"); }); }); describe("given a userRequest containing query parameters", () => { it("ignores paths in query parameters", () => { userRequest = "some/context/loader?query=foo\\bar&otherPath=testpath/other"; normalModule = new NormalModule( "javascript/auto", request, userRequest, rawRequest, loaders, resource, parser ); expect(normalModule.libIdent({ context: "some/context", })).toBe("./loader?query=foo\\bar&otherPath=testpath/other"); }); }); }); describe("#nameForCondition", () => { it("return the resource", () => { expect(normalModule.nameForCondition()).toBe(resource); }); describe("given a resource containing a ?-sign", () => { const baseResource = "some/resource"; beforeEach(() => { resource = baseResource + "?some=query"; normalModule = new NormalModule( "javascript/auto", request, userRequest, rawRequest, loaders, resource, parser ); }); it("return only the part before the ?-sign", () => { expect(normalModule.nameForCondition()).toBe(baseResource); }); }); }); describe("#createSourceForAsset", () => { let name; let content; let sourceMap; beforeEach(() => { name = "some name"; content = "some content"; sourceMap = "some sourcemap"; }); describe("given no sourcemap", () => { it("returns a RawSource", () => { expect(normalModule.createSourceForAsset(name, content)).toBeInstanceOf(RawSource); }); }); describe("given a string as the sourcemap", () => { it("returns a OriginalSource", () => { expect(normalModule.createSourceForAsset(name, content, sourceMap)).toBeInstanceOf(OriginalSource); }); }); describe("given a some other kind of sourcemap", () => { beforeEach(() => { sourceMap = () => {}; }); it("returns a SourceMapSource", () => { expect(normalModule.createSourceForAsset(name, content, sourceMap)).toBeInstanceOf(SourceMapSource); }); }); }); describe("#source", () => { describe("without the module having any source", () => { beforeEach(() => { normalModule._source = null; }); it("returns a Source containing an Error", () => { expect(normalModule.source()).toBeInstanceOf(RawSource); expect(normalModule.source().source()).toBe("throw new Error('No source available');"); }); }); }); describe("#originalSource", () => { let expectedSource = "some source"; beforeEach(() => { normalModule._source = new RawSource(expectedSource); }); it("returns an original Source", () => { expect(normalModule.originalSource()).toBe(normalModule._source); }); }); describe("#updateHashWithSource", () => { let hashSpy; let hash; beforeEach(() => { hashSpy = sinon.spy(); hash = { update: hashSpy }; }); describe("without the module having any source", () => { beforeEach(() => { normalModule._source = null; }); it("calls hash function with \"null\"", () => { normalModule.updateHashWithSource(hash); expect(hashSpy.callCount).toBe(1); expect(hashSpy.args[0][0]).toBe("null"); }); }); describe("without the module having source", () => { let expectedSource = "some source"; beforeEach(() => { normalModule._source = new RawSource(expectedSource); }); it("calls hash function with \"source\" and then the actual source of the module", function() { normalModule.updateHashWithSource(hash); expect(hashSpy.callCount).toBe(2); expect(hashSpy.args[0][0]).toBe("source"); expect(hashSpy.args[1][0]).toBe(expectedSource); }); }); }); describe("#hasDependencies", () => { it("returns true if has dependencies", () => { normalModule.addDependency(new NullDependency()); expect(normalModule.hasDependencies()).toBe(true); }); it("returns false if has dependencies", () => { expect(normalModule.hasDependencies()).toBe(false); }); }); describe("#needRebuild", () => { let fileTimestamps; let contextTimestamps; let fileDependencies; let contextDependencies; let fileA; let fileB; function setDeps(fileDependencies, contextDependencies) { normalModule.buildInfo.fileDependencies = fileDependencies; normalModule.buildInfo.contextDependencies = contextDependencies; } beforeEach(() => { fileA = "fileA"; fileB = "fileB"; fileDependencies = [fileA, fileB]; contextDependencies = [fileA, fileB]; fileTimestamps = new Map([ [fileA, 1], [fileB, 1] ]); contextTimestamps = new Map([ [fileA, 1], [fileB, 1], ]); normalModule.buildTimestamp = 2; setDeps(fileDependencies, contextDependencies); }); describe("given all timestamps are older than the buildTimestamp", () => { it("returns false", () => { expect(normalModule.needRebuild(fileTimestamps, contextTimestamps)).toBe(false); }); }); describe("given a file timestamp is newer than the buildTimestamp", () => { beforeEach(() => { fileTimestamps.set(fileA, 3); }); it("returns true", () => { expect(normalModule.needRebuild(fileTimestamps, contextTimestamps)).toBe(true); }); }); describe("given a no file timestamp exists", () => { beforeEach(() => { fileTimestamps = new Map(); }); it("returns true", () => { expect(normalModule.needRebuild(fileTimestamps, contextTimestamps)).toBe(true); }); }); describe("given a context timestamp is newer than the buildTimestamp", () => { beforeEach(() => { contextTimestamps.set(fileA, 3); }); it("returns true", () => { expect(normalModule.needRebuild(fileTimestamps, contextTimestamps)).toBe(true); }); }); describe("given a no context timestamp exists", () => { beforeEach(() => { contextTimestamps = new Map(); }); it("returns true", () => { expect(normalModule.needRebuild(fileTimestamps, contextTimestamps)).toBe(true); }); }); }); describe("#splitVariablesInUniqueNamedChunks", () => { let variables; beforeEach(() => { variables = [{ name: "foo" }, { name: "bar" }, { name: "baz" }, { name: "some" }, { name: "more" }]; }); describe("given an empty array of vars", () => { it("returns an empty array", () => { expect(normalModule.splitVariablesInUniqueNamedChunks([])).toEqual([ [] ]); }); }); describe("given an array of distrinct variables", () => { it("returns an array containing an array containing the variables", () => { expect(normalModule.splitVariablesInUniqueNamedChunks(variables)).toEqual([variables]); }); }); describe("given an array with duplicate variables", () => { it("returns several arrays each containing only distinct variable names", () => { expect(normalModule.splitVariablesInUniqueNamedChunks(variables.concat(variables))).toEqual([variables, variables]); }); describe("and a duplicate as the last variable", () => { it("returns correctly split distinct arrays", () => { expect(normalModule.splitVariablesInUniqueNamedChunks(variables.concat(variables).concat(variables[0]))).toEqual([variables, variables, [variables[0]]]); }); }); }); }); describe("#applyNoParseRule", () => { let rule; let content; describe("given a string as rule", () => { beforeEach(() => { rule = "some-rule"; }); describe("and the content starting with the string specified in rule", () => { beforeEach(() => { content = rule + "some-content"; }); it("returns true", () => { expect(normalModule.shouldPreventParsing(rule, content)).toBe(true); }); }); describe("and the content does not start with the string specified in rule", () => { beforeEach(() => { content = "some-content"; }); it("returns false", () => { expect(normalModule.shouldPreventParsing(rule, content)).toBe(false); }); }); }); describe("given a regex as rule", () => { beforeEach(() => { rule = /some-rule/; }); describe("and the content matches the rule", () => { beforeEach(() => { content = rule + "some-content"; }); it("returns true", () => { expect(normalModule.shouldPreventParsing(rule, content)).toBe(true); }); }); describe("and the content does not match the rule", () => { beforeEach(() => { content = "some-content"; }); it("returns false", () => { expect(normalModule.shouldPreventParsing(rule, content)).toBe(false); }); }); }); }); describe("#shouldPreventParsing", () => { let applyNoParseRuleSpy; beforeEach(() => { applyNoParseRuleSpy = sinon.stub(); normalModule.applyNoParseRule = applyNoParseRuleSpy; }); describe("given no noParseRule", () => { it("returns false", () => { expect(normalModule.shouldPreventParsing()).toBe(false); expect(applyNoParseRuleSpy.callCount).toBe(0); }); }); describe("given a noParseRule", () => { let returnValOfSpy; beforeEach(() => { returnValOfSpy = true; applyNoParseRuleSpy.returns(returnValOfSpy); }); describe("that is a string", () => { it("calls and returns whatever applyNoParseRule returns", () => { expect(normalModule.shouldPreventParsing("some rule")).toBe(returnValOfSpy); expect(applyNoParseRuleSpy.callCount).toBe(1); }); }); describe("that is a regex", () => { it("calls and returns whatever applyNoParseRule returns", () => { expect(normalModule.shouldPreventParsing("some rule")).toBe(returnValOfSpy); expect(applyNoParseRuleSpy.callCount).toBe(1); }); }); describe("that is an array", () => { describe("of strings and or regexs", () => { let someRules; beforeEach(() => { someRules = [ "some rule", /some rule1/, "some rule2", ]; }); describe("and none of them match", () => { beforeEach(() => { returnValOfSpy = false; applyNoParseRuleSpy.returns(returnValOfSpy); }); it("returns false", () => { expect(normalModule.shouldPreventParsing(someRules)).toBe(returnValOfSpy); expect(applyNoParseRuleSpy.callCount).toBe(3); }); }); describe("and the first of them matches", () => { beforeEach(() => { returnValOfSpy = true; applyNoParseRuleSpy.returns(returnValOfSpy); }); it("returns true", () => { expect(normalModule.shouldPreventParsing(someRules)).toBe(returnValOfSpy); expect(applyNoParseRuleSpy.callCount).toBe(1); }); }); describe("and the last of them matches", () => { beforeEach(() => { returnValOfSpy = true; applyNoParseRuleSpy.onCall(0).returns(false); applyNoParseRuleSpy.onCall(1).returns(false); applyNoParseRuleSpy.onCall(2).returns(true); }); it("returns true", () => { expect(normalModule.shouldPreventParsing(someRules)).toBe(returnValOfSpy); expect(applyNoParseRuleSpy.callCount).toBe(3); }); }); }); }); }); }); });