"""356 B06 횡단 카드 — 키 강조 · 중심점 좌우(요구 235-17 · 18). 못박는 것 - 356-2 카드 초점 없음 — 마우스로 고른 뒤 키를 눌러도 초점 테두리(다른 색) 안 뜸 · ▲▼ 계획고는 창 듣개. - 356-3 중심점 = 보라 선 고름 끝 조각(판정 원 · 노면 판정보다 위 · 다른 고름과 하나만) · ▲▼ = 종단 계획고 · ◀▶ · 가로 끌기 = 그 측점 노선 좌우(0.5 m 안 노드 옮김 · 곡선 안 = 교각점 · 아니면 끼움 · 고정 노드 안 옮김) · 놓을 때 한 번 · 뒤 측점은 묶음이 다시 셈(바뀐 범위 = 앞 노드 ~ 끝) · 노면 그대로(364-7 · 모든 측점 계획고 · 기울기 · R 그대로) · 되돌리기 한 걸음 · B06 을 바로 열어 편집기가 없으면 종단 보기를 숨긴 채 세움. 진짜 TS 는 `helper_356_center.cjs` 가 Node 로 돌림. """ from __future__ import annotations import json import subprocess from pathlib import Path import pytest HERE = Path(__file__).resolve().parent ROOT = Path(__file__).resolve().parents[2] B06 = ROOT / "B06_Section" def test_카드_초점_없음(): view = (B06 / "B06_Section_UI_Cross_View.ts").read_text(encoding="utf-8") assert "card.tabIndex" not in view assert 'card.addEventListener("keydown"' not in view assert 'card.addEventListener("click", () => onSelect(section.station_id));' in view @pytest.fixture(scope="module") def ts() -> dict: proc = subprocess.run( ["node", str(HERE / "helper_356_center.cjs")], capture_output=True, text=True, encoding="utf-8", timeout=60, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) def test_노드_고름_끼움_옮김_고정_교각점(ts): assert ts["insert"] == { "kind": "insert", "index": 1, "at": [40, 1], } # 직선 = 측점 자리 + 좌 1 m 끼움 assert ts["near"] == {"kind": "move", "index": 1, "to": [40.3, -0.5]} # 0.5 m 안 노드 = 옮김 assert ts["nearLocked"] == {"kind": "locked", "index": 1} # 고정 노드 = 안 옮김 hit = ts["curveHit"] assert hit["kind"] == "move" and hit["index"] == 1 # 곡선 안 = 그 교각점 ax, ay = ts["curveApex"] assert ((hit["to"][0] - ax) ** 2 + (hit["to"][1] - ay) ** 2) ** 0.5 == pytest.approx(1.0) def test_뒤_측점은_묶음이_다시_셈(ts): assert ts["range"] == {"fromM": 0, "toM": None} # 앞 노드 ~ 끝(Infinity) def test_높이_그대로_되돌리기_한_걸음_바로_열기(ts): assert ts["opened"] == 1 and ts["moved"] is True # 편집기 없음 → 종단 보기 숨긴 채 세움 assert ts["planned"] == [[0, 0], [40, 1], [100, 0]] assert len(ts["applied"]) == 1 # 편집기 한 걸음 assert ts["zRefit"] != pytest.approx(ts["zBefore"], abs=1e-3) # 묶음 다시 맞춤이면 쓸림 assert ts["graded"] == 1 and ts["zAfter"] == pytest.approx(ts["zBefore"], abs=1e-3) # 364-7 노면 그대로 — 바뀐 구간 모든 측점 계획고 · 최대 기울기 · 종단곡선 R 그대로 assert ts["heightsAfter"] == pytest.approx(ts["heightsBefore"], abs=1e-3) assert ts["gradeAfter"] == pytest.approx(ts["gradeBefore"], abs=1e-6) assert sum(ts["curvesAfter"], []) == pytest.approx(sum(ts["curvesBefore"], [])) assert ts["canUndo"] and ts["undoOne"] and not ts["canUndoAfter"] # 노선 + 계획고 = 한 걸음 locked = ts["locked"] assert locked["moved"] is False and locked["toast"][1] == "info" assert locked["planned"] == [[0, 0], [40.3, 0], [100, 0]] def test_배선(): pick = (B06 / "B06_Section_UI_Cross_Design_Pick.ts").read_text(encoding="utf-8") assert "center: section.chainage_m," in pick # designLineMoves → 카드 고름 끝 조각 assert 'if (axis === "center") return centerShift?.step(dir);' in pick # 364-7 덧 — 중심점 ◀▶ 툴팁 = 노선 좌우 · ↺ · 소단 ▲▼ 숨김 assert "`이 측점 노선을 화면 ${screen}으로 0.1 m`" in pick assert '[toLeft.title, toRight.title] = [stepTitle("왼쪽"), stepTitle("오른쪽")];' in pick assert 'move.controls.children[1]?.classList.toggle("is-hidden", axis === "center");' in pick assert 'lift.row.classList.toggle("is-hidden", axis !== "depth");' in pick order = (B06 / "B06_Section_UI_Cross_Pick_Order.ts").read_text(encoding="utf-8") assert "layer.append(...surfaces, ...edges, ...lines, ...centers);" in order edit = (ROOT / "B05_Profile" / "B05_Profile_UI_RouteEdit.ts").read_text(encoding="utf-8") assert "bindRouteShift(host, projectId, snapshotNow, applyEdit," in edit page = (ROOT / "A00_Common" / "design" / "design_page.ts").read_text(encoding="utf-8") assert 'setRouteShiftOpener(() => shared.ensureView("profile"), showToast);' in page