chromium/third_party/blink/web_tests/http/tests/inspector-protocol/resources/navigation-helper.js

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(() => {
  // Map from urlSuffix to list of resolve functions.
  const frameNavigatedDelegatesMap = new Map();
  // Map frameId to list of resolve functions.
  const frameStoppedLoadingDelegatesMap = new Map();

  async function initProtocolRecursively(dp, session, initDelegate) {
    await dp.Target.setAutoAttach(
        {autoAttach: true, waitForDebuggerOnStart: true, flatten: true});

    dp.Target.onAttachedToTarget(async event => {
      const childDp = session.createChild(
          event.params.sessionId).protocol;
      await initProtocolRecursively(childDp, session, initDelegate);
    });

    dp.Page.onFrameNavigated(event => {
      // Check if there are any frameNavigated delegates that need to be
      // resolved.
      frameNavigatedDelegatesMap.keys().forEach(urlSuffix => {
        if (event.params.frame.url.endsWith(urlSuffix)) {
          for (const resolve of frameNavigatedDelegatesMap.get(urlSuffix)) {
            resolve(event.params.frameId);
          }
          frameNavigatedDelegatesMap.delete(urlSuffix);
        }
      });
    });

    dp.Page.onFrameStoppedLoading(event => {
      // Check if there are any frameStoppedLoading delegates that need to be
      // resolved.
      (frameStoppedLoadingDelegatesMap.get(event.frameId) ?? []).forEach(
          resolve => {
            resolve();
          });
    });

    await initDelegate(dp);

    await dp.Page.enable();
    await dp.Runtime.runIfWaitingForDebugger();
  };

  function onceFrameNavigated(urlSuffix) {
    return new Promise(resolve => {
      if (frameNavigatedDelegatesMap.get(urlSuffix) === undefined) {
        frameNavigatedDelegatesMap.set(urlSuffix, []);
      }
      frameNavigatedDelegatesMap.get(urlSuffix).push(resolve);
    });
  }

  async function onceFrameStoppedLoading(urlSuffix) {
    const frameId = await onceFrameNavigated(urlSuffix);
    return new Promise(resolve => {
      if (frameStoppedLoadingDelegatesMap.get(frameId) === undefined) {
        frameStoppedLoadingDelegatesMap.set(frameId, []);
      }
      frameStoppedLoadingDelegatesMap.get(frameId).push(resolve);
    });
  }

  return {
    // Call the initDelegate function on the given session and all the attached
    // in future targets.
    initProtocolRecursively,
    // Returns a promise that resolves when a frame with the given urlSuffix
    // has been navigated.
    onceFrameNavigated,
    // Returns a promise that resolves when a frame with the given urlSuffix
    // has been navigated and stopped loading.
    onceFrameStoppedLoading
  };
})()