Files
Aislo/resources/tester/test_585_1_kakao_mouse.py
T
eomsangdonandClaude Sonnet 5.5 104160edcd feat(설정 마우스): 카카오 공용 지도도 화면 옮기기 단추를 따름 — 가운데 늘 · 오른쪽 고르면 오른쪽도 (PLAN 588-5 · 요구 445 C3)
- 옮기기 단추 = 설정(isAuxPanButton) · 끌기 중 놓침 = buttonMask · 오른쪽 끌기 뒤 메뉴 안 뜸
- 왼쪽 끌기 · 표지 누름 · 손가락 = 카카오 제 것 그대로 · 휠 방향 그대로
- 시험: 설정 오른쪽 · 가운데 늘 · 왼쪽 안 가로챔 대조

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-29 19:29:11 +09:00

127 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""585-1 공용 카카오 지도 = ☰ [설정] 마우스 따름(요구 445 A1) — 휠 = 설정 확대 방향 한 단 · 마우스 자리 고정 ·
가운데 끌기 = 옮김 · 지점 색 이름표 · 차례 색 여섯 돌림(가짜 kakao.maps 로 node 에서 돌림).
./venv/Scripts/python.exe -m pytest resources/tester/test_585_1_kakao_mouse.py -q
"""
import json
import re
import subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
IMPORTS = re.compile(r"^import[^;]*;\n", re.MULTILINE)
KMAP = "ui_template/ui_template_kakao_map.ts"
PREFS = "A00_Common/input_prefs.ts"
PALETTE = "ui_template/ui_template_palette.ts"
def _read(rel):
return (ROOT / rel).read_text(encoding="utf-8")
STUBS = """
const handlers: Record<string, any> = {};
const el = (tag: string, o: any = {}) => ({ tag, hidden: false, textContent: o.text ?? "",
className: o.className, dataset: {}, children: o.children ?? [], style: {} as any,
classList: { list: [] as string[], add(c: string) { this.list.push(c); } },
clientWidth: 400, clientHeight: 300,
getBoundingClientRect: () => ({ left: 10, top: 20 }),
setPointerCapture() {},
addEventListener(type: string, fn: any, o: any) { if (o?.capture) handlers[type] = fn; } });
const requestAnimationFrame = (f: () => void) => setTimeout(f, 0);
(globalThis as any).window = globalThis;
(globalThis as any).document = { createElement: () => ({}), head: { append: () => undefined } };
const API_BASE_URL = "";
(globalThis as any).fetch = async () => ({ ok: true, json: async () => ({ key: "k" }) });
const store: Record<string, string> = {};
(globalThis as any).addEventListener = () => undefined;
(globalThis as any).removeEventListener = () => undefined;
(globalThis as any).localStorage = { getItem: (k: string) => store[k] ?? null };
const LOG: any = { levels: [], centers: [], labels: [] };
class LatLng { lat: number; lng: number;
constructor(lat: number, lng: number) { this.lat = lat; this.lng = lng; }
getLat() { return this.lat; } getLng() { return this.lng; } }
const overlay = () => ({ setMap: () => undefined });
(globalThis as any).kakao = { maps: {
load: (f: () => void) => f(), LatLng, Point: function (x: number, y: number) { return { x, y }; },
LatLngBounds: class { extend() {} },
Map: class { level = 7; relayout() {} setBounds() {} setMapTypeId() {} setCenter(p: any) {
LOG.centers.push([p.lng, p.lat]); }
getLevel() { return this.level; }
setLevel(l: number, o: any) { this.level = l; LOG.levels.push([l, o?.anchor?.lng, o?.anchor?.lat]); }
getProjection() { return { coordsFromContainerPoint: (p: any) => new LatLng(p.y, p.x) }; } },
MapTypeId: { ROADMAP: 1, HYBRID: 3 },
Polyline: function () { return overlay(); },
Marker: function () { return overlay(); },
CustomOverlay: function (o: any) { LOG.labels.push(o.content); return overlay(); },
event: { addListener: () => undefined },
} };
"""
SCRIPT = """
const m = editMap({ hint: "h", onMove: () => undefined });
m.set([{ key: "0", name: "지점 1", lon: 127.9, lat: 35.68, movable: true, color: "#123456" },
{ key: "1", name: "지점 2", lon: 127.8, lat: 35.6, movable: true }], []);
await new Promise((r) => setTimeout(r, 20));
const ev = (o: any) => ({ preventDefault() {}, stopPropagation() {}, ctrlKey: false, pointerType: "mouse", ...o });
const wheel = (deltaY: number, t: number) =>
handlers.wheel(ev({ deltaY, clientX: 110, clientY: 70, timeStamp: t }));
wheel(-100, 1000); // 기본 = 밂 → 앞으로 = 확대(단 −1)
wheel(-100, 1050); // 한 단 쉼(180 ms) 안 = 버림
store["aislo:pref:input-prefs"] = JSON.stringify({ wheelZoom: "pull" });
wheel(-100, 2000); // 당김 설정 → 앞으로 = 축소(단 +1)
wheel(100, 3000); // 당김 → 몸 쪽 = 확대
handlers.pointerdown(ev({ button: 0, pointerId: 1, clientX: 0, clientY: 0 })); // 왼쪽 = 카카오 몫
handlers.pointermove(ev({ pointerId: 1, buttons: 1, clientX: 5, clientY: 5 }));
handlers.pointerdown(ev({ button: 1, pointerId: 2, clientX: 50, clientY: 50 }));
handlers.pointermove(ev({ pointerId: 2, buttons: 4, clientX: 60, clientY: 45 }));
handlers.pointerup(ev({ pointerId: 2 }));
handlers.pointermove(ev({ pointerId: 2, buttons: 4, clientX: 90, clientY: 90 })); // 놓은 뒤 = 안 옮김
const before = LOG.centers.length;
handlers.pointerdown(ev({ button: 2, pointerId: 3, clientX: 50, clientY: 50 })); // 오른쪽 아직 옮기기 아님
handlers.pointermove(ev({ pointerId: 3, buttons: 2, clientX: 60, clientY: 60 }));
const rightOff = LOG.centers.length - before;
store["aislo:pref:input-prefs"] = JSON.stringify({ wheelZoom: "pull", panButton: "right" });
handlers.pointerdown(ev({ button: 2, pointerId: 4, clientX: 50, clientY: 50 })); // 오른쪽 = 옮기기
handlers.pointermove(ev({ pointerId: 4, buttons: 2, clientX: 70, clientY: 40 }));
handlers.pointerup(ev({ pointerId: 4 }));
handlers.pointerdown(ev({ button: 1, pointerId: 5, clientX: 0, clientY: 0 })); // 가운데는 늘
handlers.pointermove(ev({ pointerId: 5, buttons: 4, clientX: 3, clientY: 3 }));
handlers.pointerup(ev({ pointerId: 5 }));
handlers.pointerdown(ev({ button: 0, pointerId: 6, clientX: 0, clientY: 0 })); // 왼쪽 = 카카오 몫
handlers.pointermove(ev({ pointerId: 6, buttons: 1, clientX: 9, clientY: 9 }));
const [first, second] = LOG.labels;
console.log(JSON.stringify({ levels: LOG.levels, centers: LOG.centers, rightOff,
colored: [first.style.background, first.classList.list], plain: second.style.background ?? null,
colors: Array.from({ length: 8 }, (_, i) => pointColor(i)) }));
"""
def test_휠_설정_방향_가운데_끌기_지점_색():
src = (
STUBS
+ IMPORTS.sub("", _read(PREFS))
+ IMPORTS.sub("", _read(PALETTE)).replace(
"getComputedStyle(document.documentElement).getPropertyValue(name).trim()", '""'
)
+ IMPORTS.sub("", _read(KMAP))
+ SCRIPT
)
result = subprocess.run(
["node", "--experimental-strip-types", "--no-warnings",
"--input-type=module-typescript", "-"], input=src,
capture_output=True, text=True, encoding="utf-8", timeout=60,
) # fmt: skip
assert result.returncode == 0, result.stderr
got = json.loads(result.stdout)
# 마우스 자리 = 상자 안 (100, 50) 고정 · 단마다 한 번
assert got["levels"] == [[6, 100, 50], [7, 100, 50], [6, 100, 50]]
# 가운데 끌기 (+10, −5) = 중심을 반대로 → 상자 가운데 (200, 150) − 민 만큼
# 설정 가운데(기본) 일 때 오른쪽 누름 = 안 옮김 · 오른쪽 설정 = (+20, −10) · 가운데 늘 (+3, +3) · 왼쪽 = 안 옮김
assert got["rightOff"] == 0
assert got["centers"] == [[190, 155], [180, 160], [197, 147]]
assert got["colored"] == ["#123456", ["is-colored"]] and got["plain"] is None
# 여섯 색 차례 돌림 · 일곱째 = 첫째
assert len(set(got["colors"][:6])) == 6 and got["colors"][6:] == got["colors"][:2]