- 중심점 = 보라 선 고름 끝 조각(판정 원 · 보라 선 위 · 다른 고름과 하나만) · 십자는 누름 통과 - 좌우 = 노선 편집기가 등록한 host(B05_Profile_UI_RouteEdit_Shift) — 0.5 m 안 노드 옮김 · 곡선 안 = 교각점 · 아니면 끼움 · 고정 노드 안 옮김 - 끄는 동안 · 키를 잇는 동안 십자만 옮겨 보임 · 놓을 때 한 번 커밋 - 뒤 측점은 계산 묶음이 조용히 · 그 측점 계획고 = 옮기기 전 값(계획고 편집) · 노선 + 계획고 = 되돌리기 한 걸음 - B06 을 바로 열어 편집기가 없으면 종단 보기를 숨긴 채 세움(design_page 등록) - 시험 test_356 · helper_356(노드 고름 · 뒤 측점 범위 · 높이 그대로 · 되돌리기 한 걸음 · 바로 열기) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ
86 lines
3.9 KiB
Python
86 lines
3.9 KiB
Python
"""356 B06 횡단 카드 — 키 강조 · 중심점 좌우(요구 235-17 · 18).
|
|
|
|
못박는 것
|
|
- 356-2 카드 초점 없음 — 마우스로 고른 뒤 키를 눌러도 초점 테두리(다른 색) 안 뜸 · ▲▼ 계획고는 창 듣개.
|
|
- 356-3 중심점 = 보라 선 고름 끝 조각(판정 원 · 노면 판정보다 위 · 다른 고름과 하나만) · ▲▼ = 종단 계획고 ·
|
|
◀▶ · 가로 끌기 = 그 측점 노선 좌우(0.5 m 안 노드 옮김 · 곡선 안 = 교각점 · 아니면 끼움 · 고정 노드 안 옮김) ·
|
|
놓을 때 한 번 · 뒤 측점은 묶음이 다시 셈(바뀐 범위 = 앞 노드 ~ 끝) · 그 측점 계획고 그대로 · 되돌리기 한 걸음 ·
|
|
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)
|
|
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
|
|
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
|