import os from pathlib import Path import pytest from playwright.sync_api import sync_playwright ROOT = Path(__file__).resolve().parents[2] def test_edge_indexeddb_cache_and_tab_isolation_when_server_running(): with sync_playwright() as p: browser = p.chromium.launch(channel="msedge", headless=True) context = browser.new_context() page1 = context.new_page() try: page1.goto("http://100.65.141.15:5175", timeout=5000) except Exception: pytest.skip("EST 5175 server not reachable") page1.wait_for_function("() => Boolean(EstApp.state.project)") # 1. 탭 1에서 프로젝트 이름 수정 및 비동기 캐시 완료 대기 page1.evaluate("""async () => { EstApp.change(p => { p.name = '탭 1 프로젝트 수정'; }); await new Promise(r => setTimeout(r, 100)); }""") # 2. 탭 1 새로고침 후 복원 확인 page1.reload() page1.wait_for_function("() => Boolean(EstApp.state.project)") name1 = page1.evaluate("EstApp.state.project.name") assert name1 == "탭 1 프로젝트 수정" # 3. 탭 2 독립 생성 page2 = context.new_page() page2.goto("http://100.65.141.15:5175") page2.wait_for_function("() => Boolean(EstApp.state.project)") # 탭 2는 탭 1의 세션 스토리지를 공유하지 않고 독립적으로 시작 page2.evaluate("EstApp.change(p => { p.name = '탭 2 독자 프로젝트'; })") name2 = page2.evaluate("EstApp.state.project.name") assert name2 == "탭 2 독자 프로젝트" # 4. 탭 1 다시 새로고침 시 탭 2에 의해 덮어써지지 않는지 확인 page1.reload() page1.wait_for_function("() => Boolean(EstApp.state.project)") assert page1.evaluate("EstApp.state.project.name") == "탭 1 프로젝트 수정" browser.close() def test_edge_indexeddb_large_main_estx_reload_restore_when_server_running(): sample = Path("C:/Dasansoft/Est Plus 2/Data/ProjectData/main.estx") if not sample.exists(): sample = Path("resources/knowledge/original/원가계산/다산소프트/2026-07-main.estx") if not sample.exists(): pytest.skip("main.estx sample not available") with sync_playwright() as p: browser = p.chromium.launch(channel="msedge", headless=True) page = browser.new_page() try: page.goto("http://100.65.141.15:5175", timeout=5000) except Exception: pytest.skip("EST 5175 server not reachable") page.wait_for_function("() => Boolean(EstApp.state.project)") # 대용량 main.estx 업로드 page.locator("#open-file").set_input_files(str(sample)) page.wait_for_function( "() => EstApp.state.project.tables.EstMainDat.length > 50", timeout=30000 ) # 수정 후 캐시 대기 page.evaluate("EstApp.change(p => { p.name = '대용량 main 수정본'; })") page.wait_for_timeout(2000) # 새로고침 후 복원 확인 page.reload() page.wait_for_function("() => Boolean(EstApp.state.project)", timeout=30000) restored_name = page.evaluate("EstApp.state.project.name") restored_rows = page.evaluate("EstApp.state.project.tables?.EstMainDat?.length || 0") assert restored_name == "대용량 main 수정본" assert restored_rows > 50 # 대용량 캐시 저장 실패 시 안내 메시지 검증 notice = page.evaluate("""async () => { const originalSave = EstApp.cache; // 인위적으로 IndexedDB 에러 유발 모의 const db = await (new Promise(r => { const req = indexedDB.open("est-independent-cache", 1); req.onsuccess = () => r(req.result); })); // 읽기 전용 모드로 변경 시도하거나 sessionStorage 차단 모의 const res = await EstApp.cache("x".repeat(100)); return EstApp.state.notice; }""") assert isinstance(notice, str) browser.close() def test_edge_duplicate_tab_isolation_and_inheritance_when_server_running(): with sync_playwright() as p: browser = p.chromium.launch(channel="msedge", headless=True) context = browser.new_context() page1 = context.new_page() try: page1.goto("http://100.65.141.15:5175", timeout=5000) except Exception: pytest.skip("EST 5175 server not reachable") page1.wait_for_function("() => Boolean(EstApp.state.project)") # 탭 1에서 이름 수정 page1.evaluate("""async () => { EstApp.change(p => { p.name = '원래 탭 프로젝트'; }); await new Promise(r => setTimeout(r, 200)); }""") tab1_id = page1.evaluate("sessionStorage.getItem('est-tab-instance-id')") assert tab1_id == page1.evaluate("window.name") # 브라우저의 "탭 복제(Duplicate Tab)" 시뮬레이션: # Chromium 복제 탭은 이전 탭의 sessionStorage 전체를 복제받지만, window.name은 빈 문자열("")로 시작합니다. tab1_data = page1.evaluate(f"sessionStorage.getItem('est-web-v2-working-{tab1_id}')") page_dup = context.new_page() # 1회성 init script: 최초 로드 시 복제 순간 모의 후 플래그로 1회만 동작하도록 제어 # 브라우저 실제 환경에서는 복제 순간 1회만 window.name이 빈 문자열이고 sessionStorage에 부모 데이터가 복제됨. # page_dup.reload() 시 add_init_script가 다시 실행되어 window.name을 지우거나 부모 id로 되돌리는 현상을 방지하기 위해 sessionStorage 플래그 사용 page_dup.add_init_script(f""" if (!sessionStorage.getItem('__test_cloned_injected')) {{ sessionStorage.setItem('__test_cloned_injected', '1'); sessionStorage.setItem('est-tab-instance-id', '{tab1_id}'); if ({"true" if tab1_data else "false"}) {{ sessionStorage.setItem('est-web-v2-working-{tab1_id}', {repr(tab1_data) if tab1_data else '""'}); }} window.name = ''; }} """) page_dup.goto("http://100.65.141.15:5175") page_dup.wait_for_function("() => Boolean(EstApp.state.project)") # 1) 복제 탭은 부모 탭의 데이터('원래 탭 프로젝트')를 성공적으로 상속받았는지 확인 info = page_dup.evaluate("""() => { return { windowName: window.name, sessionTab: sessionStorage.getItem('est-tab-instance-id'), parentTabId: EstApp.parentTabId, name: EstApp.state.project.name, keys: Object.keys(sessionStorage) }; }""") print("DEBUG INFO:", info) dup_name = info["name"] assert dup_name == "원래 탭 프로젝트" # 2) 복제 탭은 부모 탭과 다른 새 고유 인스턴스 ID를 발급받았는지 확인 dup_tab_id = page_dup.evaluate("sessionStorage.getItem('est-tab-instance-id')") assert dup_tab_id != tab1_id assert dup_tab_id == page_dup.evaluate("window.name") # 3) 복제 탭에서 데이터를 독립적으로 수정했을 때 원래 탭에 영향을 주지 않는지 확인 page_dup.evaluate("""async () => { EstApp.change(p => { p.name = '복제 탭에서만 변경'; }); await new Promise(r => setTimeout(r, 200)); }""") # 원래 탭 1 새로고침 시 원래 데이터 유지 확인 page1.reload() page1.wait_for_function("() => Boolean(EstApp.state.project)") assert page1.evaluate("EstApp.state.project.name") == "원래 탭 프로젝트" # 복제 탭 새로고침 시 복제 탭 변경 사항 유지 확인 page_dup.reload() page_dup.wait_for_function("() => Boolean(EstApp.state.project)") assert page_dup.evaluate("EstApp.state.project.name") == "복제 탭에서만 변경" browser.close()