Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

// META: title=WebLocks granted to a dedicated worker in BFCache should be deferred.
// META: timeout=long
// META: script=/common/dispatcher/dispatcher.js
// META: script=/common/get-host-info.sub.js
// META: script=/common/utils.js
// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js
// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
// META: script=/html/browsers/browsing-the-web/remote-context-helper-tests/resources/test-helper.js
'use strict';
promise_test(async t => {
const rcHelper = new RemoteContextHelper();
// Open a window with noopener so that BFCache will work.
const rc1 = await rcHelper.addWindow(
/*extraConfig=*/ {}, /*options=*/ { features: 'noopener' });
// BroadcastChannel to receive the grant notification from worker.
const bc = new BroadcastChannel('bfcache_lock_test_channel');
let grantedReceived = false;
bc.onmessage = t.step_func(e => {
if (e.data === 'granted') {
grantedReceived = true;
}
});
// Acquire the lock in the main test window first.
let mainLockResolver;
const mainLockPromise = new Promise(resolve => { mainLockResolver = resolve; });
navigator.locks.request('bfcache_weblock_test', async lock => {
mainLockResolver();
// Keep holding the lock until we decide to release it.
await new Promise(resolve => {
t.add_cleanup(resolve);
globalThis.releaseMainLock = resolve;
});
});
await mainLockPromise;
// Start a worker in the remote context.
const worker = await rc1.addWorker(
/*workerVar=*/ undefined,
{
scripts: [],
}
);
// In the worker, request the same lock.
// Since the main window holds it, this will pend.
await worker.executeScript(() => {
navigator.locks.request('bfcache_weblock_test', () => {
const bc = new BroadcastChannel('bfcache_lock_test_channel');
bc.postMessage('granted');
});
});
// Prepare rc1 for BFCache.
await prepareForBFCache(rc1);
// Navigate away.
const rc1Away = await rc1.navigateToNew();
await assertSimplestScriptRuns(rc1Away);
// Now rc1 and its worker should be in BFCache.
// Wait a bit to ensure they are frozen.
await new Promise(resolve => t.step_timeout(resolve, 1000));
// Release the lock in the main window.
// If the worker is correctly frozen, it will acquire the lock but will not run the callback.
globalThis.releaseMainLock();
// Wait to see if the worker does not run the callback.
await new Promise(resolve => t.step_timeout(resolve, 1000));
// Assert that we have not received the message yet.
assert_false(grantedReceived, "Lock should not be granted while in BFCache");
// Restore rc1 from BFCache.
await rc1Away.historyBack();
await assertImplementsBFCacheOptional(rc1);
// Now that it is restored, the worker should unfreeze and run the callback.
// Wait for the message to arrive.
if (!grantedReceived) {
await new Promise(resolve => {
bc.addEventListener('message', t.step_func(e => {
if (e.data === 'granted') {
resolve();
}
}));
// Set a timeout just in case it never arrives.
t.step_timeout(() => resolve(), 2000);
});
}
assert_true(grantedReceived, "Lock should be granted after restore");
}, 'WebLocks grant to worker in BFCache is deferred');