From f08c4809510d1a947a727a2342a13a9902dff975 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sun, 12 Dec 2021 18:36:14 +0100 Subject: [PATCH 1/2] Correctly handle resolving promises with other promises --- src/lualib/Promise.ts | 8 ++++ test/unit/builtins/async-await.spec.ts | 57 ++++++++++++++++++++++++++ test/unit/builtins/promise.spec.ts | 43 +++++++++++++++++++ 3 files changed, 108 insertions(+) diff --git a/src/lualib/Promise.ts b/src/lualib/Promise.ts index 76f119c38..de21de94a 100644 --- a/src/lualib/Promise.ts +++ b/src/lualib/Promise.ts @@ -128,6 +128,14 @@ class __TS__Promise implements Promise { } private resolve(data: T): void { + if (data instanceof __TS__Promise) { + data.then( + v => this.resolve(v), + err => this.reject(err) + ); + return; + } + // Resolve this promise, if it is still pending. This function is passed to the constructor function. if (this.state === __TS__PromiseState.Pending) { this.state = __TS__PromiseState.Fulfilled; diff --git a/test/unit/builtins/async-await.spec.ts b/test/unit/builtins/async-await.spec.ts index aba6b15eb..2440bd76f 100644 --- a/test/unit/builtins/async-await.spec.ts +++ b/test/unit/builtins/async-await.spec.ts @@ -384,6 +384,63 @@ test("async function can forward varargs", () => { .expectToEqual(["resolved", "A", "B", "C"]); }); +test("async function adopts pending promise", () => { + util.testFunction` + let resolve: (v: string) => void = () => {}; + async function receive(): Promise { + return new Promise(res => { + resolve = res; + }); + } + + receive().then(v => { + log(v); + }); + + resolve("delayed resolve"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["delayed resolve"]); +}); + +test("async function adopts resolved promise", () => { + util.testFunction` + async function receive(): Promise { + return new Promise(resolve => { + resolve("resolved!"); + }); + } + + receive().then(v => { + log(v); + }); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["resolved!"]); +}); + +test("async function adopts rejected promise", () => { + util.testFunction` + async function receive(): Promise { + return new Promise((_, reject) => { + reject("rejected"); + }); + } + + receive().catch(err => { + log(err); + }); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["rejected"]); +}); + test.each(["async function abc() {", "const abc = async () => {"])( "can throw error after await in async function (%p)", functionHeader => { diff --git a/test/unit/builtins/promise.spec.ts b/test/unit/builtins/promise.spec.ts index 60e30dcf1..1a5c68092 100644 --- a/test/unit/builtins/promise.spec.ts +++ b/test/unit/builtins/promise.spec.ts @@ -751,6 +751,49 @@ test("catch after then catches rejected promise", () => { .expectToEqual(["catch", "test error"]); }); +test("promise unwraps resolved promise result", () => { + util.testFunction` + const { promise, resolve } = defer(); + promise.then(v => log(v)); + + resolve(Promise.resolve("result")); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["result"]); +}); + +test("resolving promise with rejected promise rejects the promise", () => { + util.testFunction` + const { promise, resolve } = defer(); + promise.catch(err => log(err)); + + resolve(Promise.reject("reject")); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["reject"]); +}); + +test("resolving promise with pending promise will keep pending until promise2 resolved", () => { + util.testFunction` + const { promise, resolve } = defer(); + promise.then(v => log("promise 1", v)); + + const { promise: promise2, resolve: resolve2 } = defer(); + promise2.then(v => log("promise 2", v)); + + resolve(promise2); + resolve2("result"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise 2", "result", "promise 1", "result"]); +}); + describe("Promise.all", () => { test("resolves once all arguments are resolved", () => { util.testFunction` From 368e59b24611130f21af918df3f26fd9455f346d Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sun, 12 Dec 2021 18:42:56 +0100 Subject: [PATCH 2/2] Additional test --- test/unit/builtins/promise.spec.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/unit/builtins/promise.spec.ts b/test/unit/builtins/promise.spec.ts index 1a5c68092..10a0c767a 100644 --- a/test/unit/builtins/promise.spec.ts +++ b/test/unit/builtins/promise.spec.ts @@ -794,6 +794,23 @@ test("resolving promise with pending promise will keep pending until promise2 re .expectToEqual(["promise 2", "result", "promise 1", "result"]); }); +test("resolving promise with pending promise will keep pending until promise2 rejects", () => { + util.testFunction` + const { promise, resolve } = defer(); + promise.catch(v => log("promise 1", v)); + + const { promise: promise2, reject: reject2 } = defer(); + promise2.catch(v => log("promise 2", v)); + + resolve(promise2); + reject2("rejection"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise 2", "rejection", "promise 1", "rejection"]); +}); + describe("Promise.all", () => { test("resolves once all arguments are resolved", () => { util.testFunction`