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") ); });