stackchain-dashboard/tests/e2e/test_mobile_comment_reactions_release.py
timmy 7662cca9e6
All checks were successful
CI / lint (pull_request) Successful in 3m36s
CI / build-release (pull_request) Successful in 6s
CI / browser-journey (pull_request) Successful in 6m19s
CI / release-candidate (pull_request) Has been skipped
feat: act on Search and Following comments (Closes #1388)
2026-08-25 09:11:14 +00:00

116 lines
5.1 KiB
Python

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(
'<main><div id="status" aria-live="polite"></div>'
'<div id="comments"><article class="issue-comment" data-comment-id="91">'
'<p>Ship feedback</p><div id="actions"></div></article></div></main>'
)
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(
'<main><section id="search-preview-conversation" class="search-preview-conversation">'
'<div id="search-preview-comments"></div>'
'<div id="search-preview-conversation-status"></div>'
'<button id="retry-search-preview-conversation" hidden></button>'
'<button id="load-older-search-preview-comments" hidden></button>'
'</section></main>'
)
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()