UNPKG

yoonite-saga

Version:

> Orchestration de workflows transactionnels avec gestion de compensation (pattern Saga)

98 lines (91 loc) 2.9 kB
import { IsInt, IsString, Min } from "class-validator"; import { SagaBuilder } from "./saga-builder"; import { SagaProcessor } from "./saga-processor"; describe("SagaProcessor", () => { class TestDto { @IsString() name: string; @IsInt() @Min(1) count: number; } it("should execute a simple workflow and enrich context", async () => { const builder = new SagaBuilder(); const workflow = builder .step("init") .invoke(() => ({ name: "foo", count: 2 })) .build(); const processor = new SagaProcessor(); processor.add(workflow); const result = await processor.start(); expect(result.state).toBe("success"); expect(result.context).toEqual({ name: "foo", count: 2 }); expect(result.errors).toHaveLength(0); }); it("should validate context and fail if invalid", async () => { const builder = new SagaBuilder(); const workflow = builder .step("invalid") .invoke(() => ({ name: 123, count: 0 })) .validate(TestDto) .build(); const processor = new SagaProcessor(); processor.add(workflow); const result = await processor.start(); expect(result.state).toBe("failed"); expect(result.errors.length).toBeGreaterThan(0); expect(result.errors[0].message).toContain("Validation failed"); }); it("should skip step if condition is false", async () => { const builder = new SagaBuilder(); const workflow = builder .step("step1") .invoke(() => ({ a: 1 })) .step("step2") .condition(() => false) .invoke(() => ({ b: 2 })) .build(); const processor = new SagaProcessor(); processor.add(workflow); const result = await processor.start(); expect(result.context).toEqual({ a: 1 }); expect(result.state).toBe("success"); }); it("should execute compensation on error", async () => { let compensated = false; const builder = new SagaBuilder(); const workflow = builder .step("step1") .invoke(() => ({ a: 1 })) .withCompensation(() => { compensated = true; }) .step("step2") .invoke(() => { throw new Error("fail"); }) .build(); const processor = new SagaProcessor(); processor.add(workflow); const result = await processor.start(); expect(result.state).toBe("failed"); expect(compensated).toBe(true); }); it("should inject services and use them in invokes", async () => { const log: string[] = []; const services = { logger: { log: (msg: string) => log.push(msg) }, }; const builder = new SagaBuilder(); const workflow = builder .step("log") .invoke((ctx, { logger }) => { logger.log("hello"); }) .build(); const processor = new SagaProcessor(services); processor.add(workflow); await processor.start(); expect(log).toContain("hello"); }); });