Files
wehub-resource-sync e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:40:13 +08:00

159 lines
4.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { GorpServer } from "../src/GorpServer";
import type { GorpMessage } from "../src/Gorp";
type State = { count: number; items: Record<string, { name: string }> };
type Command =
| { type: "addItem"; id: string; name: string }
| { type: "incCount" };
const initial = (): State => ({ count: 0, items: {} });
const flushMicrotasks = () => new Promise<void>((r) => queueMicrotask(r));
function recordSubscriber() {
const envs: GorpMessage[] = [];
return {
envs,
callback: (env: GorpMessage) =>
envs.push({ ops: env.ops.slice(), ack: env.ack }),
};
}
describe("GorpServer — state writes", () => {
it("emits a set op for a deep state write via the proxy", async () => {
const server = new GorpServer<State, Command>({
initialState: initial(),
mutator: () => {},
});
const sub = recordSubscriber();
server.subscribe(sub.callback);
server.state.count = 5;
await flushMicrotasks();
expect(sub.envs).toEqual([
{ ops: [{ type: "set", path: ["count"], value: 5 }], ack: undefined },
]);
});
it("assigning to state emits a single root set op", async () => {
const server = new GorpServer<State, Command>({
initialState: initial(),
mutator: () => {},
});
const sub = recordSubscriber();
server.subscribe(sub.callback);
const next: State = { count: 99, items: { x: { name: "ex" } } };
server.state = next;
await flushMicrotasks();
expect(sub.envs[0]!.ops).toEqual([{ type: "set", path: [], value: next }]);
});
it("coalesces multiple writes in one tick into a single envelope", async () => {
const server = new GorpServer<State, Command>({
initialState: initial(),
mutator: () => {},
});
const sub = recordSubscriber();
server.subscribe(sub.callback);
server.state.count += 1;
server.state.items.a = { name: "alpha" };
await flushMicrotasks();
expect(sub.envs).toHaveLength(1);
expect(sub.envs[0]!.ops).toHaveLength(2);
});
});
describe("GorpServer — receive", () => {
it("runs the handler and reports ack: 0 after one receive", async () => {
const seen: Command[] = [];
const server = new GorpServer<State, Command>({
initialState: initial(),
mutator: (_state, cmd) => {
seen.push(cmd);
},
});
const sub = recordSubscriber();
server.subscribe(sub.callback);
server.receive({ type: "incCount" });
await flushMicrotasks();
expect(seen).toEqual([{ type: "incCount" }]);
expect(sub.envs[0]!.ack).toBe(0);
});
it("bundles handler-driven ops and ack in the same envelope", async () => {
const server = new GorpServer<State, Command>({
initialState: initial(),
mutator: (_state, cmd) => {
if (cmd.type === "addItem") {
server.state.items[cmd.id] = { name: cmd.name };
}
},
});
const sub = recordSubscriber();
server.subscribe(sub.callback);
server.receive({ type: "addItem", id: "a", name: "alpha" });
await flushMicrotasks();
expect(sub.envs).toHaveLength(1);
expect(sub.envs[0]!.ack).toBe(0);
expect(sub.envs[0]!.ops).toEqual([
{ type: "set", path: ["items", "a"], value: { name: "alpha" } },
]);
});
it("ack advances monotonically across receives in one tick", async () => {
const server = new GorpServer<State, Command>({
initialState: initial(),
mutator: () => {},
});
const sub = recordSubscriber();
server.subscribe(sub.callback);
server.receive({ type: "incCount" });
server.receive({ type: "incCount" });
server.receive({ type: "incCount" });
await flushMicrotasks();
expect(sub.envs).toHaveLength(1);
expect(sub.envs[0]!.ack).toBe(2);
});
it("ack persists across flushes (cumulative)", async () => {
const server = new GorpServer<State, Command>({
initialState: initial(),
mutator: () => {},
});
const sub = recordSubscriber();
server.subscribe(sub.callback);
server.receive({ type: "incCount" });
await flushMicrotasks();
expect(sub.envs[0]!.ack).toBe(0);
server.receive({ type: "incCount" });
await flushMicrotasks();
expect(sub.envs[1]!.ack).toBe(1);
});
});
describe("GorpServer — subscribe", () => {
it("unsubscribes cleanly", async () => {
const server = new GorpServer<State, Command>({
initialState: initial(),
mutator: () => {},
});
const sub = recordSubscriber();
const unsubscribe = server.subscribe(sub.callback);
unsubscribe();
server.state.count = 1;
await flushMicrotasks();
expect(sub.envs).toHaveLength(0);
});
it("suppresses no-op flushes (no ops, ack unchanged)", async () => {
const server = new GorpServer<State, Command>({
initialState: initial(),
mutator: () => {},
});
const sub = recordSubscriber();
server.subscribe(sub.callback);
await flushMicrotasks();
expect(sub.envs).toHaveLength(0);
});
});