85 lines
3.7 KiB
TypeScript
85 lines
3.7 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "node:test";
|
|
|
|
import type { IBrandRepository } from "../application/brand.repository";
|
|
import { BrandUseCases } from "../application/brand.use-cases";
|
|
import { mapBrandInput } from "../application/brand-input.mapper";
|
|
import { BrandPersistenceMapper } from "../infrastructure/persistence/brand-persistence.mapper";
|
|
|
|
import { Brand } from "./brand.aggregate";
|
|
|
|
function brand(name = "LG", builtin = true) {
|
|
const props = mapBrandInput({ name, active: true }, builtin);
|
|
assert.ok(props.isSuccess);
|
|
const created = Brand.create(props.data);
|
|
assert.ok(created.isSuccess);
|
|
return created.data;
|
|
}
|
|
test("Marcas: nombre normalizado, UUID v7, protección de serie, estado e idempotencia", () => {
|
|
for (const name of ["", " ", "x".repeat(101)]) {
|
|
assert.equal(mapBrandInput({ name, active: true }).isSuccess, false);
|
|
}
|
|
const original = brand(" LG ");
|
|
assert.equal(original.id.toPrimitive()[14], "7");
|
|
assert.equal(original.name.toPrimitive(), "LG");
|
|
const same = original.update({ name: original.name, active: true, builtin: true });
|
|
assert.ok(same.isSuccess);
|
|
assert.equal(same.data, original);
|
|
const inactive = original.update({ name: original.name, active: false, builtin: true });
|
|
assert.ok(inactive.isSuccess);
|
|
assert.equal(inactive.data.id.toPrimitive(), original.id.toPrimitive());
|
|
assert.equal(inactive.data.active, false);
|
|
const renamed = mapBrandInput({ name: "Otra", active: true }, true);
|
|
assert.ok(renamed.isSuccess);
|
|
const blocked = original.update(renamed.data);
|
|
assert.equal(blocked.isSuccess, false);
|
|
if (!blocked.isSuccess) {
|
|
assert.equal(blocked.error.code, "BUILTIN_PROTECTED");
|
|
}
|
|
assert.equal(original.update({ ...renamed.data, builtin: false }).isSuccess, false);
|
|
const custom = brand("Propia", false);
|
|
assert.ok(custom.update({ ...renamed.data, builtin: false }).isSuccess);
|
|
});
|
|
test("Marcas: mapper bidireccional conserva identidad y rechaza persistencia inválida", () => {
|
|
const mapper = new BrandPersistenceMapper();
|
|
const original = brand();
|
|
const row = mapper.toPersistence(original);
|
|
const restored = mapper.toDomain({ ...row, active: 1, builtin: 1 });
|
|
assert.ok(restored.id.equals(original.id));
|
|
assert.ok(restored.name.equals(original.name));
|
|
assert.throws(() => mapper.toDomain({ ...row, active: 2 }));
|
|
assert.throws(() => mapper.toDomain({ ...row, id: "invalid" }));
|
|
assert.throws(() => mapper.toDomain({ ...row, name: " " }));
|
|
});
|
|
test("Marcas: catálogo rechaza duplicados, también inactivos, y permite renombrar personalizados", async () => {
|
|
let brands: Brand[] = [brand(), brand("Propia", false)];
|
|
const repository: IBrandRepository = {
|
|
list: async () => brands,
|
|
save: async (action) => {
|
|
const result = action(brands);
|
|
if (result.isSuccess) {
|
|
brands = [...brands.filter((item) => !item.id.equals(result.data.id)), result.data];
|
|
}
|
|
return result;
|
|
},
|
|
};
|
|
const useCases = new BrandUseCases(repository);
|
|
const existing = brands[1];
|
|
assert.ok(existing);
|
|
const disabled = await useCases.save(existing.id.toPrimitive(), {
|
|
name: "Propia",
|
|
active: false,
|
|
});
|
|
assert.ok(disabled.isSuccess);
|
|
const duplicate = await useCases.save(undefined, { name: " PROPIA ", active: true });
|
|
assert.equal(duplicate.isSuccess, false);
|
|
if (!duplicate.isSuccess) {
|
|
assert.equal(duplicate.error.code, "NAME_EXISTS");
|
|
}
|
|
const renamed = await useCases.save(existing.id.toPrimitive(), { name: "Nueva", active: true });
|
|
assert.ok(renamed.isSuccess);
|
|
assert.equal(renamed.data.id.toPrimitive(), existing.id.toPrimitive());
|
|
const invalid = await useCases.save("invalid", { name: "Nueva", active: true });
|
|
assert.equal(invalid.isSuccess, false);
|
|
});
|