Eric Bower
·
2025-06-06
store.test.ts
1import {
2 type Operation,
3 type Result,
4 createScope,
5 parallel,
6 put,
7 take,
8} from "../index.js";
9import {
10 StoreContext,
11 StoreUpdateContext,
12 createStore,
13 updateStore,
14} from "../store/index.js";
15import { expect, test } from "../test.js";
16
17interface User {
18 id: string;
19 name: string;
20}
21
22interface State {
23 users: { [key: string]: User };
24 theme: string;
25 token: string;
26 dev: boolean;
27}
28
29function findUserById(state: State, { id }: { id: string }) {
30 return state.users[id];
31}
32
33function findUsers(state: State) {
34 return state.users;
35}
36
37interface UpdateUserProps {
38 id: string;
39 name: string;
40}
41
42const updateUser =
43 ({ id, name }: UpdateUserProps) =>
44 (state: State) => {
45 // use selectors to find the data you want to mutate
46 const user = findUserById(state, { id });
47 user.name = name;
48
49 // different ways to update a `zod` record
50 const users = findUsers(state);
51 users[id].name = name;
52
53 (users as any)[2] = undefined;
54 users[3] = { id: "", name: "" };
55
56 // or mutate state directly without selectors
57 state.dev = true;
58 };
59
60test("update store and receives update from channel `StoreUpdateContext`", async () => {
61 expect.assertions(1);
62 const [scope] = createScope();
63 const initialState: Partial<State> = {
64 users: { 1: { id: "1", name: "testing" }, 2: { id: "2", name: "wow" } },
65 dev: false,
66 };
67 createStore({ scope, initialState });
68 let store;
69 await scope.run(function* (): Operation<Result<void>[]> {
70 const result = yield* parallel([
71 function* () {
72 store = yield* StoreContext.expect();
73 const chan = yield* StoreUpdateContext.expect();
74 const msgList = yield* chan;
75 yield* msgList.next();
76 },
77 function* () {
78 yield* updateStore(updateUser({ id: "1", name: "eric" }));
79 },
80 ]);
81 return yield* result;
82 });
83 expect((store as any)?.getState()).toEqual({
84 users: { 1: { id: "1", name: "eric" }, 3: { id: "", name: "" } },
85 dev: true,
86 });
87});
88
89test("update store and receives update from `subscribe()`", async () => {
90 expect.assertions(1);
91 const initialState: Partial<State> = {
92 users: { 1: { id: "1", name: "testing" }, 2: { id: "2", name: "wow" } },
93 dev: false,
94 theme: "",
95 token: "",
96 };
97 const store = createStore({ initialState });
98
99 store.subscribe(() => {
100 expect(store.getState()).toEqual({
101 users: { 1: { id: "1", name: "eric" }, 3: { id: "", name: "" } },
102 dev: true,
103 theme: "",
104 token: "",
105 });
106 });
107
108 await store.run(function* () {
109 yield* updateStore(updateUser({ id: "1", name: "eric" }));
110 });
111});
112
113test("emit Action and update store", async () => {
114 expect.assertions(1);
115 const initialState: Partial<State> = {
116 users: { 1: { id: "1", name: "testing" }, 2: { id: "2", name: "wow" } },
117 dev: false,
118 theme: "",
119 token: "",
120 };
121 const store = createStore({ initialState });
122
123 await store.run(function* (): Operation<void> {
124 const result = yield* parallel([
125 function* (): Operation<void> {
126 const action = yield* take<UpdateUserProps>("UPDATE_USER");
127 yield* updateStore(updateUser(action.payload));
128 },
129 function* () {
130 yield* put({ type: "UPDATE_USER", payload: { id: "1", name: "eric" } });
131 },
132 ]);
133 yield* result;
134 });
135
136 expect(store.getState()).toEqual({
137 users: { 1: { id: "1", name: "eric" }, 3: { id: "", name: "" } },
138 theme: "",
139 token: "",
140 dev: true,
141 });
142});
143
144test("resets store", async () => {
145 expect.assertions(2);
146 const initialState: Partial<State> = {
147 users: { 1: { id: "1", name: "testing" }, 2: { id: "2", name: "wow" } },
148 dev: false,
149 theme: "",
150 token: "",
151 };
152 const store = createStore({ initialState });
153
154 await store.run(function* () {
155 yield* store.update((s) => {
156 s.users = { 3: { id: "3", name: "hehe" } };
157 s.dev = true;
158 s.theme = "darkness";
159 });
160 });
161
162 expect(store.getState()).toEqual({
163 users: { 3: { id: "3", name: "hehe" } },
164 theme: "darkness",
165 token: "",
166 dev: true,
167 });
168
169 await store.run(store.reset(["users"]));
170
171 expect(store.getState()).toEqual({
172 users: { 3: { id: "3", name: "hehe" } },
173 dev: false,
174 theme: "",
175 token: "",
176 });
177});