Files
Aislo/resources/tester/test_164_detail_zoom.py
T
eomsangdonandClaude Opus 5.5 410c4042b6 feat(b06): 면적표 열 연동 · [상세] 그림 테마 색 · 칸 가득(173-3 · 173-4)
- 면적표 글자 = 그림 칸 폭 비례(clamp · cqw) · 표 높이 변수 같은 식 · 4열부터 「계」만(그리드 data-columns)
- [상세] 그림 = 테마 토큰(어두운 고정색 지움) · 카드 그리기 함수로 모달 칸 크기에 맞춰 새로 그림(fitPlotBase · 빈 띠 없음)
- 칸 크기 바뀌면 다시 그림(ResizeObserver) · clip id 카드와 가름 · 그리는 동안 refresh 되먹임 막음
- 시험 test_173_areas_detail 새로 · test_164 · test_150 단정 고침

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JywHxQuWPk6UYXTebyrBoU
2026-10-10 08:42:45 +09:00

105 lines
4.2 KiB
Python

"""PLAN 164 — B06 [상세] 그림 줌 · 팬(164-1) · 표 강조 붉은 한 벌(164-2).
짝: `B06_Section/B06_Section_UI_Cross_Detail.ts`(`attachDetailZoom` · 칸 누름) ·
`_UI_Style_Cross_Detail.css`(칸 비율 · 붉은 강조). 실제 TS 를 `helper_164_detail_zoom.cjs` 가 Node 로 돌린다.
"""
from __future__ import annotations
import json
import os
import subprocess
import pytest
HERE = os.path.dirname(__file__)
ROOT = os.path.join(HERE, "..", "..")
B06 = os.path.join(ROOT, "B06_Section")
pytestmark = pytest.mark.skipif(
not os.path.isdir(os.path.join(ROOT, "config", "node_modules")),
reason="프론트엔드 의존성 미설치",
)
def _read(name: str) -> str:
with open(os.path.join(B06, name), encoding="utf-8") as f:
return f.read().replace(chr(13), "")
@pytest.fixture(scope="module")
def out() -> dict:
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
["node", os.path.join(HERE, "helper_164_detail_zoom.cjs")],
capture_output=True,
text=True,
encoding="utf-8",
timeout=60,
)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
def test_복제_자식을_g_하나로_감쌈_비율(out):
assert out["wrapped"] is True # 축 · 눈금 · 도형이 한 장으로 움직임
assert out.get("ratio") is None # 173-4 — 칸 = viewBox(칸 크기로 새로 그림) · 비율 변수 없음
assert out["before"] is None
def test_휠_당기면_확대_커서_고정(out):
assert out["wheelIn"]["scale"] == pytest.approx(1.15)
assert out["cursorFixed"] == pytest.approx(300) # 커서 아래 svg x 300 이 제자리
assert out["wheelOut"] < out["wheelIn"]["scale"]
assert out["max"] == 16
def test_가운데_단추_팬_좌클릭은_팬_아님(out):
assert out["leftDrag"] == {"scale": 1, "tx": 0, "ty": 0}
# 1배에서도 팬 · 화면 200·40 px = svg 100·20(칸 2 배)
assert out["middlePan"] == {"scale": 1, "tx": 100, "ty": 20}
assert out["panClickStopped"] is True
def test_다시_떠도_배율_유지_더블클릭_원복(out):
assert out["restored"] == "translate(100 20) scale(1)"
assert out["reset"] == "translate(0 0) scale(1)"
def test_모달_배선_단추_칸_비율():
src = _read("B06_Section_UI_Cross_Detail.ts")
css = _read("B06_Section_UI_Style_Cross_Detail.css")
assert "wheelZoom: true" in src and "attachSvgZoomPan({" in src
assert "cad.replaceChildren(clone, buildZoomControls(handle))" in src
assert "attachDetailZoom(clone, zoom, (next) => (zoom = next))" in src
assert "position: relative;" in css
# 173-4 — 그림 = 칸 크기로 새로 그림 · svg 칸 가득
assert ".b06-detail__cad > svg {\n display: block;\n width: 100%;\n height: 100%;" in css
assert "--ratio" not in css and "--ratio" not in src
def test_강조_붉은_한_벌_고름_hover_다름_빈칸():
css = _read("B06_Section_UI_Style_Cross_Detail.css")
for selector in (
".b06-detail__cad .b06-chart__area.is-active > polygon {\n fill: color-mix(in srgb, var(--color-danger)",
".b06-detail__cad .b06-chart__design-hit.is-active {\n stroke: color-mix(in srgb, var(--color-danger)",
".b06-detail__cad .b06-chart__center.is-active line {\n stroke: var(--color-danger);",
".b06-detail__cad .b06-chart__spoil-fill.is-active {\n stroke: var(--color-danger);",
".b06-detail__qtable .is-picked {\n background: color-mix(in srgb, var(--color-danger) 18%",
".b06-detail__qtable tr:has(.is-picked) {",
".b06-detail__qtable [data-key][data-empty] {\n cursor: default;",
):
assert selector in css, selector
assert "royal-amethyst" not in css and "--color-warning);" not in css.split("/* 그림 강조")[1]
assert (
".b06-detail__qtable [data-key]:hover {\n background: color-mix(in srgb, var(--color-danger) 8%"
in css
)
def test_빈칸_누름_없음_이름_칸_첫_키():
src = _read("B06_Section_UI_Cross_Detail.ts")
assert 'el.toggleAttribute("data-empty", !present.has(el.dataset.key ?? ""))' in src
assert 'if (!key || el.hasAttribute("data-empty")) return;' in src
assert 'cell("th", groupL, { row: 2 }, keyL)' in src
assert 'cell("th", groupM, { row: 2 }, keyM)' in src