FactuGES_ERP/apps/server/src/lib/modules/module-loader.test.ts

153 lines
3.4 KiB
TypeScript
Raw Normal View History

import assert from "node:assert/strict";
import test from "node:test";
import type { IModuleServer, ModuleParams } from "@erp/core/api";
import { resetModelsRegistry } from "./model-loader";
import { initModules, registerModule, resetModuleRegistry } from "./module-loader";
import { listServices, resetServiceRegistry } from "./service-registry";
type FakeDatabase = {
sync: () => Promise<void>;
models: Record<string, unknown>;
};
function buildModuleParams(): ModuleParams & {
config: { database: { syncMode: string } };
database: FakeDatabase;
logger: Console;
} {
return {
getService: () => {
throw new Error("Base params getService should not be called directly in tests.");
},
config: {
database: {
syncMode: "none",
},
},
database: {
sync: async () => undefined,
models: {},
},
logger: console,
};
}
function resetModuleTestState(): void {
resetServiceRegistry();
resetModuleRegistry();
resetModelsRegistry();
}
test("module-loader permite dependencias externas declaradas", async (t) => {
resetModuleTestState();
t.after(resetModuleTestState);
let receivedService = "";
const catalogsModule: IModuleServer = {
name: "catalogs",
version: "1.0.0",
setup: () => ({
services: {
general: {
name: "catalogs-service",
},
},
}),
};
const companiesModule: IModuleServer = {
name: "companies",
version: "1.0.0",
dependencies: ["catalogs"],
start: ({ getService }) => {
const service = getService<{ name: string }>("catalogs:general");
receivedService = service.name;
},
};
registerModule(catalogsModule);
registerModule(companiesModule);
await initModules(buildModuleParams());
assert.equal(receivedService, "catalogs-service");
assert.deepEqual(listServices().sort(), ["catalogs:general"]);
});
test("module-loader falla cuando una dependencia usada no está declarada", async (t) => {
resetModuleTestState();
t.after(resetModuleTestState);
registerModule({
name: "catalogs",
version: "1.0.0",
setup: () => ({
services: {
general: {
name: "catalogs-service",
},
},
}),
});
registerModule({
name: "companies",
version: "1.0.0",
start: ({ getService }) => {
getService("catalogs:general");
},
});
await assert.rejects(
() => initModules(buildModuleParams()),
/without declaring dependency on "catalogs"/i
);
});
test("module-loader sigue detectando ciclos reales entre módulos", async (t) => {
resetModuleTestState();
t.after(resetModuleTestState);
registerModule({
name: "companies",
version: "1.0.0",
dependencies: ["catalogs"],
});
registerModule({
name: "catalogs",
version: "1.0.0",
dependencies: ["companies"],
});
await assert.rejects(() => initModules(buildModuleParams()), /cyclic dependency detected/i);
});
test("module-loader rechaza la autoreferencia explícita por nombre de módulo", async (t) => {
resetModuleTestState();
t.after(resetModuleTestState);
registerModule({
name: "companies",
version: "1.0.0",
setup: () => ({
services: {
general: {
name: "companies-service",
},
},
}),
start: ({ getService }) => {
getService("companies:general");
},
});
await assert.rejects(
() => initModules(buildModuleParams()),
/without declaring dependency on "companies"/i
);
});