<!
DOCTYPE html>
<
meta charset=utf-8>
<
title>Web Locks API: Frames</
title>
<
link rel=help href=
"https://w3c.github.io/web-locks/">
<
script src=
"/resources/testharness.js"></
script>
<
script src=
"/resources/testharnessreport.js"></
script>
<
script src=
"resources/helpers.js"></
script>
<
style>
iframe { display: none; }</
style>
<
script>
'use strict';
promise_test(async t => {
assert_implements(navigator.locks);
const res = uniqueName(t);
const
frame = await
iframe(
'resources/iframe.html');
t.add_cleanup(() => {
frame.remove(); });
const lock_id = (await postToFrameAndWait(
frame, {op:
'request', name: res, mode:
'shared'})).lock_id;
await navigator.locks.request(res, {mode:
'shared'}, async lock => {
await postToFrameAndWait(
frame, {op:
'release', lock_id});
});
},
'Window and Frame - shared mode');
promise_test(async t => {
assert_implements(navigator.locks);
const res = uniqueName(t);
const
frame = await
iframe(
'resources/iframe.html');
t.add_cleanup(() => {
frame.remove(); });
//
frame acquires the lock.
const lock_id = (await postToFrameAndWait(
frame, {op:
'request', name: res})).lock_id;
// This request should be blocked.
let lock_granted = false;
const blocked = navigator.locks.request(res, lock => { lock_granted = true; });
// Verify that we can
't get it.
let available = undefined;
await navigator.locks.request(
res, {ifAvailable: true}, lock => { available = lock !== null; });
assert_false(available);
assert_false(lock_granted);
// Ask the
frame to release it.
await postToFrameAndWait(
frame, {op:
'release', lock_id});
await blocked;
// Now we
've got it.
assert_true(lock_granted);
},
'Window and Frame - exclusive mode');
promise_test(async t => {
assert_implements(navigator.locks);
const res = uniqueName(t);
const frame1 = await
iframe(
'resources/iframe.html');
const frame2 = await
iframe(
'resources/iframe.html');
// frame1 acquires the lock.
const lock_id = (await postToFrameAndWait(
frame1, {op:
'request', name: res})).lock_id;
// frame2
's request should be blocked.
let lock_granted = false;
const blocked = postToFrameAndWait(
frame2, {op:
'request', name: res});
blocked.then(f => { lock_granted = true; });
// Verify that frame2 can
't get it.
assert_true((await postToFrameAndWait(frame2, {
op:
'request', name: res, ifAvailable: true
})).failed,
'Lock request should have failed');
assert_false(lock_granted);
// Ask frame1 to release it.
await postToFrameAndWait(frame1, {op:
'release', lock_id});
await blocked;
// Now frame2 can get it.
assert_true(lock_granted);
frame1.parentElement.removeChild(frame1);
frame2.parentElement.removeChild(frame2);
},
'Frame and Frame - exclusive mode');
promise_test(async t => {
assert_implements(navigator.locks);
const res = uniqueName(t);
const
frame = await
iframe(
'resources/iframe.html');
//
Frame acquires the lock.
await postToFrameAndWait(
frame, {op:
'request', name: res});
// This request should be blocked.
let lock_granted = false;
const blocked = navigator.locks.request(
res, lock => { lock_granted = true; });
// Verify that we can
't get it.
let available = undefined;
await navigator.locks.request(
res, {ifAvailable: true}, lock => { available = lock !== null; });
assert_false(available);
assert_false(lock_granted);
// Implicitly release it by terminating the
frame.
frame.remove();
await blocked;
// Now we
've got it.
assert_true(lock_granted);
},
'Terminated Frame with held lock');
promise_test(async t => {
assert_implements(navigator.locks);
const res = uniqueName(t);
const
frame = await
iframe(
'resources/iframe.html');
//
Frame acquires the lock.
await postToFrameAndWait(
frame, {op:
'request', name: res});
// This request should be blocked.
let lock_granted = false;
const blocked = navigator.locks.request(
res, lock => { lock_granted = true; });
// Verify that we can
't get it.
let available = undefined;
await navigator.locks.request(
res, {ifAvailable: true}, lock => { available = lock !== null; });
assert_false(available);
assert_false(lock_granted);
// Implicitly release it by navigating the
frame.
frame.src =
'about:blank';
await blocked;
// Now we
've got it.
assert_true(lock_granted);
},
'Navigated Frame with held lock');
promise_test(async t => {
assert_implements(navigator.locks);
const res = uniqueName(t);
// frame1 requests and holds res - should be granted immediately.
// frame2 requests res - should be blocked.
// frame3 requests res - should be blocked.
// frame2 is navigated.
// frame1 releases res.
// frame3
's request should be granted.
const frame1 = await
iframe(
'resources/iframe.html');
const frame2 = await
iframe(
'resources/iframe.html');
const frame3 = await
iframe(
'resources/iframe.html');
t.add_cleanup(() => { frame1.remove(); });
t.add_cleanup(() => { frame2.remove(); });
t.add_cleanup(() => { frame3.remove(); });
// frame1 requests and holds res - should be granted immediately.
const lock_id = (await postToFrameAndWait(
frame1, {op:
'request', name: res})).lock_id;
// frame2 requests res - should be blocked.
// (don
't attach listeners as they will keep the frame alive)
frame2.contentWindow.postMessage({op:
'request', name: res},
'*');
// frame3 requests res - should be blocked.
let lock_granted = false;
const blocked = postToFrameAndWait(frame3, {op:
'request', name: res});
blocked.then(f => { lock_granted = true; });
// Verify that frame3 can
't get it.
assert_true((await postToFrameAndWait(frame3, {
op:
'request', name: res, ifAvailable: true
})).failed,
'Lock request should have failed');
assert_false(lock_granted);
// Navigate frame2.
frame2.src =
'about:blank';
// frame1 releases lock
await postToFrameAndWait(frame1, {op:
'release', lock_id});
// frame3
's request should be granted.
await blocked;
assert_true(lock_granted);
},
'Navigated Frame with pending request');
promise_test(async t => {
assert_implements(navigator.locks);
const res = uniqueName(t);
// frame1 requests and holds res - should be granted immediately.
// frame2 requests res - should be blocked.
// frame3 requests res - should be blocked.
// frame2 is removed.
// frame1 drops lock.
// frame3
's request should be granted.
const frame1 = await
iframe(
'resources/iframe.html');
const frame2 = await
iframe(
'resources/iframe.html');
const frame3 = await
iframe(
'resources/iframe.html');
t.add_cleanup(() => { frame1.remove(); });
t.add_cleanup(() => { frame3.remove(); });
// frame1 requests and holds res - should be granted immediately.
const lock_id = (await postToFrameAndWait(
frame1, {op:
'request', name: res})).lock_id;
// frame2 requests res - should be blocked.
// (don
't attach listeners as they will keep the frame alive)
frame2.contentWindow.postMessage({op:
'request', name: res},
'*');
// frame3 requests res - should be blocked.
let lock_granted = false;
const blocked = postToFrameAndWait(frame3, {op:
'request', name: res});
blocked.then(f => { lock_granted = true; });
// So frame3 can
't get it
assert_true((await postToFrameAndWait(frame3, {
op:
'request', name: res, ifAvailable: true
})).failed,
'Lock request should have failed');
assert_false(lock_granted);
// Remove frame2.
frame2.remove();
// frame1 releases lock
await postToFrameAndWait(frame1, {op:
'release', lock_id});
// frame3
's request should be granted.
await blocked;
assert_true(lock_granted);
},
'Removed Frame with pending request');
promise_test(async t => {
assert_implements(navigator.locks);
const res = uniqueName(t);
const
frame = await
iframe(
'about:blank');
// Remove a
frame while it is in the process of requesting a lock.
// The promise returned by `request` will never resolve since its
frame no
// longer exists, but the lock should still be released.
await new Promise(resolve => {
frame.contentWindow.navigator.locks.request(res, () => {
frame.remove();
resolve();
});
});
assert_false((await navigator.locks.query()).held.includes(res));
},
'Removed Frame as lock is granted');
</
script>