signal.https.any.js (7985B)
1 // META: title=Web Locks API: AbortSignal integration 2 // META: script=resources/helpers.js 3 // META: global=window,dedicatedworker,sharedworker,serviceworker 4 5 'use strict'; 6 7 promise_test(async t => { 8 const res = uniqueName(t); 9 10 // These cases should not work: 11 for (const signal of ['string', 12.34, false, {}, Symbol(), () => {}, self]) { 12 await promise_rejects_js( 13 t, TypeError, 14 navigator.locks.request( 15 res, {signal}, t.unreached_func('callback should not run')), 16 'Bindings should throw if the signal option is a not an AbortSignal'); 17 } 18 }, 'The signal option must be an AbortSignal'); 19 20 promise_test(async t => { 21 const res = uniqueName(t); 22 const controller = new AbortController(); 23 controller.abort(); 24 25 await promise_rejects_dom( 26 t, 'AbortError', 27 navigator.locks.request(res, {signal: controller.signal}, 28 t.unreached_func('callback should not run')), 29 'Request should reject with AbortError'); 30 }, 'Passing an already aborted signal aborts'); 31 32 promise_test(async t => { 33 const res = uniqueName(t); 34 35 const controller = new AbortController(); 36 const reason = 'My dog ate it.'; 37 controller.abort(reason); 38 39 const promise = 40 navigator.locks.request(res, {signal: controller.signal}, 41 t.unreached_func('callback should not run')); 42 43 await promise_rejects_exactly( 44 t, reason, promise, "Rejection should give the abort reason"); 45 }, 'Passing an already aborted signal rejects with the custom abort reason.'); 46 47 promise_test(async t => { 48 const res = uniqueName(t); 49 50 const controller = new AbortController(); 51 controller.abort(); 52 53 const promise = 54 navigator.locks.request(res, {signal: controller.signal}, 55 t.unreached_func('callback should not run')); 56 57 await promise_rejects_exactly( 58 t, controller.signal.reason, promise, 59 "Rejection should give the abort reason"); 60 }, 'Passing an already aborted signal rejects with the default abort reason.'); 61 62 promise_test(async t => { 63 const res = uniqueName(t); 64 65 // Grab a lock and hold it until this subtest completes. 66 requestLockAndHold(t, res); 67 68 const controller = new AbortController(); 69 70 const promise = 71 navigator.locks.request(res, {signal: controller.signal}, 72 t.unreached_func('callback should not run')); 73 74 // Verify the request is enqueued: 75 const state = await navigator.locks.query(); 76 assert_equals(state.held.filter(lock => lock.name === res).length, 1, 77 'Number of held locks'); 78 assert_equals(state.pending.filter(lock => lock.name === res).length, 1, 79 'Number of pending locks'); 80 81 const rejected = promise_rejects_dom( 82 t, 'AbortError', promise, 'Request should reject with AbortError'); 83 84 controller.abort(); 85 86 await rejected; 87 88 }, 'An aborted request results in AbortError'); 89 90 promise_test(async t => { 91 const res = uniqueName(t); 92 93 // Grab a lock and hold it until this subtest completes. 94 requestLockAndHold(t, res); 95 96 const controller = new AbortController(); 97 98 const promise = 99 navigator.locks.request(res, {signal: controller.signal}, lock => {}); 100 101 // Verify the request is enqueued: 102 const state = await navigator.locks.query(); 103 assert_equals(state.held.filter(lock => lock.name === res).length, 1, 104 'Number of held locks'); 105 assert_equals(state.pending.filter(lock => lock.name === res).length, 1, 106 'Number of pending locks'); 107 108 const rejected = promise_rejects_dom( 109 t, 'AbortError', promise, 'Request should reject with AbortError'); 110 111 let callback_called = false; 112 t.step_timeout(() => { 113 callback_called = true; 114 controller.abort(); 115 }, 10); 116 117 await rejected; 118 assert_true(callback_called, 'timeout should have caused the abort'); 119 120 }, 'Abort after a timeout'); 121 122 promise_test(async t => { 123 const res = uniqueName(t); 124 125 const controller = new AbortController(); 126 127 let got_lock = false; 128 await navigator.locks.request( 129 res, {signal: controller.signal}, async lock => { got_lock = true; }); 130 131 assert_true(got_lock, 'Lock should be acquired if abort is not signaled.'); 132 133 }, 'Signal that is not aborted'); 134 135 promise_test(async t => { 136 const res = uniqueName(t); 137 138 const controller = new AbortController(); 139 140 let got_lock = false; 141 const p = navigator.locks.request( 142 res, {signal: controller.signal}, lock => { got_lock = true; }); 143 144 // Even though lock is grantable, this abort should be processed synchronously. 145 controller.abort(); 146 147 await promise_rejects_dom(t, 'AbortError', p, 'Request should abort'); 148 149 assert_false(got_lock, 'Request should be aborted if signal is synchronous'); 150 151 await navigator.locks.request(res, lock => { got_lock = true; }); 152 assert_true(got_lock, 'Subsequent request should not be blocked'); 153 154 }, 'Synchronously signaled abort'); 155 156 promise_test(async t => { 157 const res = uniqueName(t); 158 159 const controller = new AbortController(); 160 161 // Make a promise that resolves when the lock is acquired. 162 const [acquired_promise, acquired_func] = makePromiseAndResolveFunc(); 163 164 // Request the lock. 165 let release_func; 166 const released_promise = navigator.locks.request( 167 res, {signal: controller.signal}, lock => { 168 acquired_func(); 169 170 // Hold lock until release_func is called. 171 const [waiting_promise, waiting_func] = makePromiseAndResolveFunc(); 172 release_func = waiting_func; 173 return waiting_promise; 174 }); 175 176 // Wait for the lock to be acquired. 177 await acquired_promise; 178 179 // Signal an abort. 180 controller.abort(); 181 182 // Release the lock. 183 release_func('resolved ok'); 184 185 assert_equals(await released_promise, 'resolved ok', 186 'Lock released promise should not reject'); 187 188 }, 'Abort signaled after lock granted'); 189 190 promise_test(async t => { 191 const res = uniqueName(t); 192 193 const controller = new AbortController(); 194 195 // Make a promise that resolves when the lock is acquired. 196 const [acquired_promise, acquired_func] = makePromiseAndResolveFunc(); 197 198 // Request the lock. 199 let release_func; 200 const released_promise = navigator.locks.request( 201 res, {signal: controller.signal}, lock => { 202 acquired_func(); 203 204 // Hold lock until release_func is called. 205 const [waiting_promise, waiting_func] = makePromiseAndResolveFunc(); 206 release_func = waiting_func; 207 return waiting_promise; 208 }); 209 210 // Wait for the lock to be acquired. 211 await acquired_promise; 212 213 // Release the lock. 214 release_func('resolved ok'); 215 216 // Signal an abort. 217 controller.abort(); 218 219 assert_equals(await released_promise, 'resolved ok', 220 'Lock released promise should not reject'); 221 222 }, 'Abort signaled after lock released'); 223 224 promise_test(async t => { 225 const res = uniqueName(t); 226 227 const controller = new AbortController(); 228 const first = requestLockAndHold(t, res, { signal: controller.signal }); 229 const next = navigator.locks.request(res, () => "resolved"); 230 controller.abort(); 231 232 await promise_rejects_dom(t, "AbortError", first, "Request should abort"); 233 assert_equals( 234 await next, 235 "resolved", 236 "The next request is processed after abort" 237 ); 238 }, "Abort should process the next pending lock request"); 239 240 promise_test(async t => { 241 const res = uniqueName(t); 242 243 const controller = new AbortController(); 244 const promise = requestLockAndHold(t, res, { signal: controller.signal }); 245 246 const reason = "My cat handled it"; 247 controller.abort(reason); 248 249 await promise_rejects_exactly(t, reason, promise, "Rejection should give the abort reason"); 250 }, "Aborted promise should reject with the custom abort reason"); 251 252 promise_test(async t => { 253 const res = uniqueName(t); 254 255 const controller = new AbortController(); 256 const promise = requestLockAndHold(t, res, { signal: controller.signal }); 257 258 controller.abort(); 259 260 await promise_rejects_exactly(t, controller.signal.reason, promise, "Should be the same reason"); 261 }, "Aborted promise should reject with the default abort reason");