/** * Resource Schema Tests */ import { describe, test, expect } from "bun:test"; import { defineResource, validateResourceDefinition, getPluralName, getEnabledEndpoints, isFieldRequired, getFieldDefault, } from "../schema"; import { userResourceFixture, postResourceFixture, productResourceFixture, minimalResourceFixture, invalidResourceFixtures, } from "./fixtures"; describe("defineResource", () => { test("should accept valid resource definition", () => { const result = defineResource(userResourceFixture); expect(result.name).toBe("user"); expect(result.fields).toBeDefined(); expect(result.options).toBeDefined(); }); test("should apply default options", () => { const result = defineResource(minimalResourceFixture); expect(result.options?.autoPlural).toBe(true); expect(result.options?.endpoints).toBeDefined(); expect(result.options?.endpoints?.list).toBe(true); expect(result.options?.endpoints?.get).toBe(true); expect(result.options?.endpoints?.create).toBe(true); expect(result.options?.endpoints?.update).toBe(true); expect(result.options?.endpoints?.delete).toBe(true); }); test("should merge custom options with defaults", () => { const result = defineResource(productResourceFixture); expect(result.options?.endpoints?.list).toBe(true); expect(result.options?.endpoints?.update).toBe(false); expect(result.options?.endpoints?.delete).toBe(false); }); test("should apply default pagination settings", () => { const result = defineResource(minimalResourceFixture); expect(result.options?.pagination?.defaultLimit).toBe(10); expect(result.options?.pagination?.maxLimit).toBe(100); }); test("should preserve custom pagination settings", () => { const result = defineResource(userResourceFixture); expect(result.options?.pagination?.defaultLimit).toBe(20); expect(result.options?.pagination?.maxLimit).toBe(100); }); }); describe("validateResourceDefinition", () => { test("should validate correct resource definition", () => { expect(() => { validateResourceDefinition(userResourceFixture); }).not.toThrow(); }); test("should throw on missing name", () => { expect(() => { validateResourceDefinition(invalidResourceFixtures.noName); }).toThrow("Resource name is required"); }); test("should throw on invalid name format", () => { expect(() => { validateResourceDefinition(invalidResourceFixtures.invalidName); }).toThrow(/Invalid resource name/); }); test("should throw on empty fields", () => { expect(() => { validateResourceDefinition(invalidResourceFixtures.noFields); }).toThrow(/must have at least one field/); }); test("should throw on invalid field name", () => { expect(() => { validateResourceDefinition(invalidResourceFixtures.invalidFieldName); }).toThrow(/Invalid field name/); }); test("should throw on invalid field type", () => { expect(() => { validateResourceDefinition(invalidResourceFixtures.invalidFieldType); }).toThrow(/Invalid field type/); }); test("should throw on array without items", () => { expect(() => { validateResourceDefinition(invalidResourceFixtures.arrayWithoutItems); }).toThrow(/missing "items" property/); }); }); describe("getPluralName", () => { test("should add 's' for simple pluralization", () => { const result = getPluralName(userResourceFixture); expect(result).toBe("users"); }); test("should use conservative English pluralization for common resource names", () => { expect(getPluralName({ ...minimalResourceFixture, name: "party" })).toBe("parties"); expect(getPluralName({ ...minimalResourceFixture, name: "box" })).toBe("boxes"); }); test("should use custom plural name if provided", () => { const result = getPluralName(productResourceFixture); expect(result).toBe("inventory"); }); test("should respect autoPlural: false", () => { const definition = { ...minimalResourceFixture, options: { autoPlural: false }, }; const result = getPluralName(definition); expect(result).toBe("item"); }); }); describe("getEnabledEndpoints", () => { test("should return all enabled endpoints", () => { const result = getEnabledEndpoints(userResourceFixture); expect(result).toEqual(["list", "get", "create", "update", "delete"]); }); test("should return only enabled endpoints", () => { const result = getEnabledEndpoints(productResourceFixture); expect(result).toEqual(["list", "get", "create"]); expect(result).not.toContain("update"); expect(result).not.toContain("delete"); }); test("should return all endpoints by default", () => { const result = getEnabledEndpoints(minimalResourceFixture); expect(result).toEqual(["list", "get", "create", "update", "delete"]); }); }); describe("isFieldRequired", () => { test("should return true for required fields", () => { const field = userResourceFixture.fields.email; expect(isFieldRequired(field)).toBe(true); }); test("should return false for optional fields", () => { const field = userResourceFixture.fields.age; expect(isFieldRequired(field)).toBe(false); }); test("should return false by default", () => { const field = { type: "string" as const }; expect(isFieldRequired(field)).toBe(false); }); }); describe("getFieldDefault", () => { test("should return default value if provided", () => { const field = userResourceFixture.fields.isActive; expect(getFieldDefault(field)).toBe(true); }); test("should return undefined if no default", () => { const field = userResourceFixture.fields.email; expect(getFieldDefault(field)).toBeUndefined(); }); test("should handle array default", () => { const field = postResourceFixture.fields.tags; const defaultValue = getFieldDefault(field); expect(Array.isArray(defaultValue)).toBe(true); expect(defaultValue).toEqual([]); }); });