"""PLAN 370-3 — B06 암 경계선 고름 · 방향키 · 세로 끌기 · 아래 띠 공용 칸(요구 240-22). 짝: `B06_Section/B06_Section_UI_Cross_Design_Pick.ts`(rock 축 · 판정 선) · `B06_Section/B06_Section_UI_Cross_Line_Cell.ts`(공용 칸) · `B06_Section_UI_Cross_Center.ts`(`bindAxisDrag`). 실제 TS 를 `helper_370_3_rock_cell.cjs` 가 Node 로 돌린다. """ from __future__ import annotations import json import subprocess from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] HELPER = Path(__file__).parent / "helper_370_3_rock_cell.cjs" B06 = ROOT / "B06_Section" pytestmark = pytest.mark.skipif( not (ROOT / "config" / "node_modules").is_dir(), reason="프론트엔드 의존성 미설치" ) @pytest.fixture(scope="module") def out() -> dict: done = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", str(HELPER)], cwd=str(ROOT), capture_output=True, text=True, encoding="utf-8" ) assert done.returncode == 0, done.stderr return json.loads(done.stdout) def test_안_고르면_공용_칸은_암_버튼과_값(out: dict) -> None: idle = out["idle"] assert idle["title"] == "암 경계선" and idle["value"] == "-0.5m" assert idle["slots"] == ["up", "reset", "down"] assert idle["upPassed"] is True # 안 고르면 ▲▼ = 종단 계획고 그대로 assert idle["offsets"] == [0.1, -0.1] and idle["resets"] == 1 def test_암_경계선_판정_선(out: dict) -> None: hit = out["hit"] assert hit["found"] and hit["tag"] == "path" and hit["moves"] == 2 # 끊긴 두 토막 한 판정 assert hit["below"] and hit["picked"] == [3] # 설계선 판정 아래 · 키 차례 = 조각 셋 뒤 def test_암_고름은_위아래만_암_키는_암만(out: dict) -> None: got = out["picked"] assert got["active"] and got["key"] # 키 rock 으로 기억 assert got["title"] == "암 경계선" and got["slots"] == ["up", "reset", "down"] assert got["leftBlocked"] and got["rightBlocked"] # ◀▶ 막음 assert got["upTaken"] and got["downTaken"] # ▲▼ = 암(종단으로 안 샘) assert got["sideValues"] == {"left": 0, "right": 0} assert got["offsets"][:2] == [0.1, -0.1] def test_세로_끌기는_놓을_때_한_번(out: dict) -> None: drag = out["drag"] assert drag["stopped"] is True # 카드 팬으로 안 번짐 assert drag["during"]["rock"] == drag["during"]["hit"] # 점선 · 판정 선 같이 dy = float(drag["during"]["rock"].split()[1].removesuffix("px")) assert abs(dy - (-0.3 * 12)) < 1e-9 # 위로 0.3 m(화면 px = m × 12) assert drag["during"]["value"] == "-0.2m — 놓으면 반영" assert drag["sent"] == [0.3] # 0.34 m → 걸음 0.1 맞춤 · 한 번 assert drag["clickSwallowed"] is True assert out["idleDrag"]["stopped"] is False # 안 고르면 끌기 아님 def test_풀면_암_칸_사면_고르면_그_선_칸(out: dict) -> None: assert out["released"]["title"] == "암 경계선" and out["released"]["upPassed"] slope = out["slope"] assert slope["title"] == "사면 이동 (좌)" and slope["slots"] == ["left", "reset", "right"] assert slope["value"].startswith("길이 ") and "\n" not in slope["value"] assert slope["arrowSlots"] == slope["slots"] # 숨은 버튼은 방향키 슬롯 없음 def test_토사는_빈_칸_판정_선_없음(out: dict) -> None: soil = out["soil"] assert soil["empty"] is True and soil["slots"] == [] and soil["rockHit"] is False def test_배선_떠_있는_선_조정창_걷음() -> None: pick = (B06 / "B06_Section_UI_Cross_Design_Pick.ts").read_text(encoding="utf-8") assert "buildPanelShell" not in pick and "b06-cross-card__line-dims" not in pick view = (B06 / "B06_Section_UI_Cross_View.ts").read_text(encoding="utf-8") assert "rockBoundary && rockCellSpec(section, rockBoundary)" in view chrome = (B06 / "B06_Section_UI_Cross_Card_Chrome.ts").read_text(encoding="utf-8") assert "if (lineCell) {" in chrome detail = (B06 / "B06_Section_UI_Cross_Detail_Pick.ts").read_text(encoding="utf-8") assert ".b06-chart__design-hit:not(.b06-chart__rock-hit)" in detail # 상세 표 강조에 안 섞임 css = (B06 / "B06_Section_UI_Style_Cross.css").read_text(encoding="utf-8") assert ".b06-cross-card__linecell.is-empty {" in css and "text-overflow: ellipsis;" in css