2024-01-01 21:11:32 +00:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2024-04-29 02:57:30 +00:00
|
|
|
import { assertEquals, assertRejects } from "@std/assert";
|
2022-02-21 04:51:39 +00:00
|
|
|
import { abortable } from "./abortable.ts";
|
|
|
|
|
2023-12-18 22:29:13 +00:00
|
|
|
Deno.test("abortable() handles promise", async () => {
|
2022-02-21 04:51:39 +00:00
|
|
|
const c = new AbortController();
|
2023-11-10 03:31:16 +00:00
|
|
|
const { promise, resolve } = Promise.withResolvers<string>();
|
|
|
|
const t = setTimeout(() => resolve("Hello"), 100);
|
|
|
|
const result = await abortable(promise, c.signal);
|
2022-02-21 04:51:39 +00:00
|
|
|
assertEquals(result, "Hello");
|
|
|
|
clearTimeout(t);
|
|
|
|
});
|
|
|
|
|
2023-12-18 22:29:13 +00:00
|
|
|
Deno.test("abortable() handles promise with aborted signal after delay", async () => {
|
2022-02-21 04:51:39 +00:00
|
|
|
const c = new AbortController();
|
2023-11-10 03:31:16 +00:00
|
|
|
const { promise, resolve } = Promise.withResolvers<string>();
|
|
|
|
const t = setTimeout(() => resolve("Hello"), 100);
|
2022-02-21 04:51:39 +00:00
|
|
|
setTimeout(() => c.abort(), 50);
|
2024-06-21 06:37:23 +00:00
|
|
|
const error = await assertRejects(
|
|
|
|
() => abortable(promise, c.signal),
|
2022-02-21 04:51:39 +00:00
|
|
|
DOMException,
|
2024-06-21 06:37:23 +00:00
|
|
|
"The signal has been aborted",
|
|
|
|
);
|
|
|
|
assertEquals(error.name, "AbortError");
|
|
|
|
clearTimeout(t);
|
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("abortable() handles promise with aborted signal after delay with reason", async () => {
|
|
|
|
const c = new AbortController();
|
|
|
|
const { promise, resolve } = Promise.withResolvers<string>();
|
|
|
|
const t = setTimeout(() => resolve("Hello"), 100);
|
|
|
|
setTimeout(() => c.abort(new Error("This is my reason")), 50);
|
|
|
|
await assertRejects(
|
|
|
|
() => abortable(promise, c.signal),
|
|
|
|
Error,
|
|
|
|
"This is my reason",
|
2022-02-21 04:51:39 +00:00
|
|
|
);
|
|
|
|
clearTimeout(t);
|
|
|
|
});
|
|
|
|
|
2023-12-18 22:29:13 +00:00
|
|
|
Deno.test("abortable() handles promise with already aborted signal", async () => {
|
2022-02-21 04:51:39 +00:00
|
|
|
const c = new AbortController();
|
2023-11-10 03:31:16 +00:00
|
|
|
const { promise, resolve } = Promise.withResolvers<string>();
|
|
|
|
const t = setTimeout(() => resolve("Hello"), 100);
|
2022-02-21 04:51:39 +00:00
|
|
|
c.abort();
|
2024-06-21 06:37:23 +00:00
|
|
|
const error = await assertRejects(
|
2022-02-21 04:51:39 +00:00
|
|
|
async () => {
|
2023-11-10 03:31:16 +00:00
|
|
|
await abortable(promise, c.signal);
|
2022-02-21 04:51:39 +00:00
|
|
|
},
|
|
|
|
DOMException,
|
2024-06-21 06:37:23 +00:00
|
|
|
"The signal has been aborted",
|
|
|
|
);
|
|
|
|
assertEquals(error.name, "AbortError");
|
|
|
|
clearTimeout(t);
|
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("abortable() handles promise with already aborted signal with reason", async () => {
|
|
|
|
const c = new AbortController();
|
|
|
|
const { promise, resolve } = Promise.withResolvers<string>();
|
|
|
|
const t = setTimeout(() => resolve("Hello"), 100);
|
|
|
|
c.abort(new Error("This is my reason"));
|
|
|
|
await assertRejects(
|
|
|
|
() => abortable(promise, c.signal),
|
|
|
|
Error,
|
|
|
|
"This is my reason",
|
2022-02-21 04:51:39 +00:00
|
|
|
);
|
|
|
|
clearTimeout(t);
|
|
|
|
});
|
|
|
|
|
2023-12-18 22:29:13 +00:00
|
|
|
Deno.test("abortable.AsyncIterable()", async () => {
|
2022-02-21 04:51:39 +00:00
|
|
|
const c = new AbortController();
|
2023-11-10 03:31:16 +00:00
|
|
|
const { promise, resolve } = Promise.withResolvers<string>();
|
|
|
|
const t = setTimeout(() => resolve("Hello"), 100);
|
2022-02-21 04:51:39 +00:00
|
|
|
const a = async function* () {
|
|
|
|
yield "Hello";
|
2023-11-10 03:31:16 +00:00
|
|
|
await promise;
|
2022-02-21 04:51:39 +00:00
|
|
|
yield "World";
|
|
|
|
};
|
2023-11-10 19:00:28 +00:00
|
|
|
const items = await Array.fromAsync(abortable(a(), c.signal));
|
2022-02-21 04:51:39 +00:00
|
|
|
assertEquals(items, ["Hello", "World"]);
|
|
|
|
clearTimeout(t);
|
|
|
|
});
|
|
|
|
|
2023-12-18 22:29:13 +00:00
|
|
|
Deno.test("abortable.AsyncIterable() handles aborted signal after delay", async () => {
|
2022-02-21 04:51:39 +00:00
|
|
|
const c = new AbortController();
|
2023-11-10 03:31:16 +00:00
|
|
|
const { promise, resolve } = Promise.withResolvers<string>();
|
|
|
|
const t = setTimeout(() => resolve("Hello"), 100);
|
2022-02-21 04:51:39 +00:00
|
|
|
const a = async function* () {
|
|
|
|
yield "Hello";
|
2023-11-10 03:31:16 +00:00
|
|
|
await promise;
|
2022-02-21 04:51:39 +00:00
|
|
|
yield "World";
|
|
|
|
};
|
|
|
|
setTimeout(() => c.abort(), 50);
|
|
|
|
const items: string[] = [];
|
2024-06-21 06:37:23 +00:00
|
|
|
const error = await assertRejects(
|
2022-02-21 04:51:39 +00:00
|
|
|
async () => {
|
|
|
|
for await (const item of abortable(a(), c.signal)) {
|
|
|
|
items.push(item);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
DOMException,
|
2024-06-21 06:37:23 +00:00
|
|
|
"The signal has been aborted",
|
2022-02-21 04:51:39 +00:00
|
|
|
);
|
2024-06-21 06:37:23 +00:00
|
|
|
assertEquals(error.name, "AbortError");
|
2022-02-21 04:51:39 +00:00
|
|
|
assertEquals(items, ["Hello"]);
|
|
|
|
clearTimeout(t);
|
|
|
|
});
|
|
|
|
|
2023-12-18 22:29:13 +00:00
|
|
|
Deno.test("abortable.AsyncIterable() handles already aborted signal", async () => {
|
2022-02-21 04:51:39 +00:00
|
|
|
const c = new AbortController();
|
2023-11-10 03:31:16 +00:00
|
|
|
const { promise, resolve } = Promise.withResolvers<string>();
|
|
|
|
const t = setTimeout(() => resolve("Hello"), 100);
|
2022-02-21 04:51:39 +00:00
|
|
|
const a = async function* () {
|
|
|
|
yield "Hello";
|
2023-11-10 03:31:16 +00:00
|
|
|
await promise;
|
2022-02-21 04:51:39 +00:00
|
|
|
yield "World";
|
|
|
|
};
|
|
|
|
c.abort();
|
|
|
|
const items: string[] = [];
|
2024-06-21 06:37:23 +00:00
|
|
|
const error = await assertRejects(
|
2022-02-21 04:51:39 +00:00
|
|
|
async () => {
|
|
|
|
for await (const item of abortable(a(), c.signal)) {
|
|
|
|
items.push(item);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
DOMException,
|
2024-06-21 06:37:23 +00:00
|
|
|
"The signal has been aborted",
|
2022-02-21 04:51:39 +00:00
|
|
|
);
|
2024-06-21 06:37:23 +00:00
|
|
|
assertEquals(error.name, "AbortError");
|
2022-02-21 04:51:39 +00:00
|
|
|
assertEquals(items, []);
|
|
|
|
clearTimeout(t);
|
|
|
|
});
|
2024-08-01 00:25:42 +00:00
|
|
|
|
|
|
|
Deno.test("abortable.AsyncIterable() calls return before throwing", async () => {
|
|
|
|
const c = new AbortController();
|
|
|
|
let returnCalled = false;
|
2024-08-01 05:30:49 +00:00
|
|
|
let timeoutId: number;
|
2024-08-01 00:25:42 +00:00
|
|
|
const iterable: AsyncIterable<string> = {
|
|
|
|
[Symbol.asyncIterator]: () => ({
|
|
|
|
next: () =>
|
2024-08-01 05:30:49 +00:00
|
|
|
new Promise((resolve) => {
|
|
|
|
timeoutId = setTimeout(
|
|
|
|
() => resolve({ value: "Hello", done: false }),
|
|
|
|
1,
|
|
|
|
);
|
|
|
|
}),
|
2024-08-01 00:25:42 +00:00
|
|
|
return: () => {
|
|
|
|
returnCalled = true;
|
|
|
|
return Promise.resolve({ value: undefined, done: true });
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
};
|
|
|
|
setTimeout(() => c.abort(), 1);
|
|
|
|
const items: string[] = [];
|
|
|
|
const error = await assertRejects(
|
|
|
|
async () => {
|
|
|
|
for await (const item of abortable(iterable, c.signal)) {
|
|
|
|
items.push(item);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
DOMException,
|
|
|
|
"The signal has been aborted",
|
|
|
|
);
|
|
|
|
assertEquals(returnCalled, true);
|
|
|
|
assertEquals(error.name, "AbortError");
|
|
|
|
assertEquals(items, []);
|
2024-08-01 05:30:49 +00:00
|
|
|
clearTimeout(timeoutId!);
|
2024-08-01 00:25:42 +00:00
|
|
|
});
|
2024-08-05 05:31:35 +00:00
|
|
|
|
|
|
|
Deno.test("abortable.AsyncIterable() behaves just like original when not aborted", async () => {
|
|
|
|
async function* gen() {
|
|
|
|
yield 1;
|
|
|
|
yield await Promise.resolve(2);
|
|
|
|
yield 3;
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
const normalIterator = gen();
|
|
|
|
const abortController = new AbortController();
|
|
|
|
const abortableIterator = abortable(gen(), abortController.signal);
|
|
|
|
|
|
|
|
assertEquals(await abortableIterator.next(), await normalIterator.next());
|
|
|
|
assertEquals(await abortableIterator.next(), await normalIterator.next());
|
|
|
|
assertEquals(await abortableIterator.next(), await normalIterator.next());
|
|
|
|
assertEquals(await abortableIterator.next(), await normalIterator.next());
|
|
|
|
assertEquals(await abortableIterator.next(), await normalIterator.next());
|
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("abortable.AsyncIterable() behaves just like original when return is called", async () => {
|
|
|
|
async function* gen() {
|
|
|
|
yield 1;
|
|
|
|
yield await Promise.resolve(2);
|
|
|
|
yield 3;
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
const normalIterator = gen();
|
|
|
|
const abortController = new AbortController();
|
|
|
|
const abortableIterator = abortable(gen(), abortController.signal);
|
|
|
|
|
|
|
|
assertEquals(
|
|
|
|
await abortableIterator.next(123),
|
|
|
|
await normalIterator.next(123),
|
|
|
|
);
|
|
|
|
assertEquals(
|
|
|
|
await abortableIterator.return(321),
|
|
|
|
await normalIterator.return(321),
|
|
|
|
);
|
|
|
|
assertEquals(await abortableIterator.next(), await normalIterator.next());
|
|
|
|
});
|