Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/lualib/Promise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ class __TS__Promise<T> implements Promise<T> {
}

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;
Expand Down
57 changes: 57 additions & 0 deletions test/unit/builtins/async-await.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> {
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<string> {
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<string> {
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 => {
Expand Down
60 changes: 60 additions & 0 deletions test/unit/builtins/promise.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,66 @@ test("catch after then catches rejected promise", () => {
.expectToEqual(["catch", "test error"]);
});

test("promise unwraps resolved promise result", () => {
util.testFunction`
const { promise, resolve } = defer<string>();
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<string>();
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<string>();
promise.then(v => log("promise 1", v));

const { promise: promise2, resolve: resolve2 } = defer<string>();
promise2.then(v => log("promise 2", v));

resolve(promise2);
resolve2("result");

return allLogs;
`
.setTsHeader(promiseTestLib)
.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<string>();
promise.catch(v => log("promise 1", v));

const { promise: promise2, reject: reject2 } = defer<string>();
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`
Expand Down