const assert = require("node:assert/strict"); const { test } = require("node:test"); const { loadTypeScript } = require("./load-typescript.cjs"); const layer = loadTypeScript("src/features/mapLayers/lib/layer-info.ts"); const { subscribeFlowDirectionMoveEnd } = loadTypeScript( "src/features/mapLayers/lib/flow-direction-listener.ts", ); test("레이어 camel/snake 별칭과 기존 우선순위 유지", () => { assert.equal( layer.getLayerTypeName({ lyrTyNm: " A ", lyrTypeNm: "B", lyr_type_nm: "C", }), "A", ); assert.equal( layer.getLayerTypeName({ lyr_type_nm: " tb_il_swage_prcs_fclt " }), "tb_il_swage_prcs_fclt", ); assert.equal( layer.getLayerFilterSql({ filter_sql: "FCLT_CPCT >= 500" }), "fclt_cpct>=500", ); assert.equal(layer.getLayerTypeName(null), ""); }); test("처리시설 500 경계·동시체크·해제 모드 유지", () => { const large = { lyrTyNm: "tb_il_swage_prcs_fclt", filtrSql: "FCLT_CPCT >= 500", }; const small = { lyr_type_nm: "tb_il_swage_prcs_fclt", lyrNm: "500톤 미만" }; assert.equal(layer.getSwagePrcsFcltLayerMode([]), "none"); assert.equal(layer.getSwagePrcsFcltLayerMode([{ data: large }]), "gte500"); assert.equal(layer.getSwagePrcsFcltLayerMode([small]), "lt500"); assert.equal(layer.getSwagePrcsFcltLayerMode([large, small]), "all"); assert.equal( layer.getSwagePrcsFcltCapacityKind({ ...large, lyrTyNm: "other" }), null, ); }); test("중첩 유하방향·관측소 정규화는 원본을 변경하지 않고 계약 플래그 유지", () => { const original = [ { lyrNm: "root", children: [ { lyrNm: "유하방향", minZoom: 0, clickPsblYn: "Y" }, { lyr_type_nm: "tb_ms_rain_obsvtr_pstn_info", clickPsblYn: "Y" }, { lyrTyNm: "other", clickPsblYn: "Y" }, ], }, ]; const before = JSON.stringify(original); const normalized = layer.normalizeRainObservationLayerInteraction( layer.normalizeFlowDirectionLayerInfos(original), ); const [flow, rain, other] = normalized[0].children; assert.equal(flow.lyrTyNm, "tb_sn_swage_ppl_flow_direction"); assert.equal(flow.srvcNm, "api"); assert.equal(flow.cmncNm, "bbox"); assert.equal(flow.minViewSize, 0); assert.equal(flow.clickPsblYn, "N"); assert.equal(rain.clickPsblYn, "N"); assert.equal(other.clickPsblYn, "Y"); assert.equal(JSON.stringify(original), before); }); test("map/map2·줌·zIndex·BBOX 계산의 0과 빈값 구분", () => { assert.equal( layer.getFlowDirectionModeByPathname("/map2/"), "PIPE_START_END", ); assert.equal(layer.getFlowDirectionModeByPathname("/map"), "PIPE_DEPTH"); assert.equal(layer.getFiniteNumber(" "), null); assert.equal(layer.getFiniteNumber("NaN"), null); assert.equal(layer.getFiniteNumber(0), 0); assert.equal(layer.getFlowDirectionMinZoom({}), 13); assert.equal(layer.getFlowDirectionMinZoom({ minViewSize: 0 }), 0); assert.equal(layer.getFlowDirectionZIndex({ drawOrdr: 0 }), 0); assert.equal(layer.getFlowDirectionZIndex({}), 9998); assert.deepEqual( layer.expandFlowDirectionExtent([0, 10, 100, 110]), [-35, -25, 135, 145], ); assert.equal( layer.formatFlowDirectionBbox([1.23456, -4, 5, 6]), "1.235,-4.000,5.000,6.000", ); }); test("관로 캐시 키는 같은 시설이라도 geometry가 다르면 구분", () => { const feature = (coords) => ({ getId: () => null, get: (name) => (name === "fclt_mng_no" ? " P-1 " : undefined), getGeometry: () => ({ getCoordinates: () => coords }), }); assert.equal( layer.getFlowDirectionFeatureCacheKey( feature([ [0, 0], [1, 1], ]), ), "fclt:P-1:[[0,0],[1,1]]", ); assert.notEqual( layer.getFlowDirectionFeatureCacheKey( feature([ [0, 0], [1, 1], ]), ), layer.getFlowDirectionFeatureCacheKey( feature([ [0, 0], [2, 2], ]), ), ); }); test("moveend는 최신 체크·레이어를 읽고 구독 해제·재구독 뒤 중복 호출하지 않는다", () => { const listeners = new Map(); const map = { on(event, handler) { assert.equal(event, "moveend"); const key = {}; listeners.set(key, handler); return key; }, }; const unsubscribe = (key) => listeners.delete(key); let state = { checked: false, layerInfo: { id: "A" } }; const calls = []; const move = () => [...listeners.values()].forEach((handler) => handler()); const cleanup = subscribeFlowDirectionMoveEnd( map, () => state, (info) => calls.push(info.id), unsubscribe, ); move(); state = { checked: true, layerInfo: { id: "B" } }; move(); state = { checked: true, layerInfo: null }; move(); assert.deepEqual(calls, ["B"]); cleanup(); state = { checked: true, layerInfo: { id: "C" } }; move(); assert.deepEqual(calls, ["B"]); const cleanupNext = subscribeFlowDirectionMoveEnd( map, () => state, (info) => calls.push(info.id), unsubscribe, ); move(); assert.deepEqual(calls, ["B", "C"]); assert.equal(listeners.size, 1); cleanupNext(); assert.equal(listeners.size, 0); });