UNPKG

alepha

Version:

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

267 lines (207 loc) 6.27 kB
import { $hook, $inject, Alepha } from "alepha"; import { describe, expect, it } from "vitest"; import { $mode } from "../primitives/$mode.ts"; describe("$mode", () => { it("should activate when direct env is set", async () => { class Target { mode = $mode({ env: "MIGRATE" }); } const alepha = Alepha.create({ env: { MIGRATE: "true" } }); alepha.with(Target); const target = alepha.inject(Target); expect(target.mode).toBe(true); }); it("should activate when MODE env matches", async () => { class Target { mode = $mode({ env: "MIGRATE" }); } // Use `new Alepha()` to avoid `process.env` overwriting MODE const alepha = new Alepha({ env: { MODE: "MIGRATE" } }); alepha.with(Target); const target = alepha.inject(Target); expect(target.mode).toBe(true); }); it("should return false when env does not match", async () => { class Target { mode = $mode({ env: "MIGRATE" }); } const alepha = Alepha.create({ env: {} }); alepha.with(Target); const target = alepha.inject(Target); expect(target.mode).toBe(false); }); it("should prune unrelated services from graph", async () => { const stack: string[] = []; class Target { mode = $mode({ env: "MIGRATE" }); onStart = $hook({ on: "start", handler: async () => { stack.push("Target.start"); }, }); } class Unrelated { onStart = $hook({ on: "start", handler: async () => { stack.push("Unrelated.start"); }, }); } const alepha = Alepha.create({ env: { MIGRATE: "true" } }); alepha.with(Target).with(Unrelated); await alepha.start(); expect(stack).toContain("Target.start"); expect(stack).not.toContain("Unrelated.start"); }); it("should keep dependencies of the mode class", async () => { const stack: string[] = []; class Dep { onStart = $hook({ on: "start", handler: async () => { stack.push("Dep.start"); }, }); } class Target { dep = $inject(Dep); mode = $mode({ env: "SEED" }); onStart = $hook({ on: "start", handler: async () => { stack.push("Target.start"); }, }); } const alepha = Alepha.create({ env: { SEED: "true" } }); alepha.with(Target); await alepha.start(); expect(stack).toContain("Dep.start"); expect(stack).toContain("Target.start"); }); it("should fire ready callback then stop", async () => { let readyFired = false; class Target { mode = $mode({ env: "MIGRATE", ready: async () => { readyFired = true; }, }); } const alepha = Alepha.create({ env: { MIGRATE: "true" } }); alepha.with(Target); await alepha.start(); expect(readyFired).toBe(true); expect(alepha.isStarted()).toBe(false); }); it("should stop even if ready callback throws", async () => { class Target { mode = $mode({ env: "MIGRATE", ready: async () => { throw new Error("boom"); }, }); } const alepha = Alepha.create({ env: { MIGRATE: "true" } }); alepha.with(Target); // The error is wrapped by the event system await expect(alepha.start()).rejects.toThrow(/ready/); expect(alepha.isStarted()).toBe(false); }); it("should not prune when env does not match", async () => { const stack: string[] = []; class ModeClass { mode = $mode({ env: "MIGRATE" }); onStart = $hook({ on: "start", handler: async () => { stack.push("ModeClass.start"); }, }); } class Other { onStart = $hook({ on: "start", handler: async () => { stack.push("Other.start"); }, }); } const alepha = Alepha.create({ env: {} }); alepha.with(ModeClass).with(Other); await alepha.start(); // Both should fire — no pruning happened expect(stack).toContain("ModeClass.start"); expect(stack).toContain("Other.start"); }); it("should preserve substitutions through prune", async () => { class Base { value = "base"; } class Override extends Base { override value = "override"; } class Target { dep = $inject(Base); mode = $mode({ env: "TEST_MODE" }); } const alepha = Alepha.create({ env: { TEST_MODE: "true" } }); alepha.with({ provide: Base, use: Override }).with(Target); await alepha.start(); const target = alepha.inject(Target); expect(target.dep.value).toBe("override"); }); it("should skip .with() calls after target is set (early cutoff)", async () => { const stack: string[] = []; class Target { mode = $mode({ env: "MIGRATE" }); onStart = $hook({ on: "start", handler: async () => { stack.push("Target.start"); }, }); } class LateRegistration { onStart = $hook({ on: "start", handler: async () => { stack.push("LateRegistration.start"); }, }); } const alepha = Alepha.create({ env: { MIGRATE: "true" } }); alepha.with(Target); // This .with() should be skipped because target is already set alepha.with(LateRegistration); await alepha.start(); expect(stack).toContain("Target.start"); expect(stack).not.toContain("LateRegistration.start"); // LateRegistration should not be in the graph at all const graph = alepha.graph(); expect(graph.LateRegistration).toBeUndefined(); }); it("should work without ready callback (long-running mode)", async () => { const stack: string[] = []; class WorkerMode { mode = $mode({ env: "WORKER" }); onReady = $hook({ on: "ready", handler: async () => { stack.push("WorkerMode.ready"); }, }); } const alepha = Alepha.create({ env: { WORKER: "true" } }); alepha.with(WorkerMode); await alepha.start(); // Ready hook fires, but no auto-stop expect(stack).toContain("WorkerMode.ready"); expect(alepha.isStarted()).toBe(true); await alepha.stop(); }); });