state-event-target
Version:
Primary state with event-driven replicas.
110 lines (87 loc) • 3.21 kB
text/typescript
import { describe, it, expect, vi } from "vitest";
import { KVDataEventTarget } from "../src/KVDataEventTarget";
describe("KVDataEventTarget", () => {
it("should initialize with entries", () => {
const simpleStore = new KVDataEventTarget<string, number>([
["key1", 100],
["key2", 200],
]);
expect(simpleStore.peek("key1")).toBe(100);
expect(simpleStore.peek("key2")).toBe(200);
const customStore = new KVDataEventTarget<{ id: string }, string>(
[
[{ id: "user1" }, "Alice"],
[{ id: "user2" }, "Bob"],
],
{ getKey: (param) => param.id },
);
expect(customStore.peek({ id: "user1" })).toBe("Alice");
expect(customStore.peek({ id: "user2" })).toBe("Bob");
});
it("should return a stable promise per key-value in getAsync", async () => {
const store = new KVDataEventTarget<string, number>();
const p1 = store.getAsync("key1");
const p2 = store.getAsync("key1");
// Same key, no value yet.
expect(p1).toBe(p2);
// Same key, same value.
store.set("key1", 99);
const p3 = store.getAsync("key1");
const p4 = store.getAsync("key1");
expect(p3).toBe(p4);
store.set("key1", 99);
const p5 = store.getAsync("key1");
expect(p3).toBe(p5);
// Same key, different value.
store.set("key1", 101);
const p6 = store.getAsync("key1");
expect(p3).not.toBe(p6);
});
it("should resolve getAsync() when value is set", async () => {
const store = new KVDataEventTarget<string, string>();
const promise = store.getAsync("keyX");
store.set("keyX", "loaded");
await expect(promise).resolves.toBe("loaded");
});
it("should return a value synchronously after it is set", () => {
const store = new KVDataEventTarget<string, boolean>();
store.set("isReady", true);
expect(store.read("isReady")).toBe(true);
expect(store.peek("isReady")).toBe(true);
});
it("should emit 'state:update' when a key is set", () => {
const store = new KVDataEventTarget<string, string>();
const callback = vi.fn();
store.addEventListener("state:update", callback);
store.set("user", "Alice");
expect(callback).toHaveBeenCalledWith(
expect.objectContaining({
detail: { param: "user", key: "user", value: "Alice" },
}),
);
});
it("should clear all values and pending promises on clear()", async () => {
const store = new KVDataEventTarget<string, number>();
store.set("score", 42);
expect(store.read("score")).toBe(42);
store.clear();
expect(store.peek("score")).toBe(undefined);
const promise = store.getAsync("score");
expect(promise).not.toBeUndefined();
store.set("score", 100);
await expect(promise).resolves.toBe(100);
});
it("should remove all pending resolvers on destroy", async () => {
const store = new KVDataEventTarget<string, number>();
const promise = store.getAsync("count");
store.destroy();
store.set("count", 999);
// Should NOT resolve since it's destroyed
await expect(
Promise.race([
promise,
new Promise((_, reject) => setTimeout(reject, 50)),
]),
).rejects.toBeUndefined();
});
});