~james/core

core/web/src/lib/action.test.ts -rw-r--r-- 1.5 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 15 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import { describe, expect, it } from "vitest";
import { createAction } from "#lib/action.svelte.ts";

describe("createAction", () => {
	it("derives ergonomic projections from one state", async () => {
		let resolve!: (value: string) => void;
		const action = createAction(() => new Promise<string>((done) => (resolve = done)));

		expect(action.loading).toBe(false);
		expect(action.data).toBeUndefined();
		expect(action.error).toBeUndefined();

		const running = action.run();
		expect(action.loading).toBe(true);

		resolve("done");
		await running;
		expect(action.data).toBe("done");
	});

	it("converts failures", async () => {
		const action = createAction(
			async () => {
				throw new Error("nope");
			},
			(cause) => (cause instanceof Error ? cause.message : "unknown")
		);

		await action.run();
		expect(action.error).toBe("nope");
	});

	it("ignores an older result after a newer run starts", async () => {
		const resolvers: Array<(value: string) => void> = [];
		const names: string[] = [];
		const action = createAction(
			(name: string) =>
				new Promise<string>((resolve) => {
					names.push(name);
					resolvers.push(resolve);
				})
		);
		const first = action.run("first");
		const second = action.run("second");
		expect(names).toEqual(["first", "second"]);
		expect(action.args).toEqual(["second"]);

		resolvers[0]("stale");
		await first;
		expect(action.loading).toBe(true);

		resolvers[1]("current");
		await second;
		expect(action.data).toBe("current");
		expect(action.args).toBeUndefined();
	});
});