import { describe, expect, it } from "bun:test"; import { Effect, Schema } from "effect"; import { StateSchema, IssueSchema, IssuesResponseSchema, StatesResponseSchema, ProjectSchema, ProjectsResponseSchema, LabelSchema, LabelsResponseSchema, MemberSchema, MembersResponseSchema, CycleSchema, CyclesResponseSchema, } from "@/config"; async function decode( schema: Schema.Schema, data: unknown, ): Promise { return Effect.runPromise( Schema.decodeUnknown(schema)(data).pipe( Effect.mapError((e) => new Error(String(e))), ), ); } describe("StateSchema", () => { it("decodes a valid state", async () => { const state = await decode(StateSchema, { id: "s1", name: "In Progress", group: "started", }); expect(state.id).toBe("s1"); expect(state.group).toBe("started"); }); it("accepts optional color", async () => { const state = await decode(StateSchema, { id: "s1", name: "Done", group: "completed", color: "#00ff00", }); expect(state.color).toBe("#00ff00"); }); it("rejects missing required fields", async () => { await expect(decode(StateSchema, { id: "s1" })).rejects.toThrow(); }); }); describe("IssueSchema", () => { const base = { id: "i1", sequence_id: 42, name: "Fix bug", priority: "high", state: "uuid-state", }; it("decodes with string state", async () => { const issue = await decode(IssueSchema, base); expect(issue.sequence_id).toBe(42); expect(issue.state).toBe("uuid-state"); }); it("decodes with object state", async () => { const issue = await decode(IssueSchema, { ...base, state: { id: "s1", name: "In Progress", group: "started" }, }); expect(typeof issue.state).toBe("object"); }); it("accepts null description_html", async () => { const issue = await decode(IssueSchema, { ...base, description_html: null, }); expect(issue.description_html).toBeNull(); }); it("rejects missing name", async () => { await expect( decode(IssueSchema, { ...base, name: undefined }), ).rejects.toThrow(); }); }); describe("IssuesResponseSchema", () => { it("decodes results array", async () => { const data = { results: [ { id: "i1", sequence_id: 1, name: "Issue 1", priority: "low", state: "s1", }, { id: "i2", sequence_id: 2, name: "Issue 2", priority: "high", state: "s2", }, ], }; const resp = await decode(IssuesResponseSchema, data); expect(resp.results).toHaveLength(2); }); it("decodes empty results", async () => { const resp = await decode(IssuesResponseSchema, { results: [] }); expect(resp.results).toHaveLength(0); }); }); describe("StatesResponseSchema", () => { it("decodes results", async () => { const resp = await decode(StatesResponseSchema, { results: [{ id: "s1", name: "Backlog", group: "backlog" }], }); expect(resp.results[0].name).toBe("Backlog"); }); }); describe("ProjectSchema", () => { it("decodes a project", async () => { const p = await decode(ProjectSchema, { id: "p1", identifier: "ACME", name: "Acme Project", }); expect(p.identifier).toBe("ACME"); }); it("accepts optional description", async () => { const p = await decode(ProjectSchema, { id: "p1", identifier: "ACME", name: "InstUI", description: "desc", }); expect(p.description).toBe("desc"); }); }); describe("ProjectsResponseSchema", () => { it("decodes results", async () => { const resp = await decode(ProjectsResponseSchema, { results: [{ id: "p1", identifier: "WEB", name: "Web Project" }], }); expect(resp.results[0].identifier).toBe("WEB"); }); }); describe("LabelSchema", () => { it("decodes a label", async () => { const label = await decode(LabelSchema, { id: "l1", name: "bug" }); expect(label.name).toBe("bug"); }); it("accepts null color", async () => { const label = await decode(LabelSchema, { id: "l1", name: "bug", color: null, }); expect(label.color).toBeNull(); }); }); describe("LabelsResponseSchema", () => { it("decodes results", async () => { const resp = await decode(LabelsResponseSchema, { results: [{ id: "l1", name: "bug" }], }); expect(resp.results).toHaveLength(1); }); }); describe("MemberSchema", () => { it("decodes a member", async () => { const m = await decode(MemberSchema, { id: "u1", display_name: "Aaron", email: "aaron@example.com", }); expect(m.display_name).toBe("Aaron"); }); it("accepts null email", async () => { const m = await decode(MemberSchema, { id: "u1", display_name: "Aaron", email: null, }); expect(m.email).toBeNull(); }); }); describe("MembersResponseSchema (flat array)", () => { it("decodes a flat array", async () => { const members = await decode(MembersResponseSchema, [ { id: "u1", display_name: "Aaron" }, { id: "u2", display_name: "Bea" }, ]); expect(members).toHaveLength(2); }); }); describe("CycleSchema", () => { it("decodes a cycle", async () => { const c = await decode(CycleSchema, { id: "c1", name: "Sprint 1" }); expect(c.name).toBe("Sprint 1"); }); it("accepts optional dates", async () => { const c = await decode(CycleSchema, { id: "c1", name: "Sprint 1", start_date: "2025-01-01", end_date: "2025-01-14", }); expect(c.start_date).toBe("2025-01-01"); }); }); describe("CyclesResponseSchema", () => { it("decodes results", async () => { const resp = await decode(CyclesResponseSchema, { results: [{ id: "c1", name: "Sprint 1" }], }); expect(resp.results[0].id).toBe("c1"); }); });