from __future__ import annotations import os import re from pathlib import Path import pytest if os.getenv("STACKCHAIN_RUN_RELEASE_E2E") != "1": pytest.skip("rendered mobile Search Preview checks run only in the browser gate", allow_module_level=True) pytest.importorskip("playwright.sync_api") from playwright.sync_api import expect, sync_playwright ROOT = Path(__file__).resolve().parents[2] FRONTEND = ROOT / "frontend" @pytest.mark.parametrize(("width", "height"), [(320, 568), (390, 844)]) def test_rendered_mobile_search_preview_navigation_preserves_reading_space_and_draft(width, height): html = re.sub(r'', "", (FRONTEND / "index.html").read_text()) with sync_playwright() as playwright: browser = playwright.chromium.launch() page = browser.new_page(viewport={"width": width, "height": height}) page.set_content(html) page.add_style_tag(path=FRONTEND / "dashboard.css") page.locator("#search-preview").evaluate("node => node.classList.add('open')") page.locator("#search-preview-reply-workspace").evaluate("node => node.hidden = false") page.locator(".search-preview-navigation").evaluate("node => node.hidden = false") page.locator("#search-preview-overview").evaluate("node => node.style.minHeight = '500px'") page.locator("#search-preview-conversation").evaluate("node => node.style.minHeight = '500px'") page.locator("#search-preview-reply-workspace").evaluate("node => node.style.minHeight = '500px'") page.locator("#search-preview-actions").evaluate("node => node.style.minHeight = '300px'") page.add_script_tag(path=FRONTEND / "mobile-search-preview-nav.js") navigation = page.locator(".mobile-search-preview-nav") expect(navigation).to_be_visible() buttons = navigation.locator("button") assert buttons.count() == 4 for button in buttons.all(): bounds = button.bounding_box() assert bounds and bounds["height"] >= 44 assert page.evaluate("document.documentElement.scrollWidth <= window.innerWidth") assert page.locator(".search-preview-panel").evaluate("node => node.scrollWidth <= node.clientWidth") page.locator("#search-preview-reply").fill("Keep this reply while navigating") navigation.locator('[data-search-preview-section="conversation"]').click() expect(navigation.locator('[data-search-preview-section="conversation"]')).to_have_attribute( "aria-current", "location" ) navigation.locator('[data-search-preview-section="reply"]').click() expect(page.locator("#search-preview-reply")).to_be_focused() assert page.locator("#search-preview-reply").input_value() == "Keep this reply while navigating" navigation.locator('[data-search-preview-section="actions"]').click() expect(navigation.locator('[data-search-preview-section="actions"]')).to_have_attribute( "aria-current", "location" ) continuation = page.locator(".search-preview-navigation") assert continuation.evaluate("node => getComputedStyle(node).position") == "sticky" assert continuation.evaluate("node => getComputedStyle(node).bottom") == "0px" assert page.locator("#search-preview-actions").evaluate("node => getComputedStyle(node).position") == "static" page.locator("#next-search-result").click() expect(navigation.locator('[data-search-preview-section="overview"]')).to_have_attribute( "aria-current", "location" ) assert page.locator("#search-preview-reply").input_value() == "Keep this reply while navigating" page.set_viewport_size({"width": 800, "height": 700}) expect(navigation).to_be_hidden() browser.close()