212 lines
7.9 KiB
TypeScript
212 lines
7.9 KiB
TypeScript
import assert from "node:assert/strict";
|
|
|
|
import { CatalogResponseSchema, SaveDefinitionResponseSchema } from "@metis/assets/common";
|
|
import { createAssetModule } from "@metis/assets/module";
|
|
import type { Sequelize } from "sequelize";
|
|
import { z } from "zod/v4";
|
|
export async function verifyAssets(
|
|
request: (path: string, body?: unknown, origin?: string, token?: string) => Promise<Response>,
|
|
companyId: string,
|
|
otherId: string,
|
|
database: Sequelize
|
|
) {
|
|
const global = "/asset-catalog/global";
|
|
const company = `/asset-catalog/${companyId}`;
|
|
const other = `/asset-catalog/${otherId}`;
|
|
async function read(path: string) {
|
|
const response = await request(path);
|
|
assert.equal(response.status, 200);
|
|
return CatalogResponseSchema.parse(await response.json());
|
|
}
|
|
async function save(path: string, values: unknown) {
|
|
const response = await request(path, { values });
|
|
assert.ok([200, 201].includes(response.status), await response.clone().text());
|
|
return SaveDefinitionResponseSchema.parse(await response.json());
|
|
}
|
|
async function error(path: string, body: unknown, code: string, status = 409) {
|
|
const response = await request(path, body);
|
|
assert.equal(response.status, status);
|
|
const data = z.object({ code: z.string() }).parse(await response.json());
|
|
assert.equal(data.code, code);
|
|
}
|
|
const initial = await read(global);
|
|
assert.equal(initial.items.length, 47);
|
|
assert.equal(initial.items.filter((item) => item.values.kind === "template").length, 12);
|
|
assert.ok(initial.items.every((item) => item.builtin && item.id.charAt(14) === "7"));
|
|
assert.ok(
|
|
initial.items.every((item) =>
|
|
item.bindings.every((binding) => !binding.required && binding.id.charAt(14) === "7")
|
|
)
|
|
);
|
|
const stock = initial.items.find((item) => item.values.name === "Procesador");
|
|
assert.ok(stock);
|
|
await error(
|
|
`${global}/${stock.id}/update`,
|
|
{ values: { ...stock.values, name: "Renombrado" } },
|
|
"BUILTIN_PROTECTED"
|
|
);
|
|
assert.equal(
|
|
(await request(`${global}/${stock.id}/status`, { active: false }, "https://other.example"))
|
|
.status,
|
|
403
|
|
);
|
|
assert.equal(
|
|
(await request(`${global}/${stock.id}/status`, { active: false }, undefined, "a".repeat(64)))
|
|
.status,
|
|
403
|
|
);
|
|
assert.equal((await request(`${global}/${stock.id}/status`, { active: false })).status, 200);
|
|
await createAssetModule(database, (_request, _response, next) => next());
|
|
const restarted = await read(global);
|
|
assert.equal(restarted.items.find((item) => item.id === stock.id)?.effectiveActive, false);
|
|
assert.deepEqual(
|
|
restarted.items.map((item) => item.id).sort(),
|
|
initial.items.map((item) => item.id).sort()
|
|
);
|
|
assert.equal((await request(`${global}/${stock.id}/status`, { active: true })).status, 200);
|
|
assert.equal((await request(`${company}/${stock.id}/status`, { active: false })).status, 200);
|
|
assert.equal(
|
|
(await read(company)).items.find((item) => item.id === stock.id)?.effectiveActive,
|
|
false
|
|
);
|
|
assert.equal(
|
|
(await read(other)).items.find((item) => item.id === stock.id)?.effectiveActive,
|
|
true
|
|
);
|
|
assert.equal((await read(global)).items.find((item) => item.id === stock.id)?.active, true);
|
|
assert.equal((await request(`${company}/${stock.id}/status`, { active: null })).status, 200);
|
|
assert.equal((await read(company)).items.find((item) => item.id === stock.id)?.overridden, false);
|
|
const localValues = {
|
|
kind: "field",
|
|
name: "Código interno",
|
|
type: "text",
|
|
description: "",
|
|
unit: "",
|
|
choices: [],
|
|
};
|
|
const local = await save(company, localValues);
|
|
const field = local.items.find((item) => item.id === local.savedId);
|
|
assert.ok(field);
|
|
assert.equal(field.companyId, companyId);
|
|
assert.equal(field.builtin, false);
|
|
assert.ok(!(await read(other)).items.some((item) => item.id === field.id));
|
|
assert.ok(!(await read(global)).items.some((item) => item.id === field.id));
|
|
await error(company, { values: { ...localValues, name: " código INTERNO " } }, "NAME_EXISTS");
|
|
await error(`${other}/${field.id}/update`, { values: localValues }, "DEFINITION_NOT_FOUND", 404);
|
|
await error(
|
|
`${company}/${field.id}/update`,
|
|
{ values: { ...localValues, type: "number" } },
|
|
"FIELD_TYPE_FIXED"
|
|
);
|
|
const templateValues = {
|
|
kind: "template",
|
|
name: "Equipo especial",
|
|
description: "",
|
|
fields: [
|
|
{ fieldId: field.id, required: false },
|
|
{ fieldId: stock.id, required: false },
|
|
],
|
|
};
|
|
await error(global, { values: templateValues }, "FIELD_UNAVAILABLE");
|
|
await error(other, { values: templateValues }, "FIELD_UNAVAILABLE");
|
|
const template = await save(company, templateValues);
|
|
const saved = template.items.find((item) => item.id === template.savedId);
|
|
assert.ok(saved);
|
|
const edited = await save(`${company}/${saved.id}/update`, {
|
|
...templateValues,
|
|
name: "Equipo especial actualizado",
|
|
});
|
|
assert.equal(edited.savedId, saved.id);
|
|
assert.deepEqual(edited.items.find((item) => item.id === saved.id)?.bindings, saved.bindings);
|
|
await error(
|
|
company,
|
|
{
|
|
values: {
|
|
...templateValues,
|
|
name: "Duplicado",
|
|
fields: [templateValues.fields[0], templateValues.fields[0]],
|
|
},
|
|
},
|
|
"INVALID_FIELDS"
|
|
);
|
|
const status = await request(`${company}/${field.id}/status`, { active: false });
|
|
assert.equal(status.status, 200);
|
|
await error(
|
|
company,
|
|
{ values: { ...templateValues, name: "Campo inactivo" } },
|
|
"FIELD_UNAVAILABLE"
|
|
);
|
|
assert.ok((await read(company)).items.some((item) => item.id === saved.id));
|
|
await save(`${company}/${saved.id}/update`, {
|
|
...templateValues,
|
|
name: "Equipo especial actualizado",
|
|
});
|
|
const list = {
|
|
kind: "field",
|
|
name: "Estado batería",
|
|
type: "choice",
|
|
unit: "",
|
|
description: "",
|
|
choices: ["Buena", "Sustituir"],
|
|
};
|
|
const custom = await save(global, list);
|
|
await error(
|
|
`${global}/${custom.savedId}/update`,
|
|
{ values: { ...list, choices: ["Buena"] } },
|
|
"FIELD_TYPE_FIXED"
|
|
);
|
|
await save(`${global}/${custom.savedId}/update`, {
|
|
...list,
|
|
choices: [...list.choices, "Desconocida"],
|
|
});
|
|
await error(global, { values: { ...list, name: "Sin valores", choices: [] } }, "INVALID_CHOICES");
|
|
const monitor = initial.items.find((item) => item.values.name === "Monitor");
|
|
assert.ok(monitor && monitor.values.kind === "template");
|
|
const binding = monitor.bindings[0];
|
|
assert.ok(binding);
|
|
try {
|
|
await database.query("UPDATE asset_definitions SET `values`=:values WHERE id=:id", {
|
|
replacements: {
|
|
id: monitor.id,
|
|
values: JSON.stringify({
|
|
...monitor.values,
|
|
fields: monitor.values.fields.map((entry, index) =>
|
|
index === 0 ? { ...entry, fieldId: field.id } : entry
|
|
),
|
|
}),
|
|
},
|
|
});
|
|
await database.query("UPDATE asset_template_fields SET fieldId=:fieldId WHERE id=:id", {
|
|
replacements: { fieldId: field.id, id: binding.id },
|
|
});
|
|
const corrupt = await request(global);
|
|
assert.equal(corrupt.status, 500);
|
|
const hidden = z.object({ code: z.string() }).parse(await corrupt.json());
|
|
assert.equal(hidden.code, "INTERNAL_ERROR");
|
|
} finally {
|
|
await database.query("UPDATE asset_template_fields SET fieldId=:fieldId WHERE id=:id", {
|
|
replacements: { fieldId: binding.fieldId, id: binding.id },
|
|
});
|
|
await database.query("UPDATE asset_definitions SET `values`=:values WHERE id=:id", {
|
|
replacements: { values: JSON.stringify(monitor.values), id: monitor.id },
|
|
});
|
|
}
|
|
const concurrent = await Promise.all([
|
|
request(company, { values: { ...localValues, name: "Concurrente" } }),
|
|
request(company, { values: { ...localValues, name: "Concurrente" } }),
|
|
]);
|
|
assert.deepEqual(concurrent.map((response) => response.status).sort(), [201, 409]);
|
|
await error(
|
|
`/asset-catalog/${"82be74bb-894f-4cca-ac7b-dedc96c15689"}`,
|
|
undefined,
|
|
"COMPANY_NOT_FOUND",
|
|
404
|
|
);
|
|
await error(
|
|
global,
|
|
{ values: { ...localValues, name: "Injection", builtin: true } },
|
|
"INVALID_REQUEST",
|
|
400
|
|
);
|
|
}
|