feat(평면): 353-2 등고선 하이라이트 자물쇠 — 호버 · 고른 직후 단추 · 누르면 그 높이 고정 · 다시 누르면 풂
- 등고선 위를 지나거나 고른 직후 커서 옆에 자물쇠 단추(캔버스 위 DOM · aria-pressed · 호버 판정 = 집기와 같은 hitPreparedLayer) - 잠긴 동안 빈 곳 · 다른 가닥을 눌러도 고른 것 그대로 · 잠긴 높이 위에서만 눌린 단추가 떠 풂 - 높이값으로 쥠 — 분석 지형을 바꿔도 같은 높이 가닥을 다시 짚음 · 페이지 동안만(저장 안 함) - 새 파일 logic/B05_Profile_ContourLock(규칙) · UI_RouteEdit_ContourLock(단추) · 모양 css · RouteEdit.ts 는 고르기 · 지형 바꿈 두 줄 + 세우기만(700줄) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Se7ytqbohmBQnfYpwYFnYf
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"""353-2 평면 등고선 자물쇠 — 규칙(`logic/B05_Profile_ContourLock.ts`)을 Node 로 돌려 판정 +
|
||||
편집기 이음(고르기 막음 · 지형 바꿔도 같은 높이 · 호버 = 집기와 같은 hitPreparedLayer).
|
||||
|
||||
./venv/Scripts/python.exe -m pytest resources/tester/test_353_2_contour_lock.py -q
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
B05 = ROOT / "B05_Profile"
|
||||
LOGIC = B05 / "logic" / "B05_Profile_ContourLock.ts"
|
||||
TS = ROOT / "config" / "node_modules" / "typescript"
|
||||
|
||||
DRIVER = r"""
|
||||
const fs = require("fs");
|
||||
const ts = require(process.argv[1]);
|
||||
const js = ts.transpileModule(fs.readFileSync(process.argv[2], "utf8"), {
|
||||
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
||||
}).outputText;
|
||||
const m = { exports: {} };
|
||||
new Function("exports", "module", js)(m.exports, m);
|
||||
const L = m.exports;
|
||||
const levels = [101, 102, 105, 102, null];
|
||||
console.log(JSON.stringify({
|
||||
hoverFree: L.lockButtonState(102, null),
|
||||
hoverNone: L.lockButtonState(null, null),
|
||||
hoverLocked: L.lockButtonState(102, 102),
|
||||
hoverOther: L.lockButtonState(105, 102),
|
||||
lock: L.toggleLock(null, 102),
|
||||
unlock: L.toggleLock(102, 105),
|
||||
pickFree: L.canPickContour(null),
|
||||
pickLocked: L.canPickContour(102),
|
||||
again: L.featureOfLevel(levels, 102),
|
||||
gone: L.featureOfLevel(levels, 110),
|
||||
none: L.featureOfLevel(levels, null),
|
||||
}));
|
||||
"""
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def got() -> dict:
|
||||
run = subprocess.run( # noqa: S603 — 고정 실행 파일
|
||||
["node", "-e", DRIVER, str(TS), str(LOGIC)], capture_output=True, text=True, timeout=60
|
||||
)
|
||||
assert run.returncode == 0, run.stderr
|
||||
return json.loads(run.stdout)
|
||||
|
||||
|
||||
def test_안_잠김_단추는_높이_있는_가닥_위에서(got) -> None:
|
||||
assert got["hoverFree"] == {"visible": True, "pressed": False}
|
||||
assert got["hoverNone"]["visible"] is False
|
||||
|
||||
|
||||
def test_잠김_단추는_그_높이_위에서만_눌린_모양(got) -> None:
|
||||
assert got["hoverLocked"] == {"visible": True, "pressed": True}
|
||||
assert got["hoverOther"]["visible"] is False
|
||||
|
||||
|
||||
def test_누르면_잠금_다시_누르면_풂(got) -> None:
|
||||
assert got["lock"] == 102 and got["unlock"] is None
|
||||
|
||||
|
||||
def test_잠긴_동안_고르기_막음(got) -> None:
|
||||
assert got["pickFree"] is True and got["pickLocked"] is False
|
||||
|
||||
|
||||
def test_지형_바꿔도_같은_높이를_다시_짚음(got) -> None:
|
||||
assert got["again"] == 1 and got["gone"] == -1 and got["none"] == -1
|
||||
|
||||
|
||||
def test_편집기_이음() -> None:
|
||||
edit = (B05 / "B05_Profile_UI_RouteEdit.ts").read_text("utf-8")
|
||||
assert "if (contourLock.canPick()) pickedContour = index;" in edit
|
||||
assert "pickedContour = contourLock.reattach(contours?.layer ?? null);" in edit
|
||||
lock = (B05 / "B05_Profile_UI_RouteEdit_ContourLock.ts").read_text("utf-8")
|
||||
assert "hitPreparedLayer(" in lock and 'setAttribute("aria-pressed"' in lock
|
||||
assert "sessionStorage" not in lock and "writeState" not in lock # 페이지 동안만
|
||||
Reference in New Issue
Block a user