Eric Bower
·
2025-06-06
schema.test.ts
1import { createSchema, createStore, select, slice } from "../store/index.js";
2import { expect, test } from "../test.js";
3
4interface User {
5 id: string;
6 name: string;
7}
8interface UserWithRoles extends User {
9 roles: string[];
10}
11
12const emptyUser = { id: "", name: "" };
13
14test("default schema", async () => {
15 const [schema, initialState] = createSchema();
16 const store = createStore({ initialState });
17 expect(store.getState()).toEqual({
18 cache: {},
19 loaders: {},
20 });
21
22 await store.run(function* () {
23 yield* schema.update(schema.loaders.start({ id: "1" }));
24 yield* schema.update(schema.cache.add({ "1": true }));
25 });
26
27 expect(schema.cache.selectTable(store.getState())).toEqual({
28 "1": true,
29 });
30 expect(
31 schema.loaders.selectById(store.getState(), { id: "1" }).status,
32 "loading",
33 );
34});
35
36test("general types and functionality", async () => {
37 expect.assertions(8);
38 const [db, initialState] = createSchema({
39 users: slice.table<User>({
40 initialState: { "1": { id: "1", name: "wow" } },
41 empty: emptyUser,
42 }),
43 token: slice.str(),
44 counter: slice.num(),
45 dev: slice.any<boolean>(false),
46 currentUser: slice.obj<User>(emptyUser),
47 cache: slice.table({ empty: {} }),
48 loaders: slice.loaders(),
49 });
50 const store = createStore({ initialState });
51
52 expect(store.getState()).toEqual({
53 users: { "1": { id: "1", name: "wow" } },
54 token: "",
55 counter: 0,
56 dev: false,
57 currentUser: { id: "", name: "" },
58 cache: {},
59 loaders: {},
60 });
61 const userMap = db.users.selectTable(store.getState());
62 expect(userMap).toEqual({ "1": { id: "1", name: "wow" } });
63
64 await store.run(function* () {
65 yield* db.update([
66 db.users.add({ "2": { id: "2", name: "bob" } }),
67 db.users.patch({ "1": { name: "zzz" } }),
68 ]);
69
70 const users = yield* select(db.users.selectTable);
71 expect(users).toEqual({
72 "1": { id: "1", name: "zzz" },
73 "2": { id: "2", name: "bob" },
74 });
75
76 yield* db.update(db.counter.increment());
77 const counter = yield* select(db.counter.select);
78 expect(counter).toBe(1);
79
80 yield* db.update(db.currentUser.update({ key: "name", value: "vvv" }));
81 const curUser = yield* select(db.currentUser.select);
82 expect(curUser).toEqual({ id: "", name: "vvv" });
83
84 yield* db.update(db.loaders.start({ id: "fetch-users" }));
85 const fetchLoader = yield* select(db.loaders.selectById, {
86 id: "fetch-users",
87 });
88 expect(fetchLoader.id).toBe("fetch-users");
89 expect(fetchLoader.status).toBe("loading");
90 expect(fetchLoader.lastRun).not.toBe(0);
91 });
92});
93
94test("can work with a nested object", async () => {
95 expect.assertions(3);
96 const [db, initialState] = createSchema({
97 currentUser: slice.obj<UserWithRoles>({ id: "", name: "", roles: [] }),
98 cache: slice.table({ empty: {} }),
99 loaders: slice.loaders(),
100 });
101 const store = createStore({ initialState });
102 await store.run(function* () {
103 yield* db.update(db.currentUser.update({ key: "name", value: "vvv" }));
104 const curUser = yield* select(db.currentUser.select);
105 expect(curUser).toEqual({ id: "", name: "vvv", roles: [] });
106
107 yield* db.update(db.currentUser.update({ key: "roles", value: ["admin"] }));
108 const curUser2 = yield* select(db.currentUser.select);
109 expect(curUser2).toEqual({ id: "", name: "vvv", roles: ["admin"] });
110
111 yield* db.update(
112 db.currentUser.update({ key: "roles", value: ["admin", "users"] }),
113 );
114 const curUser3 = yield* select(db.currentUser.select);
115 expect(curUser3).toEqual({
116 id: "",
117 name: "vvv",
118 roles: ["admin", "users"],
119 });
120 });
121});