diff --git a/test/language/expressions/await/async-await-interleaved.js b/test/language/expressions/await/async-await-interleaved.js new file mode 100644 index 0000000000..33cde9f685 --- /dev/null +++ b/test/language/expressions/await/async-await-interleaved.js @@ -0,0 +1,43 @@ +// 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 +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] +---*/ + +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/test/language/expressions/await/async-generator-interleaved.js b/test/language/expressions/await/async-generator-interleaved.js new file mode 100644 index 0000000000..fdc3076eed --- /dev/null +++ b/test/language/expressions/await/async-generator-interleaved.js @@ -0,0 +1,41 @@ +// 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 +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] +---*/ + +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/test/language/expressions/await/await-monkey-patched-promise.js b/test/language/expressions/await/await-monkey-patched-promise.js new file mode 100644 index 0000000000..ff2bebe6ea --- /dev/null +++ b/test/language/expressions/await/await-monkey-patched-promise.js @@ -0,0 +1,49 @@ +// 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 +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] +---*/ + +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/test/language/expressions/await/await-non-promise-thenable.js b/test/language/expressions/await/await-non-promise-thenable.js new file mode 100644 index 0000000000..0efa2d688c --- /dev/null +++ b/test/language/expressions/await/await-non-promise-thenable.js @@ -0,0 +1,55 @@ +// 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 +esid: await +description: > + This test demonstrates that "then" on a non-native promise + will still get called. +flags: [async] +features: [async-functions] +---*/ + +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/test/language/expressions/await/await-non-promise.js b/test/language/expressions/await/await-non-promise.js new file mode 100644 index 0000000000..dadef94fcb --- /dev/null +++ b/test/language/expressions/await/await-non-promise.js @@ -0,0 +1,43 @@ +// 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 +esid: await +description: > + This test demonstrates that "then" on a non-native promise + will still get called. +flags: [async] +features: [async-functions] +---*/ + +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/test/language/expressions/await/for-await-of-interleaved.js b/test/language/expressions/await/for-await-of-interleaved.js new file mode 100644 index 0000000000..f8cf07d70a --- /dev/null +++ b/test/language/expressions/await/for-await-of-interleaved.js @@ -0,0 +1,57 @@ +// 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 +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] +---*/ + +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);