FactuGES_ERP/tests/e2e/support/e2e-lifecycle.test.ts
David da362fef64 feat(e2e): implement end-to-end testing framework with database preparation and lifecycle management
- Add E2ESchemaDatabaseConfig interface for database configuration validation.
- Implement assertE2ESchemaDatabaseConfig function to enforce schema requirements.
- Create prepareE2ESchema function to handle schema preparation and initialization.
- Develop E2E lifecycle management functions to provision, prepare, and run tests.
- Introduce Docker Compose setup for E2E database environment.
- Add Playwright configuration for E2E testing.
- Implement various test cases to validate E2E schema preparation and lifecycle.
- Create utility functions for environment variable management and database assertions.
- Establish smoke tests to verify initial data setup and integrity.
2026-09-22 16:49:08 +02:00

195 lines
5.3 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { runE2ELifecycle } from "./e2e-lifecycle.ts";
test("prepara antes de ejecutar el hijo y limpia tras éxito", async () => {
const events: string[] = [];
const result = await runE2ELifecycle({
provision: async () => ({
environment: { DB_NAME: "e2e" },
destroy: async () => events.push("cleanup"),
}),
prepare: async () => {
events.push("prepare");
},
bootstrap: async () => {
events.push("bootstrap");
},
runChild: async (env) => {
events.push(env.DB_NAME);
return 0;
},
});
assert.equal(result, 0);
assert.deepEqual(events, ["prepare", "bootstrap", "e2e", "cleanup"]);
});
test("limpia tras código de salida no cero y conserva su código", async () => {
let cleaned = false;
const result = await runE2ELifecycle({
provision: async () => ({
environment: {},
destroy: async () => {
cleaned = true;
},
}),
prepare: async () => undefined,
bootstrap: async () => undefined,
runChild: async () => 3,
});
assert.equal(result, 3);
assert.equal(cleaned, true);
});
test("no intenta limpiar si falla el provisionado", async () => {
await assert.rejects(
() =>
runE2ELifecycle({
provision: async () => {
throw new Error("provision");
},
prepare: async () => undefined,
bootstrap: async () => undefined,
runChild: async () => 0,
}),
/provision/
);
});
test("un fallo de cleanup no oculta una excepción del hijo", async () => {
await assert.rejects(
() =>
runE2ELifecycle({
provision: async () => ({
environment: {},
destroy: async () => {
throw new Error("cleanup");
},
}),
prepare: async () => undefined,
bootstrap: async () => undefined,
runChild: async () => {
throw new Error("child");
},
}),
(error: unknown) =>
error instanceof AggregateError &&
error.errors.some((value) => value instanceof Error && value.message === "child") &&
error.errors.some((value) => value instanceof Error && value.message === "cleanup")
);
});
test("un fallo de cleanup tras éxito hace fallar el lifecycle", async () => {
await assert.rejects(
() =>
runE2ELifecycle({
provision: async () => ({
environment: {},
destroy: async () => {
throw new Error("cleanup");
},
}),
prepare: async () => undefined,
bootstrap: async () => undefined,
runChild: async () => 0,
}),
/cleanup/
);
});
test("un fallo de preparación impide el hijo y mantiene cleanup", async () => {
const events: string[] = [];
await assert.rejects(
() =>
runE2ELifecycle({
provision: async () => ({
environment: {},
destroy: async () => {
events.push("cleanup");
},
}),
prepare: async () => {
events.push("prepare");
throw new Error("prepare");
},
bootstrap: async () => undefined,
runChild: async () => {
events.push("child");
return 0;
},
}),
/prepare/
);
assert.deepEqual(events, ["prepare", "cleanup"]);
});
test("preserva el fallo de preparación y el de cleanup", async () => {
await assert.rejects(
() =>
runE2ELifecycle({
provision: async () => ({
environment: {},
destroy: async () => {
throw new Error("cleanup");
},
}),
prepare: async () => {
throw new Error("prepare");
},
bootstrap: async () => undefined,
runChild: async () => 0,
}),
(error: unknown) =>
error instanceof AggregateError &&
error.errors.some((value) => value instanceof Error && value.message === "prepare") &&
error.errors.some((value) => value instanceof Error && value.message === "cleanup")
);
});
test("un fallo de bootstrap impide el hijo y mantiene cleanup", async () => {
const events: string[] = [];
await assert.rejects(
() =>
runE2ELifecycle({
provision: async () => ({ environment: {}, destroy: async () => events.push("cleanup") }),
prepare: async () => events.push("prepare"),
bootstrap: async () => {
events.push("bootstrap");
throw new Error("bootstrap");
},
runChild: async () => {
events.push("child");
return 0;
},
}),
/bootstrap/
);
assert.deepEqual(events, ["prepare", "bootstrap", "cleanup"]);
});
test("preserva el fallo de bootstrap y el de cleanup", async () => {
await assert.rejects(
() =>
runE2ELifecycle({
provision: async () => ({
environment: {},
destroy: async () => {
throw new Error("cleanup");
},
}),
prepare: async () => undefined,
bootstrap: async () => {
throw new Error("bootstrap");
},
runChild: async () => 0,
}),
(error: unknown) =>
error instanceof AggregateError &&
error.errors.some((value) => value instanceof Error && value.message === "bootstrap") &&
error.errors.some((value) => value instanceof Error && value.message === "cleanup")
);
});