103 lines · 3.7 KB · TypeScript
RawDownload
import { CommandId, EventId, ProjectId, type OrchestrationEvent } from "@t3tools/contracts";import { expect, it } from "@effect/vitest";import * as Effect from "effect/Effect";import * as NodeServices from "@effect/platform-node/NodeServices"; import { decideOrchestrationCommand } from "./decider.ts";import { createEmptyReadModel, projectEvent } from "./projector.ts"; const now = "2026-01-01T00:00:00.000Z";const projectId = ProjectId.make("project-env-mode"); const seedProjectCreated = (sequence: number): OrchestrationEvent => ({  sequence,  eventId: EventId.make(`evt-project-env-mode-${sequence}`),  aggregateKind: "project",  aggregateId: projectId,  type: "project.created",  occurredAt: now,  commandId: CommandId.make(`cmd-project-env-mode-${sequence}`),  causationEventId: null,  correlationId: CommandId.make(`cmd-project-env-mode-${sequence}`),  metadata: {},  payload: {    projectId,    title: "Env mode",    workspaceRoot: "/tmp/env-mode",    defaultModelSelection: null,    scripts: [],    createdAt: now,    updatedAt: now,  },}); it.layer(NodeServices.layer)("decider project defaultThreadEnvMode", (it) => {  it.effect("propagates defaultThreadEnvMode through meta.update into the read model", () =>    Effect.gen(function* () {      const readModel = yield* projectEvent(createEmptyReadModel(now), seedProjectCreated(1));      expect(readModel.projects[0]?.defaultThreadEnvMode).toBeNull();       const result = yield* decideOrchestrationCommand({        command: {          type: "project.meta.update",          commandId: CommandId.make("cmd-project-env-mode-set"),          projectId,          defaultThreadEnvMode: "worktree",        },        readModel,      });       const event = Array.isArray(result) ? result[0] : result;      expect(event.type).toBe("project.meta-updated");      expect((event.payload as { defaultThreadEnvMode?: unknown }).defaultThreadEnvMode).toBe(        "worktree",      );       const updated = yield* projectEvent(readModel, { ...event, sequence: 2 });      expect(updated.projects[0]?.defaultThreadEnvMode).toBe("worktree");    }),  );   it.effect("omits the field when unset and clears it on explicit null", () =>    Effect.gen(function* () {      const readModel = yield* projectEvent(createEmptyReadModel(now), seedProjectCreated(1));       const unrelated = yield* decideOrchestrationCommand({        command: {          type: "project.meta.update",          commandId: CommandId.make("cmd-project-env-mode-title"),          projectId,          title: "Renamed",        },        readModel,      });      const unrelatedEvent = Array.isArray(unrelated) ? unrelated[0] : unrelated;      expect("defaultThreadEnvMode" in (unrelatedEvent.payload as object)).toBe(false);       const set = yield* decideOrchestrationCommand({        command: {          type: "project.meta.update",          commandId: CommandId.make("cmd-project-env-mode-set"),          projectId,          defaultThreadEnvMode: "worktree",        },        readModel,      });      const setEvent = Array.isArray(set) ? set[0] : set;      const afterSet = yield* projectEvent(readModel, { ...setEvent, sequence: 2 });       const clear = yield* decideOrchestrationCommand({        command: {          type: "project.meta.update",          commandId: CommandId.make("cmd-project-env-mode-clear"),          projectId,          defaultThreadEnvMode: null,        },        readModel: afterSet,      });      const clearEvent = Array.isArray(clear) ? clear[0] : clear;      const afterClear = yield* projectEvent(afterSet, { ...clearEvent, sequence: 3 });      expect(afterClear.projects[0]?.defaultThreadEnvMode).toBeNull();    }),  );});