- Add server-side auth token loader (auth.server.ts) with SSR cookie forwarding - Add project-requests client for explicit/signal/existing issue dispatch - Refactor auth layout and app layout for SSR auth gating - Update auth-client and auth-provider for convex token flow - Extend project-issue primitives with request result schema - Wire projectIssues backend mutation for request handling - Update slice-one page and project-workspace hook - Adjust routes (remove unused), Caddy config, and env templates
89 lines
2.7 KiB
TypeScript
89 lines
2.7 KiB
TypeScript
import { Effect } from "effect";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
decodeProjectIssueRequest,
|
|
ProjectIssueTransitionError,
|
|
ProjectIssueValidationError,
|
|
projectIssueDraftFromSignal,
|
|
queueProjectIssue,
|
|
validateProjectIssueDraft,
|
|
} from "./project-issue";
|
|
|
|
describe("project issue primitives", () => {
|
|
it("normalizes an explicit project request", () => {
|
|
const request = Effect.runSync(
|
|
decodeProjectIssueRequest({
|
|
body: " Investigate the staging failure. ",
|
|
kind: "explicit",
|
|
projectId: "project-1",
|
|
title: " Staging failure ",
|
|
})
|
|
);
|
|
|
|
expect(request).toEqual({
|
|
body: "Investigate the staging failure.",
|
|
kind: "explicit",
|
|
projectId: "project-1",
|
|
title: "Staging failure",
|
|
});
|
|
});
|
|
|
|
it("accepts an existing issue request without creating a duplicate", () => {
|
|
const request = Effect.runSync(
|
|
decodeProjectIssueRequest({
|
|
issueId: "issue-1",
|
|
kind: "existing",
|
|
})
|
|
);
|
|
|
|
expect(request).toEqual({ issueId: "issue-1", kind: "existing" });
|
|
});
|
|
|
|
it("rejects invalid issue drafts before persistence", () => {
|
|
const error = Effect.runSync(
|
|
Effect.flip(
|
|
validateProjectIssueDraft({
|
|
body: "too short",
|
|
title: "No",
|
|
})
|
|
)
|
|
);
|
|
|
|
expect(error).toBeInstanceOf(ProjectIssueValidationError);
|
|
expect(error.reason).toBe("TitleTooShort");
|
|
});
|
|
|
|
it("projects a project Signal into the existing issue shape", () => {
|
|
const draft = Effect.runSync(
|
|
projectIssueDraftFromSignal({
|
|
problemStatement: {
|
|
constraints: ["Do not change production"],
|
|
desiredOutcome: "Staging deploys successfully",
|
|
summary: "The deploy fails during DNS resolution",
|
|
title: "Fix staging deploy DNS failure",
|
|
},
|
|
signalId: "signal-1",
|
|
})
|
|
);
|
|
|
|
expect(draft.title).toBe("Fix staging deploy DNS failure");
|
|
expect(draft.body).toContain("The deploy fails during DNS resolution");
|
|
expect(draft.body).toContain("Source Signal: signal-1");
|
|
});
|
|
|
|
it("queues retryable issue states and preserves active states", () => {
|
|
expect(Effect.runSync(queueProjectIssue("open"))).toBe("queued");
|
|
expect(Effect.runSync(queueProjectIssue("failed"))).toBe("queued");
|
|
expect(Effect.runSync(queueProjectIssue("needs-input"))).toBe("queued");
|
|
expect(Effect.runSync(queueProjectIssue("working"))).toBe("working");
|
|
});
|
|
|
|
it("does not reopen completed issues", () => {
|
|
const error = Effect.runSync(Effect.flip(queueProjectIssue("completed")));
|
|
|
|
expect(error).toBeInstanceOf(ProjectIssueTransitionError);
|
|
expect(error.reason).toBe("CompletedIssue");
|
|
});
|
|
});
|