forked from jappel/leistungsbilanz-ts
tsx runs tests without type checking and tsconfig.json covers only src, so 71 type errors had accumulated unnoticed. tsconfig.tests.json now checks every test and helper, and npm run typecheck includes it. Fixtures gain the fields the DTOs have grown since they were written (manualQuantity, circuit apparent power/cos phi, downstream board loads, section totals, building, cover and board info fields). Repository lookups that return "row ?? null" now declare the null in their type, which their callers already handle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
87 lines
3.5 KiB
TypeScript
87 lines
3.5 KiB
TypeScript
import path from "node:path";
|
|
import assert from "node:assert/strict";
|
|
import { describe, it } from "node:test";
|
|
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
|
import { createDatabaseContext } from "../src/db/database-context.js";
|
|
import { parseExternalModelStateSnapshot } from "../src/domain/models/project-state-snapshot.model.js";
|
|
import { createDefaultExternalModelConfiguration } from "../src/external-model/configuration/external-model-configuration.js";
|
|
|
|
const lowerId = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee-ffffffff";
|
|
const upperId = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE-FFFFFFFF";
|
|
|
|
function fullBatch(id: string, importedAtIso: string) {
|
|
return {
|
|
id,
|
|
projectId: "p",
|
|
sourceId: "s",
|
|
importKind: "follow_up" as const,
|
|
importedAtIso,
|
|
fileName: `${id}.xlsx`,
|
|
sha256: "a".repeat(64),
|
|
objectCount: 1,
|
|
appliedProjectRevision: 3,
|
|
configurationSnapshot: createDefaultExternalModelConfiguration(),
|
|
originalContentBase64: "AA==",
|
|
document: {
|
|
sheetName: "Bauteilliste",
|
|
headerRowNumber: 1,
|
|
firstDataRowNumber: 3,
|
|
firstDataColumnNumber: 1,
|
|
columns: [],
|
|
rows: [],
|
|
issues: [],
|
|
},
|
|
};
|
|
}
|
|
|
|
describe("Linear XLSX external model foundation", () => {
|
|
it("keeps only the newest batch complete", () => {
|
|
const newest = fullBatch("new", "2026-02-01T00:00:00.000Z");
|
|
const older = {
|
|
...fullBatch("old", "2026-01-01T00:00:00.000Z"),
|
|
appliedProjectRevision: null,
|
|
configurationSnapshot: null,
|
|
originalContentBase64: null,
|
|
document: null,
|
|
};
|
|
assert.doesNotThrow(() => parseExternalModelStateSnapshot({
|
|
source: { id: "s", projectId: "p", name: "Revit", sourceType: "revit_xlsx" },
|
|
importBatches: [older, newest],
|
|
roomMappings: [],
|
|
objects: [],
|
|
}));
|
|
assert.throws(() => parseExternalModelStateSnapshot({
|
|
source: { id: "s", projectId: "p", name: "Revit", sourceType: "revit_xlsx" },
|
|
importBatches: [newest, fullBatch("newer", "2026-03-01T00:00:00.000Z")],
|
|
roomMappings: [],
|
|
objects: [],
|
|
}), /Nur der letzte Importbatch/);
|
|
});
|
|
|
|
it("compares Worksharing-IDs exactly and allows duplicate IfcGUID values", () => {
|
|
const context = createDatabaseContext(":memory:");
|
|
try {
|
|
migrate(context.db, { migrationsFolder: path.resolve("src", "db", "migrations") });
|
|
context.sqlite.exec(`
|
|
INSERT INTO projects (id, name) VALUES ('p', 'Projekt');
|
|
INSERT INTO external_model_sources (id, project_id, name) VALUES ('s', 'p', 'Revit');
|
|
INSERT INTO external_import_batches
|
|
(id, project_id, source_id, import_kind, imported_at_iso, file_name, sha256, object_count)
|
|
VALUES ('b', 'p', 's', 'initial', '2026-01-01T00:00:00.000Z', 'model.xlsx', '${"a".repeat(64)}', 2);
|
|
`);
|
|
const insert = context.sqlite.prepare(`
|
|
INSERT INTO external_model_objects
|
|
(id, project_id, source_id, worksharing_id, ifc_guid, device_type_id,
|
|
last_seen_import_batch_id, last_accepted_import_batch_id,
|
|
accepted_source_values, planning_values, overridden_fields)
|
|
VALUES (?, 'p', 's', ?, 'same-IfcGUID', 'type', 'b', 'b', '{}', '{}', '[]')
|
|
`);
|
|
insert.run("o1", lowerId);
|
|
insert.run("o2", upperId);
|
|
assert.equal(context.sqlite.prepare<[], { count: number }>("SELECT count(*) AS count FROM external_model_objects").get()!.count, 2);
|
|
assert.throws(() => insert.run("o3", lowerId), /UNIQUE constraint failed/);
|
|
} finally {
|
|
context.close();
|
|
}
|
|
});
|
|
});
|