"""Production-build browser regression for workspace-scoped loading and lazy UI. Run `npm run build` in gallery_ui, start `python scripts/preview.py --port 8189`, then run `python scripts/browser_optimization_smoke.py http://127.0.0.1:8189`. The isolated preview has synthetic sample images; this is not a ComfyUI test. """ from __future__ import annotations import asyncio import sys from playwright.async_api import async_playwright, expect BASE = sys.argv[1].rstrip("/") if len(sys.argv) > 1 else "http://127.0.0.1:8189" PREFERENCES = """ localStorage.setItem('universal-extractor-locale', 'zh-CN'); localStorage.setItem('universal-extractor:onboarding-tour-v1-completed', 'true'); localStorage.setItem('universal-extractor:ui-preferences', JSON.stringify({ enableImagePrefetch: false, enableLiveGalleryRefresh: false })); """ async def main() -> None: async with async_playwright() as playwright: browser = await playwright.chromium.launch(args=["--no-sandbox"]) try: context = await browser.new_context(viewport={"width": 1440, "height": 900}) await context.add_init_script(PREFERENCES) page = await context.new_page() requests: list[str] = [] errors: list[str] = [] page.on("request", lambda request: requests.append(request.url)) page.on("pageerror", lambda error: errors.append(str(error))) # Opening a deep link into the library must not request gallery rows # or ship optional gallery-mode/modal JS on the first screen. await page.goto(BASE + "/gallery/?tab=library", wait_until="networkidle") await expect(page.get_by_text("Demo prompts.json").first).to_be_visible() assert any("/LibraryWorkspace-" in url for url in requests), requests assert not any("/api/images?" in url or "/api/images/freshness" in url for url in requests), requests assert not any("/DualFolderWorkspace-" in url or "/ImageDetailModal-" in url or "/VariantGroupsView-" in url for url in requests), requests print("PASS library deep link: no gallery image requests or optional gallery chunks") requests.clear() await page.goto(BASE + "/gallery/", wait_until="networkidle") await expect(page.locator(".ue-gallery-card").first).to_be_visible() assert not any("/ImageDetailModal-" in url or "/DualFolderWorkspace-" in url or "/VariantGroupsView-" in url for url in requests), requests await page.locator('[data-tour-id="gallery-density"]').click() await expect(page.locator(".ue-density-panel output")).to_have_text("6") await page.keyboard.press("Escape") print("PASS fresh desktop: six-column preference and optional UI not fetched") # An existing user preference wins over the new default; Reset is # an explicit user action and writes six for later sessions. await page.evaluate("localStorage.setItem('universal-extractor:grid-columns', '4')") await page.reload(wait_until="networkidle") await page.locator('[data-tour-id="gallery-density"]').click() await expect(page.locator(".ue-density-panel output")).to_have_text("4") await page.get_by_role("button", name="恢复默认(每行 6 张)").click() await expect(page.locator(".ue-density-panel output")).to_have_text("6") assert await page.evaluate("localStorage.getItem('universal-extractor:grid-columns')") == "6" await page.keyboard.press("Escape") print("PASS saved density: respected; explicit reset persists six") requests.clear() await page.locator(".ue-gallery-card img").first.click() await expect(page.locator(".ue-lightbox-shell")).to_be_visible() assert any("/ImageDetailModal-" in url for url in requests), requests await page.keyboard.press("Escape") await expect(page.locator(".ue-lightbox-shell")).to_have_count(0) print("PASS image detail: lazy chunk fetched only on demand") requests.clear() await page.get_by_role("combobox", name="图库模式").select_option("organize") await expect(page.locator(".ue-dual-workspace")).to_be_visible() assert any("/DualFolderWorkspace-" in url for url in requests), requests await page.get_by_role("combobox", name="图库模式").select_option("browse") await expect(page.locator(".ue-gallery-card").first).to_be_visible() print("PASS dual-folder mode: lazy chunk fetched, return restores gallery") requests.clear() await page.locator('summary[aria-label="更多操作"]').click() await page.get_by_role("button", name="变体", exact=True).click() await expect(page.locator(".ue-variant-workspace")).to_be_visible() assert any("/VariantGroupsView-" in url for url in requests), requests assert not errors, errors print("PASS variants: lazy chunk fetched; no page errors") await context.close() # Broken/blocked browser storage must not prevent the gallery from # painting or cause an uncaught page error. blocked = await browser.new_context(viewport={"width": 1440, "height": 900}) await blocked.add_init_script(""" Storage.prototype.getItem = () => { throw new DOMException('denied', 'SecurityError'); }; Storage.prototype.setItem = () => { throw new DOMException('denied', 'SecurityError'); }; Storage.prototype.removeItem = () => { throw new DOMException('denied', 'SecurityError'); }; """) page = await blocked.new_page() storage_errors: list[str] = [] page.on("pageerror", lambda error: storage_errors.append(str(error))) await page.goto(BASE + "/gallery/", wait_until="networkidle") await expect(page.locator(".ue-gallery-card").first).to_be_visible() assert not storage_errors, storage_errors print("PASS blocked localStorage: gallery rendered without uncaught errors") await blocked.close() finally: await browser.close() if __name__ == "__main__": asyncio.run(main())