diff options
Diffstat (limited to 'js/src/tests/test262/language/expressions/await')
23 files changed, 718 insertions, 0 deletions
diff --git a/js/src/tests/test262/language/expressions/await/async-await-interleaved.js b/js/src/tests/test262/language/expressions/await/async-await-interleaved.js new file mode 100644 index 0000000000..16ef6cad4f --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/async-await-interleaved.js @@ -0,0 +1,45 @@ +// |reftest| async +// Copyright 2018 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Maya Lekova <mslekova@chromium.org> +esid: await +description: > + Await on async functions and builtin Promises are properly interleaved, + meaning await takes only 1 tick on the microtask queue. +flags: [async] +features: [async-functions] +includes: [compareArray.js] +---*/ + +const actual = []; +const expected = [ + 'Await: 1', + 'Promise: 1', + 'Await: 2', + 'Promise: 2' +]; + +async function pushAwait(value) { + actual.push('Await: ' + value); +} + +async function callAsync() { + await pushAwait(1); + await pushAwait(2); +} + +function checkAssertions() { + assert.compareArray(actual, expected, + 'Async/await and promises should be interleaved'); +} + +callAsync(); + +new Promise(function (resolve) { + actual.push('Promise: 1'); + resolve(); +}).then(function () { + actual.push('Promise: 2'); +}).then(checkAssertions).then($DONE, $DONE); diff --git a/js/src/tests/test262/language/expressions/await/async-generator-interleaved.js b/js/src/tests/test262/language/expressions/await/async-generator-interleaved.js new file mode 100644 index 0000000000..d19d7dbacf --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/async-generator-interleaved.js @@ -0,0 +1,43 @@ +// |reftest| async +// Copyright 2018 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Maya Lekova <mslekova@chromium.org> +esid: await +description: > + Await on async generator functions and builtin Promises are properly + interleaved, meaning await takes only 1 tick on the microtask queue. +flags: [async] +features: [async-functions, async-iteration] +includes: [compareArray.js] +---*/ + +const actual = []; +const expected = [ 'await', 1, 'await', 2 ]; +const iterations = 2; + +async function pushAwait() { + actual.push('await'); +} + +async function* callAsync() { + for (let i = 0; i < iterations; i++) { + await pushAwait(); + } + return 0; +} + +function checkAssertions() { + assert.compareArray(actual, expected, + 'Async/await and promises should be interleaved'); +} + +callAsync().next(); + +new Promise(function (resolve) { + actual.push(1); + resolve(); +}).then(function () { + actual.push(2); +}).then(checkAssertions).then($DONE, $DONE); diff --git a/js/src/tests/test262/language/expressions/await/await-BindingIdentifier-in-global.js b/js/src/tests/test262/language/expressions/await/await-BindingIdentifier-in-global.js new file mode 100644 index 0000000000..2fb4088b44 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-BindingIdentifier-in-global.js @@ -0,0 +1,15 @@ +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await is allowed as a binding identifier in global scope +---*/ + +async function await() { return 1 } +assert(await instanceof Function); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/language/expressions/await/await-BindingIdentifier-nested.js b/js/src/tests/test262/language/expressions/await/await-BindingIdentifier-nested.js new file mode 100644 index 0000000000..b2cb7179f1 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-BindingIdentifier-nested.js @@ -0,0 +1,20 @@ +// |reftest| error:SyntaxError +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await is not allowed as an identifier in functions nested in async functions +negative: + phase: parse + type: SyntaxError +---*/ + +$DONOTEVALUATE(); + +async function foo() { + function await() { + } +} diff --git a/js/src/tests/test262/language/expressions/await/await-awaits-thenable-not-callable.js b/js/src/tests/test262/language/expressions/await/await-awaits-thenable-not-callable.js new file mode 100644 index 0000000000..ac41188431 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-awaits-thenable-not-callable.js @@ -0,0 +1,22 @@ +// |reftest| async +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await can await any thenable. If the thenable's then is not callable, + await evaluates to the thenable +flags: [async] +includes: [asyncHelpers.js] +---*/ + +async function foo() { + var thenable = { then: 42 }; + var res = await thenable; + assert.sameValue(res, thenable); +} + +asyncTest(foo); + diff --git a/js/src/tests/test262/language/expressions/await/await-awaits-thenables-that-throw.js b/js/src/tests/test262/language/expressions/await/await-awaits-thenables-that-throw.js new file mode 100644 index 0000000000..b1060d5632 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-awaits-thenables-that-throw.js @@ -0,0 +1,33 @@ +// |reftest| async +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await can await any thenable. +flags: [async] +includes: [asyncHelpers.js] +---*/ + +var error = {}; +var thenable = { + then: function (resolve, reject) { + throw error; + } +} +async function foo() { + var caught = false; + try { + await thenable; + } catch(e) { + caught = true; + assert.sameValue(e, error); + } + + assert(caught); +} + +asyncTest(foo); + diff --git a/js/src/tests/test262/language/expressions/await/await-awaits-thenables.js b/js/src/tests/test262/language/expressions/await/await-awaits-thenables.js new file mode 100644 index 0000000000..ab9de6170e --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-awaits-thenables.js @@ -0,0 +1,23 @@ +// |reftest| async +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await can await any thenable. +flags: [async] +includes: [asyncHelpers.js] +---*/ + +var thenable = { + then: function (resolve, reject) { + resolve(42); + } +} +async function foo() { + assert.sameValue(await thenable, 42); +} + +asyncTest(foo); diff --git a/js/src/tests/test262/language/expressions/await/await-in-function.js b/js/src/tests/test262/language/expressions/await/await-in-function.js new file mode 100644 index 0000000000..7a083e16ba --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-in-function.js @@ -0,0 +1,14 @@ +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await is an identifier in a function +---*/ + +function foo(await) { return await; } +assert.sameValue(foo(1), 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/language/expressions/await/await-in-generator.js b/js/src/tests/test262/language/expressions/await/await-in-generator.js new file mode 100644 index 0000000000..67995f7b70 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-in-generator.js @@ -0,0 +1,15 @@ +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await in a generator is an identifier +features: [generators] +---*/ + +function* foo(await) { yield await; }; +assert.sameValue(foo(1).next().value, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/language/expressions/await/await-in-global.js b/js/src/tests/test262/language/expressions/await/await-in-global.js new file mode 100644 index 0000000000..675e63a1d3 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-in-global.js @@ -0,0 +1,14 @@ +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await is an identifier in global scope +---*/ + +var await = 1; +assert.sameValue(await, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/language/expressions/await/await-in-nested-function.js b/js/src/tests/test262/language/expressions/await/await-in-nested-function.js new file mode 100644 index 0000000000..0d2151bd81 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-in-nested-function.js @@ -0,0 +1,22 @@ +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await is allowed as an identifier in functions nested in async functions +---*/ + +var await; +async function foo() { + function bar() { + await = 1; + } + bar(); +} +foo(); + +assert.sameValue(await, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/language/expressions/await/await-in-nested-generator.js b/js/src/tests/test262/language/expressions/await/await-in-nested-generator.js new file mode 100644 index 0000000000..41197fbffe --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-in-nested-generator.js @@ -0,0 +1,23 @@ +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await is allowed as an identifier in generator functions nested in async functions +features: [generators] +---*/ + +var await; +async function foo() { + function* bar() { + await = 1; + } + bar().next(); +} +foo(); + +assert.sameValue(await, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/language/expressions/await/await-monkey-patched-promise.js b/js/src/tests/test262/language/expressions/await/await-monkey-patched-promise.js new file mode 100644 index 0000000000..0ac7415bf5 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-monkey-patched-promise.js @@ -0,0 +1,51 @@ +// |reftest| async +// Copyright 2018 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Maya Lekova <mslekova@chromium.org> +esid: await +description: > + This test demonstrates that monkey-patched "then" on native promises will + not get called. Adapted from example by Kevin Smith: + https://github.com/tc39/ecma262/pull/1250#issuecomment-401082195 +flags: [async] +features: [async-functions] +includes: [compareArray.js] +---*/ + +let thenCallCount = 0; +const value = 42; + +const actual = []; +const expected = [ + 'Promise: 1', + 'Await: ' + value, + 'Promise: 2', +]; + +const patched = Promise.resolve(value); +patched.then = function(...args) { + thenCallCount++; + Promise.prototype.then.apply(this, args); +}; + +async function trigger() { + actual.push('Await: ' + await patched); +} + +function checkAssertions() { + assert.compareArray(actual, expected, + 'Async/await and promises should be interleaved'); + assert.sameValue(thenCallCount, 0, + 'Monkey-patched "then" on native promises should not be called.') +} + +trigger().then(checkAssertions).then($DONE, $DONE); + +new Promise(function (resolve) { + actual.push('Promise: 1'); + resolve(); +}).then(function () { + actual.push('Promise: 2'); +}); diff --git a/js/src/tests/test262/language/expressions/await/await-non-promise-thenable.js b/js/src/tests/test262/language/expressions/await/await-non-promise-thenable.js new file mode 100644 index 0000000000..bad7cc6776 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-non-promise-thenable.js @@ -0,0 +1,57 @@ +// |reftest| async +// Copyright 2018 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Maya Lekova <mslekova@chromium.org> +esid: await +description: > + This test demonstrates that "then" on a non-native promise + will still get called. +flags: [async] +features: [async-functions] +includes: [compareArray.js] +---*/ + +let thenCallCount = 0; + +const actual = []; +const expected = [ + 'Promise: 1', + 'Promise: 2', + 'Await: 1', + 'Promise: 3', + 'Promise: 4', + 'Await: 2', +]; + +const patched = {}; +patched.then = function(fulfill, reject) { + thenCallCount++; + fulfill(thenCallCount); +}; + +async function trigger() { + actual.push('Await: ' + await patched); + actual.push('Await: ' + await patched); +} + +function checkAssertions() { + assert.compareArray(actual, expected, + 'Async/await and promises should be interleaved'); + assert.sameValue(thenCallCount, 2, + '"then" on non-native promises should be called.'); +} + +trigger().then(checkAssertions).then($DONE, $DONE); + +new Promise(function (resolve) { + actual.push('Promise: 1'); + resolve(); +}).then(function () { + actual.push('Promise: 2'); +}).then(function () { + actual.push('Promise: 3'); +}).then(function () { + actual.push('Promise: 4'); +}); diff --git a/js/src/tests/test262/language/expressions/await/await-non-promise.js b/js/src/tests/test262/language/expressions/await/await-non-promise.js new file mode 100644 index 0000000000..1aaf1094a2 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-non-promise.js @@ -0,0 +1,45 @@ +// |reftest| async +// Copyright 2018 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Maya Lekova <mslekova@chromium.org> +esid: await +description: > + This test demonstrates that "then" on a non-native promise + will still get called. +flags: [async] +features: [async-functions] +includes: [compareArray.js] +---*/ + +const value = 1; + +const actual = []; +const expected = [ + 'Await: 1', + 'Promise: 1', + 'Promise: 2', +]; + +function pushAwaitSync(value) { + actual.push('Await: ' + value); +} + +async function trigger() { + await pushAwaitSync(value); +} + +function checkAssertions() { + assert.compareArray(actual, expected, + 'Async/await and promises should be interleaved'); +} + +trigger().then(checkAssertions).then($DONE, $DONE); + +new Promise(function (resolve) { + actual.push('Promise: 1'); + resolve(); +}).then(function () { + actual.push('Promise: 2'); +}); diff --git a/js/src/tests/test262/language/expressions/await/await-throws-rejections.js b/js/src/tests/test262/language/expressions/await/await-throws-rejections.js new file mode 100644 index 0000000000..175211b1cf --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/await-throws-rejections.js @@ -0,0 +1,27 @@ +// |reftest| async +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await throws errors from rejected promises +flags: [async] +includes: [asyncHelpers.js] +---*/ + +async function foo() { + var err = {}; + var caught = false; + try { + await Promise.reject(err); + } catch(e) { + caught = true; + assert.sameValue(e, err); + } + + assert(caught); +} + +asyncTest(foo); diff --git a/js/src/tests/test262/language/expressions/await/browser.js b/js/src/tests/test262/language/expressions/await/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/browser.js diff --git a/js/src/tests/test262/language/expressions/await/early-errors-await-not-simple-assignment-target.js b/js/src/tests/test262/language/expressions/await/early-errors-await-not-simple-assignment-target.js new file mode 100644 index 0000000000..27416be4f6 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/early-errors-await-not-simple-assignment-target.js @@ -0,0 +1,19 @@ +// |reftest| error:SyntaxError +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + await is not a simple assignment target and cannot be assigned to. +negative: + phase: parse + type: SyntaxError +---*/ + +$DONOTEVALUATE(); + +async function foo() { + (await 1) = 1; +} diff --git a/js/src/tests/test262/language/expressions/await/for-await-of-interleaved.js b/js/src/tests/test262/language/expressions/await/for-await-of-interleaved.js new file mode 100644 index 0000000000..39bcda612e --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/for-await-of-interleaved.js @@ -0,0 +1,59 @@ +// |reftest| async +// Copyright 2018 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Maya Lekova <mslekova@chromium.org> +esid: await +description: > + for-await-of iteration and builtin Promises are properly interleaved, + meaning await in for-of loop takes only 1 tick on the microtask queue. +flags: [async] +features: [async-functions, async-iteration, generators] +includes: [compareArray.js] +---*/ + +const actual = []; +const expected = [ + 'Promise: 6', + 'Promise: 5', + 'Await: 3', + 'Promise: 4', + 'Promise: 3', + 'Await: 2', + 'Promise: 2', + 'Promise: 1', + 'Await: 1', + 'Promise: 0' +]; +const iterations = 3; + +async function* naturalNumbers(start) { + let current = start; + while (current > 0) { + yield Promise.resolve(current--); + } +} + +async function trigger() { + for await (const num of naturalNumbers(iterations)) { + actual.push('Await: ' + num); + } +} + +async function checkAssertions() { + assert.compareArray(actual, expected, + 'Async/await and promises should be interleaved'); +} + +function countdown(counter) { + actual.push('Promise: ' + counter); + if (counter > 0) { + return Promise.resolve(counter - 1).then(countdown); + } else { + checkAssertions().then($DONE, $DONE); + } +} + +trigger(); +countdown(iterations * 2); diff --git a/js/src/tests/test262/language/expressions/await/no-operand.js b/js/src/tests/test262/language/expressions/await/no-operand.js new file mode 100644 index 0000000000..cecd869687 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/no-operand.js @@ -0,0 +1,19 @@ +// |reftest| error:SyntaxError +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + await requries an operand. +negative: + phase: parse + type: SyntaxError +---*/ + +$DONOTEVALUATE(); + +async function foo() { + await; +} diff --git a/js/src/tests/test262/language/expressions/await/shell.js b/js/src/tests/test262/language/expressions/await/shell.js new file mode 100644 index 0000000000..ae18ad584d --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/shell.js @@ -0,0 +1,113 @@ +// GENERATED, DO NOT EDIT +// file: asyncHelpers.js +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: | + A collection of assertion and wrapper functions for testing asynchronous built-ins. +defines: [asyncTest] +---*/ + +function asyncTest(testFunc) { + if (!Object.hasOwn(globalThis, "$DONE")) { + throw new Test262Error("asyncTest called without async flag"); + } + if (typeof testFunc !== "function") { + $DONE(new Test262Error("asyncTest called with non-function argument")); + return; + } + try { + testFunc().then( + function () { + $DONE(); + }, + function (error) { + $DONE(error); + } + ); + } catch (syncError) { + $DONE(syncError); + } +} + +assert.throwsAsync = async function (expectedErrorConstructor, func, message) { + var innerThenable; + if (message === undefined) { + message = ""; + } else { + message += " "; + } + if (typeof func === "function") { + try { + innerThenable = func(); + if ( + innerThenable === null || + typeof innerThenable !== "object" || + typeof innerThenable.then !== "function" + ) { + message += + "Expected to obtain an inner promise that would reject with a" + + expectedErrorConstructor.name + + " but result was not a thenable"; + throw new Test262Error(message); + } + } catch (thrown) { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but an exception was thrown synchronously while obtaining the inner promise"; + throw new Test262Error(message); + } + } else { + message += + "assert.throwsAsync called with an argument that is not a function"; + throw new Test262Error(message); + } + + try { + return innerThenable.then( + function () { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but no exception was thrown at all"; + throw new Test262Error(message); + }, + function (thrown) { + var expectedName, actualName; + if (typeof thrown !== "object" || thrown === null) { + message += "Thrown value was not an object!"; + throw new Test262Error(message); + } else if (thrown.constructor !== expectedErrorConstructor) { + expectedName = expectedErrorConstructor.name; + actualName = thrown.constructor.name; + if (expectedName === actualName) { + message += + "Expected a " + + expectedName + + " but got a different error constructor with the same name"; + } else { + message += + "Expected a " + expectedName + " but got a " + actualName; + } + throw new Test262Error(message); + } + } + ); + } catch (thrown) { + if (typeof thrown !== "object" || thrown === null) { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but innerThenable synchronously threw a value that was not an object "; + } else { + message += + "Expected a " + + expectedErrorConstructor.name + + " to be thrown asynchronously but a " + + thrown.constructor.name + + " was thrown synchronously"; + } + throw new Test262Error(message); + } +}; diff --git a/js/src/tests/test262/language/expressions/await/syntax-await-has-UnaryExpression-with-MultiplicativeExpression.js b/js/src/tests/test262/language/expressions/await/syntax-await-has-UnaryExpression-with-MultiplicativeExpression.js new file mode 100644 index 0000000000..b9af142520 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/syntax-await-has-UnaryExpression-with-MultiplicativeExpression.js @@ -0,0 +1,19 @@ +// |reftest| async +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await's operand is a UnaryExpression +flags: [async] +includes: [asyncHelpers.js] +---*/ + +async function foo() { + let x = 2; + let y = await Promise.resolve(2) * x + assert.sameValue(y, 4); +} +asyncTest(foo); diff --git a/js/src/tests/test262/language/expressions/await/syntax-await-has-UnaryExpression.js b/js/src/tests/test262/language/expressions/await/syntax-await-has-UnaryExpression.js new file mode 100644 index 0000000000..464d9b5c14 --- /dev/null +++ b/js/src/tests/test262/language/expressions/await/syntax-await-has-UnaryExpression.js @@ -0,0 +1,20 @@ +// |reftest| async +// Copyright 2016 Microsoft, Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +author: Brian Terlson <brian.terlson@microsoft.com> +esid: pending +description: > + Await's operand is a UnaryExpression +flags: [async] +includes: [asyncHelpers.js] +---*/ + +async function foo() { + let x = 1; + let y = await x++; + assert.sameValue(y, 1); + assert.sameValue(x, 2); +} +asyncTest(foo); |