test: align packaged journeys with demand hydration
Some checks failed
CI / lint (pull_request) Successful in 4m2s
CI / build-release (pull_request) Successful in 6s
CI / browser-journey (pull_request) Failing after 7m47s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy 2026-08-27 12:17:20 +00:00
parent 5d9cec1dd7
commit 8909bedd78
10 changed files with 27 additions and 9 deletions

View File

@ -8472,7 +8472,8 @@
});
let pushControllerReady = Promise.resolve(null);
if ('serviceWorker' in navigator) {
pushControllerReady = navigator.serviceWorker.register('service-worker.js').then(async () => {
pushControllerReady = (workspaceLifecycle.serviceWorkerReady ||
navigator.serviceWorker.register('service-worker.js')).then(async () => {
await issueCaptureFeatures.load('push-notifications');
const controller = createPushNotifications({
control:qs('#push-updates'),

View File

@ -72,6 +72,8 @@ async function loadWorkspace({
retryButton?.addEventListener?.('click', retryFailed);
const handleOnline = () => { cameOnline = true; void retryFailed(); };
window?.addEventListener('online', handleOnline);
const serviceWorkerReady = window?.navigator?.serviceWorker?.register ?
window.navigator.serviceWorker.register('service-worker.js') : Promise.resolve(null);
try {
await retryOnce('work-core');
@ -105,7 +107,7 @@ async function loadWorkspace({
};
const hydrationSelector = [
'[data-mobile-task]:not([data-mobile-task="work"]):not([data-mobile-task="queues"])',
'[data-mobile-task]:not([data-mobile-task="queues"])',
'[data-progressive-loading="true"]',
'#app-menu-toggle',
'#work-settings-toggle',
@ -130,6 +132,7 @@ async function loadWorkspace({
deepLinkReady,
workspaceReady,
markWorkspaceReady,
serviceWorkerReady,
get optionalReady() { return hydrateWorkspace(); },
retryFeature(name) {
if (!failed.has(name)) return Promise.resolve(true);

View File

@ -13,7 +13,7 @@ pytest.importorskip("playwright.sync_api")
from playwright.sync_api import expect, sync_playwright
from fake_gitea import FakeGiteaServer
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, release_server
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, hydrate_workspace, release_server
@pytest.mark.parametrize(("width", "height"), [(320, 568), (390, 844)])
@ -85,6 +85,7 @@ def test_release_artifact_reopens_human_gates_with_one_fresh_mobile_snapshot(
page.locator('input[name="access_token"]').fill(ACCESS_TOKEN)
page.locator("#submit-sign-in").click()
page.wait_for_url(origin + "/", wait_until="networkidle")
hydrate_workspace(page)
page.evaluate("document.querySelector('#open-human-gates').click()")
expect(page.locator("#human-gates")).to_be_visible()
@ -244,6 +245,7 @@ def test_release_artifact_reviews_live_human_gate_history_and_receipt_on_phone(t
page.locator('input[name="access_token"]').fill(ACCESS_TOKEN)
page.locator("#submit-sign-in").click()
page.wait_for_url(origin + "/", wait_until="networkidle")
hydrate_workspace(page)
page.evaluate("document.querySelector('#open-human-gates').click()")
expect(page.locator("#human-gates")).to_be_visible()
cached_before = page.evaluate("Object.keys(localStorage).sort()")

View File

@ -114,6 +114,13 @@ def release_server(archive: Path, tmp_path: Path, gitea_url: str):
process.communicate()
def hydrate_workspace(page) -> None:
page.evaluate(
"async () => { const lifecycle = await window.stackchainWorkspaceLifecycle; "
"await lifecycle.hydrateWorkspace(); await lifecycle.workspaceReady; }"
)
def indexed_issue_records(page: Page) -> list[dict]:
return page.evaluate(
"""async () => {

View File

@ -12,7 +12,7 @@ pytest.importorskip("playwright.sync_api")
from playwright.sync_api import expect, sync_playwright
from fake_gitea import FakeGiteaServer
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, release_server
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, hydrate_workspace, release_server
def test_release_artifact_finds_and_reopens_photo_only_reply_from_mobile_my_work(tmp_path: Path):
@ -60,6 +60,7 @@ def test_release_artifact_finds_and_reopens_photo_only_reply_from_mobile_my_work
})"""
)
page.reload(wait_until="networkidle")
hydrate_workspace(page)
stored = page.evaluate(
"""() => new Promise((resolve,reject)=>{
const request=indexedDB.open('stackchain-conversation-reply-drafts-v1',1);

View File

@ -12,7 +12,7 @@ pytest.importorskip("playwright.sync_api")
from playwright.sync_api import expect, sync_playwright
from fake_gitea import FakeGiteaServer
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, release_server
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, hydrate_workspace, release_server
@pytest.mark.parametrize(("width", "height"), [(320, 568), (390, 844)])
@ -50,6 +50,7 @@ def test_release_artifact_reviews_and_shares_a_private_mobile_today_summary(
page.locator('input[name="access_token"]').fill(ACCESS_TOKEN)
page.locator("#submit-sign-in").click()
page.wait_for_url(origin + "/", wait_until="networkidle")
hydrate_workspace(page)
page.evaluate(
"""

View File

@ -12,7 +12,7 @@ pytest.importorskip("playwright.sync_api")
from playwright.sync_api import expect, sync_playwright
from fake_gitea import FakeGiteaServer
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, release_server
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, hydrate_workspace, release_server
@pytest.mark.parametrize(("width", "height"), [(320, 568), (390, 844)])
@ -47,6 +47,7 @@ def test_release_artifact_renders_and_applies_mobile_today_wrap_up(
page.locator('input[name="access_token"]').fill(ACCESS_TOKEN)
page.locator("#submit-sign-in").click()
page.wait_for_url(origin + "/", wait_until="networkidle")
hydrate_workspace(page)
page.evaluate(
"""

View File

@ -13,7 +13,7 @@ pytest.importorskip("playwright.sync_api")
from playwright.sync_api import expect, sync_playwright
from fake_gitea import FakeGiteaServer
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, release_server
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, hydrate_workspace, release_server
@pytest.mark.parametrize(("width", "height"), [(320, 568), (390, 844)])
@ -71,6 +71,7 @@ def test_release_artifact_resolves_cross_device_tomorrow_conflicts_on_mobile(
page.locator('input[name="access_token"]').fill(ACCESS_TOKEN)
page.locator("#submit-sign-in").click()
page.wait_for_url(origin + "/", wait_until="networkidle")
hydrate_workspace(page)
def stage_phone_plan():
page.evaluate(

View File

@ -12,7 +12,7 @@ pytest.importorskip("playwright.sync_api")
from playwright.sync_api import expect, sync_playwright
from fake_gitea import FakeGiteaServer
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, release_server
from test_mobile_offline_issue_release import ACCESS_TOKEN, ROOT, hydrate_workspace, release_server
def test_release_artifact_reviews_wrap_up_commitments_on_a_phone(tmp_path: Path):
@ -36,6 +36,7 @@ def test_release_artifact_reviews_wrap_up_commitments_on_a_phone(tmp_path: Path)
'issue:acme/mobile:41:', 'issue:acme/mobile:42:'
]))""")
page.reload(wait_until="networkidle")
hydrate_workspace(page)
dialog = page.locator("#today-handoff-dialog")
expect(dialog).to_be_visible()

View File

@ -72,7 +72,7 @@ const createLoader=()=>({load:async name=>{
let lifecycle=await loadWorkspace({document,createLoader});
let prevented=0,stopped=0,replayed=0,actionReady=false,replayedReady=false;
const target={
closest(selector){return selector.includes('data-mobile-task') ? this : null;},
closest(selector){return selector.includes(':not([data-mobile-task="work"])') ? null : this;},
click(){replayed++; replayedReady=actionReady;},
};
await listeners.click?.callback({target,preventDefault(){prevented++;},stopImmediatePropagation(){stopped++;}});