release: WRNexusJS 0.6.0
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { createStoreContainer, defineStore } from "../src/index.ts";
|
||||
|
||||
const CounterStore = defineStore({
|
||||
name: "CounterStore",
|
||||
kind: "global" as const,
|
||||
createSharedState: () => ({ count: 0 }),
|
||||
createClientState: () => ({ viewport: 0 }),
|
||||
createServerState: () => ({ secret: "server-only" }),
|
||||
computed: { doubled: (state: Readonly<{ count: number }>) => state.count * 2 },
|
||||
actions: {
|
||||
increment: [
|
||||
{
|
||||
runtime: "client" as const,
|
||||
handler: ({ state }: any, amount = 1) => {
|
||||
state.count += amount;
|
||||
},
|
||||
},
|
||||
{
|
||||
runtime: "server" as const,
|
||||
handler: ({ state }: any, amount = 1) => {
|
||||
state.count += amount * 2;
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
test("isolates request-scoped server stores and excludes server state", async () => {
|
||||
const first = createStoreContainer({ runtime: "server", request: {} });
|
||||
const second = createStoreContainer({ runtime: "server", request: {} });
|
||||
const a = await first.use(CounterStore);
|
||||
const b = await second.use(CounterStore);
|
||||
await a.increment(2);
|
||||
expect(a.count).toBe(4);
|
||||
expect(a.doubled).toBe(8);
|
||||
expect(b.count).toBe(0);
|
||||
expect(first.serialize()).toEqual({ CounterStore: { count: 4 } });
|
||||
});
|
||||
|
||||
test("store state is readonly outside actions and supports snapshots/reset", async () => {
|
||||
const container = createStoreContainer({ runtime: "client" });
|
||||
const store = await container.use(CounterStore);
|
||||
expect(() => {
|
||||
(store.state as any).count = 5;
|
||||
}).toThrow("WRN-STORE-READONLY");
|
||||
await store.increment(3);
|
||||
expect(store.snapshot().count).toBe(3);
|
||||
store.reset();
|
||||
expect(store.count).toBe(0);
|
||||
});
|
||||
|
||||
test("HMR preserves compatible state and resets incompatible fields", async () => {
|
||||
const container = createStoreContainer({ runtime: "client" });
|
||||
const store = await container.use(CounterStore);
|
||||
await store.increment(2);
|
||||
const result = await container.hotUpdate(
|
||||
defineStore({
|
||||
...CounterStore,
|
||||
createSharedState: () => ({ count: 0, added: true }),
|
||||
} as any),
|
||||
);
|
||||
expect(result.preserved).toContain("count");
|
||||
});
|
||||
|
||||
test("store lifecycle hooks may update state and page stores dispose cleanly", async () => {
|
||||
const calls: string[] = [];
|
||||
const LifecycleStore = defineStore({
|
||||
name: "LifecycleStore",
|
||||
kind: "page" as const,
|
||||
createSharedState: () => ({ ready: false }),
|
||||
lifecycle: {
|
||||
clientInit: async ({ state }: any) => {
|
||||
calls.push("clientInit");
|
||||
state.ready = true;
|
||||
},
|
||||
dispose: async ({ state }: any) => {
|
||||
calls.push("dispose");
|
||||
state.ready = false;
|
||||
},
|
||||
},
|
||||
});
|
||||
const container = createStoreContainer({ runtime: "client", routeId: "/one" });
|
||||
const store = await container.use(LifecycleStore);
|
||||
expect(store.ready).toBe(true);
|
||||
await container.disposePageStores();
|
||||
expect(calls).toEqual(["clientInit", "dispose"]);
|
||||
});
|
||||
Reference in New Issue
Block a user