- Implemented ProcessFeedback component for error handling in process forms. - Created ProcessHelp component to provide contextual assistance for users. - Added internationalization support for process-related strings in Spanish and English. - Developed ProcessStartForm for initiating new processes with person and template selection. - Introduced ProcessTemplateForm for creating and editing process templates. - Built ProcessTemplatesPage to display and manage process templates. - Enhanced ProcessesPage to list current processes and allow for creation and detail viewing. - Added unit tests for various components to ensure functionality and correctness.
158 lines
5.6 KiB
TypeScript
158 lines
5.6 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "node:test";
|
|
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
import { createInstance } from "i18next";
|
|
import type { ReactNode } from "react";
|
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
import { I18nextProvider } from "react-i18next";
|
|
|
|
import { PersonProcessSchema } from "../../common/processes";
|
|
import { companiesEnglish, companiesSpanish } from "../i18n";
|
|
|
|
import { processKeys } from "./process-api";
|
|
import { ProcessDetail } from "./process-detail";
|
|
import { ProcessEditForm } from "./process-edit-form";
|
|
import { ProcessStartForm } from "./process-start-form";
|
|
import { ProcessTemplateForm } from "./process-template-form";
|
|
import { ProcessTemplatesPage } from "./process-templates-page";
|
|
import { ProcessesPage } from "./processes-page";
|
|
|
|
const company = {
|
|
id: "0199b200-0000-7000-8000-000000000001",
|
|
name: "Empresa",
|
|
active: true,
|
|
people: [],
|
|
contacts: [],
|
|
sites: [],
|
|
departments: [],
|
|
assignments: [],
|
|
};
|
|
async function render(language: string, node: ReactNode) {
|
|
const i18n = createInstance();
|
|
await i18n.init({
|
|
lng: language,
|
|
resources: { es: { companies: companiesSpanish }, en: { companies: companiesEnglish } },
|
|
});
|
|
const client = new QueryClient({
|
|
defaultOptions: { queries: { retry: false, staleTime: Number.POSITIVE_INFINITY } },
|
|
});
|
|
client.setQueryData(processKeys.company(company.id), { processes: [] });
|
|
client.setQueryData(processKeys.catalog(), { templates: [] });
|
|
try {
|
|
return renderToStaticMarkup(
|
|
<I18nextProvider i18n={i18n}>
|
|
<QueryClientProvider client={client}>{node}</QueryClientProvider>
|
|
</I18nextProvider>
|
|
).replaceAll("'", "'");
|
|
} finally {
|
|
client.clear();
|
|
}
|
|
}
|
|
test("procesos: listados es/en sin formularios junto a los datos", async () => {
|
|
for (const language of ["es", "en"]) {
|
|
const text = language === "es" ? companiesSpanish : companiesEnglish;
|
|
const html = await render(language, <ProcessesPage company={company} csrfToken="test" />);
|
|
assert.ok(html.includes(text.processes.new) && html.includes(text.processes.templates));
|
|
assert.ok(!html.includes("<form"));
|
|
const templates = await render(language, <ProcessTemplatesPage csrfToken="test" />);
|
|
assert.ok(templates.includes(text.processes.globalTemplates));
|
|
assert.ok(!templates.includes("<form"));
|
|
}
|
|
});
|
|
test("procesos: alta rápida y ayuda inferior antes del pie", async () => {
|
|
for (const language of ["es", "en"]) {
|
|
const text = language === "es" ? companiesSpanish : companiesEnglish;
|
|
const html = await render(
|
|
language,
|
|
<ProcessStartForm company={company} csrfToken="test" onSaved={() => undefined} />
|
|
);
|
|
assert.ok(html.includes(text.newPerson) && html.includes(text.processes.newTemplate));
|
|
assert.ok(html.indexOf(text.processes.help.title) > html.indexOf(text.mail.notes));
|
|
assert.ok(html.indexOf(text.save) > html.indexOf(text.processes.help.title));
|
|
}
|
|
});
|
|
test("plantillas: instrucciones, desactivación y ayuda global es/en sin datos de compañía", async () => {
|
|
for (const language of ["es", "en"]) {
|
|
const text = language === "es" ? companiesSpanish : companiesEnglish;
|
|
const html = await render(
|
|
language,
|
|
<ProcessTemplateForm csrfToken="test" onSaved={() => undefined} />
|
|
);
|
|
assert.ok(html.includes(text.processes.instructionsHelp));
|
|
assert.ok(html.includes(text.processes.templateHelp.scope));
|
|
assert.ok(html.indexOf(text.save) > html.indexOf(text.processes.templateHelp.title));
|
|
}
|
|
});
|
|
|
|
test("seguimiento: origen personal, revisión actual y edición sin afirmar retirada real; cerrados sin editar", async () => {
|
|
const reference = {
|
|
kind: "remote",
|
|
id: company.id,
|
|
label: "VPN de trabajo",
|
|
sourceKind: "personal_mobile",
|
|
};
|
|
const values = {
|
|
personId: company.id,
|
|
templateId: company.id,
|
|
templateName: "Salida",
|
|
kind: "offboarding",
|
|
name: "Salida Ana",
|
|
notes: null,
|
|
state: "open",
|
|
tasks: [
|
|
{
|
|
id: company.id,
|
|
title: "VPN de trabajo",
|
|
status: "done",
|
|
notes: "Conserva hasta entrega",
|
|
reference,
|
|
},
|
|
],
|
|
};
|
|
const process = PersonProcessSchema.parse({
|
|
id: company.id,
|
|
companyId: company.id,
|
|
values,
|
|
review: [reference],
|
|
history: [
|
|
{
|
|
id: company.id,
|
|
actorId: company.id,
|
|
actorName: "Técnico",
|
|
recordedAt: "2026-10-06T12:00:00.000Z",
|
|
values,
|
|
},
|
|
],
|
|
});
|
|
for (const language of ["es", "en"]) {
|
|
const text = language === "es" ? companiesSpanish : companiesEnglish;
|
|
const html = await render(
|
|
language,
|
|
<ProcessDetail csrfToken="test" person="Ana" process={process} />
|
|
);
|
|
assert.ok(html.includes(text.remote.personal_mobile));
|
|
assert.ok(html.includes(text.processes.stillRecorded));
|
|
assert.ok(
|
|
html.includes(text.processes.resolutionHelp) && html.includes(text.processes.refresh)
|
|
);
|
|
assert.ok(!html.includes("<form"));
|
|
const editor = await render(
|
|
language,
|
|
<ProcessEditForm csrfToken="test" onSaved={() => undefined} process={process} />
|
|
);
|
|
assert.ok(editor.includes(text.processes.taskNotes));
|
|
assert.ok(editor.includes(text.processes.resolutionHelp));
|
|
assert.ok(editor.indexOf(text.save) > editor.indexOf(text.processes.help.title));
|
|
const closed = await render(
|
|
language,
|
|
<ProcessDetail
|
|
csrfToken="test"
|
|
person="Ana"
|
|
process={{ ...process, values: { ...process.values, state: "completed" } }}
|
|
/>
|
|
);
|
|
assert.ok(!(closed.includes(text.processes.update) || closed.includes(text.processes.refresh)));
|
|
}
|
|
});
|