import assert from "node:assert/strict"; import { test } from "node:test"; import { UniqueID } from "@repo/rdx-ddd"; import { Maybe } from "@repo/rdx-utils"; import { AssetCatalog } from "./asset-catalog.aggregate"; import { seedAssetCatalog } from "./asset-catalog-seed"; import type { AssetDefinitionSpec } from "./asset-definition"; import { AssetDefinitionValues } from "./value-objects/asset-definition-values.vo"; const global = Maybe.none(); function values(spec: AssetDefinitionSpec) { const result = AssetDefinitionValues.create(spec); assert.ok(result.isSuccess); return result.data; } function field(name: string) { return values({ kind: "field", name, type: "text", unit: "", choices: [], description: "" }); } function changed(result: ReturnType) { assert.ok(result.isSuccess); return result.data; } test("el catálogo inicial es idempotente, con UUID propios y características opcionales", () => { const catalog = seedAssetCatalog(AssetCatalog.create()); assert.equal(catalog.definitions.length, 47); assert.equal(seedAssetCatalog(catalog), catalog); const ids = [ catalog.id, ...catalog.definitions.map((item) => item.id), ...catalog.definitions.flatMap((item) => item.bindings.map((binding) => binding.id)), ].map((id) => id.toPrimitive()); assert.equal(new Set(ids).size, ids.length); assert.ok(ids.every((id) => id.charAt(14) === "7")); const templates = catalog.definitions.filter((item) => item.values.data.kind === "template"); assert.equal(templates.length, 12); assert.ok(templates.every((item) => item.bindings.every((field) => !field.required))); const rehydrated = AssetCatalog.rehydrate( { definitions: catalog.definitions, availability: catalog.availability }, catalog.id ); assert.ok(rehydrated.id.equals(catalog.id)); assert.ok(rehydrated.definitions[0]?.id.equals(catalog.definitions[0]?.id)); const stock = catalog.definitions[0]; assert.ok(stock); const protectedResult = catalog.save(global, Maybe.some(stock.id), field("Cambio")); assert.ok(!protectedResult.isSuccess); assert.equal(protectedResult.error.code, "BUILTIN_PROTECTED"); }); test("la disponibilidad por compañía conserva el global y los campos desactivados", () => { let catalog = seedAssetCatalog(AssetCatalog.create()); const first = Maybe.some(UniqueID.generateNewID()); const second = Maybe.some(UniqueID.generateNewID()); const stock = catalog.definitions[0]; assert.ok(stock); catalog = changed(catalog.setActive(first, stock.id, false)); assert.equal(catalog.active(stock, first), false); assert.equal(catalog.active(stock, second), true); assert.equal(stock.active, true); assert.equal(catalog.definitions.length, 47); const overrideId = catalog.availability[0]?.id; assert.ok(overrideId); assert.equal(changed(catalog.setActive(first, stock.id, false)), catalog); catalog = changed(catalog.setActive(first, stock.id, null)); assert.equal(catalog.active(stock, first), true); assert.ok(catalog.availability[0]?.id.equals(overrideId)); catalog = changed(catalog.setActive(global, stock.id, false)); assert.equal(seedAssetCatalog(catalog), catalog); assert.equal(catalog.active(catalog.definitions[0] ?? stock, first), false); }); test("las plantillas validan ámbito, campos activos e identidad estable al editar", () => { let catalog = seedAssetCatalog(AssetCatalog.create()); const company = Maybe.some(UniqueID.generateNewID()); const other = Maybe.some(UniqueID.generateNewID()); catalog = changed(catalog.save(company, Maybe.none(), field("Campo local"))); const local = catalog.definitions.at(-1); assert.ok(local); const template = values({ kind: "template", name: "Plantilla local", description: "", fields: [{ fieldId: local.id.toPrimitive(), required: false }], }); assert.ok(!catalog.save(global, Maybe.none(), template).isSuccess); assert.ok(!catalog.save(other, Maybe.none(), template).isSuccess); catalog = changed(catalog.save(company, Maybe.none(), template)); const saved = catalog.definitions.at(-1); assert.ok(saved); assert.equal(changed(catalog.save(company, Maybe.some(saved.id), template)), catalog); const updated = values({ ...template.data, name: "Otra denominación" }); catalog = changed(catalog.save(company, Maybe.some(saved.id), updated)); const edited = catalog.definitions.at(-1); assert.ok(edited); assert.ok(edited.id.equals(saved.id)); assert.ok(edited.bindings[0]?.id.equals(saved.bindings[0]?.id)); catalog = changed(catalog.setActive(company, local.id, false)); assert.ok( !catalog.save(company, Maybe.none(), values({ ...template.data, name: "Nueva" })).isSuccess ); assert.ok(catalog.save(company, Maybe.some(saved.id), updated).isSuccess); assert.ok(!catalog.visible(other).some((item) => item.id.equals(local.id))); }); test("los campos validan listas, igualdad semántica, duplicados y tipo fijo", () => { const list: AssetDefinitionSpec = { kind: "field", name: "Batería", description: "", type: "choice", unit: "", choices: ["Buena", "Sustituir"], }; assert.ok(!AssetDefinitionValues.create({ ...list, choices: [] }).isSuccess); assert.ok(!AssetDefinitionValues.create({ ...list, choices: ["Buena", " buena "] }).isSuccess); assert.ok(!AssetDefinitionValues.create({ ...list, type: "text" }).isSuccess); const frozen = values(list); assert.ok(Object.isFrozen(frozen.data)); if (frozen.data.kind === "field") { assert.ok(Object.isFrozen(frozen.data.choices)); } let catalog = AssetCatalog.create(); catalog = changed(catalog.save(global, Maybe.none(), frozen)); const saved = catalog.definitions[0]; assert.ok(saved); assert.ok(!catalog.save(global, Maybe.none(), values({ ...list, name: " batería " })).isSuccess); assert.ok(!catalog.save(global, Maybe.some(saved.id), field("Batería")).isSuccess); assert.ok( !catalog.save(global, Maybe.some(saved.id), values({ ...list, choices: ["Buena"] })).isSuccess ); assert.ok( catalog.save( global, Maybe.some(saved.id), values({ ...list, choices: [...list.choices, "Desconocida"] }) ).isSuccess ); });