chromium/chrome/test/data/web_apps/simple_isolated_app/controlled_frame_api_test.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.

const ORIGINAL_PATH = '/controlled_frame.html';
const TEST_PAGE_1_PATH = '/controlled_frame_api_test_page1.html';
const TEST_PAGE_2_PATH = '/controlled_frame_api_test_page2.html';

let host = '';

// Returns the full URL for the |path| using the Controlled Frame's host.
function getControlledFrameUrl(path) {
  return `http://${host}${path}`;
}

// Returns a promise that runs |callback| then resolves when |controlledFrame|'s
// loading has stopped or rejects if the loading was aborted for some reason.
function runCallbackAndWaitForLoadStop(controlledFrame, callback) {
  return new Promise(async (resolve, reject) => {
    controlledFrame.addEventListener('loadstop', () => {
      resolve('SUCCESS');
    });
    controlledFrame.addEventListener('loadabort', () => {
      reject(`ERROR: Load aborted for ${e.url} with reason ${e.reason}`);
    });
    await callback(controlledFrame);
  });
}

// Navigates |controlledFrame| to |path| and waits until loading has stopped.
async function navigateFrame(controlledFrame, path) {
  const callback = function() {
    controlledFrame.setAttribute('src', getControlledFrameUrl(path));
  };
  return await runCallbackAndWaitForLoadStop(controlledFrame, callback);
}

// Runs the test for |apiName| using |controlledFrame|.
async function testAPI(controlledFrame, apiName) {
  host = new URL(controlledFrame.src).host;
  const capitalizedApiName = apiName.charAt(0).toUpperCase() + apiName.slice(1);
  const testFunctionName = `test${capitalizedApiName}`;
  return window[testFunctionName](controlledFrame);
}

async function testBack(controlledFrame) {
  // Navigate once to be able to use the Promise version of back().
  await navigateFrame(controlledFrame, TEST_PAGE_1_PATH);
  const TEST_PAGE_1_URL = getControlledFrameUrl(TEST_PAGE_1_PATH);
  if (controlledFrame.src !== TEST_PAGE_1_URL) {
    return `ERROR: navigateFrame() failed to navigate to ${TEST_PAGE_1_URL}`;
  }

  const callPromiseBack = async function() {
    await controlledFrame.back();
  };
  await runCallbackAndWaitForLoadStop(controlledFrame, callPromiseBack);

  const ORIGINAL_URL = getControlledFrameUrl(ORIGINAL_PATH);
  if (controlledFrame.src !== ORIGINAL_URL) {
    return `ERROR: back() failed to return page to ${ORIGINAL_URL}`;
  }

  // Navigate again to test the non-promise version of the API.
  await navigateFrame(controlledFrame, TEST_PAGE_1_PATH);
  if (controlledFrame.src !== TEST_PAGE_1_URL) {
    return `ERROR: navigateFrame() failed to navigate to ${TEST_PAGE_1_URL}`;
  }

  let result;
  const callBack = async function() {
    await new Promise((resolve) => {
      result = controlledFrame.back(resolve);
    });
  };
  await runCallbackAndWaitForLoadStop(controlledFrame, callBack);

  if (result instanceof Promise) {
    return 'ERROR: back(callback) should not return a Promise';
  }
  if (controlledFrame.src !== ORIGINAL_URL) {
    return `ERROR: back(callback) failed to return page to ${ORIGINAL_URL}`;
  }
  return 'SUCCESS';
}

async function testForward(controlledFrame) {
  // Navigate once and go back to be able to use the Promise version of
  // forward().
  await navigateFrame(controlledFrame, TEST_PAGE_1_PATH);
  const TEST_PAGE_1_URL = getControlledFrameUrl(TEST_PAGE_1_PATH);
  if (controlledFrame.src !== TEST_PAGE_1_URL) {
    return `ERROR: navigateFrame() failed to navigate to ${TEST_PAGE_1_URL}`;
  }

  const callBack = async function() {
    await controlledFrame.back();
  };
  await runCallbackAndWaitForLoadStop(controlledFrame, callBack);

  const ORIGINAL_URL = getControlledFrameUrl(ORIGINAL_PATH);
  if (controlledFrame.src !== ORIGINAL_URL) {
    return `ERROR: back() failed to return page to ${ORIGINAL_URL}`;
  }

  const callPromiseForward = async function() {
    await controlledFrame.forward();
  };
  await runCallbackAndWaitForLoadStop(controlledFrame, callPromiseForward);
  if (controlledFrame.src !== TEST_PAGE_1_URL) {
    return `ERROR: forward() failed to return to page ${TEST_PAGE_1_PATH}`
  }

  // Go back again to test the non-promise version of the API.
  await runCallbackAndWaitForLoadStop(controlledFrame, callBack);
  if (controlledFrame.src !== ORIGINAL_URL) {
    return `ERROR: back(callback) failed to return page to ${ORIGINAL_URL}`;
  }

  let result;
  const callForward = async function() {
    await new Promise((resolve) => {
      result = controlledFrame.forward(resolve);
    });
  };
  await runCallbackAndWaitForLoadStop(controlledFrame, callForward);

  if (result instanceof Promise) {
    return 'ERROR: forward(callback) should not return a Promise';
  }
  if (controlledFrame.src !== TEST_PAGE_1_URL) {
    return `ERROR: forward(callback) failed to return to page \
        ${TEST_PAGE_1_PATH}`;
  }
  return 'SUCCESS';
}

async function testGo(controlledFrame) {
  // Navigate twice to test go with indices greater than 1.
  await navigateFrame(controlledFrame, TEST_PAGE_1_PATH);
  const TEST_PAGE_1_URL = getControlledFrameUrl(TEST_PAGE_1_PATH);
  if (controlledFrame.src !== TEST_PAGE_1_URL) {
    return `ERROR: navigateFrame() failed to navigate to ${TEST_PAGE_1_URL}`;
  }

  await navigateFrame(controlledFrame, TEST_PAGE_2_PATH);
  const TEST_PAGE_2_URL = getControlledFrameUrl(TEST_PAGE_2_PATH);
  if (controlledFrame.src !== TEST_PAGE_2_URL) {
    return `ERROR: navigateFrame() failed to navigate to ${TEST_PAGE_2_URL}`;
  }

  // Go back to the first page.
  const goPromiseCallback = async function(index) {
    return await controlledFrame.go(index);
  };
  const ORIGINAL_URL = getControlledFrameUrl(ORIGINAL_PATH);
  await runCallbackAndWaitForLoadStop(
      controlledFrame, goPromiseCallback.bind(this, -2));
  if (controlledFrame.src !== ORIGINAL_URL) {
    return `ERROR: go() failed to navigate back to ${ORIGINAL_URL}`;
  }

  // Go forward to the last navigated page.
  await runCallbackAndWaitForLoadStop(
      controlledFrame, goPromiseCallback.bind(this, 2));
  if (controlledFrame.src !== TEST_PAGE_2_URL) {
    return `ERROR: go() failed to navigate forward to ${TEST_PAGE_2_URL}`;
  }

  // Test the non-promise version of the API.
  let result;
  const goCallback = async function(index) {
    await new Promise((resolve) => {
      result = controlledFrame.go(index, resolve);
    });
  };

  await runCallbackAndWaitForLoadStop(
      controlledFrame, goCallback.bind(this, -2));
  if (result instanceof Promise) {
    return 'ERROR: go(callback) should not return a Promise';
  }
  if (controlledFrame.src !== ORIGINAL_URL) {
    return `ERROR: go(callback) failed to navigate back to ${ORIGINAL_URL}`;
  }

  await runCallbackAndWaitForLoadStop(
      controlledFrame, goCallback.bind(this, 2));
  if (result instanceof Promise) {
    return 'ERROR: go(callback) should not return a Promise';
  }
  if (controlledFrame.src !== TEST_PAGE_2_URL) {
    return `ERROR: go(callback) failed to navigate forward to \
        ${TEST_PAGE_2_URL}`;
  }

  return 'SUCCESS';
}