metis-desk/modules/assets/src/api/domain/asset-relationship.test.ts
2026-10-10 12:01:58 +02:00

144 lines
5.0 KiB
TypeScript

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 { AssetRelationship } from "./asset-relationship.aggregate";
import { AssetDefinitionValues } from "./value-objects/asset-definition-values.vo";
import type { RelationshipValuesData } from "./value-objects/asset-relationship-values.vo";
import { AssetRelationshipValues } from "./value-objects/asset-relationship-values.vo";
const sourceId = UniqueID.generateNewID().toPrimitive();
const targetId = UniqueID.generateNewID().toPrimitive();
const typeId = UniqueID.generateNewID().toPrimitive();
function input(symmetric = false): RelationshipValuesData {
return {
sourceId,
targetId,
typeId,
name: " Alojado en ",
inverseName: " Aloja ",
symmetric,
notes: " rack 1 ",
};
}
function values(data = input()) {
const result = AssetRelationshipValues.create(data);
assert.ok(result.isSuccess);
return result.data;
}
test("Las relaciones validan sus extremos, normalizan nombres y distinguen dirección", () => {
const first = values();
assert.equal(first.toPrimitive().name, "Alojado en");
assert.equal(first.notes, "rack 1");
assert.notEqual(
first.key(),
values({ ...input(), sourceId: targetId, targetId: sourceId }).key()
);
const symmetric = values(input(true));
assert.equal(
symmetric.key(),
values({ ...input(true), sourceId: targetId, targetId: sourceId }).key()
);
assert.equal(symmetric.toPrimitive().inverseName, "Alojado en");
const self = AssetRelationshipValues.create({ ...input(), targetId: sourceId });
assert.ok(!self.isSuccess);
assert.equal(self.error.code, "SELF_RELATIONSHIP");
assert.ok(!AssetRelationshipValues.create({ ...input(), targetId: "bad" }).isSuccess);
assert.ok(!AssetRelationshipValues.create({ ...input(), inverseName: " " }).isSuccess);
assert.ok(!AssetRelationshipValues.create({ ...input(), notes: "x".repeat(10001) }).isSuccess);
assert.ok(Object.isFrozen(first));
});
test("Retirar conserva UUID, extremos y auditoría; repetir la retirada no modifica el historial", () => {
const company = UniqueID.generateNewID();
const actor = UniqueID.generateNewID();
const otherActor = UniqueID.generateNewID();
const created = AssetRelationship.create(company, values(), actor, "2026-10-04T10:00:00.000Z");
assert.ok(created.isSuccess);
const link = created.data;
assert.equal(link.id.toPrimitive().charAt(14), "7");
assert.ok(link.active);
assert.ok(!link.end(otherActor, "2026-10-03T10:00:00.000Z").isSuccess);
const ended = link.end(otherActor, "2026-10-04T11:00:00.000Z");
assert.ok(ended.isSuccess);
assert.equal(ended.data.active, false);
assert.ok(ended.data.id.equals(link.id));
assert.equal(ended.data.values, link.values);
assert.ok(ended.data.createdBy.equals(actor));
assert.ok(ended.data.endedBy.getOrUndefined()?.equals(otherActor));
const retry = ended.data.end(actor, "2026-10-04T12:00:00.000Z");
assert.ok(retry.isSuccess);
assert.equal(retry.data, ended.data);
assert.ok(link.active);
});
test("Tipos de relación de serie protegidos, ámbito de compañía y dirección fija", () => {
const scope = Maybe.some(UniqueID.generateNewID());
const other = Maybe.some(UniqueID.generateNewID());
let catalog = seedAssetCatalog(AssetCatalog.create());
const stock = catalog.definitions.find((item) => item.values.data.kind === "relation");
assert.ok(stock);
const spec = {
kind: "relation",
name: "Conectado a",
inverseName: "Conectado a",
description: "",
symmetric: true,
} as const;
const custom = AssetDefinitionValues.create({
...spec,
name: "Replica a",
inverseName: "Replicado desde",
symmetric: false,
});
assert.ok(custom.isSuccess);
const protectedChange = catalog.save(Maybe.none(), Maybe.some(stock.id), custom.data);
assert.ok(!protectedChange.isSuccess);
assert.equal(protectedChange.error.code, "BUILTIN_PROTECTED");
const status = catalog.setActive(scope, stock.id, false);
assert.ok(status.isSuccess);
catalog = status.data;
assert.equal(catalog.active(stock, scope), false);
assert.equal(catalog.active(stock, other), true);
const added = catalog.save(scope, Maybe.none(), custom.data);
assert.ok(added.isSuccess);
catalog = added.data;
const item = catalog.definitions.at(-1);
assert.ok(item);
assert.equal(
catalog.visible(other).some((entry) => entry.id.equals(item.id)),
false
);
const converted = AssetDefinitionValues.create({ ...spec, name: "Replica a" });
assert.ok(converted.isSuccess);
const rejected = catalog.save(scope, Maybe.some(item.id), converted.data);
assert.ok(!rejected.isSuccess);
assert.equal(rejected.error.code, "RELATION_DIRECTION_FIXED");
const unchanged = catalog.save(scope, Maybe.some(item.id), custom.data);
assert.ok(unchanged.isSuccess);
assert.equal(unchanged.data, catalog);
});