Eric Bower
·
2025-06-06
take-helper.test.ts
1import { spawn } from "effection";
2import type { AnyAction } from "../index.js";
3import { sleep, take, takeEvery, takeLatest, takeLeading } from "../index.js";
4import { createStore } from "../store/index.js";
5import { expect, test } from "../test.js";
6
7test("should cancel previous tasks and only use latest", async () => {
8 const actual: string[] = [];
9 function* worker(action: AnyAction) {
10 if (action.payload !== "3") {
11 yield* sleep(3000);
12 }
13 actual.push(action.payload);
14 }
15
16 function* root() {
17 const task = yield* spawn(() => takeLatest("ACTION", worker));
18 yield* take("CANCEL_WATCHER");
19 yield* task.halt();
20 }
21 const store = createStore({ initialState: {} });
22 const task = store.run(root);
23
24 store.dispatch({ type: "ACTION", payload: "1" });
25 store.dispatch({ type: "ACTION", payload: "2" });
26 store.dispatch({ type: "ACTION", payload: "3" });
27 store.dispatch({ type: "CANCEL_WATCHER" });
28
29 await task;
30
31 expect(actual).toEqual(["3"]);
32});
33
34test("should keep first action and discard the rest", async () => {
35 let called = 0;
36 const actual: string[] = [];
37 function* worker(action: AnyAction) {
38 called += 1;
39 yield* sleep(100);
40 actual.push(action.payload);
41 }
42
43 function* root() {
44 const task = yield* spawn(() => takeLeading("ACTION", worker));
45 yield* sleep(150);
46 yield* task.halt();
47 }
48 const store = createStore({ initialState: {} });
49 const task = store.run(root);
50
51 store.dispatch({ type: "ACTION", payload: "1" });
52 store.dispatch({ type: "ACTION", payload: "2" });
53 store.dispatch({ type: "ACTION", payload: "3" });
54
55 await task;
56
57 expect(actual).toEqual(["1"]);
58 expect(called).toEqual(1);
59});
60
61test("should receive all actions", async () => {
62 const loop = 10;
63 const actual: string[][] = [];
64
65 function* root() {
66 const task = yield* spawn(() =>
67 takeEvery("ACTION", (action) => worker("a1", "a2", action)),
68 );
69 yield* take("CANCEL_WATCHER");
70 yield* task.halt();
71 }
72
73 // deno-lint-ignore require-yield
74 function* worker(arg1: string, arg2: string, action: AnyAction) {
75 actual.push([arg1, arg2, action.payload]);
76 }
77
78 const store = createStore({ initialState: {} });
79 const task = store.run(root);
80
81 for (let i = 1; i <= loop / 2; i += 1) {
82 store.dispatch({
83 type: "ACTION",
84 payload: i,
85 });
86 }
87
88 // no further task should be forked after this
89 store.dispatch({
90 type: "CANCEL_WATCHER",
91 });
92
93 for (let i = loop / 2 + 1; i <= loop; i += 1) {
94 store.dispatch({
95 type: "ACTION",
96 payload: i,
97 });
98 }
99 await task;
100
101 expect(actual).toEqual([
102 ["a1", "a2", 1],
103 ["a1", "a2", 2],
104 ["a1", "a2", 3],
105 ["a1", "a2", 4],
106 ["a1", "a2", 5],
107 ]);
108});