Files
frontend/apps/sn/tests/api-url-contract.test.cjs
T
2026-09-15 10:00:42 +09:00

147 lines
4.6 KiB
JavaScript

const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const { test } = require("node:test");
const { loadTypeScript } = require("./load-typescript.cjs");
const root = path.resolve(__dirname, "..");
// 제거된 서버 alias가 실제 SN 호출 코드·URL 주석에 다시 들어오지 않도록 검증한다.
const retiredSegments = [
"gis-upload",
"ppl-analysis",
"flood-dngr-map",
"sbmrg-dngr-map",
"rain-anls",
"depth-map",
"grid-map",
"aged-status-by-ctpv",
"swage-prcs-zones",
"repair-histories",
"savewithfile",
"fcltppl",
"fcltmhl",
"fcltpump",
"fcltstofcbr",
];
function sourceFiles(directory) {
return fs.readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
const filename = path.join(directory, entry.name);
return entry.isDirectory()
? sourceFiles(filename)
: /\.(?:tsx?|jsx?)$/.test(entry.name)
? [filename]
: [];
});
}
test("SN 실서비스와 business_components 호출은 단일 API 경로만 사용", () => {
const violations = [];
const sources = [];
for (const filename of [
...sourceFiles(path.join(root, "app")),
...sourceFiles(path.join(root, "src")),
...sourceFiles(
path.resolve(root, "../../packages/common/business_components/src"),
),
]) {
const source = fs.readFileSync(filename, "utf8");
sources.push(source);
for (const segment of retiredSegments) {
if (source.includes(`/${segment}`))
violations.push(`${path.relative(root, filename)}: ${segment}`);
}
}
assert.deepEqual(violations, []);
const allSources = sources.join("\n");
for (const segment of [
"pplAnalysis",
"floodDngrMap",
"sbmrgDngrMap",
"rainAnls",
"depthMap",
"gridMap",
"agedStatusByCtpv",
"saveWithFile",
"fcltPpl",
"fcltMhl",
"fcltPump",
"fcltStofcbr",
]) {
assert.ok(
allSources.includes(`/${segment}`),
`canonical API missing: ${segment}`,
);
}
});
test("침수 상세 API는 rainAnls/depthMap을 호출하고 기존 응답 필드를 보존", async () => {
const calls = [];
const client = loadTypeScript(
"app/(map-layout)/map/components/fldngHstry/fldngHstryClient.ts",
{
"@/components/lib/api": {
getData: async (url) => {
calls.push(url);
return url.includes("/rainAnls/")
? { rain_bgng_tm: "2026-09-11 01:00", rain_tot: 0 }
: {
depthMaps: [{ fid: "depth" }],
waterLevelMaps: [{ fid: "level" }],
};
},
},
},
);
const result = await client.loadFldngHstryDetail("F/1");
assert.deepEqual(calls, [
"v1/fldng/hstry/rainAnls/F%2F1",
"v1/fldng/hstry/depthMap/F%2F1",
]);
assert.equal(result.rainAnalysis.rain_bgng_tm, "2026-09-11 01:00");
assert.equal(result.rainAnalysis.rainBgngTm, "2026-09-11 01:00");
assert.equal(result.rainAnalysis.rain_tot, 0);
assert.equal(result.rainAnalysis.rainTot, 0);
assert.deepEqual(result.fldngHstryDepthRows, [{ fid: "depth" }]);
assert.deepEqual(result.fldngHstryWtlvRows, [{ fid: "level" }]);
assert.equal(result.complete, true);
});
test("SN proxy는 gisUpload 단일 route이며 BE GET 목록·POST·하위 작업을 구분", () => {
const screen = fs.readFileSync(
path.join(
root,
"app/(map-layout)/map/components/gisManagement/GisManagementPopupPage.tsx",
),
"utf8",
);
const proxy = fs.readFileSync(
path.join(root, "app/api/gisUpload/route.ts"),
"utf8",
);
assert.ok(screen.includes("v1/map/gisUploadHistories?"));
assert.ok(screen.includes('"/api/gisUpload"'));
assert.ok(!screen.includes('"/api/gis-upload"'));
assert.equal(fs.existsSync(path.join(root, "app/api/gis-upload/route.ts")), false);
assert.ok(!screen.includes("v1/map/gisUploads?"));
assert.ok(screen.includes("v1/map/gisUploads/swagePpl/downloadJobs?"));
assert.ok(proxy.includes('"/sewerage-service/api/v1/map/gisUploads"'));
assert.ok(proxy.includes("export async function POST"));
});
test("서비스 식별자·CMS 계약은 보존되고 fclt+suffix 동적 조합이 없다", () => {
const api = fs.readFileSync(
path.join(root, "app/components/lib/api/index.ts"),
"utf8",
);
const helpers = fs.readFileSync(
path.join(root, "app/components/lib/common/apiHelpers.ts"),
"utf8",
);
assert.ok(api.includes("/sewerage-service/api"));
assert.ok(api.includes("/cms-service"));
assert.ok(api.includes("/geoserver"));
assert.ok(helpers.includes("/api/v1/code/cache/"));
assert.doesNotMatch(helpers, /fclt\$\{|["']fclt["']\s*\+/);
});