Verify worker recovery and retained offline feature fallback

This commit is contained in:
Jonathan Sykes
2026-10-09 09:50:31 +08:00
parent 009a155568
commit 6b8d590638
3 changed files with 53 additions and 17 deletions

View File

@@ -102,7 +102,9 @@ async function run(name) {
await page.waitForFunction(() => !!navigator.serviceWorker.controller, { timeout: 90000 });
assert.equal(await page.locator('meta[name="ytp-build"]').getAttribute('content'), oldTag);
assert.equal(banners, 0, 'no first-install banner');
console.log(name,'old shell installed');
await stop(); unlinkSync(join(cwd, 'public')); await start(false);
console.log(name,'new server started');
const backend = `http://127.0.0.1:${port}`;
const manifest = await (await fetch(`${backend}/api/manifest`)).json();
assert.notEqual(manifest.buildTag, oldTag);
@@ -119,10 +121,12 @@ async function run(name) {
proxy.resetStats(); proxy.startTracking();
const started = Date.now();
// Use the old application's public functions; no simulated update helper.
console.log(name,'requesting old-client update');
await page.evaluate(async () => {
await checkBuildTag();
await (await navigator.serviceWorker.getRegistration()).update();
});
console.log(name,'old-client update check returned');
await waitAsync(page,async () => !!(await navigator.serviceWorker.getRegistration())?.waiting);
await page.waitForFunction(() => /Update available/.test(document.querySelector('#modalTitle')?.textContent || '') && !document.querySelector('#modal').classList.contains('hidden'));
assert.equal(banners, 1, 'exactly one offer before refresh');
@@ -137,17 +141,24 @@ async function run(name) {
return !reg.installing && reg.waiting?.state==='installed' &&
!!await cache.match('/__ytp_candidate/'+tag);
}, manifest.buildTag);
console.log(name,'candidate installed');
const status = await page.evaluate(async()=>SwUpdate.askCacheStatus((await navigator.serviceWorker.getRegistration()).waiting,{timeoutMs:4000}));
assert.equal(status?.ready,true,'new worker confirms persistent cache to old helper');
assert.equal(status.version,manifest.buildTag,'status belongs to the target build');
console.log(name,'ready status received');
const oldTab = await context.newPage();
await oldTab.goto(origin,{waitUntil:'load'});
assert.equal(await oldTab.locator('meta[name="ytp-build"]').getAttribute('content'),oldTag);
const oldBytes = await oldTab.evaluate(async()=>await (await fetch('/app.js')).text());
await page.locator('#modal').getByRole('button', { name: 'Refresh UI', exact: true }).click();
console.log(name,'clicking legacy refresh');
await page.locator('#modal').getByRole('button', { name: 'Refresh UI', exact: true }).click({noWaitAfter:true,timeout:15000});
console.log(name,'legacy refresh clicked');
await page.waitForFunction(tag => document.querySelector('meta[name="ytp-build"]')?.content === tag && typeof checkBuildTag === 'function', manifest.buildTag, { timeout: 90000 });
console.log(name,'new page loaded');
await page.waitForFunction(() => !sessionStorage.getItem('ytpUpdateAttempt'));
console.log(name,'update outcome cleared');
await page.evaluate(async () => { await checkBuildTag(); await checkBuildTag(); await checkBuildTag(); });
console.log(name,'banner rechecks complete');
await sleep(2000);
assert.equal(navigations - before, 1, 'one reload, no update loop');
assert.equal(banners, 1, 'no banner after applying the current build');
@@ -225,7 +236,7 @@ async function run(name) {
const result = { browser: name, oldTag, newTag: manifest.buildTag, banners, updateReloads: 1, cachedFiles: cacheResult.count, durationMs, wireBytes: stats.totalWireBytes, offline: true, legacyURLs: 21, profile, userInitiatedOnly: true, playbackGuard: true, evictionRepair: true, incrementalRefresh: true, offlineTransportErrors: errors.length };
console.log(JSON.stringify(result));
return result;
} finally {
} catch(error) { console.error(name,error.stack); throw error; } finally {
await browser?.close();
if (proxy) { proxy.server.closeAllConnections(); await proxy.close(); }
await stop();