repos / starfx

a micro-mvc framework for react apps
git clone https://github.com/neurosnap/starfx.git

starfx / src / test
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});