# -*- coding: utf-8 -*- """B05 패치 스커트(`B05_Profile_UI_Corridor_Skirt.ts`) 단위검증 — 2026-08-27. 프론트에 JS 테스트 러너가 없어 Node 헬퍼(helper_b05_patch_skirt.cjs)가 TS를 ⚠ 도우미 확장자가 **`.cjs`** 인 이유(2026-09-07) — 루트 `package.json` 에 `"type": "module"` 이 있어 `.js` 는 Node 판·환경에 따라 ESM 으로 읽힌다. 그러면 도우미의 `require` 가 「require is not defined in ES module scope」로 죽는다(보조 창 폴더에서 실제로 9건이 그렇게 실패했고, 같은 파일이 이 폴더에서는 통과해 **환경 차이**임이 드러났다). `.cjs` 는 `type` 과 무관하게 언제나 CommonJS 라 어느 폴더·어느 Node 에서도 같게 돈다. 트랜스파일해 실행하고, pytest는 그 결과(JSON)를 검증한다. """ import json import os import subprocess import pytest HERE = os.path.dirname(os.path.abspath(__file__)) @pytest.fixture(scope="module") def skirt_results(): proc = subprocess.run( ["node", os.path.join(HERE, "helper_b05_patch_skirt.cjs")], capture_output=True, text=True, timeout=60, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) def test_floating_edge_builds_hatched_skirt(skirt_results): """뜬 모서리(지반 위 0.5m)는 마디마다 판 2장 + 빗금 UV + patchSkirt 표식.""" r = skirt_results["floating"] assert r["walls"] == 1 assert r["triangles"] == 4 # 마디 2개 × 2장 assert r["hatched"] is True assert r["marked"] is True def test_submerged_edge_builds_nothing(skirt_results): """잠긴 모서리(지반 아래)는 판 없음 — 지형이 덮는다.""" r = skirt_results["submerged"] assert r["walls"] == 0 assert r["skipped"] == 2 def test_structure_ending_run_excluded(skirt_results): """소유 측점 행 낙차 2m > 허용 0.5m — 벽 뒷면·구체 상단에서 끝나는 줄은 리본째 제외.""" r = skirt_results["toeGate"] assert r["walls"] == 0 assert r["reaches"] is False def test_tall_segment_skipped(skirt_results): """게이트 통과 후에도 낙차 3m 초과 마디는 건너뛴다(지느러미 방지).""" r = skirt_results["tall"] assert r["skippedTall"] == 2 # 94를 낀 두 마디 assert r["tris"] == 2 # 남은 정상 마디 1개 × 2장 assert r["walls"] == 1 def test_non_patch_and_cut_ignored(skirt_results): """patch 표식 없는 리본·절토 리본은 스커트 대상이 아니다.""" assert skirt_results["ignored"]["walls"] == 0