diff --git a/test/ConfigTestCases.test.js b/test/ConfigTestCases.test.js index 9ebd6f94a49..2206cef1763 100644 --- a/test/ConfigTestCases.test.js +++ b/test/ConfigTestCases.test.js @@ -174,7 +174,6 @@ describe("ConfigTestCases", () => { function _require(currentDirectory, module) { if (Array.isArray(module) || /^\.\.?\//.test(module)) { - let fn; let content; let p; if (Array.isArray(module)) { @@ -189,45 +188,47 @@ describe("ConfigTestCases", () => { p = path.join(currentDirectory, module); content = fs.readFileSync(p, "utf-8"); } - if ( - options.target === "web" || - options.target === "webworker" - ) { - fn = vm.runInNewContext( - "(function(require, module, exports, __dirname, __filename, it, beforeEach, afterEach, expect, jest, window) {" + - 'function nsObj(m) { Object.defineProperty(m, Symbol.toStringTag, { value: "Module" }); return m; }' + - content + - "\n})", - globalContext, - p - ); - } else { - fn = vm.runInThisContext( - "(function(require, module, exports, __dirname, __filename, it, beforeEach, afterEach, expect, jest) {" + - "global.expect = expect; " + - 'function nsObj(m) { Object.defineProperty(m, Symbol.toStringTag, { value: "Module" }); return m; }' + - content + - "\n})", - p - ); - } const m = { exports: {} }; - fn.call( - m.exports, - _require.bind(null, path.dirname(p)), - m, - m.exports, - path.dirname(p), - p, - _it, - _beforeEach, - _afterEach, + let runInNewContext = false; + const moduleScope = { + require: _require.bind(null, path.dirname(p)), + module: m, + exports: m.exports, + __dirname: path.dirname(p), + __filename: p, + it: _it, + beforeEach: _beforeEach, + afterEach: _afterEach, expect, jest, - globalContext - ); + _globalAssign: { expect }, + nsObj: m => { + Object.defineProperty(m, Symbol.toStringTag, { + value: "Module" + }); + return m; + } + }; + if ( + options.target === "web" || + options.target === "webworker" + ) { + moduleScope.window = globalContext; + runInNewContext = true; + } + if (testConfig.moduleScope) { + testConfig.moduleScope(moduleScope); + } + const args = Object.keys(moduleScope).join(", "); + if (!runInNewContext) + content = `Object.assign(global, _globalAssign); ${content}`; + const code = `(function({${args}}) {${content}\n})`; + const fn = runInNewContext + ? vm.runInNewContext(code, globalContext, p) + : vm.runInThisContext(code, p); + fn.call(m.exports, moduleScope); return m.exports; } else if ( testConfig.modules && @@ -239,6 +240,7 @@ describe("ConfigTestCases", () => { let filesCount = 0; if (testConfig.noTests) return process.nextTick(done); + if (testConfig.beforeExecute) testConfig.beforeExecute(); for (let i = 0; i < optionsArr.length; i++) { const bundlePath = testConfig.findBundle(i, optionsArr[i]); if (bundlePath) { @@ -256,9 +258,9 @@ describe("ConfigTestCases", () => { "Should have found at least one bundle file per webpack config" ) ); + if (testConfig.afterExecute) testConfig.afterExecute(); if (getNumberOfTests() < filesCount) return done(new Error("No tests exported by test case")); - if (testConfig.afterExecute) testConfig.afterExecute(); done(); }); }) diff --git a/test/configCases/externals/externals-system/index.js b/test/configCases/externals/externals-system/index.js index 2e8fb5a7f1f..8f634069218 100644 --- a/test/configCases/externals/externals-system/index.js +++ b/test/configCases/externals/externals-system/index.js @@ -1,16 +1,11 @@ /* This test verifies that webpack externals are properly indicated as dependencies to System. * Also that when System provides the external variables to webpack that the variables get plumbed * through correctly and are usable by the webpack bundle. -*/ -afterEach(function(done) { - delete global.System; - done() -}) - + */ it("should get an external from System", function() { const external1 = require("external1"); - expect(external1).toBe('the external1 value'); + expect(external1).toBe("the external1 value"); const external2 = require("external2"); - expect(external2).toBe('the external2 value'); + expect(external2).toBe("the external2 value"); }); diff --git a/test/configCases/externals/externals-system/test.config.js b/test/configCases/externals/externals-system/test.config.js new file mode 100644 index 00000000000..3f8225baf26 --- /dev/null +++ b/test/configCases/externals/externals-system/test.config.js @@ -0,0 +1,16 @@ +const System = require("../../../helpers/fakeSystem"); + +module.exports = { + beforeExecute: () => { + System.init({ + external1: "the external1 value", + external2: "the external2 value" + }); + }, + moduleScope(scope) { + scope.System = System; + }, + afterExecute: () => { + System.execute("(anonym)"); + } +}; diff --git a/test/configCases/externals/externals-system/webpack.config.js b/test/configCases/externals/externals-system/webpack.config.js index be11a7f1152..9a4ae5336e5 100644 --- a/test/configCases/externals/externals-system/webpack.config.js +++ b/test/configCases/externals/externals-system/webpack.config.js @@ -1,4 +1,3 @@ -const webpack = require("../../../../"); module.exports = { output: { libraryTarget: "system" @@ -6,26 +5,5 @@ module.exports = { externals: { external1: "external1", external2: "external2" - }, - plugins: [ - new webpack.BannerPlugin({ - raw: true, - banner: ` - System = { - register: function(deps, fn) { - function dynamicExport() {} - var mod = fn(dynamicExport); - deps.forEach((dep, i) => { - mod.setters[i](System.registry[dep]); - }) - mod.execute(); - }, - registry: { - external1: 'the external1 value', - external2: 'the external2 value', - }, - } - ` - }) - ] + } }; diff --git a/test/configCases/target/system-export/index.js b/test/configCases/target/system-export/index.js index 44798c17df8..bfe3bb7e747 100644 --- a/test/configCases/target/system-export/index.js +++ b/test/configCases/target/system-export/index.js @@ -1,22 +1,13 @@ // This test verifies that values exported by a webpack bundle are consumable by systemjs. export const namedThing = { - hello: 'there' -} + hello: "there" +}; -export default 'the default export' +export default "the default export"; -it("should successfully export values to System", function(done) { - var fs = require("fs"); - var source = fs.readFileSync(__filename, "utf-8"); - - // set timeout allows the webpack bundle to finish exporting, which exports to System at the very - // end of its execution. - setTimeout(() => { - expect(global.SystemExports['default']).toBe('the default export') - expect(global.SystemExports.namedThing).toBe(namedThing) - delete global.System; - delete global.SystemExports - done() - }) -}); \ No newline at end of file +it("should successfully export values to System", function() { + const exports = eval("System").registry["(anonym)"].exports; + expect(exports["default"]).toBe("the default export"); + expect(exports.namedThing).toBe(namedThing); +}); diff --git a/test/configCases/target/system-export/test.config.js b/test/configCases/target/system-export/test.config.js new file mode 100644 index 00000000000..97ebf538dbe --- /dev/null +++ b/test/configCases/target/system-export/test.config.js @@ -0,0 +1,13 @@ +const System = require("../../../helpers/fakeSystem"); + +module.exports = { + beforeExecute: () => { + System.init(); + }, + moduleScope(scope) { + scope.System = System; + }, + afterExecute: () => { + System.execute("(anonym)"); + } +}; diff --git a/test/configCases/target/system-export/webpack.config.js b/test/configCases/target/system-export/webpack.config.js index 2c09f946d53..063b492074e 100644 --- a/test/configCases/target/system-export/webpack.config.js +++ b/test/configCases/target/system-export/webpack.config.js @@ -1,4 +1,3 @@ -const webpack = require("../../../../"); module.exports = { output: { libraryTarget: "system" @@ -6,23 +5,5 @@ module.exports = { node: { __dirname: false, __filename: false - }, - plugins: [ - new webpack.BannerPlugin({ - raw: true, - banner: ` - global.SystemExports = { - 'export': function(exports) { - Object.assign(global.SystemExports, exports); - } - }; - global.System = { - register: function(deps, fn) { - var mod = fn(global.SystemExports['export']); - mod.execute(); - } - }; - ` - }) - ] + } }; diff --git a/test/configCases/target/system-named/index.js b/test/configCases/target/system-named/index.js index 0dafc34d9ce..5f355e1d11f 100644 --- a/test/configCases/target/system-named/index.js +++ b/test/configCases/target/system-named/index.js @@ -1,15 +1,5 @@ /* This test verifies that when output.library is specified that the compiled bundle provides -* the library name to System during the System.register -*/ + * the library name to System during the System.register + */ -afterEach(function(done) { - delete global.System; - done() -}) - -it("should call System.register with a name", function() { - var fs = require("fs"); - var source = fs.readFileSync(__filename, "utf-8"); - - expect(source).toMatch(/.*System\.register\("named-system-module", \[[^\]]*\]/); -}); \ No newline at end of file +it("should call System.register with a name", function() {}); diff --git a/test/configCases/target/system-named/test.config.js b/test/configCases/target/system-named/test.config.js new file mode 100644 index 00000000000..8b3f83a51f9 --- /dev/null +++ b/test/configCases/target/system-named/test.config.js @@ -0,0 +1,13 @@ +const System = require("../../../helpers/fakeSystem"); + +module.exports = { + beforeExecute: () => { + System.init(); + }, + moduleScope(scope) { + scope.System = System; + }, + afterExecute: () => { + System.execute("named-system-module"); + } +}; diff --git a/test/configCases/target/system-named/webpack.config.js b/test/configCases/target/system-named/webpack.config.js index 838038e8c9c..1f4b76b0ca1 100644 --- a/test/configCases/target/system-named/webpack.config.js +++ b/test/configCases/target/system-named/webpack.config.js @@ -1,4 +1,3 @@ -const webpack = require("../../../../"); module.exports = { output: { library: "named-system-module", @@ -7,19 +6,5 @@ module.exports = { node: { __dirname: false, __filename: false - }, - plugins: [ - new webpack.BannerPlugin({ - raw: true, - banner: ` - System = { - register: function(name, deps, fn) { - function dynamicExport() {} - var mod = fn(dynamicExport); - mod.execute(); - } - } - ` - }) - ] + } }; diff --git a/test/configCases/target/system-unnamed/index.js b/test/configCases/target/system-unnamed/index.js index 0991f8cda3c..7f2b1a91ee9 100644 --- a/test/configCases/target/system-unnamed/index.js +++ b/test/configCases/target/system-unnamed/index.js @@ -1,15 +1,5 @@ /* This test verifies that when there is no output.library specified that the call to -* System.register does not include a name argument. -*/ + * System.register does not include a name argument. + */ -afterEach(function(done) { - delete global.System; - done() -}) - -it("should call System.register without a name", function() { - var fs = require("fs"); - var source = fs.readFileSync(__filename, "utf-8"); - - expect(source).toMatch(/.*System\.register\(\[[^\]]*\], function\(__WEBPACK_DYNAMIC_EXPORT__\) {\s+(var .*;)?\s*return \{\s+setters: [^]+,[^]+execute: function\(\) {/); -}); \ No newline at end of file +it("should call System.register without a name", function() {}); diff --git a/test/configCases/target/system-unnamed/test.config.js b/test/configCases/target/system-unnamed/test.config.js new file mode 100644 index 00000000000..97ebf538dbe --- /dev/null +++ b/test/configCases/target/system-unnamed/test.config.js @@ -0,0 +1,13 @@ +const System = require("../../../helpers/fakeSystem"); + +module.exports = { + beforeExecute: () => { + System.init(); + }, + moduleScope(scope) { + scope.System = System; + }, + afterExecute: () => { + System.execute("(anonym)"); + } +}; diff --git a/test/configCases/target/system-unnamed/webpack.config.js b/test/configCases/target/system-unnamed/webpack.config.js index 41c2d0fcf1a..063b492074e 100644 --- a/test/configCases/target/system-unnamed/webpack.config.js +++ b/test/configCases/target/system-unnamed/webpack.config.js @@ -1,4 +1,3 @@ -const webpack = require("../../../../"); module.exports = { output: { libraryTarget: "system" @@ -6,20 +5,5 @@ module.exports = { node: { __dirname: false, __filename: false - }, - plugins: [ - new webpack.BannerPlugin({ - raw: true, - banner: ` - System = { - register: function(deps, fn) { - function dynamicExport() {} - - var mod = fn(dynamicExport) - mod.execute() - } - } - ` - }) - ] + } }; diff --git a/test/helpers/fakeSystem.js b/test/helpers/fakeSystem.js new file mode 100644 index 00000000000..2b83c4b9341 --- /dev/null +++ b/test/helpers/fakeSystem.js @@ -0,0 +1,80 @@ +const System = { + register: (name, deps, fn) => { + if (!System.registry) { + throw new Error("System is no initialized"); + } + if (typeof name !== "string") { + fn = deps; + deps = name; + name = "(anonym)"; + } + if (!Array.isArray(deps)) { + fn = deps; + deps = []; + } + const dynamicExport = result => { + if (System.registry[name] !== entry) { + throw new Error(`Module ${name} calls dynamicExport too late`); + } + entry.exports = result; + }; + if (name in System.registry) { + throw new Error(`Module ${name} is already registered`); + } + const mod = fn(dynamicExport); + if (deps.length > 0) { + if (!Array.isArray(mod.setters)) { + throw new Error( + `Module ${name} must have setters, because it has dependencies` + ); + } + if (mod.setters.length !== deps.length) { + throw new Error( + `Module ${name} has incorrect number of setters for the dependencies` + ); + } + } + const entry = { + name, + deps, + fn, + mod, + executed: false, + exports: undefined + }; + System.registry[name] = entry; + }, + registry: undefined, + init: modules => { + System.registry = {}; + if (modules) { + for (const name of Object.keys(modules)) { + System.registry[name] = { + executed: true, + exports: modules[name] + }; + } + } + }, + execute: name => { + const m = System.registry[name]; + if (!m) throw new Error(`Module ${name} not registered`); + if (m.executed) throw new Error(`Module ${name} was already executed`); + return System.ensureExecuted(name); + }, + ensureExecuted: name => { + const m = System.registry[name]; + if (!m) throw new Error(`Module ${name} not registered`); + if (!m.executed) { + m.executed = true; + for (let i = 0; i < m.deps.length; i++) { + const dep = m.deps[i]; + System.ensureExecuted(dep); + m.mod.setters[i](System.registry[dep].exports); + } + m.mod.execute(); + } + return m.exports; + } +}; +module.exports = System;