chromium/chrome/test/data/extensions/api_test/webnavigation/getFrame/test_getFrame.js

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

const inServiceWorker = 'ServiceWorkerGlobalScope' in self;
const scriptUrl = '_test_resources/api_test/webnavigation/framework.js';
let ready;
let onScriptLoad = chrome.test.loadScript(scriptUrl);

const kNotSpecifiedErrorMessage =
  'Either documentId or both tabId and frameId must be specified.';

if (inServiceWorker) {
  ready = onScriptLoad;
} else {
  let onWindowLoad = new Promise((resolve) => {
    window.onload = resolve;
  });
  ready = Promise.all([onWindowLoad, onScriptLoad]);
}

ready.then(async function() {
  var URL = chrome.runtime.getURL("a.html");
  var URL_FRAMES = chrome.runtime.getURL("b.html");
  let config = await promise(chrome.test.getConfig);
  let port = config.testServer.port;
  var processId = -1;
  var documentId;
  let tab = await promise(chrome.tabs.create, {"url": "about:blank"});

  chrome.test.runTests([
    function testGetFrame() {
      var done = chrome.test.listenForever(chrome.webNavigation.onCommitted,
        function (details) {
          if (details.tabId != tab.id || details.url != URL)
            return;
          processId = details.processId;
          documentId = details.documentId;
          chrome.webNavigation.getFrame(
              {frameId: 0, tabId: tab.id, processId: processId},
              function(details) {
            chrome.test.assertEq(
                {errorOccurred: false,
                 url: URL,
                 parentFrameId: -1,
                 documentId: documentId,
                 documentLifecycle: "active",
                 frameType: "outermost_frame",
               },
                details);
            done();
          });
      });
      chrome.tabs.update(tab.id, {url: URL});
    },

    function testGetInvalidFrame() {
      chrome.webNavigation.getFrame(
          {tabId: tab.id, frameId: 1, processId: processId},
        function (details) {
          chrome.test.assertEq(null, details);
          chrome.test.succeed();
      });
    },

    function testGetFrameNoValues() {
      chrome.webNavigation.getFrame({},
        function (details) {
          chrome.test.assertEq(null, details);
          chrome.test.assertLastError(kNotSpecifiedErrorMessage);
          chrome.test.succeed();
      });
    },

    function testGetFrameNoFrameId() {
      chrome.webNavigation.getFrame({tabId: tab.id, processId: processId},
        function (details) {
          chrome.test.assertEq(null, details);
          chrome.test.assertLastError(kNotSpecifiedErrorMessage);
          chrome.test.succeed();
      });
    },

    function testGetFrameDocumentId() {
      chrome.webNavigation.getFrame({tabId: tab.id, documentId: documentId},
        function (details) {
          chrome.test.assertEq({
              errorOccurred: false,
              url: URL,
              parentFrameId: -1,
              documentId: documentId,
              documentLifecycle: "active",
              frameType: "outermost_frame",
            }, details);
          chrome.test.succeed();
      });
    },

    function testGetFrameDocumentIdAndFrameId() {
      chrome.webNavigation.getFrame({tabId: tab.id, frameId: 0,
                                     processId: processId,
                                     documentId: documentId},
        function (details) {
          chrome.test.assertEq({
              errorOccurred: false,
              url: URL,
              parentFrameId: -1,
              documentId: documentId,
              documentLifecycle: "active",
              frameType: "outermost_frame",
            }, details);
          chrome.test.succeed();
      });
    },

    function testGetFrameDocumentIdAndFrameIdDoNotMatch() {
      chrome.webNavigation.getFrame({tabId: tab.id, frameId: 1,
                                     processId: processId,
                                     documentId: documentId},
        function (details) {
          chrome.test.assertEq(null, details);
          chrome.test.succeed();
      });
    },

    function testGetFrameInvalidDocumentId() {
      chrome.webNavigation.getFrame({tabId: tab.id, frameId: 0,
                                     processId: processId,
                                     documentId: "42AB"},
        function (details) {
          chrome.test.assertLastError("Invalid documentId.");
          chrome.test.assertEq(null, details);
          chrome.test.succeed();
      });
    },

    function testGetAllFrames() {
      chrome.webNavigation.getAllFrames({tabId: tab.id}, function (details) {
          chrome.test.assertEq(
              [{errorOccurred: false,
                frameId: 0,
                parentFrameId: -1,
                processId: processId,
                url: URL,
                documentId: documentId,
                documentLifecycle: "active",
                frameType: "outermost_frame"}],
               details);
          chrome.test.succeed();
      });
    },
    async function testGetPrerenderingFrames() {
      // This test is not valid for MV3+ because it uses
      // chrome.tabs.executeScript. See crbug.com/332328868
      if (chrome.runtime.getManifest().manifest_version > 2) {
        chrome.test.succeed();
        return;
      }

      const urlPrefix =
      `http://a.test:${port}/extensions/api_test/webnavigation/getFrame/`;
      const initialUrl = urlPrefix + "a.html?initial";
      const prerenderTargetUrl = urlPrefix + "a.html";
      const initiatorUrl = urlPrefix + "prerender.html";

      let tab = await promise(chrome.tabs.create, {url: initialUrl});

      var done = chrome.test.listenForever(
        chrome.webNavigation.onCommitted,
        function (details) {
          // Ignore frames other than the pre-rendered frame.
          if (details.tabId != tab.id || details.url != prerenderTargetUrl)
            return;
          // prerendered main frame shouldn't have frameId = 0.
          if (details.frameId == 0)
            return;
          chrome.webNavigation.getAllFrames(
              {tabId: tab.id},
            function (frameDetails) {
              chrome.test.assertEq(
                  [{errorOccurred: false,
                    frameId: details.frameId,
                    parentFrameId: -1,
                    processId: details.processId,
                    url: prerenderTargetUrl,
                    documentId: details.documentId,
                    documentLifecycle: "prerender",
                    frameType: "outermost_frame"}],
                    frameDetails.filter(ob => ob.url === prerenderTargetUrl));
              done();
          });
      });

      // TODO(crbug.com/40206306): Modify the testcase to be triggering
      // concurrent multiple prerendering pages once it is supported.
      // Navigate to a page that initiates prerendering "a.html".
      chrome.tabs.update(tab.id, {"url": initiatorUrl});
    },
    async function testGetPrerenderingFramesAndSubframes() {
      const urlPrefix =
      `http://a.test:${port}/extensions/api_test/webnavigation/getFrame/`;
      const initialUrl = urlPrefix + "a.html?initial";
      const prerenderTargetUrl = urlPrefix + "c.html";
      const prerenderTargetSubframeUrl = urlPrefix + "a.html";
      const initiatorUrl = urlPrefix + "prerender_multipleframes.html";

      let tab = await promise(chrome.tabs.create, {"url": initialUrl});

      var done = chrome.test.listenForever(
        chrome.webNavigation.onCommitted,
        function (details) {
          // Ignore frames other than the pre-rendered subframe to ensure all
          // frames are loaded.
          if (details.tabId != tab.id ||
              details.url != prerenderTargetSubframeUrl)
            return;

          // A prerendered subframe is expected to have a parent.
          if (details.parentFrameId == -1)
            return;

          chrome.webNavigation.getAllFrames(
              {tabId: tab.id},
            function (frameDetails) {
              chrome.test.assertEq(
                  [{errorOccurred: false,
                    frameId: details.parentFrameId,
                    parentFrameId: -1,
                    processId: details.processId,
                    url: prerenderTargetUrl,
                    documentId: details.parentDocumentId,
                    documentLifecycle: "prerender",
                    frameType: "outermost_frame"},
                    {errorOccurred: false,
                    frameId: details.frameId,
                    parentFrameId: details.parentFrameId,
                    processId: details.processId,
                    url: prerenderTargetSubframeUrl,
                    documentId: details.documentId,
                    parentDocumentId: details.parentDocumentId,
                    documentLifecycle: "prerender",
                    frameType: "sub_frame"}],
                    frameDetails.filter(ob => ob.documentLifecycle ===
                      "prerender"));
              done();
          });
      });

      // Navigate to a page that initiates prerendering "c.html", which contains
      // a subframe "a.html".
      chrome.tabs.update(tab.id, {"url": initiatorUrl});
    },
    async function testGetPrerenderingFramesInNewTab() {
      // This test is not valid for MV3+ because it uses
      // chrome.tabs.executeScript. See crbug.com/332328868
      if (chrome.runtime.getManifest().manifest_version > 2) {
        chrome.test.succeed();
        return;
      }

      const urlPrefix =
          `http://a.test:${port}/extensions/api_test/webnavigation/getFrame/`;
      const initialUrl = urlPrefix + 'a.html?initial';
      const prerenderTargetUrl = urlPrefix + 'c.html';
      const initiatorUrl = urlPrefix + 'prerender_new_tab.html';

      let initiatorTab = await promise(chrome.tabs.create, {'url': initialUrl});

      var done = chrome.test.listenForever(
          chrome.webNavigation.onCommitted, function(details) {
            // Ignore frames other than the pre-rendered frame.
            if (details.url != prerenderTargetUrl)
              return;

            // Trigger prerendered frame activation upon the first navigation.
            // The prerender tab will not be in BrowserList when it is not
            // activated yet.
            if (details.documentLifecycle === 'prerender') {
              // Inject a script that activates the pre-rendered page.
              chrome.tabs.executeScript(
                  initiatorTab.id,
                  {code: 'document.getElementById(\'link\').click();'});
              return;
            }

            chrome.test.assertNe(initiatorTab.id, details.tabId);

            chrome.webNavigation.getAllFrames(
                {tabId: details.tabId}, function(frameDetails) {
                  chrome.test.assertEq(
                      [{
                        errorOccurred: false,
                        frameId: 0,
                        parentFrameId: -1,
                        processId: details.processId,
                        url: prerenderTargetUrl,
                        documentId: details.documentId,
                        documentLifecycle: 'active',
                        frameType: 'outermost_frame'
                      }],
                      frameDetails.filter(ob => ob.url === prerenderTargetUrl));
                  done();
                });
          });

      // Navigate to a page that initiates prerendering "c.html", which contains
      // a subframe "a.html".
      chrome.tabs.update(initiatorTab.id, {'url': initiatorUrl});
    },
    async function testGetActivatedPrerenderingFrames() {
      // This test is not valid for MV3+ because it uses
      // chrome.tabs.executeScript. See crbug.com/332328868
      if (chrome.runtime.getManifest().manifest_version > 2) {
        chrome.test.succeed();
        return;
      }

      const urlPrefix =
          `http://a.test:${port}/extensions/api_test/webnavigation/getFrame/`;
      const initialUrl = urlPrefix + "a.html?initial";
      const prerenderTargetUrl = urlPrefix + "a.html";
      const initiatorUrl = urlPrefix + "prerender.html";

      let tab = await promise(chrome.tabs.create, {"url": initialUrl});

      var done = chrome.test.listenForever(
        chrome.webNavigation.onCommitted,
        function (details) {
          // Ignore frames other than the pre-rendered frame.
          if (details.tabId != tab.id || details.url != prerenderTargetUrl)
            return;

          // Trigger prerendered frame activation upon the first navigation.
          if (details.documentLifecycle === 'prerender') {
            // Inject a script that activates the pre-rendered page.
            chrome.tabs.executeScript(tab.id,
              {code: 'window.location.href = "./a.html";'});
            return;
          }

          chrome.webNavigation.getAllFrames(
              {tabId: tab.id},
            function (frameDetails) {
              chrome.test.assertEq(
                  [{errorOccurred: false,
                    frameId: 0,
                    parentFrameId: -1,
                    processId: details.processId,
                    url: prerenderTargetUrl,
                    documentId: details.documentId,
                    documentLifecycle: "active",
                    frameType: "outermost_frame"}],
                    frameDetails.filter(ob => ob.url === prerenderTargetUrl));
              done();
          });
      });

      // Navigate to a page that initiates prerendering "a.html".
      chrome.tabs.update(tab.id, {"url": initiatorUrl});
    },
    // Load an URL with a frame which is detached during load.
    // getAllFrames should only return the remaining (main) frame.
    async function testFrameDetach() {
      // TODO(crbug.com/40758628): Extremely flaky for Service Worker. Note that
      // this test is also (very infrequently) flaky for non-Service Worker.
      if (inServiceWorker)
        chrome.test.succeed();

      let tab = await promise(chrome.tabs.create, {"url": "about:blank"});
      var done = chrome.test.listenForever(
        chrome.webNavigation.onCommitted,
        function (details) {
          if (details.tabId != tab.id || details.url != URL_FRAMES)
            return;
          processId = details.processId;
          documentId = details.documentId;
          chrome.webNavigation.getAllFrames(
              {tabId: tab.id},
            function (details) {
              chrome.test.assertEq(
                  [{errorOccurred: false,
                    frameId: 0,
                    parentFrameId: -1,
                    processId: processId,
                    url: URL_FRAMES,
                    documentId: documentId,
                    documentLifecycle: "active",
                    frameType: "outermost_frame"}],
                   details);
              chrome.test.succeed();
          });
      });
      chrome.tabs.update(tab.id, {url: URL_FRAMES});
    },
  ]);
});