Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QND7Co43B24zK2P937rdxt
176 lines
6.0 KiB
Python
176 lines
6.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""돋보기(계획서 218-1 · 220) 회귀검증 — 오른쪽 길게 누름 · Z 누름 동안 켬 · 크기 · 배율 · 복제 지움 · 붙는 페이지.
|
|
|
|
Node 헬퍼(`helper_218_1_loupe.cjs`)가 `ui_template/ui_template_loupe.ts` 를 트랜스파일해
|
|
가짜 창 · 가짜 시계 · 가짜 요소로 돌리고, 여기서 값을 판정함.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import re
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
ROOT = os.path.dirname(os.path.dirname(HERE))
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def r():
|
|
proc = subprocess.run(
|
|
["node", os.path.join(HERE, "helper_218_1_loupe.cjs")],
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
timeout=60,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
def _read(rel):
|
|
with open(os.path.join(ROOT, rel), encoding="utf-8") as f:
|
|
return f.read()
|
|
|
|
|
|
def test_크기_배율_상수(r):
|
|
c = r["consts"]
|
|
assert (c["d"], c["zoom"], c["hold"], c["refresh"]) == (
|
|
360,
|
|
2,
|
|
400,
|
|
500,
|
|
) # 220-1 지름 240 → 360
|
|
assert r["capture"]["rootSize"] == ["360px", "360px"]
|
|
# 커서(500,400)가 원 가운데(180,180)에 2배로 옴
|
|
assert r["capture"]["stageTransform"] == "translate(-820px, -620px) scale(2)"
|
|
|
|
|
|
def test_창_캡처_단계로_들음(r):
|
|
assert r["listeners"] == [
|
|
[t, True]
|
|
for t in (
|
|
"mousemove",
|
|
"mouseover",
|
|
"mousedown",
|
|
"mouseup",
|
|
"contextmenu",
|
|
"keydown",
|
|
"keyup",
|
|
)
|
|
] + [["wheel", {"capture": True, "passive": False}], ["blur", True]]
|
|
|
|
|
|
def test_길게_누름_0_4초_넘어야_켜고_떼면_끔_메뉴는_안_뜸(r):
|
|
lg = r["long"]
|
|
assert lg["before"] == 0 # 0.399 초 = 아직
|
|
assert lg["on"] == "show" and lg["show"] == ["show", 300, 200]
|
|
assert lg["moved"] == ["move", 310, 205] # 커서 따라감
|
|
assert lg["off"] == "hide"
|
|
assert lg["menuPrevented"] and lg["menuStopped"] # 브라우저 · 우리 메뉴 둘 다 안 뜸
|
|
assert lg["nextStopped"] is False # 한 번만 먹음
|
|
|
|
|
|
def test_짧게_누르면_지금_우클릭_그대로(r):
|
|
assert r["short"] == {"log": 0, "menuPrevented": False, "menuStopped": False}
|
|
|
|
|
|
def test_왼쪽_단추_무시_창_밖에서_떼면_끔(r):
|
|
mm = r["mouseMisc"]
|
|
assert mm["left"] == 0
|
|
assert mm["lostBeforeHold"] == 0 # 0.4 초 전에 뗌 — 안 켬
|
|
assert mm["lostAfterHold"] == "hide"
|
|
|
|
|
|
def test_Z_누름_켬_뗌_끔(r):
|
|
k = r["key"]
|
|
assert k["on"] == "show" # 한글 자판(ㅋ)도 code KeyZ
|
|
assert k["repeatLen"] == 1 # 누르고 있는 동안 다시 안 그림
|
|
assert k["off"] == "hide"
|
|
assert k["noCombo"] # Ctrl · Alt · Meta 조합 · 다른 키는 안 켬
|
|
assert k["shift"] == "show"
|
|
assert k["fieldBlur"] == "show" # 칸 초점 빠짐으론 안 끔
|
|
assert k["blur"] == "hide" # 창이 초점을 잃으면 끔
|
|
|
|
|
|
def test_입력_칸에선_안_켬(r):
|
|
t = r["key"]["typing"]
|
|
for name in ("input", "inputNoType", "number", "textarea", "select", "editable"):
|
|
assert t[name] is False, name
|
|
assert t["checkbox"] and t["button"]
|
|
|
|
|
|
def test_붙일_주소_밖이면_안_켬(r):
|
|
assert r["off"] == {"log": 0, "menuStopped": False}
|
|
|
|
|
|
def test_붙는_페이지_B01_B09_M01_M02(r):
|
|
on = [k for k, v in r["routes"].items() if v]
|
|
assert on == [
|
|
"b01-account",
|
|
"b02-proj-register",
|
|
"b03-file-input",
|
|
"b04-preprocess",
|
|
"b05-profile",
|
|
"b06-section",
|
|
"b07-design-detail",
|
|
"b08-quantity",
|
|
"b09-estimation",
|
|
"m01-master-data",
|
|
"m02-master-template",
|
|
] # 220 — A 영역 · 로그인 · B10 · B11 은 뺌
|
|
main = _read("A00_Common/main.ts")
|
|
assert 'from "@ui/ui_template_loupe"' in main
|
|
assert re.search(r"initLoupe\(window, \(\) => LOUPE_ROUTE\.test\(currentRoute\(\)\)\)", main)
|
|
|
|
|
|
def test_화면_끝에서_안_잘림(r):
|
|
o = r["origin"]
|
|
assert o["mid"] == {"left": 320, "top": 220}
|
|
assert o["topLeft"] == {"left": 4, "top": 4}
|
|
assert o["bottomRight"] == {"left": 1000 - 360 - 4, "top": 800 - 360 - 4}
|
|
|
|
|
|
def test_화면_뜨기(r):
|
|
c = r["capture"]
|
|
assert (
|
|
c["rootClass"] == "ui-loupe"
|
|
and c["inert"]
|
|
and c["ariaHidden"] == "true"
|
|
and not c["hidden"]
|
|
)
|
|
assert c["pageBox"] == ["0px", "0px", "1000px", "800px"]
|
|
assert c["isClone"]
|
|
assert c["canvasDrawn"] == ["canvas2d"] and c["blankDrawn"] == 0
|
|
assert c["inputValue"] == "12.5" and c["checkChecked"]
|
|
assert c["scrollTop"] == 120
|
|
assert c["offscreenChildren"] == 0 and c["offscreenSize"] == ["100px", "100px"] # 보이는 영역만
|
|
assert c["rowKept"] == 1 # 표 줄은 칸 너비 때문에 그대로
|
|
assert c["svgKept"] == 1
|
|
# iframe(CAD) 은 복제하지 않음 — 같은 크기 빈 상자(221-1)
|
|
assert c["frameTag"] == "DIV" and c["frameDrawn"] == [] and c["frameEmpty"] == 0
|
|
assert c["frameSize"] == ["320px", "240px"]
|
|
assert c["watching"] and c["observeOpts"]["subtree"] and c["scrollListen"]
|
|
|
|
|
|
def test_바뀌면_0_5초_뒤_다시_뜸_끄면_복제_지움(r):
|
|
h = r["hide"]
|
|
assert h["sameBefore"] and h["recaptured"]
|
|
assert h["nearEdge"] == "translate(4px, 4px)"
|
|
assert h["stageChildren"] == 0 # 복제 지움
|
|
assert h["hidden"] and h["disconnected"] and h["scrollListen"] is False
|
|
assert h["noRecaptureAfterHide"] == 0
|
|
assert h["reuseRoot"] == 2 # 원 · 배율 글 하나씩을 다시 씀
|
|
|
|
|
|
def test_테두리_그림자_토큰():
|
|
css = _read("ui_template/ui_template_loupe.css")
|
|
assert "--loupe-border: var(--color-accent)" in css
|
|
assert "--loupe-shadow: var(--shadow-lg)" in css
|
|
assert "border-radius: 50%" in css and "pointer-events: none" in css
|
|
assert ".ui-loupe__cross" in css
|
|
theme = _read("ui_template/ui_template_theme.css")
|
|
dark = theme[theme.index(':root[data-theme="dark"]') :]
|
|
assert "--color-accent" in dark and "--shadow-lg" in dark # 어두움에서도 토큰이 바뀜
|