From fd0e4381ae202e3c4a92ee8df83b736d3a889561 Mon Sep 17 00:00:00 2001 From: Aneesh Divakarakurup Date: Mon, 3 Oct 2016 12:26:03 -0700 Subject: [PATCH] Enabling async functions by default Enabling async functions by default. Also added one new test case to verify the arguments.callee behavior. --- lib/Common/ConfigFlagsList.h | 12 +- test/DebuggerCommon/async.js | 32 + test/DebuggerCommon/async.js.dbg.baseline | 109 + test/DebuggerCommon/async_step_out.js | 36 + .../async_step_out.js.dbg.baseline | 28 + test/DebuggerCommon/async_step_over.js | 42 + .../async_step_over.js.dbg.baseline | 28 + test/DebuggerCommon/rlexe.xml | 18 + test/es6/es6_stable.baseline | 4 +- test/es6/es6_stable.enable_disable.baseline | 4 +- test/es6/rlexe.xml | 19 +- test/es7/asyncawait-functionality.baseline | 2 + test/es7/asyncawait-functionality.js | 1895 +++++++++-------- 13 files changed, 1266 insertions(+), 963 deletions(-) create mode 100644 test/DebuggerCommon/async.js create mode 100644 test/DebuggerCommon/async.js.dbg.baseline create mode 100644 test/DebuggerCommon/async_step_out.js create mode 100644 test/DebuggerCommon/async_step_out.js.dbg.baseline create mode 100644 test/DebuggerCommon/async_step_over.js create mode 100644 test/DebuggerCommon/async_step_over.js.dbg.baseline diff --git a/lib/Common/ConfigFlagsList.h b/lib/Common/ConfigFlagsList.h index 435e0dabff1..269abe3ccdc 100644 --- a/lib/Common/ConfigFlagsList.h +++ b/lib/Common/ConfigFlagsList.h @@ -565,12 +565,7 @@ PHASE(All) #else #define DEFAULT_CONFIG_ArrayBufferTransfer (false) #endif -#ifdef COMPILE_DISABLE_ES7AsyncAwait - // If ES7AsyncAwait needs to be disabled by compile flag, DEFAULT_CONFIG_ES7AsyncAwait should be false - #define DEFAULT_CONFIG_ES7AsyncAwait (false) -#else - #define DEFAULT_CONFIG_ES7AsyncAwait (false) -#endif +#define DEFAULT_CONFIG_ES7AsyncAwait (true) #define DEFAULT_CONFIG_ES7ExponentionOperator (true) #define DEFAULT_CONFIG_ES7TrailingComma (true) #define DEFAULT_CONFIG_ES7ValuesEntries (true) @@ -943,10 +938,7 @@ FLAGNRC(Boolean, ES6Experimental , "Enable all experimental features", FLAGPR (Boolean, ES6, ES6Species , "Enable ES6 '@@species' properties and built-in behaviors" , DEFAULT_CONFIG_ES6Species) -#ifndef COMPILE_DISABLE_ES7AsyncAwait - #define COMPILE_DISABLE_ES7AsyncAwait 0 -#endif -FLAGPR_REGOVR_EXP(Boolean, ES6, ES7AsyncAwait , "Enable ES7 'async' and 'await' keywords" , DEFAULT_CONFIG_ES7AsyncAwait) +FLAGPR (Boolean, ES6, ES7AsyncAwait , "Enable ES7 'async' and 'await' keywords" , DEFAULT_CONFIG_ES7AsyncAwait) FLAGPR (Boolean, ES6, ES6Classes , "Enable ES6 'class' and 'extends' keywords" , DEFAULT_CONFIG_ES6Classes) FLAGPR (Boolean, ES6, ES6DateParseFix , "Enable ES6 Date.parse fixes" , DEFAULT_CONFIG_ES6DateParseFix) FLAGPR (Boolean, ES6, ES6DefaultArgs , "Enable ES6 Default Arguments" , DEFAULT_CONFIG_ES6DefaultArgs) diff --git a/test/DebuggerCommon/async.js b/test/DebuggerCommon/async.js new file mode 100644 index 00000000000..d56baaf69c6 --- /dev/null +++ b/test/DebuggerCommon/async.js @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +function foo() { + return this.x; /**bp:locals(1);stack()**/ +} + +async function af1(a) { + await a; + return await foo.call({ x : 100 }); /**bp:locals();stack()**/ +} + +async function af2() { + return await af1(10); +} + +var p = af2();/**bp: + resume('step_into');stack(); + resume('step_into');stack(); + resume('step_into');stack(); +**/ +p.then(result => { + if (result === 100) { + print("PASS"); + } + }, + error => { + print("Failed : " + error); + } +); diff --git a/test/DebuggerCommon/async.js.dbg.baseline b/test/DebuggerCommon/async.js.dbg.baseline new file mode 100644 index 00000000000..b79170c1516 --- /dev/null +++ b/test/DebuggerCommon/async.js.dbg.baseline @@ -0,0 +1,109 @@ +[ + { + "callStack": [ + { + "line": 15, + "column": 4, + "sourceText": "return await af1(10)", + "function": "af2" + }, + { + "line": 18, + "column": 0, + "sourceText": "var p = af2()", + "function": "Global code" + } + ] + }, + { + "callStack": [ + { + "line": 10, + "column": 4, + "sourceText": "await a", + "function": "af1" + }, + { + "line": 15, + "column": 4, + "sourceText": "return await af1(10)", + "function": "af2" + }, + { + "line": 18, + "column": 0, + "sourceText": "var p = af2()", + "function": "Global code" + } + ] + }, + { + "callStack": [ + { + "line": 15, + "column": 4, + "sourceText": "return await af1(10)", + "function": "af2" + }, + { + "line": 18, + "column": 0, + "sourceText": "var p = af2()", + "function": "Global code" + } + ] + }, + { + "this": "Object {...}", + "arguments": "Object {...}", + "locals": { + "a": "number 10" + } + }, + { + "callStack": [ + { + "line": 11, + "column": 4, + "sourceText": "return await foo.call({ x : 100 })", + "function": "af1" + } + ] + }, + { + "this": { + "x": "number 100" + }, + "arguments": { + "#__proto__": "Object {...}", + "length": "number 0", + "callee": "function ", + "Symbol.iterator": "function " + }, + "globals": { + "WScript": "Object {...}", + "print": "function print", + "console": "Object {...}", + "foo": "function ", + "af1": "function ", + "af2": "function ", + "p": "Promise [...]" + } + }, + { + "callStack": [ + { + "line": 6, + "column": 4, + "sourceText": "return this.x", + "function": "foo" + }, + { + "line": 11, + "column": 4, + "sourceText": "return await foo.call({ x : 100 })", + "function": "af1" + } + ] + } +] \ No newline at end of file diff --git a/test/DebuggerCommon/async_step_out.js b/test/DebuggerCommon/async_step_out.js new file mode 100644 index 00000000000..e0be8600253 --- /dev/null +++ b/test/DebuggerCommon/async_step_out.js @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +function foo() { + return 100; +} + +async function af1(a) { + return await foo(); +} + +async function af2() { + return await af1(10); +} + +var p = 1;/**bp: + resume('step_over'); + resume('step_into'); + resume('step_into'); + resume('step_out');stack(); + resume('step_out');stack();**/ +// If we put the break point in the below line after stepping out from af2 we will execute the same break +// point again which will add more break points. To avoid this adding the break point to a dummy statement. +p = af2(); + +p.then(result => { + if (result === 100) { + print("PASS"); + } + }, + error => { + print("Failed : " + error); + } +); \ No newline at end of file diff --git a/test/DebuggerCommon/async_step_out.js.dbg.baseline b/test/DebuggerCommon/async_step_out.js.dbg.baseline new file mode 100644 index 00000000000..a5d8d662dbe --- /dev/null +++ b/test/DebuggerCommon/async_step_out.js.dbg.baseline @@ -0,0 +1,28 @@ +[ + { + "callStack": [ + { + "line": 14, + "column": 4, + "sourceText": "return await af1(10)", + "function": "af2" + }, + { + "line": 25, + "column": 0, + "sourceText": "p = af2()", + "function": "Global code" + } + ] + }, + { + "callStack": [ + { + "line": 25, + "column": 0, + "sourceText": "p = af2()", + "function": "Global code" + } + ] + } +] \ No newline at end of file diff --git a/test/DebuggerCommon/async_step_over.js b/test/DebuggerCommon/async_step_over.js new file mode 100644 index 00000000000..fd0dbcb02cb --- /dev/null +++ b/test/DebuggerCommon/async_step_over.js @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +function foo() { + return 100; +} + +async function af1(a) { + return await foo(); +} + +async function af2() { + return await af1(10); +} + +var p = af2();/**bp: + resume('step_into'); + resume('step_into'); + resume('step_over');stack(); +**/ +p.then(result => { + if (result === 100) { + print("PASS"); + } + }, + error => { + print("Failed : " + error); + } +); + +p = af2();/**bp:resume('step_over');stack();**/ +p.then(result => { + if (result === 100) { + print("PASS"); + } + }, + error => { + print("Failed : " + error); + } +); \ No newline at end of file diff --git a/test/DebuggerCommon/async_step_over.js.dbg.baseline b/test/DebuggerCommon/async_step_over.js.dbg.baseline new file mode 100644 index 00000000000..e72a3035e7d --- /dev/null +++ b/test/DebuggerCommon/async_step_over.js.dbg.baseline @@ -0,0 +1,28 @@ +[ + { + "callStack": [ + { + "line": 14, + "column": 4, + "sourceText": "return await af1(10)", + "function": "af2" + }, + { + "line": 17, + "column": 0, + "sourceText": "var p = af2()", + "function": "Global code" + } + ] + }, + { + "callStack": [ + { + "line": 33, + "column": 0, + "sourceText": "p.then(result => {\r\n if (result === 100) {\r\n print(\"PASS\");\r\n }\r\n },\r\n error => {\r\n print(\"Failed : \" + error);\r\n } \r\n)", + "function": "Global code" + } + ] + } +] \ No newline at end of file diff --git a/test/DebuggerCommon/rlexe.xml b/test/DebuggerCommon/rlexe.xml index 40758d7edb4..a5f46e1fae0 100644 --- a/test/DebuggerCommon/rlexe.xml +++ b/test/DebuggerCommon/rlexe.xml @@ -1356,6 +1356,24 @@ -debuglaunch -dbgbaseline:generators.js.dbg.baseline -ES6Generators -InspectMaxStringLength:200 + + + async.js + -debuglaunch -dbgbaseline:async.js.dbg.baseline + + + + + async_step_out.js + -debuglaunch -dbgbaseline:async_step_out.js.dbg.baseline + + + + + async_step_over.js + -debuglaunch -dbgbaseline:async_step_over.js.dbg.baseline + + TypedArray.js diff --git a/test/es6/es6_stable.baseline b/test/es6/es6_stable.baseline index 62a93c19a14..dd875587f7e 100644 --- a/test/es6/es6_stable.baseline +++ b/test/es6/es6_stable.baseline @@ -3,8 +3,8 @@ FLAG ES6 = 1 - setting child flag Simdjs = 0 FLAG Simdjs = 0 FLAG ES6 = 1 - setting child flag ES6Species = 1 FLAG ES6Species = 1 -FLAG ES6 = 1 - setting child flag ES7AsyncAwait = 0 -FLAG ES7AsyncAwait = 0 +FLAG ES6 = 1 - setting child flag ES7AsyncAwait = 1 +FLAG ES7AsyncAwait = 1 FLAG ES6 = 1 - setting child flag ES6Classes = 1 FLAG ES6Classes = 1 FLAG ES6 = 1 - setting child flag ES6DateParseFix = 1 diff --git a/test/es6/es6_stable.enable_disable.baseline b/test/es6/es6_stable.enable_disable.baseline index bc8fabf8c84..ca15fa26125 100644 --- a/test/es6/es6_stable.enable_disable.baseline +++ b/test/es6/es6_stable.enable_disable.baseline @@ -3,8 +3,8 @@ FLAG ES6 = 1 - setting child flag Simdjs = 0 FLAG Simdjs = 0 FLAG ES6 = 1 - setting child flag ES6Species = 1 FLAG ES6Species = 1 -FLAG ES6 = 1 - setting child flag ES7AsyncAwait = 0 -FLAG ES7AsyncAwait = 0 +FLAG ES6 = 1 - setting child flag ES7AsyncAwait = 1 +FLAG ES7AsyncAwait = 1 FLAG ES6 = 1 - setting child flag ES6Classes = 1 FLAG ES6Classes = 1 FLAG ES6 = 1 - setting child flag ES6DateParseFix = 1 diff --git a/test/es6/rlexe.xml b/test/es6/rlexe.xml index 28511ce67ce..01c349cd2e4 100644 --- a/test/es6/rlexe.xml +++ b/test/es6/rlexe.xml @@ -215,21 +215,20 @@ blockscope-functionbinding.js - -ES7AsyncAwait blockscope-functionbinding.baseline blockscope-functionbinding.js - -force:deferparse -ES7AsyncAwait + -force:deferparse blockscope-functionbinding.baseline blockscope-functionbinding.js - -lic:1 -InitializeInterpreterSlotsWithInvalidStackVar -ES7AsyncAwait + -lic:1 -InitializeInterpreterSlotsWithInvalidStackVar blockscope-functionbinding.baseline exclude_fre @@ -756,31 +755,31 @@ default.js - -force:deferparse -ES6DefaultArgs -ES7AsyncAwait -ES6Generators -args summary -endargs + -force:deferparse -args summary -endargs default.js - -off:deferparse -ES6DefaultArgs -ES7AsyncAwait -ES6Generators -args summary -endargs + -off:deferparse -args summary -endargs default.js - -force:CachedScope -ES6DefaultArgs -ES7AsyncAwait -ES6Generators -args summary -endargs + -force:CachedScope -args summary -endargs default-splitscope.js - -off:deferparse -ES6DefaultArgsSplitScope -ES6Generators -args summary -endargs + -off:deferparse -ES6DefaultArgsSplitScope -args summary -endargs default-splitscope.js - -force:deferparse -ES6DefaultArgsSplitScope -ES6Generators -args summary -endargs + -force:deferparse -ES6DefaultArgsSplitScope -args summary -endargs @@ -1288,7 +1287,7 @@ module-functionality.js - -ES6Module -ES7AsyncAwait -args summary -endargs + -ES6Module -args summary -endargs exclude_xplat,exclude_dynapogo @@ -1309,7 +1308,7 @@ module-namespace.js - -ES6Module -ES7AsyncAwait -Es6ToStringTag + -ES6Module -Es6ToStringTag module-namespace.baseline exclude_xplat diff --git a/test/es7/asyncawait-functionality.baseline b/test/es7/asyncawait-functionality.baseline index ee24d569084..e5ea715d582 100644 --- a/test/es7/asyncawait-functionality.baseline +++ b/test/es7/asyncawait-functionality.baseline @@ -32,6 +32,7 @@ Executing test #26 - Awaiting a function with multiple awaits Executing test #27 - Async function with nested try-catch in the body Executing test #28 - Async function with try-catch and try-finally in the body Executing test #29 - Async function and with +Executing test #30 - Async and arguments.callee Completion Results: Test #1 - Success lambda expression with no argument called with result = 'true' @@ -75,6 +76,7 @@ Test #27 - Success Caught the expected exception inside the inner catch in async Test #27 - Success Caught the expected exception inside catch in async body Test #28 - Success Caught the expected exception inside the inner catch in async body Test #28 - Success finally block is executed in async body +Test #30 - Success async function and arguments.callee Test #6 - Success await in an async function #1 called with result = '-4' Test #6 - Success await in an async function #2 called with result = '2' Test #6 - Success await in an async function catch a rejected Promise in 'err'. Error = 'Error: My Error' diff --git a/test/es7/asyncawait-functionality.js b/test/es7/asyncawait-functionality.js index 13c0f6bb635..ed43443ba63 100644 --- a/test/es7/asyncawait-functionality.js +++ b/test/es7/asyncawait-functionality.js @@ -1,939 +1,956 @@ -//------------------------------------------------------------------------------------------------------- -// Copyright (C) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -//------------------------------------------------------------------------------------------------------- - -// ES6 Async Await tests -- verifies functionality of async/await - -function echo(str) { - WScript.Echo(str); -} - -var tests = [ - { - name: "Async keyword with a lambda expressions", - body: function (index) { - var x = 12; - var y = 14; - var lambdaParenNoArg = async() => x < y; - var lambdaArgs = async(a, b, c) => a + b + c; - - lambdaParenNoArg().then(result => { - echo(`Test #${index} - Success lambda expression with no argument called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error lambda expression with no argument called with err = ${err}`); - }); - - lambdaArgs(10, 20, 30).then(result => { - echo(`Test #${index} - Success lambda expression with several arguments called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error lambda expression with several arguments called with err = ${err}`); - }); - } - }, - { - name: "Async keyword with a lambda expressions and local variable captured and shadowed", - body: function (index) { - var x = 12; - var lambdaSingleArgNoParen = async x => x; - var lambdaSingleArg = async(x) => x; - - lambdaSingleArgNoParen(x).then(result => { - echo(`Test #${index} - Success lambda expression with single argument and no paren called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error lambda expression with single argument and no paren called with err = ${err}`); - }); - - lambdaSingleArg(x).then(result => { - echo(`Test #${index} - Success lambda expression with a single argument a called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error lambda expression with a single argument called with err = ${err}`); - }); - } - }, - { - name: "Async function in a statement", - body: function (index) { - { - var namedNonAsyncMethod = function async(x, y) { return x + y; } - var unnamedAsyncMethod = async function (x, y) { return x + y; } - async function async(x, y) { return x - y; } - - var result = namedNonAsyncMethod(10, 20); - echo(`Test #${index} - Success function #1 called with result = '${result}'`); - - unnamedAsyncMethod(10, 20).then(result => { - echo(`Test #${index} - Success function #2 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error function #2 called with err = ${err}`); - }); - - async(10, 20).then(result => { - echo(`Test #${index} - Success function #3 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error function #3 called with err = ${err}`); - }); - } - { - async function async() { return 12; } - - async().then(result => { - echo(`Test #${index} - Success function #4 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error function #4 called with err = ${err}`); - }); - } - { - function async() { return 12; } - - var result = namedNonAsyncMethod(10, 20); - echo(`Test #${index} - Success function #5 called with result = '${result}'`); - } - } - }, - { - name: "Async function in an object", - body: function (index) { - var object = { - async async() { return 12; } - }; - - var object2 = { - async() { return 12; } - }; - - var object3 = { - async "a"() { return 12; }, - async 0() { return 12; }, - async 3.14() { return 12; }, - async else() { return 12; }, - }; - - object.async().then(result => { - echo(`Test #${index} - Success function in a object #1 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error function in a object #1 called with err = ${err}`); - }); - - var result = object2.async(); - echo(`Test #${index} - Success function in a object #2 called with result = '${result}'`); - - object3.a().then(result => { - echo(`Test #${index} - Success function in a object #3 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error function in a object #3 called with err = ${err}`); - }); - - object3['0']().then(result => { - echo(`Test #${index} - Success function in a object #4 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error function in a object #4 called with err = ${err}`); - }); - - object3['3.14']().then(result => { - echo(`Test #${index} - Success function in a object #5 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error function in a object #5 called with err = ${err}`); - }); - - object3.else().then(result => { - echo(`Test #${index} - Success function in a object #6 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error function in a object #6 called with err = ${err}`); - }); - } - }, - { - name: "Async classes", - body: function (index) { - class MyClass { - async asyncMethod(a) { return a; } - async async(a) { return a; } - async "a"() { return 12; } - async 0() { return 12; } - async 3.14() { return 12; } - async else() { return 12; } - static async staticAsyncMethod(a) { return a; } - } - - class MySecondClass { - async(a) { return a; } - } - - class MyThirdClass { - static async(a) { return a; } - } - - var x = "foo"; - class MyFourthClass { - async [x](a) { return a; } - } - - var myClassInstance = new MyClass(); - var mySecondClassInstance = new MySecondClass(); - var myFourthClassInstance = new MyFourthClass(); - - myClassInstance.asyncMethod(10).then(result => { - echo(`Test #${index} - Success async in a class #1 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error async in a class #1 called with err = ${err}`); - }); - - myClassInstance.async(10).then(result => { - echo(`Test #${index} - Success async in a class #2 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error async in a class #2 called with err = ${err}`); - }); - - myClassInstance.a().then(result => { - echo(`Test #${index} - Success async in a class #3 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error async in a class #3 called with err = ${err}`); - }); - - myClassInstance['0']().then(result => { - echo(`Test #${index} - Success async in a class #4 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error async in a class #4 called with err = ${err}`); - }); - - myClassInstance['3.14']().then(result => { - echo(`Test #${index} - Success async in a class #5 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error async in a class #5 called with err = ${err}`); - }); - - myClassInstance.else().then(result => { - echo(`Test #${index} - Success async in a class #6 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error async in a class #6 called with err = ${err}`); - }); - - MyClass.staticAsyncMethod(10).then(result => { - echo(`Test #${index} - Success async in a class #7 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error async in a class #7 called with err = ${err}`); - }); - - var result = mySecondClassInstance.async(10); - echo(`Test #${index} - Success async in a class #8 called with result = '${result}'`); - - var result = MyThirdClass.async(10); - echo(`Test #${index} - Success async in a class #9 called with result = '${result}'`); - - myFourthClassInstance.foo(10).then(result => { - echo(`Test #${index} - Success async in a class #10 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error async in a class #10 called with err = ${err}`); - }); - } - }, - { - name: "Await in an async function", - body: function (index) { - async function asyncMethod(val, factor) { - val = val * factor; - if (val > 0) - val = await asyncMethod(val, -1); - return val; - } - - function await(x) { - return x; - } - - async function secondAsyncMethod(x) { - return await(x); - } - - function rejectedPromiseMethod() { - return new Promise(function (resolve, reject) { - reject(Error('My Error')); - }); - } - - async function rejectAwaitMethod() { - return await rejectedPromiseMethod(); - } - - async function asyncThrowingMethod() { - throw 32; - } - - async function throwAwaitMethod() { - return await asyncThrowingMethod(); - } - - asyncMethod(2, 2).then(result => { - echo(`Test #${index} - Success await in an async function #1 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error await in an async function #1 called with err = ${err}`); - }); - - secondAsyncMethod(2).then(result => { - echo(`Test #${index} - Success await in an async function #2 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error await in an async function #2 called with err = ${err}`); - }); - - rejectAwaitMethod(2).then(result => { - echo(`Test #${index} - Failed await in an async function doesn't catch a rejected Promise. Result = '${result}'`); - }, err => { - echo(`Test #${index} - Success await in an async function catch a rejected Promise in 'err'. Error = '${err}'`); - }); - - throwAwaitMethod(2).then(result => { - echo(`Test #${index} - Failed await in an async function doesn't catch an error. Result = '${result}'`); - }, err => { - echo(`Test #${index} - Success await in an async function catch an error in 'err'. Error = '${err}'`); - }); - } - }, - { - name: "Await keyword with a lambda expressions", - body: function (index) { - { - async function asyncMethod(x, y, z) { - var lambdaExp = async(a, b, c) => a * b * c; - var lambdaResult = await lambdaExp(x, y, z); - return lambdaResult; - } - - asyncMethod(5, 5, 5).then(result => { - echo(`Test #${index} - Success await keyword with a lambda expressions #1 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error await keyword with a lambda expressions #1 called with err = ${err}`); - }); - }; - { - async function await(lambda, x, y, z) { - return await lambda(x, y, z); - } - - await(async(a, b, c) => a + b + c, 10, 20, 30).then(result => { - echo(`Test #${index} - Success await keyword with a lambda expressions #1 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error await keyword with a lambda expressions #1 called with err = ${err}`); - }); - }; - } - }, - { - name: "Async function with default arguments's value", - body: function (index) { - { - function thrower() { - throw "expected error" - } - - async function asyncMethod(argument = thrower()) { - return true; - } - - async function secondAsyncMethod(argument = false) { - return true; - } - - asyncMethod(true).then(result => { - echo(`Test #${index} - Success async function with default arguments's value overwritten #1 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error async function with default arguments's value overwritten #1 called with err = ${err}`); - }); - - // TODO:[aneeshd] Need to fix the default parameter evaluation order for both async functions and generators - asyncMethod().then(result => { - echo(`Test #${index} - Failed async function with default arguments's value has not been rejected as expected #2 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Success async function with default arguments's value has been rejected as expected by 'err' #2 called with err = '${err}'`); - }); - - secondAsyncMethod().then(result => { - echo(`Test #${index} - Success async function with default arguments's value #3 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error async function with default arguments's value #3 called with err = ${err}`); - }); - }; - } - }, - { - name: "Promise in an Async function", - body: function (index) { - { - async function asyncMethodResolved() { - let p = new Promise(function (resolve, reject) { - resolve("resolved"); - }); - - return p.then(function (result) { - return result; - }); - } - - async function asyncMethodResolvedWithAwait() { - let p = new Promise(function (resolve, reject) { - resolve("resolved"); - }); - - return await p; - } - - async function asyncMethodRejected() { - let p = new Promise(function (resolve, reject) { - reject("rejected"); - }); - - return p.then(function (result) { - return result; - }); - } - - asyncMethodResolved().then(result => { - echo(`Test #${index} - Success resolved promise in an async function #1 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error resolved promise in an async function #1 called with err = ${err}`); - }); - - asyncMethodResolvedWithAwait().then(result => { - echo(`Test #${index} - Success resolved promise in an async function #2 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error resolved promise in an async function #2 called with err = ${err}`); - }); - - asyncMethodRejected().then(result => { - echo(`Test #${index} - Failed promise in an async function has not been rejected as expected #3 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Success promise in an async function has been rejected as expected by 'err' #3 called with err = '${err}'`); - }); - }; - } - }, - { - name: "%AsyncFunction% constructor creates async functions analogous to Function constructor", - body: function (index) { - var AsyncFunction = Object.getPrototypeOf(async function () { }).constructor; - - var af = new AsyncFunction('return await Promise.resolve(0);'); - - af().then(result => { - echo(`Test #${index} - Success %AsyncFunction% created async function #1 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error %AsyncFunction% created async function #1 called with err = ${err}`); - }); - - af = new AsyncFunction('a', 'b', 'c', 'a = await a; b = await b; c = await c; return a + b + c;'); - - af(Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)).then(result => { - echo(`Test #${index} - Success %AsyncFunction% created async function #2 called with result = '${result}'`); - }, err => { - echo(`Test #${index} - Error %AsyncFunction% created async function #2 called with err = ${err}`); - }); - } - }, - { - name: "local variables with same names as formal parameters have proper redeclaration semantics (non-error cases, var and function)", - body: function (index) { - async function af1(x) { var y = x; var x = 'b'; return y + x; } - - af1('a').then(result => { - if (result === 'ab') { - echo(`Test #${index} - Success inner var x overwrote formal parameter x only after the declaration statement`); - } else { - echo(`Test #${index} - Failure x appears to have an unexpected value x = '${result}'`); - } - }, err => { - echo(`Test #${index} - Error var redeclaration with err = ${err}`); - }); - - async function af2(x) { var xx = x(); function x() { return 'afx'; } return xx; } - - af2(function () { return ''; }).then(result => { - if (result === 'afx') { - echo(`Test #${index} - Success inner function x() overwrote formal parameter x`); - } else { - echo(`Test #${index} - Failure x appears not assigned with inner function x(), x = '${result}'`); - } - }, err => { - echo(`Test #${index} - Error err = ${err}`); - }); - } - }, - { - name: "this value in async functions behaves like it does in normal functions", - body: function (index) { - async function af() { - return this; - } - - af.call(5).then(result => { - if (result == 5) { - echo(`Test #${index} - Success this value set to 5`); - } else { - echo(`Test #${index} - Failure this value is not 5, this = '${result}'`); - } - }, err => { - echo(`Test #${index} - Error err = ${err}`); - }); - - var o = { - af: af, - b: "abc" - }; - - o.af().then(result => { - if (result.af === af && result.b === "abc") { - echo(`Test #${index} - Success this value set to { af: af, b: "abc" }`); - } else { - echo(`Test #${index} - Failure this value set to something else, this = '${result}'`); - } - }, err => { - echo(`Test #${index} - Error err = ${err}`); - }); - } - }, - { - name: "arguments value in async functions behaves like it does in normal functions", - body: function (index) { - async function af() { - return arguments[0] + arguments[1]; - } - - af('a', 'b').then(result => { - if (result === 'ab') { - echo(`Test #${index} - Success result is 'ab' from arguments 'a' + 'b'`); - } else { - echo(`Test #${index} - Failure result is not 'ab', result = '${result}'`); - } - }, err => { - echo(`Test #${index} - Error err = ${err}`); - }); - } - }, - { - name: "super value in async methods behaves like it does in normal methods", - body: function (index) { - class B { - af() { - return "base"; - } - } - - class C extends B { - async af() { - return super.af() + " derived"; - } - } - - var c = new C(); - - c.af().then(result => { - if (result === 'base derived') { - echo(`Test #${index} - Success result is 'base derived' from derived method call`); - } else { - echo(`Test #${index} - Failure result is not 'base derived', result = '${result}'`); - } - }, err => { - echo(`Test #${index} - Error err = ${err}`); - }); - } - }, - { - name:"Async function with formal captured in a lambda", - body: function (index) { - async function af(d = 1) { - return () => d; - } - - af().then(result => { - if (result() === 1) { - print(`Test #${index} - Success lambda returns 1 when no arguments passed`); - } else { - print(`Test #${index} - Failure result is not 1, result = '${result()}'`); - } - }, err => { - print(`Test #${index} - Error err = ${err}`); - }); - } - }, - { - name:"Async function with formal captured in a nested function", - body: function (index) { - async function af(d = 1) { - return function () { return d; }; - } - - af().then(result => { - if (result() === 1) { - print(`Test #${index} - Success nested function returns 1 when no arguments passed`); - } else { - print(`Test #${index} - Failure result is not 1, result = '${result()}'`); - } - }, err => { - print(`Test #${index} - Error err = ${err}`); - }); - } - }, - { - name:"Async function with formal captured in eval", - body: function (index) { - async function af(d = 1) { - return eval("d"); - } - - af().then(result => { - if (result === 1) { - print(`Test #${index} - Success eval returns 1 when no arguments passed`); - } else { - print(`Test #${index} - Failure result is not 1, result = '${result}'`); - } - }, err => { - print(`Test #${index} - Error err = ${err}`); - }); - } - }, - { - name: "Async function with formal capturing in param scope", - body: function (index) { - async function af1(a, b = () => a, c = b) { - function b() { - return a; - } - var a = 2; - return [b, c]; - } - - af1(1).then(result => { - if (result[0]() === 2) { - echo(`Test #${index} - Success inner function declaration captures the body variable`); - } else { - echo(`Test #${index} - Failure a appears to have an unexpected value a = '${result}'`); - } - if (result[1]() === 1) { - echo(`Test #${index} - Success function defined in the param scope captures the param scope variable`); - } else { - echo(`Test #${index} - Failure a appears to have an unexpected value in the param scope function a = '${result}'`); - } - }, err => { - echo(`Test #${index} - Error in split scope with err = ${err}`); - }); - } - }, - { - name: "Async function with formal capturing in param scope with eval in the body", - body: function (index) { - async function af1(a, b = () => a, c = b) { - function b() { - return a; - } - var a = 2; - return eval("[b, c]"); - } - - af1(1).then(result => { - if (result[0]() === 2) { - echo(`Test #${index} - Success inner function declaration captures the body variable with eval in the body`); - } else { - echo(`Test #${index} - Failure a appears to have an unexpected value a = '${result}'`); - } - if (result[1]() === 1) { - echo(`Test #${index} - Success function defined in the param scope captures the param scope variable with eval in the body`); - } else { - echo(`Test #${index} - Failure a appears to have an unexpected value in the param scope function a = '${result}'`); - } - }, err => { - echo(`Test #${index} - Error in split scope with eval in the body with err = ${err}`); - }); - } - }, - { - name: "Async function with duplicate variable declaration in the body with eval", - body: function (index) { - async function af1(a, b) { - var a = 10; - return eval("a + b"); - } - - af1(1, 2).then(result => { - if (result === 12) { - echo(`Test #${index} - Success inner variable declaration shadows the formal`); - } else { - echo(`Test #${index} - Failure sum appears to have an unexpected value sum = '${result}'`); - } - }, err => { - echo(`Test #${index} - Error in variable redeclaration with eval with err = ${err}`); - }); - } - }, - { - name: "Async function with duplicate variable declaration in the body with child having eval", - body: function (index) { - async function af1(a, b) { - var a = 10; - return function () { return eval("a + b"); }; - } - - af1(1, 2).then(result => { - if (result() === 12) { - echo(`Test #${index} - Success inner variable declaration shadows the formal with eval in child function`); - } else { - echo(`Test #${index} - Failure sum appears to have an unexpected value sum = '${result}'`); - } - }, err => { - echo(`Test #${index} - Error in variable redeclaration with eval with err = ${err}`); - }); - } - }, - { - name: "Async function with more than one await", - body: function (index) { - async function af1() { - return 1; - } - - async function af2() { - return 2; - } - - async function af3() { - return await af1() + await af2(); - } - af3().then(result => { - if (result === 3) { - echo(`Test #${index} - Success functions completes both await calls`); - } else { - echo(`Test #${index} - Failed function failed to complete both await calls and returned ${result}`); - } - }, err => { - echo(`Test #${index} - Error in multiple awaits in a function err = ${err}`); - }); - } - }, - { - name: "Async function with more than one await with branching", - body: function (index) { - async function af1() { - return 1; - } - - async function af2() { - return 2; - } - - async function af3(a) { - return a ? await af1() : await af2(); - } - - af3(1).then(result => { - if (result === 1) { - echo(`Test #${index} - Success functions completes the first await call`); - } else { - echo(`Test #${index} - Failed function failed to complete the first await call and returned ${result}`); - } - }, err => { - echo(`Test #${index} - Error in multiple awaits with branching in a function err = ${err}`); - }); - - af3().then(result => { - if (result === 2) { - echo(`Test #${index} - Success functions completes the second await call`); - } else { - echo(`Test #${index} - Failed function failed to complete the second await call and returned ${result}`); - } - }, err => { - echo(`Test #${index} - Error in multiple awaits with branching in a function err = ${err}`); - }); - } - }, - { - name: "Async function with an exception in an await expression", - body: function (index) { - var obj = { x : 1 }; - async function af1() { - throw obj; - } - - async function af2() { - echo(`Failed : This function was not expected to be executed`); - } - - async function af3() { - return await af1() + await af2(); - } - af3().then(result => { - echo(`Test #${index} - Error an expected exception does not seem to be thrown`); - }, err => { - if (err === obj) { - echo(`Test #${index} - Success caught the expected exception`); - } else { - echo(`Test #${index} - Error an unexpected exception was thrown = ${err}`); - } - }); - } - }, - { - name: "Async functions throws on an await", - body: function (index) { - var obj = { x : 1 }; - async function af1() { - throw obj; - } - - async function af2() { - echo(`Test #${index} Failed This function was not expected to be executed`); - } - - async function af3() { - return await af1() + await af2(); - } - - af3().then(result => { - print(`Test #${index} Failed an expected exception does not seem to be thrown`); - }, err => { - if (err === obj) { - print(`Test #${index} - Success caught the expected exception`); - } else { - print(`Test #${index} - Failed an unexpected exception was thrown = ${err}`); - } - }); - } - }, - { - name: "Awaiting a function with multiple awaits", - body: function (index) { - async function af1(a, b) { - return await af2(); - - async function af2() { - a = await a * a; - b = await b * b; - - return a + b; - } - } - - af1(1, 2).then(result => { - if (result === 5) { - echo(`Test #${index} - Success Multiple awaits in the inner function completed`); - } else { - echo(`Test #${index} - Failed function failed to complete the multiple awaits in the inner function ${result}`); - } - }, err => { - echo(`Test #${index} - Error in multiple awaits in an inner function err = ${err}`); - }); - } - }, - { - name: "Async function with nested try-catch in the body", - body: function (index) { - async function af1() { - throw 42; - } - - async function af2() { - try { - try { - await af1(); - } catch (e) { - echo(`Test #${index} - Success Caught the expected exception inside the inner catch in async body`); - throw e; - } - } catch (e) { - echo(`Test #${index} - Success Caught the expected exception inside catch in async body`); - throw e; - } - echo(`Test #${index} - Failed Didn't throw an expected exception`); - } - - af2().then(result => { - echo(`Test #${index} - Failed an the expected was not thrown`); - }, err => { - if (err.x === obj.x) { - echo(`Test #${index} - Success Caught the expected exception in the promise`); - } else { - echo(`Test #${index} - Failed Caught an unexpected exception in the promise ${error}`); - } - }); - } - }, - { - name: "Async function with try-catch and try-finally in the body", - body: function (index) { - async function af1() { - throw 42; - } - - async function af2() { - try { - try { - await af1(); - } catch (e) { - echo(`Test #${index} - Success Caught the expected exception inside the inner catch in async body`); - throw e; - } - } finally { - echo(`Test #${index} - Success finally block is executed in async body`); - } - echo(`Test #${index} - Failed Didn't throw an expected exception`); - } - - af2().then(result => { - echo(`Test #${index} - Failed an the expected was not thrown`); - }, err => { - if (err.x === obj.x) { - echo(`Test #${index} - Success Caught the expected exception in the promise`); - } else { - echo(`Test #${index} - Failed Caught an unexpected exception in the promise ${error}`); - } - }); - } - }, - { - name: "Async function and with", - body: function (index) { - var obj = { - async af() { - this.b = await this.a + 10; - return this; - }, - a : 1, - b : 0 - }; - - async function af(x) { - var x = 0; - with (obj) { - x = await af(); - } - - return x; - } - - af().then(result => { - if (result.a === 1 && result.b === 11) { - echo(`Test #${index} - Success functions call inside with returns the right this object`); - } else { - echo(`Test #${index} - Failed function failed to execute with inside an async function got ${result}`); - } - }, err => { - echo(`Test #${index} - Error in with construct inside an async method err = ${err}`); - }); - } - }, -]; - -var index = 1; - -function runTest(test) { - echo('Executing test #' + index + ' - ' + test.name); - - try { - test.body(index); - } catch(e) { - echo('Caught exception: ' + e); - } - - index++; -} - -tests.forEach(runTest); - -echo('\nCompletion Results:'); +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +// ES6 Async Await tests -- verifies functionality of async/await + +function echo(str) { + WScript.Echo(str); +} + +var tests = [ + { + name: "Async keyword with a lambda expressions", + body: function (index) { + var x = 12; + var y = 14; + var lambdaParenNoArg = async() => x < y; + var lambdaArgs = async(a, b, c) => a + b + c; + + lambdaParenNoArg().then(result => { + echo(`Test #${index} - Success lambda expression with no argument called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error lambda expression with no argument called with err = ${err}`); + }); + + lambdaArgs(10, 20, 30).then(result => { + echo(`Test #${index} - Success lambda expression with several arguments called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error lambda expression with several arguments called with err = ${err}`); + }); + } + }, + { + name: "Async keyword with a lambda expressions and local variable captured and shadowed", + body: function (index) { + var x = 12; + var lambdaSingleArgNoParen = async x => x; + var lambdaSingleArg = async(x) => x; + + lambdaSingleArgNoParen(x).then(result => { + echo(`Test #${index} - Success lambda expression with single argument and no paren called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error lambda expression with single argument and no paren called with err = ${err}`); + }); + + lambdaSingleArg(x).then(result => { + echo(`Test #${index} - Success lambda expression with a single argument a called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error lambda expression with a single argument called with err = ${err}`); + }); + } + }, + { + name: "Async function in a statement", + body: function (index) { + { + var namedNonAsyncMethod = function async(x, y) { return x + y; } + var unnamedAsyncMethod = async function (x, y) { return x + y; } + async function async(x, y) { return x - y; } + + var result = namedNonAsyncMethod(10, 20); + echo(`Test #${index} - Success function #1 called with result = '${result}'`); + + unnamedAsyncMethod(10, 20).then(result => { + echo(`Test #${index} - Success function #2 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error function #2 called with err = ${err}`); + }); + + async(10, 20).then(result => { + echo(`Test #${index} - Success function #3 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error function #3 called with err = ${err}`); + }); + } + { + async function async() { return 12; } + + async().then(result => { + echo(`Test #${index} - Success function #4 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error function #4 called with err = ${err}`); + }); + } + { + function async() { return 12; } + + var result = namedNonAsyncMethod(10, 20); + echo(`Test #${index} - Success function #5 called with result = '${result}'`); + } + } + }, + { + name: "Async function in an object", + body: function (index) { + var object = { + async async() { return 12; } + }; + + var object2 = { + async() { return 12; } + }; + + var object3 = { + async "a"() { return 12; }, + async 0() { return 12; }, + async 3.14() { return 12; }, + async else() { return 12; }, + }; + + object.async().then(result => { + echo(`Test #${index} - Success function in a object #1 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error function in a object #1 called with err = ${err}`); + }); + + var result = object2.async(); + echo(`Test #${index} - Success function in a object #2 called with result = '${result}'`); + + object3.a().then(result => { + echo(`Test #${index} - Success function in a object #3 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error function in a object #3 called with err = ${err}`); + }); + + object3['0']().then(result => { + echo(`Test #${index} - Success function in a object #4 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error function in a object #4 called with err = ${err}`); + }); + + object3['3.14']().then(result => { + echo(`Test #${index} - Success function in a object #5 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error function in a object #5 called with err = ${err}`); + }); + + object3.else().then(result => { + echo(`Test #${index} - Success function in a object #6 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error function in a object #6 called with err = ${err}`); + }); + } + }, + { + name: "Async classes", + body: function (index) { + class MyClass { + async asyncMethod(a) { return a; } + async async(a) { return a; } + async "a"() { return 12; } + async 0() { return 12; } + async 3.14() { return 12; } + async else() { return 12; } + static async staticAsyncMethod(a) { return a; } + } + + class MySecondClass { + async(a) { return a; } + } + + class MyThirdClass { + static async(a) { return a; } + } + + var x = "foo"; + class MyFourthClass { + async [x](a) { return a; } + } + + var myClassInstance = new MyClass(); + var mySecondClassInstance = new MySecondClass(); + var myFourthClassInstance = new MyFourthClass(); + + myClassInstance.asyncMethod(10).then(result => { + echo(`Test #${index} - Success async in a class #1 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error async in a class #1 called with err = ${err}`); + }); + + myClassInstance.async(10).then(result => { + echo(`Test #${index} - Success async in a class #2 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error async in a class #2 called with err = ${err}`); + }); + + myClassInstance.a().then(result => { + echo(`Test #${index} - Success async in a class #3 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error async in a class #3 called with err = ${err}`); + }); + + myClassInstance['0']().then(result => { + echo(`Test #${index} - Success async in a class #4 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error async in a class #4 called with err = ${err}`); + }); + + myClassInstance['3.14']().then(result => { + echo(`Test #${index} - Success async in a class #5 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error async in a class #5 called with err = ${err}`); + }); + + myClassInstance.else().then(result => { + echo(`Test #${index} - Success async in a class #6 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error async in a class #6 called with err = ${err}`); + }); + + MyClass.staticAsyncMethod(10).then(result => { + echo(`Test #${index} - Success async in a class #7 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error async in a class #7 called with err = ${err}`); + }); + + var result = mySecondClassInstance.async(10); + echo(`Test #${index} - Success async in a class #8 called with result = '${result}'`); + + var result = MyThirdClass.async(10); + echo(`Test #${index} - Success async in a class #9 called with result = '${result}'`); + + myFourthClassInstance.foo(10).then(result => { + echo(`Test #${index} - Success async in a class #10 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error async in a class #10 called with err = ${err}`); + }); + } + }, + { + name: "Await in an async function", + body: function (index) { + async function asyncMethod(val, factor) { + val = val * factor; + if (val > 0) + val = await asyncMethod(val, -1); + return val; + } + + function await(x) { + return x; + } + + async function secondAsyncMethod(x) { + return await(x); + } + + function rejectedPromiseMethod() { + return new Promise(function (resolve, reject) { + reject(Error('My Error')); + }); + } + + async function rejectAwaitMethod() { + return await rejectedPromiseMethod(); + } + + async function asyncThrowingMethod() { + throw 32; + } + + async function throwAwaitMethod() { + return await asyncThrowingMethod(); + } + + asyncMethod(2, 2).then(result => { + echo(`Test #${index} - Success await in an async function #1 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error await in an async function #1 called with err = ${err}`); + }); + + secondAsyncMethod(2).then(result => { + echo(`Test #${index} - Success await in an async function #2 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error await in an async function #2 called with err = ${err}`); + }); + + rejectAwaitMethod(2).then(result => { + echo(`Test #${index} - Failed await in an async function doesn't catch a rejected Promise. Result = '${result}'`); + }, err => { + echo(`Test #${index} - Success await in an async function catch a rejected Promise in 'err'. Error = '${err}'`); + }); + + throwAwaitMethod(2).then(result => { + echo(`Test #${index} - Failed await in an async function doesn't catch an error. Result = '${result}'`); + }, err => { + echo(`Test #${index} - Success await in an async function catch an error in 'err'. Error = '${err}'`); + }); + } + }, + { + name: "Await keyword with a lambda expressions", + body: function (index) { + { + async function asyncMethod(x, y, z) { + var lambdaExp = async(a, b, c) => a * b * c; + var lambdaResult = await lambdaExp(x, y, z); + return lambdaResult; + } + + asyncMethod(5, 5, 5).then(result => { + echo(`Test #${index} - Success await keyword with a lambda expressions #1 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error await keyword with a lambda expressions #1 called with err = ${err}`); + }); + }; + { + async function await(lambda, x, y, z) { + return await lambda(x, y, z); + } + + await(async(a, b, c) => a + b + c, 10, 20, 30).then(result => { + echo(`Test #${index} - Success await keyword with a lambda expressions #1 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error await keyword with a lambda expressions #1 called with err = ${err}`); + }); + }; + } + }, + { + name: "Async function with default arguments's value", + body: function (index) { + { + function thrower() { + throw "expected error" + } + + async function asyncMethod(argument = thrower()) { + return true; + } + + async function secondAsyncMethod(argument = false) { + return true; + } + + asyncMethod(true).then(result => { + echo(`Test #${index} - Success async function with default arguments's value overwritten #1 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error async function with default arguments's value overwritten #1 called with err = ${err}`); + }); + + // TODO:[aneeshd] Need to fix the default parameter evaluation order for both async functions and generators + asyncMethod().then(result => { + echo(`Test #${index} - Failed async function with default arguments's value has not been rejected as expected #2 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Success async function with default arguments's value has been rejected as expected by 'err' #2 called with err = '${err}'`); + }); + + secondAsyncMethod().then(result => { + echo(`Test #${index} - Success async function with default arguments's value #3 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error async function with default arguments's value #3 called with err = ${err}`); + }); + }; + } + }, + { + name: "Promise in an Async function", + body: function (index) { + { + async function asyncMethodResolved() { + let p = new Promise(function (resolve, reject) { + resolve("resolved"); + }); + + return p.then(function (result) { + return result; + }); + } + + async function asyncMethodResolvedWithAwait() { + let p = new Promise(function (resolve, reject) { + resolve("resolved"); + }); + + return await p; + } + + async function asyncMethodRejected() { + let p = new Promise(function (resolve, reject) { + reject("rejected"); + }); + + return p.then(function (result) { + return result; + }); + } + + asyncMethodResolved().then(result => { + echo(`Test #${index} - Success resolved promise in an async function #1 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error resolved promise in an async function #1 called with err = ${err}`); + }); + + asyncMethodResolvedWithAwait().then(result => { + echo(`Test #${index} - Success resolved promise in an async function #2 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error resolved promise in an async function #2 called with err = ${err}`); + }); + + asyncMethodRejected().then(result => { + echo(`Test #${index} - Failed promise in an async function has not been rejected as expected #3 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Success promise in an async function has been rejected as expected by 'err' #3 called with err = '${err}'`); + }); + }; + } + }, + { + name: "%AsyncFunction% constructor creates async functions analogous to Function constructor", + body: function (index) { + var AsyncFunction = Object.getPrototypeOf(async function () { }).constructor; + + var af = new AsyncFunction('return await Promise.resolve(0);'); + + af().then(result => { + echo(`Test #${index} - Success %AsyncFunction% created async function #1 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error %AsyncFunction% created async function #1 called with err = ${err}`); + }); + + af = new AsyncFunction('a', 'b', 'c', 'a = await a; b = await b; c = await c; return a + b + c;'); + + af(Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)).then(result => { + echo(`Test #${index} - Success %AsyncFunction% created async function #2 called with result = '${result}'`); + }, err => { + echo(`Test #${index} - Error %AsyncFunction% created async function #2 called with err = ${err}`); + }); + } + }, + { + name: "local variables with same names as formal parameters have proper redeclaration semantics (non-error cases, var and function)", + body: function (index) { + async function af1(x) { var y = x; var x = 'b'; return y + x; } + + af1('a').then(result => { + if (result === 'ab') { + echo(`Test #${index} - Success inner var x overwrote formal parameter x only after the declaration statement`); + } else { + echo(`Test #${index} - Failure x appears to have an unexpected value x = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error var redeclaration with err = ${err}`); + }); + + async function af2(x) { var xx = x(); function x() { return 'afx'; } return xx; } + + af2(function () { return ''; }).then(result => { + if (result === 'afx') { + echo(`Test #${index} - Success inner function x() overwrote formal parameter x`); + } else { + echo(`Test #${index} - Failure x appears not assigned with inner function x(), x = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error err = ${err}`); + }); + } + }, + { + name: "this value in async functions behaves like it does in normal functions", + body: function (index) { + async function af() { + return this; + } + + af.call(5).then(result => { + if (result == 5) { + echo(`Test #${index} - Success this value set to 5`); + } else { + echo(`Test #${index} - Failure this value is not 5, this = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error err = ${err}`); + }); + + var o = { + af: af, + b: "abc" + }; + + o.af().then(result => { + if (result.af === af && result.b === "abc") { + echo(`Test #${index} - Success this value set to { af: af, b: "abc" }`); + } else { + echo(`Test #${index} - Failure this value set to something else, this = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error err = ${err}`); + }); + } + }, + { + name: "arguments value in async functions behaves like it does in normal functions", + body: function (index) { + async function af() { + return arguments[0] + arguments[1]; + } + + af('a', 'b').then(result => { + if (result === 'ab') { + echo(`Test #${index} - Success result is 'ab' from arguments 'a' + 'b'`); + } else { + echo(`Test #${index} - Failure result is not 'ab', result = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error err = ${err}`); + }); + } + }, + { + name: "super value in async methods behaves like it does in normal methods", + body: function (index) { + class B { + af() { + return "base"; + } + } + + class C extends B { + async af() { + return super.af() + " derived"; + } + } + + var c = new C(); + + c.af().then(result => { + if (result === 'base derived') { + echo(`Test #${index} - Success result is 'base derived' from derived method call`); + } else { + echo(`Test #${index} - Failure result is not 'base derived', result = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error err = ${err}`); + }); + } + }, + { + name:"Async function with formal captured in a lambda", + body: function (index) { + async function af(d = 1) { + return () => d; + } + + af().then(result => { + if (result() === 1) { + print(`Test #${index} - Success lambda returns 1 when no arguments passed`); + } else { + print(`Test #${index} - Failure result is not 1, result = '${result()}'`); + } + }, err => { + print(`Test #${index} - Error err = ${err}`); + }); + } + }, + { + name:"Async function with formal captured in a nested function", + body: function (index) { + async function af(d = 1) { + return function () { return d; }; + } + + af().then(result => { + if (result() === 1) { + print(`Test #${index} - Success nested function returns 1 when no arguments passed`); + } else { + print(`Test #${index} - Failure result is not 1, result = '${result()}'`); + } + }, err => { + print(`Test #${index} - Error err = ${err}`); + }); + } + }, + { + name:"Async function with formal captured in eval", + body: function (index) { + async function af(d = 1) { + return eval("d"); + } + + af().then(result => { + if (result === 1) { + print(`Test #${index} - Success eval returns 1 when no arguments passed`); + } else { + print(`Test #${index} - Failure result is not 1, result = '${result}'`); + } + }, err => { + print(`Test #${index} - Error err = ${err}`); + }); + } + }, + { + name: "Async function with formal capturing in param scope", + body: function (index) { + async function af1(a, b = () => a, c = b) { + function b() { + return a; + } + var a = 2; + return [b, c]; + } + + af1(1).then(result => { + if (result[0]() === 2) { + echo(`Test #${index} - Success inner function declaration captures the body variable`); + } else { + echo(`Test #${index} - Failure a appears to have an unexpected value a = '${result}'`); + } + if (result[1]() === 1) { + echo(`Test #${index} - Success function defined in the param scope captures the param scope variable`); + } else { + echo(`Test #${index} - Failure a appears to have an unexpected value in the param scope function a = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error in split scope with err = ${err}`); + }); + } + }, + { + name: "Async function with formal capturing in param scope with eval in the body", + body: function (index) { + async function af1(a, b = () => a, c = b) { + function b() { + return a; + } + var a = 2; + return eval("[b, c]"); + } + + af1(1).then(result => { + if (result[0]() === 2) { + echo(`Test #${index} - Success inner function declaration captures the body variable with eval in the body`); + } else { + echo(`Test #${index} - Failure a appears to have an unexpected value a = '${result}'`); + } + if (result[1]() === 1) { + echo(`Test #${index} - Success function defined in the param scope captures the param scope variable with eval in the body`); + } else { + echo(`Test #${index} - Failure a appears to have an unexpected value in the param scope function a = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error in split scope with eval in the body with err = ${err}`); + }); + } + }, + { + name: "Async function with duplicate variable declaration in the body with eval", + body: function (index) { + async function af1(a, b) { + var a = 10; + return eval("a + b"); + } + + af1(1, 2).then(result => { + if (result === 12) { + echo(`Test #${index} - Success inner variable declaration shadows the formal`); + } else { + echo(`Test #${index} - Failure sum appears to have an unexpected value sum = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error in variable redeclaration with eval with err = ${err}`); + }); + } + }, + { + name: "Async function with duplicate variable declaration in the body with child having eval", + body: function (index) { + async function af1(a, b) { + var a = 10; + return function () { return eval("a + b"); }; + } + + af1(1, 2).then(result => { + if (result() === 12) { + echo(`Test #${index} - Success inner variable declaration shadows the formal with eval in child function`); + } else { + echo(`Test #${index} - Failure sum appears to have an unexpected value sum = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error in variable redeclaration with eval with err = ${err}`); + }); + } + }, + { + name: "Async function with more than one await", + body: function (index) { + async function af1() { + return 1; + } + + async function af2() { + return 2; + } + + async function af3() { + return await af1() + await af2(); + } + af3().then(result => { + if (result === 3) { + echo(`Test #${index} - Success functions completes both await calls`); + } else { + echo(`Test #${index} - Failed function failed to complete both await calls and returned ${result}`); + } + }, err => { + echo(`Test #${index} - Error in multiple awaits in a function err = ${err}`); + }); + } + }, + { + name: "Async function with more than one await with branching", + body: function (index) { + async function af1() { + return 1; + } + + async function af2() { + return 2; + } + + async function af3(a) { + return a ? await af1() : await af2(); + } + + af3(1).then(result => { + if (result === 1) { + echo(`Test #${index} - Success functions completes the first await call`); + } else { + echo(`Test #${index} - Failed function failed to complete the first await call and returned ${result}`); + } + }, err => { + echo(`Test #${index} - Error in multiple awaits with branching in a function err = ${err}`); + }); + + af3().then(result => { + if (result === 2) { + echo(`Test #${index} - Success functions completes the second await call`); + } else { + echo(`Test #${index} - Failed function failed to complete the second await call and returned ${result}`); + } + }, err => { + echo(`Test #${index} - Error in multiple awaits with branching in a function err = ${err}`); + }); + } + }, + { + name: "Async function with an exception in an await expression", + body: function (index) { + var obj = { x : 1 }; + async function af1() { + throw obj; + } + + async function af2() { + echo(`Failed : This function was not expected to be executed`); + } + + async function af3() { + return await af1() + await af2(); + } + af3().then(result => { + echo(`Test #${index} - Error an expected exception does not seem to be thrown`); + }, err => { + if (err === obj) { + echo(`Test #${index} - Success caught the expected exception`); + } else { + echo(`Test #${index} - Error an unexpected exception was thrown = ${err}`); + } + }); + } + }, + { + name: "Async functions throws on an await", + body: function (index) { + var obj = { x : 1 }; + async function af1() { + throw obj; + } + + async function af2() { + echo(`Test #${index} Failed This function was not expected to be executed`); + } + + async function af3() { + return await af1() + await af2(); + } + + af3().then(result => { + print(`Test #${index} Failed an expected exception does not seem to be thrown`); + }, err => { + if (err === obj) { + print(`Test #${index} - Success caught the expected exception`); + } else { + print(`Test #${index} - Failed an unexpected exception was thrown = ${err}`); + } + }); + } + }, + { + name: "Awaiting a function with multiple awaits", + body: function (index) { + async function af1(a, b) { + return await af2(); + + async function af2() { + a = await a * a; + b = await b * b; + + return a + b; + } + } + + af1(1, 2).then(result => { + if (result === 5) { + echo(`Test #${index} - Success Multiple awaits in the inner function completed`); + } else { + echo(`Test #${index} - Failed function failed to complete the multiple awaits in the inner function ${result}`); + } + }, err => { + echo(`Test #${index} - Error in multiple awaits in an inner function err = ${err}`); + }); + } + }, + { + name: "Async function with nested try-catch in the body", + body: function (index) { + async function af1() { + throw 42; + } + + async function af2() { + try { + try { + await af1(); + } catch (e) { + echo(`Test #${index} - Success Caught the expected exception inside the inner catch in async body`); + throw e; + } + } catch (e) { + echo(`Test #${index} - Success Caught the expected exception inside catch in async body`); + throw e; + } + echo(`Test #${index} - Failed Didn't throw an expected exception`); + } + + af2().then(result => { + echo(`Test #${index} - Failed an the expected was not thrown`); + }, err => { + if (err.x === obj.x) { + echo(`Test #${index} - Success Caught the expected exception in the promise`); + } else { + echo(`Test #${index} - Failed Caught an unexpected exception in the promise ${error}`); + } + }); + } + }, + { + name: "Async function with try-catch and try-finally in the body", + body: function (index) { + async function af1() { + throw 42; + } + + async function af2() { + try { + try { + await af1(); + } catch (e) { + echo(`Test #${index} - Success Caught the expected exception inside the inner catch in async body`); + throw e; + } + } finally { + echo(`Test #${index} - Success finally block is executed in async body`); + } + echo(`Test #${index} - Failed Didn't throw an expected exception`); + } + + af2().then(result => { + echo(`Test #${index} - Failed an the expected was not thrown`); + }, err => { + if (err.x === obj.x) { + echo(`Test #${index} - Success Caught the expected exception in the promise`); + } else { + echo(`Test #${index} - Failed Caught an unexpected exception in the promise ${error}`); + } + }); + } + }, + { + name: "Async function and with", + body: function (index) { + var obj = { + async af() { + this.b = await this.a + 10; + return this; + }, + a : 1, + b : 0 + }; + + async function af(x) { + var x = 0; + with (obj) { + x = await af(); + } + + return x; + } + + af().then(result => { + if (result.a === 1 && result.b === 11) { + echo(`Test #${index} - Success functions call inside with returns the right this object`); + } else { + echo(`Test #${index} - Failed function failed to execute with inside an async function got ${result}`); + } + }, err => { + echo(`Test #${index} - Error in with construct inside an async method err = ${err}`); + }); + } + }, + { + name: "Async and arguments.callee", + body: function (index) { + async function asyncMethod() { + return arguments.callee; + } + asyncMethod().then(result => { + if (result === asyncMethod) { + echo(`Test #${index} - Success async function and arguments.callee`); + } else { + echo(`Test #${index} - Failed async function and arguments.callee called with result = '${result}'`); + } + }, err => { + echo(`Test #${index} - Error async function and arguments.callee called with err = ${err}`); + }); + } + } +]; + +var index = 1; + +function runTest(test) { + echo('Executing test #' + index + ' - ' + test.name); + + try { + test.body(index); + } catch(e) { + echo('Caught exception: ' + e); + } + + index++; +} + +tests.forEach(runTest); + +echo('\nCompletion Results:');