metis-desk/modules/companies/src/api/domain/application-configuration.test.ts

247 lines
8.0 KiB
TypeScript
Raw Normal View History

import assert from "node:assert/strict";
import { test } from "node:test";
import { UniqueID } from "@repo/rdx-ddd";
import type { ApplicationContext } from "../application/application-configuration.repository";
import { mapApplicationInput } from "../application/application-configuration-input.mapper";
import { buildApplicationResponse } from "../application/application-configuration-response.builder";
import { ApplicationConfigurationPersistenceMapper } from "../infrastructure/persistence/application-configuration-persistence.mapper";
import { ApplicationConfiguration } from "./application-configuration.aggregate";
2026-10-08 14:43:34 +00:00
import type { ApplicationConfigurationInput } from "./application-configuration-values";
import { ApplicationConfigurationInputSchema } from "./application-configuration-values";
2026-10-09 08:38:19 +00:00
import { ApplicationConfigurationValues } from "./value-objects/application-configuration-values.vo";
import { WorkProfileValues } from "./value-objects/work-profile-values.vo";
import { WorkProfile } from "./work-profile.aggregate";
const company = UniqueID.generateNewID();
const actor = UniqueID.generateNewID();
const person = UniqueID.generateNewID();
const host = UniqueID.generateNewID();
const resource = UniqueID.generateNewID();
const date = "2026-10-06T12:00:00.000Z";
2026-10-10 10:01:58 +00:00
function fixture() {
const value = WorkProfileValues.create({
name: "Ana",
personId: person.toPrimitive(),
assetId: host.toPrimitive(),
accountId: null,
active: true,
notes: null,
});
2026-10-10 10:01:58 +00:00
assert.ok(value.isSuccess);
const profile = WorkProfile.create(company, value.data, actor, date);
2026-10-10 10:01:58 +00:00
assert.ok(profile.isSuccess);
const input: ApplicationConfigurationInput = {
profileId: profile.data.id.toPrimitive(),
resourceId: resource.toPrimitive(),
delivery: "installed",
version: null,
state: "pending",
notes: null,
};
const context: ApplicationContext = {
profiles: [profile.data],
configurations: [],
people: [{ id: person, active: true }],
assets: [{ id: host, available: true }],
resources: [{ id: resource, active: true, usage: "application" }],
actors: new Map([[actor.toPrimitive(), "Técnico"]]),
};
2026-10-10 10:01:58 +00:00
return { input, context };
}
2026-10-10 10:01:58 +00:00
function values(input: ApplicationConfigurationInput) {
const value = ApplicationConfigurationValues.create(input);
2026-10-10 10:01:58 +00:00
assert.ok(value.isSuccess);
2026-10-10 10:01:58 +00:00
return value.data;
}
2026-10-10 10:01:58 +00:00
function create(input: ApplicationConfigurationInput) {
const root = ApplicationConfiguration.create(company, values(input), actor, date);
2026-10-10 10:01:58 +00:00
assert.ok(root.isSuccess);
2026-10-10 10:01:58 +00:00
return root.data;
}
2026-10-10 10:01:58 +00:00
test("aplicaciones: contrato estricto, versión opcional y solo instalada", () => {
const { input } = fixture();
2026-10-10 10:01:58 +00:00
assert.equal(
ApplicationConfigurationInputSchema.safeParse({ ...input, actorId: actor.toPrimitive() })
.success,
false
);
assert.equal(
ApplicationConfigurationValues.create({ ...input, delivery: "web", version: "1" }).isSuccess,
false
);
assert.equal(values({ ...input, version: " ", notes: " " }).toPrimitive().version, null);
assert.equal(values({ ...input, delivery: "web" }).toPrimitive().version, null);
assert.equal(
ApplicationConfigurationValues.create({ ...input, version: "a".repeat(101) }).isSuccess,
false
);
assert.equal(
ApplicationConfigurationValues.create({ ...input, notes: "a".repeat(4001) }).isSuccess,
false
);
});
test("aplicaciones: UUID, idempotencia, versión auditada, destino fijo y retirada", () => {
const { input } = fixture();
const root = create(input);
2026-10-10 10:01:58 +00:00
assert.equal(root.id.toPrimitive()[14], "7");
assert.equal(root.history[0]?.id.toPrimitive()[14], "7");
const same = root.update(values({ ...input, notes: " " }), actor, date);
2026-10-10 10:01:58 +00:00
assert.ok(same.isSuccess);
assert.equal(same.data, root);
const configured = root.update(
values({ ...input, state: "configured", version: "128" }),
actor,
date
);
2026-10-10 10:01:58 +00:00
assert.ok(configured.isSuccess);
assert.equal(configured.data.history.length, 2);
assert.equal(configured.data.history[0]?.values.version.getOrUndefined(), undefined);
assert.equal(
configured.data.update(
values({ ...input, resourceId: UniqueID.generateNewID().toPrimitive() }),
actor,
date
).isSuccess,
false
);
const removal = configured.data.update(
values({ ...configured.data.values.toPrimitive(), state: "removal_pending" }),
actor,
date
);
2026-10-10 10:01:58 +00:00
assert.ok(removal.isSuccess);
const removed = removal.data.update(
values({ ...removal.data.values.toPrimitive(), state: "removed" }),
actor,
date
);
2026-10-10 10:01:58 +00:00
assert.ok(removed.isSuccess);
assert.equal(
removed.data.update(
values({ ...removed.data.values.toPrimitive(), notes: "Otra" }),
actor,
date
).isSuccess,
false
);
assert.equal(
root.update(values({ ...input, state: "configured" }), actor, "2026-10-05T12:00:00.000Z")
.isSuccess,
false
);
assert.equal(
ApplicationConfiguration.create(company, values({ ...input, state: "removed" }), actor, date)
.isSuccess,
false
);
});
test("aplicaciones: ámbito y clasificación explícita, duplicados abiertos y reapertura nueva", () => {
const { input, context } = fixture();
const root = create(input);
const duplicate = mapApplicationInput(input, { ...context, configurations: [root] });
2026-10-10 10:01:58 +00:00
assert.ok(!duplicate.isSuccess);
assert.equal(duplicate.error.code, "APPLICATION_ALREADY_OPEN");
assert.equal(
mapApplicationInput({ ...input, resourceId: host.toPrimitive() }, context).isSuccess,
false
);
assert.equal(
mapApplicationInput(input, {
...context,
resources: [{ id: resource, active: true, usage: "certificate" }],
}).isSuccess,
false
);
assert.equal(
mapApplicationInput(input, {
...context,
resources: [{ id: resource, active: true, usage: null }],
}).isSuccess,
false
);
const closed = root.update(values({ ...input, state: "never_configured" }), actor, date);
2026-10-10 10:01:58 +00:00
assert.ok(closed.isSuccess);
assert.ok(mapApplicationInput(input, { ...context, configurations: [closed.data] }).isSuccess);
});
test("aplicaciones: inactividad conserva notas y permite retirada, impide reconfigurar", () => {
const { input, context } = fixture();
const root = create({ ...input, state: "configured" });
const inactive = {
...context,
configurations: [root],
resources: [{ id: resource, active: false, usage: "application" as const }],
};
2026-10-10 10:01:58 +00:00
assert.equal(buildApplicationResponse(root, inactive).needsReview, true);
assert.ok(
mapApplicationInput({ ...root.values.toPrimitive(), notes: "Retirar" }, inactive, root)
.isSuccess
);
assert.ok(
mapApplicationInput({ ...root.values.toPrimitive(), state: "removal_pending" }, inactive, root)
.isSuccess
);
assert.equal(
mapApplicationInput({ ...root.values.toPrimitive(), version: "2" }, inactive, root).isSuccess,
false
);
assert.equal(
mapApplicationInput({ ...root.values.toPrimitive(), delivery: "web" }, inactive, root)
.isSuccess,
false
);
assert.equal(
mapApplicationInput(input, { ...context, people: [{ id: person, active: false }] }).isSuccess,
false
);
assert.equal(
mapApplicationInput(input, { ...context, assets: [{ id: host, available: false }] }).isSuccess,
false
);
});
test("aplicaciones: persistencia preserva historial y rechaza claves y orden incoherentes", () => {
const { input } = fixture();
const root = create(input);
const mapper = new ApplicationConfigurationPersistenceMapper();
const record = mapper.toPersistence(root);
const rehydrated = mapper.toDomain(record.root, record.revisions);
2026-10-10 10:01:58 +00:00
assert.ok(rehydrated.id.equals(root.id));
assert.ok(rehydrated.history[0]?.id.equals(root.history[0]?.id));
assert.throws(() => mapper.toDomain({ ...record.root, currentKey: null }, record.revisions));
assert.throws(() =>
mapper.toDomain(
record.root,
record.revisions.map((r) => ({ ...r, position: 1 }))
)
);
assert.throws(() =>
mapper.toDomain(
record.root,
record.revisions.map((r) => ({ ...r, configurationId: company.toPrimitive() }))
)
);
});