Harden the offline e2e for slower CI timing (#38)
Some checks failed
CD / Build and push images (push) Successful in 54s
CI / Lint, typecheck, test (push) Successful in 1m59s
CI / Auth e2e pack (push) Failing after 2m12s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m11s
CD / Promote to Int (push) Successful in 11s

The offline pack passed locally but flaked in CI. Make its timing-sensitive
steps robust without changing the feature:

- Before going offline, wait until the service worker not only controls the
  page but has actually populated Cache Storage (app-shell precache complete),
  so the offline reload is guaranteed to be servable from cache.
- After coming back online, wait for the reloaded tab to reconnect (so it has
  pushed its local state) before checking a second client converges.
- Raise the service-worker-ready and convergence timeouts, and the IndexedDB
  flush wait, for headroom on slower runners.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PGdhRiwU1WRL4XxJfZYipY
This commit is contained in:
Claude Opus 4.8 2026-07-08 22:24:29 +02:00
parent af81b50fa6
commit 41b259fae5

View File

@ -25,11 +25,23 @@ test('offline: edit, reload while offline, then reconnect converges (#38)', asyn
await expect(page.locator('.editor-connection')).toHaveAttribute('data-status', 'connected', { await expect(page.locator('.editor-connection')).toHaveAttribute('data-status', 'connected', {
timeout: 15000, timeout: 15000,
}); });
// The service worker must control the page before an offline reload can be // The service worker must control the page AND have finished precaching the
// served from the cached app shell. // app shell before an offline reload can be served from cache. Checking the
await page.waitForFunction(() => navigator.serviceWorker?.controller != null, null, { // Cache Storage is populated avoids a race where the SW controls the page but
timeout: 20000, // its install (precache) has not completed yet.
}); await page.waitForFunction(
async () => {
if (!navigator.serviceWorker?.controller) return false;
const names = await caches.keys();
for (const name of names) {
const cache = await caches.open(name);
if ((await cache.keys()).length > 0) return true;
}
return false;
},
null,
{ timeout: 30000 },
);
const editor = page.locator('.ProseMirror'); const editor = page.locator('.ProseMirror');
await editor.click(); await editor.click();
@ -58,7 +70,7 @@ test('offline: edit, reload while offline, then reconnect converges (#38)', asyn
expect(apiResult).toBe('network-error'); expect(apiResult).toBe('network-error');
// Give y-indexeddb a moment to flush the offline edit before the reload. // Give y-indexeddb a moment to flush the offline edit before the reload.
await page.waitForTimeout(1000); await page.waitForTimeout(1500);
// Reload the tab while offline: the app shell loads from the service worker, // Reload the tab while offline: the app shell loads from the service worker,
// the page resolves from the offline metadata cache, and its content comes // the page resolves from the offline metadata cache, and its content comes
@ -68,13 +80,18 @@ test('offline: edit, reload while offline, then reconnect converges (#38)', asyn
await expect(reloaded).toContainText('offline extra', { timeout: 20000 }); await expect(reloaded).toContainText('offline extra', { timeout: 20000 });
await expect(reloaded).toContainText('online base'); await expect(reloaded).toContainText('online base');
// Back online: a second participant converges on the merged content. // Back online: the reloaded tab reconnects and pushes its local state to the
// server; wait for that before checking a second participant converges.
await owner.setOffline(false); await owner.setOffline(false);
await expect(page.locator('.editor-connection')).toHaveAttribute('data-status', 'connected', {
timeout: 30000,
});
const admin = await contextForUser(browser, BASE_URL, 'fixture-admin'); const admin = await contextForUser(browser, BASE_URL, 'fixture-admin');
const adminPage = await admin.newPage(); const adminPage = await admin.newPage();
await adminPage.goto(`/p/${pond.slug}/${slug}`); await adminPage.goto(`/p/${pond.slug}/${slug}`);
await expect(adminPage.locator('.ProseMirror')).toContainText('offline extra', { await expect(adminPage.locator('.ProseMirror')).toContainText('offline extra', {
timeout: 25000, timeout: 30000,
}); });
await owner.close(); await owner.close();