chromium/third_party/blink/web_tests/http/tests/locks/chromium-waiting-promise-gc.html

<!DOCTYPE html>
<meta charset=utf-8>
<title>Web Locks API: Lock held with Promise that is GC'd (Chromium-specific, relies on gc/internals)</title>
<link rel=help href="https://github.com/inexorabletash/web-locks">
<script src="/js-test-resources/gc.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
'use strict';

// For uncaught rejections.
setup({allow_uncaught_exception: true});

// Wait for a promise in a subsequent task (not just microtask in same task).
function task(t) {
  return new Promise(resolve => {
    t.step_timeout(resolve, 0);
  });
}

promise_test(async t => {
  let res = `${self.location.pathname}-${t.name}`;
  let observe_lock, observe_promise;

  // Acquire the lock, and keep it alive via a promise that never resolves.
  let resolve, acquired = new Promise(r => { resolve = r; });
  navigator.locks.request(res, lock => {
    resolve();

    // Neither |lock| nor |promise| are retained.
    const promise = new Promise(() => {});
    observe_lock = internals.observeGC(lock);
    observe_promise = internals.observeGC(promise);
    return promise;
  });
  await acquired;

  // Drain the microtask queue and trigger a GC.
  await task(t);

  asyncGC(async function () {
    assert_true(observe_lock.wasCollected, 'Lock should be collected');
    assert_true(observe_promise.wasCollected, 'Promise should be collected');

    // Now try and request the lock.
    let lock = 'should be overwritten';
    await navigator.locks.request(res, {ifAvailable: true}, l => {
      lock = l;
    });
    assert_equals(lock, null, 'Lock acquisition should have failed');
  });
}, 'GC of waiting promise does not cause lock to be released');

</script>