alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
269 lines (212 loc) • 6.73 kB
text/typescript
import { AsyncLocalStorage } from "node:async_hooks";
import { describe, expect, it } from "vitest";
import { Alepha } from "../Alepha.ts";
import { AlsProvider } from "../providers/AlsProvider.ts";
AlsProvider.create = () => new AsyncLocalStorage();
describe("fork", () => {
it("should inherit parent state", () => {
const alepha = new Alepha();
alepha.set("test", "A");
alepha.fork(() => {
expect(alepha.get("test")).toBe("A");
});
});
it("should isolate mutations from parent", () => {
const alepha = new Alepha();
alepha.set("test", "A");
alepha.fork(() => {
alepha.set("test", "B");
expect(alepha.get("test")).toBe("B");
});
expect(alepha.get("test")).toBe("A");
});
it("should walk up the tree through nested forks", () => {
const alepha = new Alepha();
alepha.set("test", "A");
alepha.fork(() => {
alepha.set("test", "B");
alepha.fork(() => {
// Walks up: current (not set) → parent ("B")
expect(alepha.get("test")).toBe("B");
alepha.set("test", "C");
expect(alepha.get("test")).toBe("C");
});
expect(alepha.get("test")).toBe("B");
});
expect(alepha.get("test")).toBe("A");
});
it("should return the callback result", () => {
const alepha = new Alepha();
const result = alepha.fork(() => 42);
expect(result).toBe(42);
});
it("should accept initial data", () => {
const alepha = new Alepha();
alepha.fork(
() => {
expect(alepha.get("seed")).toBe("hello");
},
{ seed: "hello" },
);
});
it("should not leak initial data to parent", () => {
const alepha = new Alepha();
alepha.fork(() => {}, { seed: "hello" });
expect(alepha.get("seed")).toBeUndefined();
});
it("should handle async callbacks", async () => {
const alepha = new Alepha();
alepha.set("test", "A");
await alepha.fork(async () => {
alepha.set("test", "B");
await new Promise((r) => setTimeout(r, 10));
expect(alepha.get("test")).toBe("B");
});
expect(alepha.get("test")).toBe("A");
});
it("should isolate multiple parallel forks", async () => {
const alepha = new Alepha();
alepha.set("test", "A");
await Promise.all([
alepha.fork(async () => {
alepha.set("test", "B");
await new Promise((r) => setTimeout(r, 20));
expect(alepha.get("test")).toBe("B");
}),
alepha.fork(async () => {
alepha.set("test", "C");
await new Promise((r) => setTimeout(r, 10));
expect(alepha.get("test")).toBe("C");
}),
]);
expect(alepha.get("test")).toBe("A");
});
it("should fall back to app store for unset keys", () => {
const alepha = new Alepha();
alepha.set("parent", "value");
alepha.fork(() => {
alepha.set("child", "only");
expect(alepha.get("parent")).toBe("value");
expect(alepha.get("child")).toBe("only");
});
expect(alepha.get("child")).toBeUndefined();
});
});
describe("fork scope", () => {
it("should resolve across tree by default", () => {
const alepha = new Alepha();
alepha.set("x", 1);
alepha.fork(() => {
alepha.set("x", 2);
alepha.fork(() => {
alepha.set("x", 3);
expect(alepha.get("x")).toBe(3);
});
});
});
it("should resolve app scope to root store", () => {
const alepha = new Alepha();
alepha.set("x", 1);
alepha.fork(() => {
alepha.set("x", 2);
alepha.fork(() => {
alepha.set("x", 3);
expect(alepha.get("x", "app")).toBe(1);
});
});
});
it("should resolve parent scope to immediate parent layer", () => {
const alepha = new Alepha();
alepha.set("x", 1);
alepha.fork(() => {
alepha.set("x", 2);
alepha.fork(() => {
alepha.set("x", 3);
expect(alepha.get("x", "parent")).toBe(2);
});
});
});
it("should return undefined for parent scope when key not set in parent", () => {
const alepha = new Alepha();
alepha.set("x", 1);
alepha.fork(() => {
alepha.fork(() => {
// Parent fork didn't set "x", so parent scope returns undefined
expect(alepha.get("x", "parent")).toBeUndefined();
});
});
});
it("should return undefined for app scope when key not set in app", () => {
const alepha = new Alepha();
alepha.fork(() => {
alepha.set("x", 2);
expect(alepha.get("x", "app")).toBeUndefined();
});
});
it("should walk full tree: L3 sees L2 value before L1", () => {
const alepha = new Alepha();
alepha.set("x", 1);
alepha.fork(() => {
alepha.set("x", 2);
alepha.fork(() => {
// Default: walks current (not set) → parent (2) → stops
expect(alepha.get("x")).toBe(2);
expect(alepha.get("x", "parent")).toBe(2);
expect(alepha.get("x", "app")).toBe(1);
});
});
});
it("should not walk past parent when scope is parent", () => {
const alepha = new Alepha();
alepha.set("only-in-app", "root");
alepha.fork(() => {
alepha.fork(() => {
// Parent didn't set it — scope: "parent" doesn't walk further
expect(alepha.get("only-in-app", "parent")).toBeUndefined();
// But default resolution walks to root
expect(alepha.get("only-in-app")).toBe("root");
});
});
});
it("should resolve current scope to own layer only", () => {
const alepha = new Alepha();
alepha.set("x", 1);
alepha.fork(() => {
alepha.set("x", 2);
alepha.fork(() => {
alepha.set("x", 3);
expect(alepha.get("x", "current")).toBe(3);
});
});
});
it("should return undefined for current scope when key not set in current layer", () => {
const alepha = new Alepha();
alepha.set("x", 1);
alepha.fork(() => {
alepha.set("x", 2);
alepha.fork(() => {
// Current layer didn't set "x", even though parent has it
expect(alepha.get("x", "current")).toBeUndefined();
// But default walks to parent
expect(alepha.get("x")).toBe(2);
});
});
});
it("should handle 4 levels deep", () => {
const alepha = new Alepha();
alepha.set("x", "L0");
alepha.fork(() => {
alepha.set("x", "L1");
alepha.fork(() => {
alepha.set("x", "L2");
alepha.fork(() => {
alepha.set("x", "L3");
expect(alepha.get("x")).toBe("L3");
expect(alepha.get("x", "current")).toBe("L3");
expect(alepha.get("x", "parent")).toBe("L2");
expect(alepha.get("x", "app")).toBe("L0");
});
});
});
});
});