import os from pathlib import Path import pytest if os.getenv("STACKCHAIN_RUN_RELEASE_E2E") != "1": pytest.skip( "packaged mobile comment-reaction journey runs only in its gated CI job", allow_module_level=True, ) pytest.importorskip("playwright.sync_api") from playwright.sync_api import expect, sync_playwright ROOT = Path(__file__).parents[2] FRONTEND = ROOT / "frontend" def test_comment_reactions_are_touch_safe_and_focus_preserving_at_320px(): with sync_playwright() as playwright: browser = playwright.chromium.launch(headless=True) page = browser.new_page(viewport={"width": 320, "height": 568}) page.set_content( '
' '
' '

Ship feedback

' ) page.add_style_tag(path=FRONTEND / "dashboard.css") page.add_script_tag(path=FRONTEND / "comment-actions.js") page.evaluate( """ window.reactionCalls = []; window.offline = false; const controller = createCommentActions({ getLogin: () => 'timmy', fetchJson: async (path, options = {}) => { reactionCalls.push([path, options.method || 'GET']); return { comment_id: 91, reactions: [{content: 'heart', count: options.method === 'PUT' ? 2 : 1, selected: options.method === 'PUT'}], }; }, }); document.querySelector('#actions').innerHTML = controller.actionHtml({id: 91, author: 'alex'}); controller.wire({ root: document.querySelector('#comments'), getSurface: () => ({ context: {kind: 'issue', item: {repository: 'stackchain/api', number: 7}}, status: document.querySelector('#status'), }), isOffline: () => window.offline, escapeHtml: value => String(value), }); """ ) trigger = page.get_by_role("button", name="React to this comment") trigger.click() menu = page.locator("[data-comment-reaction-menu]") expect(menu).to_be_visible() for control in menu.get_by_role("button").all(): box = control.bounding_box() assert box is not None and box["height"] >= 44 page.get_by_role("button", name="Heart 1").click() expect(menu).to_be_hidden() expect(trigger).to_be_focused() expect(page.locator("#status")).to_have_text("Reaction updated.") assert page.evaluate( "document.documentElement.scrollWidth > document.documentElement.clientWidth" ) is False assert page.evaluate("window.reactionCalls") == [ ["api/v1/repos/stackchain/api/issues/7/comments/91/reactions", "GET"], ["api/v1/repos/stackchain/api/issues/7/comments/91/reactions/heart", "PUT"], ] browser.close() def test_search_following_conversation_actions_are_touch_safe_at_320px(): with sync_playwright() as playwright: browser = playwright.chromium.launch(headless=True) page = browser.new_page(viewport={"width": 320, "height": 568}) page.set_content( '
' '
' '
' '' '' '
' ) page.add_style_tag(path=FRONTEND / "dashboard.css") page.add_script_tag(path=FRONTEND / "search-preview.js") page.add_script_tag(path=FRONTEND / "comment-actions.js") page.evaluate( """ const actions=createCommentActions({fetchJson:async()=>({}),getLogin:()=> 'timmy'}); renderSearchPreviewConversation({status:'ready',comments:[ {id:41,author:'timmy',body:'Correct this from Following'}, {id:42,author:'alexander',body:'React without leaving Search'}, ]},document,value=>String(value),value=>String(value),value=>String(value),actions); """ ) expect(page.locator(".search-preview-comment.issue-comment")).to_have_count(2) expect(page.get_by_role("button", name="Edit")).to_have_count(1) expect(page.get_by_role("button", name="Delete")).to_have_count(1) expect(page.get_by_role("button", name="React to this comment")).to_have_count(2) for control in page.locator("[data-comment-action], [data-comment-reactions-open]").all(): box = control.bounding_box() assert box is not None and box["height"] >= 44 assert page.evaluate( "document.documentElement.scrollWidth > document.documentElement.clientWidth" ) is False browser.close()