"""PLAN 505-4 — 구조물 고른 채 새로 고침 = 평면 편집기 뜸 · 빈 관경 = 빈 선택지(값 안 채움). 글 시험 = 소스 순서 · 화면 시험 = 자기 포트(5179) Playwright 머리 없는 브라우저 · 서버가 떠 있을 때만 · 검증_sub4. ./venv/Scripts/python.exe -m pytest resources/tester/test_505_4_refresh_blank_pipe.py -q """ from __future__ import annotations import json import urllib.request from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] from helper_verify_project import own_ports # noqa: E402 BASE = own_ports()[1] # 화면 서버 = OWNERS.md 이 폴더 줄 PROJECT = "c725d747-50ae-46b0-87ce-4d4e56a53cf3" # 검증_sub4(OWNERS.md) LIST_URL = f"{BASE}/api/projects/{PROJECT}/route/structures" def _read(*parts: str) -> str: return ROOT.joinpath(*parts).read_text(encoding="utf-8") def test_횡단_뜸_콜백은_만드는_도중_안_그림() -> None: edit = _read("B05_Profile", "B05_Profile_UI_RouteEdit.ts") # createCrossPreview 가 고른 측점을 만들며 곧바로 부름 — draw 는 아래 선언(closed · view)이 선 뒤에 assert "onShown: () => queueMicrotask(draw)," in edit assert "onShown: () => draw()" not in edit assert edit.index("const crossPreview = createCrossPreview(") < edit.index( "let closed = false;" ) def test_관경_빈칸은_빈_보기_채움_없음() -> None: form = _read("A00_Common", "design", "design_structure_form.ts") assert 'spec?.typeId === "pipe" && c.id === "pipe" && item.id === "diameter"' in form assert "c.required && !tag && !blankKept(c, item) ? [] : [new Option(blank," in form fill = form.index("필수 상자 빈 고르기 칸 = 정의 기본값") assert form.index("if (blankKept(c, item)) continue;", fill) < form.index( "values[item.id] =", fill ) def _up() -> bool: try: urllib.request.urlopen(BASE, timeout=3) return True except Exception: return False JS_DIAMETER = """() => [...document.querySelectorAll('select')] .filter((s) => s.offsetParent && [...s.options].some((o) => o.value === '800')) .map((s) => ({ value: s.value, first: s.options[0].value, count: s.options.length }))""" JS_CANVAS = """() => { const c = document.querySelector('.b05-routeedit__canvas'); const d = c.getContext('2d').getImageData(0, 0, c.width, c.height).data; let n = 0; for (let i = 3; i < d.length; i += 4) if (d[i] > 0) n += 1; return { visible: !!c.offsetParent, painted: n }; }""" @pytest.mark.skipif(not _up(), reason="5179 서버 없음") def test_화면_새로_고침_편집기_뜸_빈_관경_빈_선택지() -> None: sync = pytest.importorskip("playwright.sync_api") cred = json.loads((ROOT / "tmp" / "aislo_cred.json").read_text(encoding="utf-8")) with sync.sync_playwright() as play: chrome = play.chromium.launch(channel="msedge", headless=True) try: ctx = chrome.new_context(viewport={"width": 1600, "height": 1000}) login = {k: cred[k] for k in ("email", "password")} assert ctx.request.post(f"{BASE}/api/auth/login/request", data=login, timeout=60000).ok tab = ctx.new_page() errors: list[str] = [] tab.on("pageerror", lambda e: errors.append(str(e))) tab.add_init_script(f"localStorage.setItem('frd_current_project_id', '{PROJECT}')") tab.goto(f"{BASE}/#/b05-profile", wait_until="domcontentloaded") tab.wait_for_function("() => !!window.__aisloPipeline", timeout=90000) tab.wait_for_timeout(8000) before = ctx.request.get(LIST_URL).text() # 관경 빈칸 관(19+8) — 빈 선택지 · 값 안 채움 tab.locator(".b05-route__irregular-item", has_text="19+8").first.click() tab.wait_for_timeout(3000) if not tab.evaluate(JS_DIAMETER): tab.get_by_text("구조물 배치", exact=True).click() tab.wait_for_timeout(1500) assert tab.evaluate(JS_DIAMETER) == [{"value": "", "first": "", "count": 5}] assert ctx.request.get(LIST_URL).text() == before # 열기만 — 저장 값 그대로 # 고른 채 새로 고침 — 편집기가 뜸(전엔 `closed` 선언 전 씀으로 멈춤) errors.clear() tab.reload(wait_until="domcontentloaded") tab.wait_for_function("() => !!window.__aisloPipeline", timeout=90000) tab.wait_for_timeout(9000) assert not [e for e in errors if "before initialization" in e], errors canvas = tab.evaluate(JS_CANVAS) assert canvas["visible"] and canvas["painted"] > 0 assert ctx.request.get(LIST_URL).text() == before finally: chrome.close()