- 옮기기 단추 = 설정(isAuxPanButton) · 끌기 중 놓침 = buttonMask · 오른쪽 끌기 뒤 메뉴 안 뜸 - 왼쪽 끌기 · 표지 누름 · 손가락 = 카카오 제 것 그대로 · 휠 방향 그대로 - 시험: 설정 오른쪽 · 가운데 늘 · 왼쪽 안 가로챔 대조 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
127 lines
6.8 KiB
Python
127 lines
6.8 KiB
Python
"""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]
|