From e27e5fe96ceed469e9f6acf604087004c4cf688b Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 22 Oct 2026 14:31:56 +0900 Subject: [PATCH] =?UTF-8?q?test(511-B=20B-2=20=ED=99=94=EB=A9=B4):=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=5Fsub3=20B05=20=EC=B8=A1=EC=A0=90=20?= =?UTF-8?q?=E2=80=94=20=EA=B3=84=EC=82=B0=20=EC=9E=90=EB=A6=AC=20stations?= =?UTF-8?q?=20=E3=80=8C=EC=84=9C=EB=B2=84=E3=80=8D(=EC=9D=B4=20=EC=B0=BD?= =?UTF-8?q?=EC=9D=B4=20=EB=B0=9B=EB=8A=94=20=ED=8C=90=EB=A7=8C=20=C2=B7=20?= =?UTF-8?q?=ED=8C=90=20=EC=95=88=20=EA=B3=A0=EC=B9=A8)=20=EC=B8=A1?= =?UTF-8?q?=EC=A0=90=20=3D=20=ED=99=94=EB=A9=B4=20=EC=85=88=200=20?= =?UTF-8?q?=EC=B0=A8=20=C2=B7=20=EC=A0=80=EC=9E=A5=20=EB=85=B8=EC=84=A0=20?= =?UTF-8?q?59=20=C2=B7=20=EC=B4=88=EC=95=88=2061=20=C2=B7=20=EC=84=9C?= =?UTF-8?q?=EB=B2=84=20=EB=B6=80=EB=A6=84=EC=9D=80=20server=20=ED=8C=90?= =?UTF-8?q?=EB=A7=8C=20=E2=80=94=20=EC=9A=94=EA=B5=AC=20320-4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- resources/tester/test_511_b2_stations_node.py | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/resources/tester/test_511_b2_stations_node.py b/resources/tester/test_511_b2_stations_node.py index c8b593096..7d461361a 100644 --- a/resources/tester/test_511_b2_stations_node.py +++ b/resources/tester/test_511_b2_stations_node.py @@ -242,3 +242,80 @@ def test_판_stations_줄_열림_기본_both(): assert calc_sites.read_sites()["sites"]["stations"] == "both" page = (ROOT / "A00_Common/design/design_pipeline_page.ts").read_text(encoding="utf-8") assert "remote: stationsOnServer" in page + + +# ── 화면 — 계산 자리 stations 「서버」 측점 = 화면 셈 측점(검증_sub3 · Playwright · 저장 안 함) ── + +VERIFY = "12953f5a-5ba1-42ad-a427-8ac857a58bc2" # 검증_sub3(OWNERS.md) + +JS_STATIONS = r"""async () => { + const urls = performance.getEntriesByType('resource').map((e) => e.name); + const page = await import(urls.find((n) => /design_pipeline_page\.ts/.test(n))); + const pid = localStorage.getItem('frd_current_project_id'); + const pipe = page.pagePipeline(pid); + await page.reconcilePagePipeline(pid); + await pipe.settled(); + const calls = (window.__aisloCalcServer?.calls ?? []).filter((c) => c.id === 'stations.list'); + return { stations: JSON.parse(JSON.stringify(pipe.output('stations'))), + calls: calls.map((c) => ({ round: c.roundMs, node: c.nodeMs, bytes: c.bytes })), + runs: (window.__aisloPipeline?.runs ?? []).slice(-1).map((r) => r.outcome) }; +}""" + + +@pytest.fixture(scope="module") +def screens(): + from test_511_b1_calc_node_stages import BASE, JS_DRAFT, _UP, _started + + if not BASE or _UP is None or _UP != _started(BASE.replace("5178", "8005")): + pytest.skip("이 폴더 서버 없음") + sync = pytest.importorskip("playwright.sync_api") + cred = json.loads((ROOT / "tmp" / "aislo_cred.json").read_text(encoding="utf-8")) + shots = {} + with sync.sync_playwright() as play: + chrome = play.chromium.launch(channel="msedge", headless=True) + try: + for mode in ("both", "server"): + context = chrome.new_context(viewport={"width": 1600, "height": 1000}) + login = {k: cred[k] for k in ("email", "password")} + r = context.request.post( + f"{BASE}/api/auth/login/request", data=login, timeout=60000 + ) + assert r.ok, f"로그인 실패 {r.status}" # 비밀번호는 안 찍음 + if mode == "server": # 판은 안 고침 — 이 창이 받는 판만 stations = server + + def board(route): + body = route.fetch().json() + body["sites"]["stations"] = "server" + route.fulfill(json=body) + + context.route("**/api/dashboard/calc-sites", board) + page = context.new_page() + page.add_init_script( + f"localStorage.setItem('frd_current_project_id', '{VERIFY}');" + " performance.setResourceTimingBufferSize(20000);" + ) + page.goto(f"{BASE}/#/b05-profile", wait_until="domcontentloaded") + page.wait_for_function("() => !!window.__aisloPipeline", timeout=90000) + page.wait_for_timeout(9000) + shots[mode] = {"saved": page.evaluate(JS_STATIONS)} + page.evaluate(JS_DRAFT) # 교각점 하나 옮김(세션 초안 · 창과 함께 버림) + page.wait_for_timeout(3000) + shots[mode]["draft"] = page.evaluate(JS_STATIONS) + context.close() + finally: + chrome.close() + (ROOT / "tmp" / "511b2_screens.json").write_text(json.dumps(shots), encoding="utf-8") + return shots + + +import json # noqa: E402 + + +@pytest.mark.parametrize("case", ["saved", "draft"]) +def test_화면_서버_측점_화면_셈과_같음(screens, case): + both, server = screens["both"][case], screens["server"][case] + assert both["runs"] == server["runs"] == ["done"] + assert len(both["stations"]) > 10 + hit = _first_diff(both["stations"], server["stations"]) + assert hit is None, hit + assert both["calls"] == [] and server["calls"] # server 판만 서버를 부름