| // META: title=Web Locks API: navigator.locks.request method | |
| // META: script=resources/helpers.js | |
| // META: global=window,dedicatedworker,sharedworker,serviceworker | |
| 'use strict'; | |
| promise_test(async t => { | |
| const res = uniqueName(t); | |
| await promise_rejects_js(t, TypeError, navigator.locks.request()); | |
| await promise_rejects_js(t, TypeError, navigator.locks.request(res)); | |
| }, 'navigator.locks.request requires a name and a callback'); | |
| promise_test(async t => { | |
| const res = uniqueName(t); | |
| await promise_rejects_js( | |
| t, TypeError, | |
| navigator.locks.request(res, {mode: 'foo'}, lock => {})); | |
| await promise_rejects_js( | |
| t, TypeError, | |
| navigator.locks.request(res, {mode: null }, lock => {})); | |
| assert_equals(await navigator.locks.request( | |
| res, {mode: 'exclusive'}, lock => lock.mode), 'exclusive', | |
| 'mode is exclusive'); | |
| assert_equals(await navigator.locks.request( | |
| res, {mode: 'shared'}, lock => lock.mode), 'shared', | |
| 'mode is shared'); | |
| }, 'mode must be "shared" or "exclusive"'); | |
| promise_test(async t => { | |
| const res = uniqueName(t); | |
| await promise_rejects_dom( | |
| t, 'NotSupportedError', | |
| navigator.locks.request( | |
| res, {steal: true, ifAvailable: true}, lock => {}), | |
| "A NotSupportedError should be thrown if both " + | |
| "'steal' and 'ifAvailable' are specified."); | |
| }, "The 'steal' and 'ifAvailable' options are mutually exclusive"); | |
| promise_test(async t => { | |
| const res = uniqueName(t); | |
| await promise_rejects_dom( | |
| t, 'NotSupportedError', | |
| navigator.locks.request(res, {mode: 'shared', steal: true}, lock => {}), | |
| 'Request with mode=shared and steal=true should fail'); | |
| }, "The 'steal' option must be used with exclusive locks"); | |
| promise_test(async t => { | |
| const res = uniqueName(t); | |
| const controller = new AbortController(); | |
| await promise_rejects_dom( | |
| t, 'NotSupportedError', | |
| navigator.locks.request( | |
| res, {signal: controller.signal, steal: true}, lock => {}), | |
| 'Request with signal and steal=true should fail'); | |
| }, "The 'signal' and 'steal' options are mutually exclusive"); | |
| promise_test(async t => { | |
| const res = uniqueName(t); | |
| const controller = new AbortController(); | |
| await promise_rejects_dom( | |
| t, 'NotSupportedError', | |
| navigator.locks.request( | |
| res, {signal: controller.signal, ifAvailable: true}, lock => {}), | |
| 'Request with signal and ifAvailable=true should fail'); | |
| }, "The 'signal' and 'ifAvailable' options are mutually exclusive"); | |
| promise_test(async t => { | |
| const res = uniqueName(t); | |
| await promise_rejects_js( | |
| t, TypeError, navigator.locks.request(res, undefined)); | |
| await promise_rejects_js( | |
| t, TypeError, navigator.locks.request(res, null)); | |
| await promise_rejects_js( | |
| t, TypeError, navigator.locks.request(res, 123)); | |
| await promise_rejects_js( | |
| t, TypeError, navigator.locks.request(res, 'abc')); | |
| await promise_rejects_js( | |
| t, TypeError, navigator.locks.request(res, [])); | |
| await promise_rejects_js( | |
| t, TypeError, navigator.locks.request(res, {})); | |
| await promise_rejects_js( | |
| t, TypeError, navigator.locks.request(res, new Promise(r => {}))); | |
| }, 'callback must be a function'); | |
| promise_test(async t => { | |
| const res = uniqueName(t); | |
| let release; | |
| const promise = new Promise(r => { release = r; }); | |
| let returned = navigator.locks.request(res, lock => { return promise; }); | |
| const order = []; | |
| returned.then(() => { order.push('returned'); }); | |
| promise.then(() => { order.push('holding'); }); | |
| release(); | |
| await Promise.all([returned, promise]); | |
| assert_array_equals(order, ['holding', 'returned']); | |
| }, 'navigator.locks.request\'s returned promise resolves after' + | |
| ' lock is released'); | |
| promise_test(async t => { | |
| const res = uniqueName(t); | |
| const test_error = {name: 'test'}; | |
| const p = navigator.locks.request(res, lock => { | |
| throw test_error; | |
| }); | |
| assert_equals(Promise.resolve(p), p, 'request() result is a Promise'); | |
| await promise_rejects_exactly(t, test_error, p, 'result should reject'); | |
| }, 'Returned Promise rejects if callback throws synchronously'); | |
| promise_test(async t => { | |
| const res = uniqueName(t); | |
| const test_error = {name: 'test'}; | |
| const p = navigator.locks.request(res, async lock => { | |
| throw test_error; | |
| }); | |
| assert_equals(Promise.resolve(p), p, 'request() result is a Promise'); | |
| await promise_rejects_exactly(t, test_error, p, 'result should reject'); | |
| }, 'Returned Promise rejects if callback throws asynchronously'); | |
| promise_test(async t => { | |
| const res = uniqueName(t); | |
| let then_invoked = false; | |
| const test_error = { then: _ => { then_invoked = true; } }; | |
| const p = navigator.locks.request(res, async lock => { | |
| throw test_error; | |
| }); | |
| assert_equals(Promise.resolve(p), p, 'request() result is a Promise'); | |
| await promise_rejects_exactly(t, test_error, p, 'result should reject'); | |
| assert_false(then_invoked, 'then() should not be invoked'); | |
| }, 'If callback throws a thenable, its then() should not be invoked'); |