|
|
@@ -0,0 +1,296 @@
|
|
|
+//-------------------------------------------------------------------------------------------------------
|
|
|
+// Copyright (C) Microsoft. All rights reserved.
|
|
|
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
|
|
+//-------------------------------------------------------------------------------------------------------
|
|
|
+
|
|
|
+// ES6 Module functionality tests -- verifies functionality of import and export statements
|
|
|
+
|
|
|
+WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
|
|
|
+
|
|
|
+function testModuleScript(source, message, shouldFail) {
|
|
|
+ let testfunc = () => WScript.LoadModule(source, 'samethread');
|
|
|
+
|
|
|
+ if (shouldFail) {
|
|
|
+ let caught = false;
|
|
|
+
|
|
|
+ // We can't use assert.throws here because the SyntaxError used to construct the thrown error
|
|
|
+ // is from a different context so it won't be strictly equal to our SyntaxError.
|
|
|
+ try {
|
|
|
+ testfunc();
|
|
|
+ } catch(e) {
|
|
|
+ caught = true;
|
|
|
+
|
|
|
+ // Compare toString output of SyntaxError and other context SyntaxError constructor.
|
|
|
+ assert.areEqual(e.constructor.toString(), SyntaxError.toString(), message);
|
|
|
+ }
|
|
|
+
|
|
|
+ assert.isTrue(caught, `Expected error not thrown: ${message}`);
|
|
|
+ } else {
|
|
|
+ assert.doesNotThrow(testfunc, message);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+var tests = [
|
|
|
+ {
|
|
|
+ name: "Validate a simple module export",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { ModuleSimpleExport_foo } from 'ModuleSimpleExport.js';
|
|
|
+ assert.areEqual('ModuleSimpleExport', ModuleSimpleExport_foo(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleExport.js');`;
|
|
|
+ testModuleScript(functionBody, "Test importing a simple exported function", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Validate importing from multiple modules",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { ModuleSimpleExport_foo } from 'ModuleSimpleExport.js';
|
|
|
+ assert.areEqual('ModuleSimpleExport', ModuleSimpleExport_foo(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleExport.js');
|
|
|
+ import { foo2 } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('foo', foo2(), 'Failed to import foo2 from ModuleComplexExports.js');`;
|
|
|
+ testModuleScript(functionBody, "Test importing from multiple modules", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Validate a variety of more complex exports",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { foo, foo2 } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('foo', foo(), 'Failed to import foo from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('foo', foo2(), 'Failed to import foo2 from ModuleComplexExports.js');
|
|
|
+ import { bar, bar2 } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('bar', bar(), 'Failed to import bar from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('bar', bar2(), 'Failed to import bar2 from ModuleComplexExports.js');
|
|
|
+ import { let2, let3, let4, let5 } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('let2', let2, 'Failed to import let2 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('let3', let3, 'Failed to import let3 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('let2', let4, 'Failed to import let4 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('let3', let5, 'Failed to import let5 from ModuleComplexExports.js');
|
|
|
+ import { const2, const3, const4, const5 } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('const2', const2, 'Failed to import const2 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('const3', const3, 'Failed to import const3 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('const2', const4, 'Failed to import const4 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('const3', const5, 'Failed to import const5 from ModuleComplexExports.js');
|
|
|
+ import { var2, var3, var4, var5 } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('var2', var2, 'Failed to import var2 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('var3', var3, 'Failed to import var3 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('var2', var4, 'Failed to import var4 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('var3', var5, 'Failed to import var5 from ModuleComplexExports.js');
|
|
|
+ import { class2, class3, class4, class5 } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('class2', class2.static_member(), 'Failed to import class2 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('class2', new class2().member(), 'Failed to create intance of class2 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('class2', class3.static_member(), 'Failed to import class3 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('class2', new class3().member(), 'Failed to create intance of class3 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('class4', class4.static_member(), 'Failed to import class4 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('class4', new class4().member(), 'Failed to create intance of class4 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('class4', class5.static_member(), 'Failed to import class4 from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('class4', new class5().member(), 'Failed to create intance of class4 from ModuleComplexExports.js');
|
|
|
+ import _default from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('default', _default(), 'Failed to import default from ModuleComplexExports.js');
|
|
|
+ `;
|
|
|
+ testModuleScript(functionBody, "Test importing a variety of exports", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Import an export as a different binding identifier",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { ModuleSimpleExport_foo as foo3 } from 'ModuleSimpleExport.js';
|
|
|
+ assert.areEqual('ModuleSimpleExport', foo3(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleExport.js');
|
|
|
+ import { foo2 as foo4 } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('foo', foo4(), 'Failed to import foo4 from ModuleComplexExports.js');`;
|
|
|
+ testModuleScript(functionBody, "Test importing as different binding identifiers", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Import the same export under multiple local binding identifiers",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { ModuleSimpleExport_foo as foo3, ModuleSimpleExport_foo as foo4 } from 'ModuleSimpleExport.js';
|
|
|
+ assert.areEqual('ModuleSimpleExport', foo3(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleExport.js');
|
|
|
+ assert.areEqual('ModuleSimpleExport', foo4(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleExport.js');
|
|
|
+ assert.isTrue(foo3 === foo4, 'Export has the same value even if rebound');`;
|
|
|
+ testModuleScript(functionBody, "Test importing the same export under multiple binding identifier", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Exporting module changes exported value",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { target, changeTarget } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('before', target(), 'Failed to import target from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('ok', changeTarget(), 'Failed to import changeTarget from ModuleComplexExports.js');
|
|
|
+ assert.areEqual('after', target(), 'changeTarget failed to change export value');`;
|
|
|
+ testModuleScript(functionBody, "Changing exported value", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Simple re-export forwards import to correct slot",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { ModuleSimpleExport_foo } from 'ModuleSimpleReexport.js';
|
|
|
+ assert.areEqual('ModuleSimpleExport', ModuleSimpleExport_foo(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleReexport.js');`;
|
|
|
+ testModuleScript(functionBody, "Simple re-export from one module to another", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Import of renamed re-export forwards import to correct slot",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { ModuleSimpleExport_foo as ModuleSimpleExport_baz } from 'ModuleSimpleReexport.js';
|
|
|
+ assert.areEqual('ModuleSimpleExport', ModuleSimpleExport_baz(), 'Failed to import ModuleSimpleExport_foo from ModuleSimpleReexport.js');`;
|
|
|
+ testModuleScript(functionBody, "Rename simple re-export", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Renamed re-export and renamed import",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { ModuleComplexReexports_foo as ModuleComplexReexports_baz } from 'ModuleComplexReexports.js';
|
|
|
+ assert.areEqual('bar', ModuleComplexReexports_baz(), 'Failed to import ModuleComplexReexports_foo from ModuleComplexReexports.js');`;
|
|
|
+ testModuleScript(functionBody, "Rename already renamed re-export", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Explicit export/import to default binding",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { default as baz } from 'ModuleDefaultExport1.js';
|
|
|
+ assert.areEqual('ModuleDefaultExport1', baz(), 'Failed to import default from ModuleDefaultExport1.js');`;
|
|
|
+ testModuleScript(functionBody, "Explicitly export and import a local name to the default binding", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Explicit import of default binding",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { default as baz } from 'ModuleDefaultExport2.js';
|
|
|
+ assert.areEqual('ModuleDefaultExport2', baz(), 'Failed to import default from ModuleDefaultExport2.js');`;
|
|
|
+ testModuleScript(functionBody, "Explicitly import the default export binding", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Implicitly re-export default export",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import baz from 'ModuleDefaultReexport.js';
|
|
|
+ assert.areEqual('ModuleDefaultExport1', baz(), 'Failed to import default from ModuleDefaultReexport.js');`;
|
|
|
+ testModuleScript(functionBody, "Implicitly re-export the default export binding", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Implicitly re-export default export and rename the imported binding",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { default as baz } from 'ModuleDefaultReexport.js';
|
|
|
+ assert.areEqual('ModuleDefaultExport1', baz(), 'Failed to import default from ModuleDefaultReexport.js');
|
|
|
+ import { not_default as bat } from 'ModuleDefaultReexport.js';
|
|
|
+ assert.areEqual('ModuleDefaultExport2', bat(), 'Failed to import not_default from ModuleDefaultReexport.js');`;
|
|
|
+ testModuleScript(functionBody, "Implicitly re-export the default export binding and rename the import binding", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Exporting module changes value of default export",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import ModuleDefaultExport3_default from 'ModuleDefaultExport3.js';
|
|
|
+ assert.areEqual(2, ModuleDefaultExport3_default, 'Failed to import default from ModuleDefaultExport3.js');
|
|
|
+ import ModuleDefaultExport4_default from 'ModuleDefaultExport4.js';
|
|
|
+ assert.areEqual(1, ModuleDefaultExport4_default, 'Failed to import not_default from ModuleDefaultExport4.js');`;
|
|
|
+ testModuleScript(functionBody, "Exported value incorrectly bound", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Import bindings used in a nested function",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `function test() {
|
|
|
+ assert.areEqual('ModuleDefaultExport2', foo(), 'Failed to import default from ModuleDefaultExport2.js');
|
|
|
+ }
|
|
|
+ test();
|
|
|
+ import foo from 'ModuleDefaultExport2.js';
|
|
|
+ test();`;
|
|
|
+ testModuleScript(functionBody, "Failed to find imported name correctly in nested function", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Exported name may be any keyword",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { export as baz } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('ModuleComplexExports', baz, 'Failed to import export from ModuleDefaultExport2.js');
|
|
|
+ import { function as bat } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('ModuleComplexExports', bat, 'Failed to import function from ModuleDefaultExport2.js');`;
|
|
|
+ testModuleScript(functionBody, "Exported name may be a keyword (import binding must be binding identifier)", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Import binding of a keyword-named export may not be a keyword unless it is bound to a different binding identifier",
|
|
|
+ body: function () {
|
|
|
+ let functionBody = `import { export } from 'ModuleComplexExports.js';`;
|
|
|
+ testModuleScript(functionBody, "Import binding must be binding identifier even if export name is not (export)", true);
|
|
|
+ functionBody = `import { function } from 'ModuleComplexExports.js';`;
|
|
|
+ testModuleScript(functionBody, "Import binding must be binding identifier even if export name is not (function)", true);
|
|
|
+ functionBody = `import { switch } from 'ModuleComplexReexports.js';`;
|
|
|
+ testModuleScript(functionBody, "Import binding must be binding identifier even if re-export name is not (switch)", true);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Exported name may be any keyword testing re-exports",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { switch as baz } from 'ModuleComplexReexports.js';
|
|
|
+ assert.areEqual('ModuleComplexExports', baz, 'Failed to import switch from ModuleComplexReexports.js');`;
|
|
|
+ testModuleScript(functionBody, "Exported name may be a keyword including re-epxort chains", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Odd case of 'export { as as as }; import { as as as };'",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { as as as } from 'ModuleComplexExports.js';
|
|
|
+ assert.areEqual('as', as(), 'String "as" is not reserved word');`;
|
|
|
+ testModuleScript(functionBody, "Test 'import { as as as}'", false);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Typeof a module export",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import _default from 'ModuleDefaultExport2.js';
|
|
|
+ assert.areEqual('function', typeof _default, 'typeof default export from ModuleDefaultExport2.js is function');`;
|
|
|
+
|
|
|
+ WScript.LoadModule(functionBody, 'samethread');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Circular module dependency",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { circular_foo } from 'ModuleCircularFoo.js';
|
|
|
+ assert.areEqual(2, circular_foo(), 'This function calls between both modules in the circular dependency incrementing a counter in each');
|
|
|
+ import { circular_bar } from 'ModuleCircularBar.js';
|
|
|
+ assert.areEqual(4, circular_bar(), 'Second call originates in the other module but still increments the counter twice');`;
|
|
|
+
|
|
|
+ WScript.LoadModule(functionBody, 'samethread');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Implicitly re-exporting an import binding (import { foo } from ''; export { foo };)",
|
|
|
+ body: function () {
|
|
|
+ let functionBody =
|
|
|
+ `import { foo, baz, localfoo, bar, localfoo2, bar2, bar2 as bar3 } from 'ModuleComplexReexports.js';
|
|
|
+ assert.areEqual('foo', foo(), 'Simple implicit re-export');
|
|
|
+ assert.areEqual('foo', baz(), 'Renamed export imported and renamed during implicit re-export');
|
|
|
+ assert.areEqual('foo', localfoo(), 'Export renamed as import and implicitly re-exported');
|
|
|
+ assert.areEqual('foo', bar(), 'Renamed export renamed as import and renamed again during implicit re-exported');
|
|
|
+ assert.areEqual('foo', localfoo2(), 'Renamed export renamed as import and implicitly re-exported');
|
|
|
+ assert.areEqual('foo', bar2(), 'Renamed export renamed as import and renamed again during implicit re-export');
|
|
|
+ assert.areEqual('foo', bar3(), 'Renamed export renamed as import renamed during implicit re-export and renamed in final import');`;
|
|
|
+
|
|
|
+ WScript.LoadModule(functionBody, 'samethread');
|
|
|
+ }
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
|