/*
Unit tests for material credit covering materialKindSchema; materialSourceTypeSchema; creditPartyKindSchema. It also guards the documented public contract and regression-sensitive edge cases.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-1311: Compass header sweep — declares the material suite's contract for test-file scaffold coverage.
*/
import { describe, it, expect } from "vitest";
import {
materialKindSchema,
materialSourceTypeSchema,
creditPartyKindSchema,
creditRoleSchema,
materialCreditStatusSchema,
usageBasisTypeSchema,
materialCreditLabelsSchema,
} from "../material-credit.ts";
describe("materialKindSchema", () => {
it("accepts valid kinds", () => {
const result = materialKindSchema.safeParse("image");
expect(result.success).toBe(true);
});
it("rejects invalid kind", () => {
expect(() => materialKindSchema.parse("3d-model")).toThrow();
});
});
describe("materialSourceTypeSchema", () => {
it("accepts valid source types", () => {
const result = materialSourceTypeSchema.safeParse("human-made");
expect(result.success).toBe(true);
});
it("rejects invalid source type", () => {
expect(() => materialSourceTypeSchema.parse("unknown")).toThrow();
});
});
describe("creditPartyKindSchema", () => {
it("accepts valid party kinds", () => {
const result = creditPartyKindSchema.safeParse("Person");
expect(result.success).toBe(true);
});
it("rejects invalid party kind", () => {
expect(() => creditPartyKindSchema.parse("Robot")).toThrow();
});
});
describe("creditRoleSchema", () => {
it("accepts valid roles", () => {
const result = creditRoleSchema.safeParse("creator");
expect(result.success).toBe(true);
});
it("rejects invalid role", () => {
expect(() => creditRoleSchema.parse("owner")).toThrow();
});
});
// RFC-1189 AC-1: partyKindLabels is a required complete record over
// creditPartyKindSchema — the schema itself is the completeness gate for the
// public credits page's localized kind vocabulary.
const baseLabels = {
summaryLabel: "Summary",
pageTitle: "Credits",
pageDescription: "Material credits",
emptyMessage: "No credits",
detailsLabel: "Details",
createdBy: "Created by",
createdWith: "Created with",
promptBy: "Prompt by",
reviewedBy: "Reviewed by",
license: "License",
copyrightLabel: "Copyright",
rightsHolder: "Rights holder",
sourceType: "Source type",
sourceTypeLabels: Object.fromEntries(
materialSourceTypeSchema.options.map((value) => [value, value]),
),
statusLabels: Object.fromEntries(
materialCreditStatusSchema.options.map((value) => [value, value]),
),
usageBasisLabels: Object.fromEntries(usageBasisTypeSchema.options.map((value) => [value, value])),
aiUsageLabels: {
aiGenerated: "AI-generated",
aiAssisted: "AI-assisted",
humanContribution: "Human contribution",
copyrightClaimed: "Copyright claimed",
copyrightNotClaimed: "No copyright claim",
},
usedOnLabel: "Used on",
verifiedAtLabel: "Verified at",
noPreviewLabel: "No preview",
copyrightExplanation: "Explanation",
};
describe("materialCreditLabelsSchema.partyKindLabels (RFC-1189)", () => {
const fullPartyKindLabels = Object.fromEntries(
creditPartyKindSchema.options.map((value) => [value, value]),
);
it("rejects a labels block missing partyKindLabels entirely", () => {
const result = materialCreditLabelsSchema.safeParse(baseLabels);
expect(
result.success,
"partyKindLabels is required — check labels.md materialCredits block",
).toBe(false);
});
it("rejects a record missing one creditPartyKindSchema member", () => {
const labels = {
...baseLabels,
partyKindLabels: { ...fullPartyKindLabels, AIPlatform: undefined },
};
delete (labels.partyKindLabels as Record).AIPlatform;
const result = materialCreditLabelsSchema.safeParse(labels);
expect(result.success).toBe(false);
});
it("accepts a complete partyKindLabels record", () => {
const result = materialCreditLabelsSchema.safeParse({
...baseLabels,
partyKindLabels: fullPartyKindLabels,
});
expect(result.success).toBe(true);
});
});