UNPKG

alepha

Version:

Easy-to-use modern TypeScript framework for building many kind of applications.

269 lines (212 loc) 6.73 kB
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"); }); }); }); }); });