mirror of
https://github.com/denoland/std.git
synced 2024-11-21 20:50:22 +00:00
test(async): improve test coverage (#4567)
This commit is contained in:
parent
7396d36ce7
commit
61183bcbcc
@ -1,6 +1,15 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
// This `reason` comes from `AbortSignal` thus must be `any`.
|
||||
// deno-lint-ignore no-explicit-any
|
||||
export function createAbortError(reason?: any): DOMException {
|
||||
return new DOMException(
|
||||
reason ? `Aborted: ${reason}` : "Aborted",
|
||||
"AbortError",
|
||||
);
|
||||
}
|
||||
|
||||
export function exponentialBackoffWithJitter(
|
||||
cap: number,
|
||||
base: number,
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
import { exponentialBackoffWithJitter } from "./_util.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
import { createAbortError, exponentialBackoffWithJitter } from "./_util.ts";
|
||||
import { assertEquals, assertInstanceOf } from "../assert/mod.ts";
|
||||
|
||||
// test util to ensure deterministic results during testing of backoff function by polyfilling Math.random
|
||||
function prngMulberry32(seed: number) {
|
||||
@ -50,3 +50,31 @@ Deno.test("exponentialBackoffWithJitter()", () => {
|
||||
assertEquals(results as typeof row, row);
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("createAbortError()", () => {
|
||||
const error = createAbortError();
|
||||
assertInstanceOf(error, DOMException);
|
||||
assertEquals(error.name, "AbortError");
|
||||
assertEquals(error.message, "Aborted");
|
||||
});
|
||||
|
||||
Deno.test("createAbortError() handles aborted signal with reason", () => {
|
||||
const c = new AbortController();
|
||||
c.abort("Expected Reason");
|
||||
const error = createAbortError(c.signal.reason);
|
||||
assertInstanceOf(error, DOMException);
|
||||
assertEquals(error.name, "AbortError");
|
||||
assertEquals(error.message, "Aborted: Expected Reason");
|
||||
});
|
||||
|
||||
Deno.test("createAbortError() handles aborted signal without reason", () => {
|
||||
const c = new AbortController();
|
||||
c.abort();
|
||||
const error = createAbortError(c.signal.reason);
|
||||
assertInstanceOf(error, DOMException);
|
||||
assertEquals(error.name, "AbortError");
|
||||
assertEquals(
|
||||
error.message,
|
||||
"Aborted: AbortError: The signal has been aborted",
|
||||
);
|
||||
});
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
import { createAbortError } from "./_util.ts";
|
||||
|
||||
/**
|
||||
* Make {@linkcode Promise} abortable with the given signal.
|
||||
*
|
||||
@ -145,12 +147,3 @@ export async function* abortableAsyncIterable<T>(
|
||||
yield value;
|
||||
}
|
||||
}
|
||||
|
||||
// This `reason` comes from `AbortSignal` thus must be `any`.
|
||||
// deno-lint-ignore no-explicit-any
|
||||
function createAbortError(reason?: any): DOMException {
|
||||
return new DOMException(
|
||||
reason ? `Aborted: ${reason}` : "Aborted",
|
||||
"AbortError",
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { assertEquals, assertStrictEquals } from "../assert/mod.ts";
|
||||
import { debounce, type DebouncedFunction } from "./debounce.ts";
|
||||
import { delay } from "./delay.ts";
|
||||
|
||||
Deno.test("debounce() handles called", async function () {
|
||||
Deno.test("debounce() handles called", async () => {
|
||||
let called = 0;
|
||||
const d = debounce(() => called++, 100);
|
||||
d();
|
||||
@ -16,7 +16,7 @@ Deno.test("debounce() handles called", async function () {
|
||||
assertEquals(d.pending, false);
|
||||
});
|
||||
|
||||
Deno.test("debounce() handles cancelled", async function () {
|
||||
Deno.test("debounce() handles cancelled", async () => {
|
||||
let called = 0;
|
||||
const d = debounce(() => called++, 100);
|
||||
d();
|
||||
@ -30,7 +30,7 @@ Deno.test("debounce() handles cancelled", async function () {
|
||||
assertEquals(d.pending, false);
|
||||
});
|
||||
|
||||
Deno.test("debounce() handles flush", function () {
|
||||
Deno.test("debounce() handles flush", () => {
|
||||
let called = 0;
|
||||
const d = debounce(() => called++, 100);
|
||||
d();
|
||||
@ -43,7 +43,7 @@ Deno.test("debounce() handles flush", function () {
|
||||
assertEquals(d.pending, false);
|
||||
});
|
||||
|
||||
Deno.test("debounce() handles params and context", async function () {
|
||||
Deno.test("debounce() handles params and context", async () => {
|
||||
const params: Array<string | number> = [];
|
||||
const d: DebouncedFunction<[string, number]> = debounce(
|
||||
function (param1: string, param2: number) {
|
||||
@ -66,7 +66,7 @@ Deno.test("debounce() handles params and context", async function () {
|
||||
assertEquals(d.pending, false);
|
||||
});
|
||||
|
||||
Deno.test("debounce() handles number and string types", async function () {
|
||||
Deno.test("debounce() handles number and string types", async () => {
|
||||
const params: Array<string> = [];
|
||||
const fn = (param: string) => params.push(param);
|
||||
const d: DebouncedFunction<[string]> = debounce(fn, 100);
|
||||
|
@ -36,7 +36,7 @@ export interface DelayOptions {
|
||||
* ```
|
||||
*/
|
||||
export function delay(ms: number, options: DelayOptions = {}): Promise<void> {
|
||||
const { signal, persistent } = options;
|
||||
const { signal, persistent = true } = options;
|
||||
if (signal?.aborted) return Promise.reject(signal.reason);
|
||||
return new Promise((resolve, reject) => {
|
||||
const abort = () => {
|
||||
|
@ -2,10 +2,12 @@
|
||||
import { delay } from "./delay.ts";
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
assertInstanceOf,
|
||||
assertRejects,
|
||||
assertStrictEquals,
|
||||
} from "../assert/mod.ts";
|
||||
import { assertSpyCalls, stub } from "../testing/mock.ts";
|
||||
|
||||
// https://dom.spec.whatwg.org/#interface-AbortSignal
|
||||
function assertIsDefaultAbortReason(reason: unknown) {
|
||||
@ -13,7 +15,7 @@ function assertIsDefaultAbortReason(reason: unknown) {
|
||||
assertStrictEquals(reason.name, "AbortError");
|
||||
}
|
||||
|
||||
Deno.test("delay()", async function () {
|
||||
Deno.test("delay()", async () => {
|
||||
const start = new Date();
|
||||
const delayedPromise = delay(100);
|
||||
const result = await delayedPromise;
|
||||
@ -22,7 +24,7 @@ Deno.test("delay()", async function () {
|
||||
assert(diff >= 100);
|
||||
});
|
||||
|
||||
Deno.test("delay() handles abort", async function () {
|
||||
Deno.test("delay() handles abort", async () => {
|
||||
const start = new Date();
|
||||
const abort = new AbortController();
|
||||
const { signal } = abort;
|
||||
@ -34,7 +36,7 @@ Deno.test("delay() handles abort", async function () {
|
||||
assertIsDefaultAbortReason(cause);
|
||||
});
|
||||
|
||||
Deno.test("delay() checks abort reason", async function (ctx) {
|
||||
Deno.test("delay() checks abort reason", async (ctx) => {
|
||||
async function assertRejectsReason(reason: unknown) {
|
||||
const start = new Date();
|
||||
const abort = new AbortController();
|
||||
@ -69,7 +71,7 @@ Deno.test("delay() checks abort reason", async function (ctx) {
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test("delay() handles non-aborted signal", async function () {
|
||||
Deno.test("delay() handles non-aborted signal", async () => {
|
||||
const start = new Date();
|
||||
const abort = new AbortController();
|
||||
const { signal } = abort;
|
||||
@ -80,7 +82,7 @@ Deno.test("delay() handles non-aborted signal", async function () {
|
||||
assert(diff >= 100);
|
||||
});
|
||||
|
||||
Deno.test("delay() handles aborted signal after delay", async function () {
|
||||
Deno.test("delay() handles aborted signal after delay", async () => {
|
||||
const start = new Date();
|
||||
const abort = new AbortController();
|
||||
const { signal } = abort;
|
||||
@ -92,7 +94,7 @@ Deno.test("delay() handles aborted signal after delay", async function () {
|
||||
assert(diff >= 100);
|
||||
});
|
||||
|
||||
Deno.test("delay() handles already aborted signal", async function () {
|
||||
Deno.test("delay() handles already aborted signal", async () => {
|
||||
const start = new Date();
|
||||
const abort = new AbortController();
|
||||
abort.abort();
|
||||
@ -103,3 +105,35 @@ Deno.test("delay() handles already aborted signal", async function () {
|
||||
assert(diff < 100);
|
||||
assertIsDefaultAbortReason(cause);
|
||||
});
|
||||
|
||||
Deno.test("delay() handles persitent option", async () => {
|
||||
using unrefTimer = stub(Deno, "unrefTimer");
|
||||
await delay(100, { persistent: false });
|
||||
assertSpyCalls(unrefTimer, 1);
|
||||
});
|
||||
|
||||
Deno.test("delay() handles persistent option with reference error", async () => {
|
||||
using unrefTimer = stub(Deno, "unrefTimer", () => {
|
||||
throw new ReferenceError();
|
||||
});
|
||||
await delay(100, { persistent: false });
|
||||
assertSpyCalls(unrefTimer, 1);
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "delay() handles persistent option with error",
|
||||
async fn() {
|
||||
using unrefTimer = stub(Deno, "unrefTimer", () => {
|
||||
throw new Error("Error!");
|
||||
});
|
||||
try {
|
||||
await delay(100, { persistent: false });
|
||||
} catch (e) {
|
||||
assert(e instanceof Error);
|
||||
assertEquals(e.message, "Error!");
|
||||
assertSpyCalls(unrefTimer, 1);
|
||||
}
|
||||
},
|
||||
sanitizeResources: false,
|
||||
sanitizeOps: false,
|
||||
});
|
||||
|
@ -82,7 +82,6 @@ export class MuxAsyncIterator<T> implements AsyncIterable<T> {
|
||||
for (const e of this.#throws) {
|
||||
throw e;
|
||||
}
|
||||
this.#throws.length = 0;
|
||||
}
|
||||
// Clear the `yields` list and reset the `signal` promise.
|
||||
this.#yields.length = 0;
|
||||
|
@ -25,7 +25,7 @@ class CustomAsyncIterable {
|
||||
}
|
||||
}
|
||||
|
||||
Deno.test("MuxAsyncIterator()", async function () {
|
||||
Deno.test("MuxAsyncIterator()", async () => {
|
||||
const mux = new MuxAsyncIterator<number>();
|
||||
mux.add(gen123());
|
||||
mux.add(gen456());
|
||||
@ -34,7 +34,27 @@ Deno.test("MuxAsyncIterator()", async function () {
|
||||
assertEquals(results, new Set([1, 2, 3, 4, 5, 6]));
|
||||
});
|
||||
|
||||
Deno.test("MuxAsyncIterator() takes async iterable as source", async function () {
|
||||
Deno.test("MuxAsyncIterator() works with no iterables", async () => {
|
||||
const mux = new MuxAsyncIterator<number>();
|
||||
const results = new Set(await Array.fromAsync(mux));
|
||||
assertEquals(results.size, 0);
|
||||
assertEquals(results, new Set([]));
|
||||
});
|
||||
|
||||
Deno.test("MuxAsyncIterator() clears iterables after successful iteration", async () => {
|
||||
const mux = new MuxAsyncIterator<number>();
|
||||
mux.add(gen123());
|
||||
mux.add(gen456());
|
||||
const results = new Set(await Array.fromAsync(mux));
|
||||
assertEquals(results.size, 6);
|
||||
assertEquals(results, new Set([1, 2, 3, 4, 5, 6]));
|
||||
mux.add(gen123());
|
||||
const results2 = new Set(await Array.fromAsync(mux));
|
||||
assertEquals(results2.size, 3);
|
||||
assertEquals(results2, new Set([1, 2, 3]));
|
||||
});
|
||||
|
||||
Deno.test("MuxAsyncIterator() takes async iterable as source", async () => {
|
||||
const mux = new MuxAsyncIterator<number>();
|
||||
mux.add(new CustomAsyncIterable());
|
||||
const results = new Set(await Array.fromAsync(mux));
|
||||
@ -42,16 +62,28 @@ Deno.test("MuxAsyncIterator() takes async iterable as source", async function ()
|
||||
assertEquals(results, new Set([1, 2, 3]));
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "MuxAsyncIterator() throws when the source throws",
|
||||
async fn() {
|
||||
const mux = new MuxAsyncIterator<number>();
|
||||
mux.add(gen123());
|
||||
mux.add(genThrows());
|
||||
await assertRejects(
|
||||
async () => await Array.fromAsync(mux),
|
||||
Error,
|
||||
"something went wrong",
|
||||
);
|
||||
},
|
||||
Deno.test("MuxAsyncIterator() throws when the source throws", async () => {
|
||||
const mux = new MuxAsyncIterator<number>();
|
||||
mux.add(gen123());
|
||||
mux.add(genThrows());
|
||||
await assertRejects(
|
||||
async () => await Array.fromAsync(mux),
|
||||
Error,
|
||||
"something went wrong",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("MuxAsyncIterator() doesn't clear iterables after throwing", async () => {
|
||||
const mux = new MuxAsyncIterator<number>();
|
||||
mux.add(genThrows());
|
||||
await assertRejects(
|
||||
async () => await Array.fromAsync(mux),
|
||||
Error,
|
||||
"something went wrong",
|
||||
);
|
||||
await assertRejects(
|
||||
async () => await Array.fromAsync(mux),
|
||||
Error,
|
||||
"something went wrong",
|
||||
);
|
||||
});
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
assertStringIncludes,
|
||||
} from "../assert/mod.ts";
|
||||
|
||||
Deno.test("pooledMap()", async function () {
|
||||
Deno.test("pooledMap()", async () => {
|
||||
const start = new Date();
|
||||
const results = pooledMap(
|
||||
2,
|
||||
@ -66,7 +66,7 @@ Deno.test("pooledMap() returns ordered items", async () => {
|
||||
assertEquals(returned, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
||||
});
|
||||
|
||||
Deno.test("pooledMap() checks browser compat", async function () {
|
||||
Deno.test("pooledMap() checks browser compat", async () => {
|
||||
// Simulates the environment where Symbol.asyncIterator is not available
|
||||
const asyncIterFunc = ReadableStream.prototype[Symbol.asyncIterator];
|
||||
// deno-lint-ignore no-explicit-any
|
||||
|
@ -15,7 +15,7 @@ function generateErroringFunction(errorsBeforeSucceeds: number) {
|
||||
};
|
||||
}
|
||||
|
||||
Deno.test("retry()", async function () {
|
||||
Deno.test("retry()", async () => {
|
||||
const threeErrors = generateErroringFunction(3);
|
||||
const result = await retry(threeErrors, {
|
||||
minTimeout: 100,
|
||||
@ -23,7 +23,7 @@ Deno.test("retry()", async function () {
|
||||
assertEquals(result, 3);
|
||||
});
|
||||
|
||||
Deno.test("retry() fails after max errors is passed", async function () {
|
||||
Deno.test("retry() fails after max errors is passed", async () => {
|
||||
const fiveErrors = generateErroringFunction(5);
|
||||
await assertRejects(() =>
|
||||
retry(fiveErrors, {
|
||||
@ -32,7 +32,7 @@ Deno.test("retry() fails after max errors is passed", async function () {
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("retry() waits four times by default", async function () {
|
||||
Deno.test("retry() waits four times by default", async () => {
|
||||
let callCount = 0;
|
||||
const onlyErrors = function () {
|
||||
callCount++;
|
||||
@ -56,7 +56,7 @@ Deno.test("retry() waits four times by default", async function () {
|
||||
|
||||
Deno.test(
|
||||
"retry() throws if minTimeout is less than maxTimeout",
|
||||
async function () {
|
||||
async () => {
|
||||
await assertRejects(() =>
|
||||
retry(() => {}, {
|
||||
minTimeout: 1000,
|
||||
@ -68,7 +68,7 @@ Deno.test(
|
||||
|
||||
Deno.test(
|
||||
"retry() throws if maxTimeout is less than 0",
|
||||
async function () {
|
||||
async () => {
|
||||
await assertRejects(() =>
|
||||
retry(() => {}, {
|
||||
maxTimeout: -1,
|
||||
@ -79,7 +79,7 @@ Deno.test(
|
||||
|
||||
Deno.test(
|
||||
"retry() throws if jitter is bigger than 1",
|
||||
async function () {
|
||||
async () => {
|
||||
await assertRejects(() =>
|
||||
retry(() => {}, {
|
||||
jitter: 2,
|
||||
@ -91,7 +91,7 @@ Deno.test(
|
||||
Deno.test("retry() checks backoff function timings", async (t) => {
|
||||
const originalMathRandom = Math.random;
|
||||
|
||||
await t.step("wait fixed times without jitter", async function () {
|
||||
await t.step("wait fixed times without jitter", async () => {
|
||||
using time = new FakeTime();
|
||||
let resolved = false;
|
||||
const checkResolved = async () => {
|
||||
|
Loading…
Reference in New Issue
Block a user