1import { useMutate } from "@clo/react-mutation";
2import { assertEquals, assertStrictEquals } from "@std/assert";
3import { act, render, screen } from "@testing-library/react";
4import { userEvent } from "@testing-library/user-event";
5import { test, vi } from "vitest";
6import { createTestMutationClient, IterableStream } from "./share.ts";
7
8test("runWithOptions should allow react hook to do local handling", async () => {
9 vi.useFakeTimers({ shouldAdvanceTime: true });
10 const user = userEvent.setup({ delay: null });
11
12 const { client, successMessages, errorMessages } = createTestMutationClient();
13 const s = new IterableStream<string>();
14
15 const mutTest = client.define({
16 id: "test-1",
17 mutate: async () => {
18 return (await s.next()).value;
19 },
20 optimistic: ({ onSuccess }) => {
21 onSuccess(() => {});
22 },
23 refetchOnSuccess: false,
24 describe: "Test the action",
25 describeResult: "Tested the action",
26 });
27
28 let renders: Array<{ status: string; result: string | undefined }> = [];
29 function TestComponent() {
30 const { runWithOptions, status, result } = useMutate(mutTest);
31 renders.push({ status, result });
32 return (
33 <button
34 data-testid="a"
35 onClick={() => {
36 runWithOptions({ onSuccessData: () => {} });
37 }}
38 >
39 button
40 </button>
41 );
42 }
43
44 render(<TestComponent />);
45 // initial state
46 assertEquals(renders, [{ status: "idle", result: undefined }]);
47 assertEquals(successMessages, []);
48 assertEquals(errorMessages, []);
49 renders = [];
50 vi.runAllTimers();
51
52 // mutation 1 - success
53 await act(() => user.click(screen.getByTestId("a")));
54 assertEquals(renders, [{ status: "mutating", result: undefined }]);
55 renders = [];
56 await act(async () => {
57 s.push("ok");
58 vi.advanceTimersByTime(100);
59 });
60 assertEquals(successMessages, ["Tested the action"]);
61 assertEquals(errorMessages, []);
62 assertEquals(renders, [{ status: "success", result: "ok" }]);
63 renders = [];
64 await act(async () => {
65 vi.advanceTimersByTime(10000);
66 });
67 assertEquals(renders, []);
68 renders = [];
69});
70
71test("runAsHeadlessPromise rejects with the underlying error", async () => {
72 const { client, errorMessages } = createTestMutationClient();
73 const s = new IterableStream<string>();
74 const error = new Error("damn!");
75 const localErrors: unknown[] = [];
76
77 const mutTest = client.define({
78 id: "test-2",
79 mutate: async () => {
80 return (await s.next()).value;
81 },
82 optimistic: () => {},
83 describe: "Test the action",
84 describeResult: "Tested the action",
85 });
86
87 const promise = mutTest.runAsHeadlessPromise({
88 onError: (error) => localErrors.push(error),
89 });
90 s.throw(error);
91
92 let caught: unknown;
93 try {
94 await promise;
95 } catch (error) {
96 caught = error;
97 }
98
99 assertStrictEquals(caught, error);
100 assertEquals(localErrors, [error]);
101 assertEquals(errorMessages, []);
102});