test: gate mobile review cancellation journey
All checks were successful
CI / lint (pull_request) Successful in 3m20s
CI / build-release (pull_request) Successful in 6s
CI / browser-journey (pull_request) Successful in 5m24s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy 2026-08-24 08:16:21 +00:00
parent d776a2b003
commit 1f9f0f5c22
3 changed files with 97 additions and 1 deletions

View File

@ -57,7 +57,7 @@ jobs:
pip install -r requirements-e2e.txt
python3 -m playwright install --with-deps chromium
- name: Exercise packaged mobile work journeys
run: python3 -m pytest tests/e2e/test_mobile_offline_issue_release.py tests/e2e/test_mobile_search_preview_navigation.py tests/e2e/test_mobile_search_week_plan.py tests/e2e/test_mobile_find_work_release.py tests/e2e/test_mobile_home_bootstrap_release.py tests/e2e/test_mobile_sign_out_release.py tests/e2e/test_mobile_today_handoff_release.py tests/e2e/test_mobile_today_wrap_up_release.py tests/e2e/test_mobile_today_summary_release.py tests/e2e/test_mobile_tomorrow_conflict_release.py tests/e2e/test_mobile_week_ahead_release.py tests/e2e/test_mobile_today_week_reschedule_release.py tests/e2e/test_mobile_wrap_up_handoff_release.py tests/e2e/test_mobile_following_release.py tests/e2e/test_mobile_detail_watch_release.py tests/e2e/test_mobile_pull_reviewer_status_release.py tests/e2e/test_mobile_pull_reviewer_feedback_release.py -q
run: python3 -m pytest tests/e2e/test_mobile_offline_issue_release.py tests/e2e/test_mobile_search_preview_navigation.py tests/e2e/test_mobile_search_week_plan.py tests/e2e/test_mobile_find_work_release.py tests/e2e/test_mobile_home_bootstrap_release.py tests/e2e/test_mobile_sign_out_release.py tests/e2e/test_mobile_today_handoff_release.py tests/e2e/test_mobile_today_wrap_up_release.py tests/e2e/test_mobile_today_summary_release.py tests/e2e/test_mobile_tomorrow_conflict_release.py tests/e2e/test_mobile_week_ahead_release.py tests/e2e/test_mobile_today_week_reschedule_release.py tests/e2e/test_mobile_wrap_up_handoff_release.py tests/e2e/test_mobile_following_release.py tests/e2e/test_mobile_detail_watch_release.py tests/e2e/test_mobile_pull_reviewer_status_release.py tests/e2e/test_mobile_pull_reviewer_feedback_release.py -q tests/e2e/test_mobile_address_review_feedback_release.py tests/e2e/test_mobile_cancel_pull_review_request_release.py
release-candidate:
runs-on: ubuntu-latest

View File

@ -0,0 +1,88 @@
import os
from pathlib import Path
import pytest
ROOT = Path(__file__).parents[2]
if os.environ.get("STACKCHAIN_RUN_RELEASE_E2E") != "1":
pytest.skip("release browser journey is opt-in", allow_module_level=True)
@pytest.mark.parametrize("viewport", [(320, 568), (390, 844)])
def test_mobile_author_cancels_pending_review_and_opens_replacement_picker(viewport):
playwright = pytest.importorskip("playwright.sync_api")
html = (ROOT / "frontend" / "index.html").read_text()
with playwright.sync_playwright() as runtime:
try:
browser = runtime.chromium.launch(headless=True)
except Exception as error:
pytest.skip(f"Chromium is not installed: {error}")
page = browser.new_page(viewport={"width": viewport[0], "height": viewport[1]})
page.set_content(html, wait_until="domcontentloaded")
page.add_style_tag(path=ROOT / "frontend" / "dashboard.css")
page.add_script_tag(path=ROOT / "frontend" / "pull-sheet.js")
page.evaluate(
"""() => {
globalThis.confirm = () => true;
globalThis.cancelCalls = [];
globalThis.cancelItem = {
repository:'stackchain/api', number:7, key:'stackchain/api#7'
};
globalThis.cancelDetail = {
state:'open', draft:false, mergeable:true, merged:false,
ci_state:'success', head_sha:'abc1234', files:[],
reviewers:[{
login:'sam', status:'waiting', head_sha:'abc1234', blocking:true
}],
};
globalThis.cancelController = createPullSheet({
storage:null,
fetchJson:async (path, options={}) => {
cancelCalls.push({path, options});
return {
repository:'stackchain/api', number:7, reviewer:'sam',
head_sha:'abc1234', requested_reviewers:[],
};
},
});
createPullSheet.bindReviewRequestControls(
document, cancelController, () => cancelItem, () => cancelDetail
);
createPullSheet.review(cancelDetail, null, document);
document.querySelector('#pull-sheet').classList.add('open');
document.querySelector('#pull-review').open = true;
}"""
)
cancel = page.locator('[data-cancel-review-request="sam"]')
bounds = cancel.bounding_box()
assert bounds and bounds["height"] >= 44
cancel.click()
page.wait_for_function("cancelCalls.length === 1")
page.wait_for_function(
"document.querySelector('#pull-review-request-status').textContent.includes('Choose a replacement reviewer')"
)
result = page.evaluate(
"""() => ({
calls:cancelCalls,
waitingRows:document.querySelectorAll('[data-reviewer-status="waiting"]').length,
pickerOpen:document.querySelector('#pull-review-request').open,
focused:document.activeElement?.id,
scrollWidth:document.documentElement.scrollWidth,
clientWidth:document.documentElement.clientWidth,
})"""
)
browser.close()
assert result["scrollWidth"] <= result["clientWidth"]
assert result["waitingRows"] == 0
assert result["pickerOpen"] is True
assert result["focused"] == "load-pull-reviewers"
assert len(result["calls"]) == 1
assert result["calls"][0]["options"]["method"] == "DELETE"
assert result["calls"][0]["options"]["body"] == (
'{"reviewer":"sam","expected_head_sha":"abc1234"}'
)

View File

@ -85,3 +85,11 @@ def test_browser_job_runs_packaged_today_week_reschedule_journey():
browser = text[text.index(" browser-journey:") : text.index(" release-candidate:")]
assert "tests/e2e/test_mobile_today_week_reschedule_release.py" in browser
def test_browser_job_gates_latest_pull_review_mobile_journeys():
text = WORKFLOW.read_text()
browser = text[text.index(" browser-journey:") : text.index(" release-candidate:")]
assert "tests/e2e/test_mobile_address_review_feedback_release.py" in browser
assert "tests/e2e/test_mobile_cancel_pull_review_request_release.py" in browser