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