import fs from "node:fs"; import path from "node:path"; import request from "supertest"; import { describe, expect, it } from "vitest"; import { buildApp } from "../src/app.js"; const ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), "../../"); const xml = fs.readFileSync(path.join(ROOT, "data/cases/base-case.xml"), "utf-8"); describe("quality gates", () => { it("cross-model comparison has finite residuals when both solvers run", async () => { const app = buildApp(); const response = await request(app).post("/solve").send({ xml, solverModel: "both" }); expect(response.status).toBe(200); const rms = response.body.comparison.residualSummary.rms; expect(Number.isFinite(rms)).toBe(true); expect(rms).toBeGreaterThan(0); expect(response.body.comparison.pointwiseResiduals.series.length).toBe( response.body.comparison.pointwiseResiduals.points ); }); it("perturbing rod friction changes peak polished load (field sensitivity)", async () => { const app = buildApp(); const xmlHi = xml.replace( "0.2", "0.28" ); const base = await request(app).post("/solve").send({ xml, solverModel: "fdm" }); const perturbed = await request(app).post("/solve").send({ xml: xmlHi, solverModel: "fdm" }); expect(base.status).toBe(200); expect(perturbed.status).toBe(200); expect(perturbed.body.solver.maxPolishedLoad).not.toBe(base.body.solver.maxPolishedLoad); }); it("includes fieldTraceability on POST /solve", async () => { const app = buildApp(); const response = await request(app).post("/solve").send({ xml }); expect(response.status).toBe(200); expect(response.body.fieldTraceability?.schemaVersion).toBe(2); const pumpDepth = response.body.fieldTraceability.fields.find((f) => f.xmlKey === "PumpDepth"); expect(pumpDepth?.category).toBe("physics"); }); });