| Index: test/mjsunit/harmony/async-await-species.js
|
| diff --git a/test/mjsunit/harmony/async-await-species.js b/test/mjsunit/harmony/async-await-species.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bc3db83fdfa1141ede427ba27cd2f0a421abe8cf
|
| --- /dev/null
|
| +++ b/test/mjsunit/harmony/async-await-species.js
|
| @@ -0,0 +1,101 @@
|
| +// Copyright 2016 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// Flags: --harmony-async-await --allow-natives-syntax
|
| +
|
| +function assertEqualsAsync(expected, run, msg) {
|
| + var actual;
|
| + var hadValue = false;
|
| + var hadError = false;
|
| + var promise = run();
|
| +
|
| + if (typeof promise !== "object" || typeof promise.then !== "function") {
|
| + throw new MjsUnitAssertionError(
|
| + "Expected " + run.toString() +
|
| + " to return a Promise, but it returned " + PrettyPrint(promise));
|
| + }
|
| +
|
| + promise.then(function(value) { hadValue = true; actual = value; },
|
| + function(error) { hadError = true; actual = error; });
|
| +
|
| + assertFalse(hadValue || hadError);
|
| +
|
| + %RunMicrotasks();
|
| +
|
| + if (hadError) throw actual;
|
| +
|
| + assertTrue(
|
| + hadValue, "Expected '" + run.toString() + "' to produce a value");
|
| +
|
| + assertEquals(expected, actual, msg);
|
| +};
|
| +
|
| +// Rename a function so that it can help omit things from stack trace.
|
| +function test(fn) {
|
| + return Object.defineProperty(fn, "name", {
|
| + enumerable: false,
|
| + configurable: true,
|
| + value: "@" + fn.name,
|
| + writable: false
|
| + });
|
| +}
|
| +
|
| +function getStack(error) {
|
| + var stack = error.stack.split('\n').
|
| + filter(function(line) {
|
| + return /^\s*at @?[a-zA-Z0-9_]/.test(line);
|
| + }).
|
| + map(line => line.replace(/^\s*at (@?[a-zA-Z0-9_\.\[\]]+)(.*)/, "$1"));
|
| +
|
| + // remove `Promise.then()` invocation by assertEqualsAsync()
|
| + if (stack[2] === "assertEqualsAsync") return [];
|
| +
|
| + return stack.reverse();
|
| +}
|
| +
|
| +var log = [];
|
| +class FakePromise extends Promise {
|
| + constructor(executor) {
|
| + var stack = getStack(new Error("Getting Callstack"));
|
| + if (stack.length) {
|
| + var first = -1;
|
| + for (var i = 0; i < stack.length; ++i) {
|
| + if (stack[i][0] === '@') {
|
| + first = i;
|
| + break;
|
| + }
|
| + }
|
| + while (first > 0) stack.shift(), --first;
|
| + if (stack.length) {
|
| + log.push("@@Species: [" + stack.join(" > ") + "]");
|
| + }
|
| + }
|
| + return new Promise(executor);
|
| + }
|
| +};
|
| +
|
| +Object.defineProperty(Promise, Symbol.species, {
|
| + value: FakePromise,
|
| + configurable: true,
|
| + enumerable: false,
|
| + writable: false
|
| +});
|
| +
|
| +// Internal `AsyncFunctionAwait` only --- no @@species invocations.
|
| +async function asyncFn() { return await "foo"; }
|
| +assertEqualsAsync("foo", test(function testInternalOnly() { return asyncFn(); },
|
| + "should not call Promise[@@Species]"));
|
| +assertEquals([], log);
|
| +
|
| +log.length = 0;
|
| +assertEqualsAsync(
|
| + "foo",
|
| + test(function testThenOnReturnedPromise() {
|
| + return asyncFn().then(x => (log.push("Then: " + x), x));
|
| + }),
|
| + "should call Promise[@@Species] after non-internal Then");
|
| +assertEquals([
|
| + "@@Species: [@testThenOnReturnedPromise > Promise.then > FakePromise]",
|
| + "Then: foo"
|
| +], log);
|
|
|