diff --git a/apps/web/e2e/offline.spec.ts b/apps/web/e2e/offline.spec.ts index e1859c7..a79931f 100644 --- a/apps/web/e2e/offline.spec.ts +++ b/apps/web/e2e/offline.spec.ts @@ -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', { timeout: 15000, }); - // The service worker must control the page before an offline reload can be - // served from the cached app shell. - await page.waitForFunction(() => navigator.serviceWorker?.controller != null, null, { - timeout: 20000, - }); + // The service worker must control the page AND have finished precaching the + // app shell before an offline reload can be served from cache. Checking the + // Cache Storage is populated avoids a race where the SW controls the page but + // 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'); await editor.click(); @@ -58,7 +70,7 @@ test('offline: edit, reload while offline, then reconnect converges (#38)', asyn expect(apiResult).toBe('network-error'); // 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, // 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('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 expect(page.locator('.editor-connection')).toHaveAttribute('data-status', 'connected', { + timeout: 30000, + }); + const admin = await contextForUser(browser, BASE_URL, 'fixture-admin'); const adminPage = await admin.newPage(); await adminPage.goto(`/p/${pond.slug}/${slug}`); await expect(adminPage.locator('.ProseMirror')).toContainText('offline extra', { - timeout: 25000, + timeout: 30000, }); await owner.close();