forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			252 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			252 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* Any copyright is dedicated to the Public Domain.
 | 
						|
   http://creativecommons.org/publicdomain/zero/1.0/ */
 | 
						|
 | 
						|
/* This test checks that `document.fullscreenElement` is set correctly and
 | 
						|
 * proper fullscreenchange events fire when an element inside of a
 | 
						|
 * multi-origin tree of iframes calls `requestFullscreen()`. It is designed
 | 
						|
 * to make sure the fullscreen API is working properly in fission when the
 | 
						|
 * frame tree spans multiple processes.
 | 
						|
 *
 | 
						|
 * A similarly purposed Web Platform Test exists, but at the time of writing
 | 
						|
 * is manual, so it cannot be run in CI:
 | 
						|
 * `element-request-fullscreen-cross-origin-manual.sub.html`
 | 
						|
 */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
const actorModuleURI = getRootDirectory(gTestPath) + "FullscreenFrame.sys.mjs";
 | 
						|
const actorName = "FullscreenFrame";
 | 
						|
 | 
						|
const fullscreenPath =
 | 
						|
  getRootDirectory(gTestPath).replace("chrome://mochitests/content", "") +
 | 
						|
  "fullscreen.html";
 | 
						|
 | 
						|
const fullscreenTarget = "D";
 | 
						|
// TOP
 | 
						|
//  | \
 | 
						|
//  A  B
 | 
						|
//  |
 | 
						|
//  C
 | 
						|
//  |
 | 
						|
//  D
 | 
						|
//  |
 | 
						|
//  E
 | 
						|
const frameTree = {
 | 
						|
  name: "TOP",
 | 
						|
  // eslint-disable-next-line @microsoft/sdl/no-insecure-url
 | 
						|
  url: `http://example.com${fullscreenPath}`,
 | 
						|
  allow_fullscreen: true,
 | 
						|
  children: [
 | 
						|
    {
 | 
						|
      name: "A",
 | 
						|
      // eslint-disable-next-line @microsoft/sdl/no-insecure-url
 | 
						|
      url: `http://example.org${fullscreenPath}`,
 | 
						|
      allow_fullscreen: true,
 | 
						|
      children: [
 | 
						|
        {
 | 
						|
          name: "C",
 | 
						|
          // eslint-disable-next-line @microsoft/sdl/no-insecure-url
 | 
						|
          url: `http://example.com${fullscreenPath}`,
 | 
						|
          allow_fullscreen: true,
 | 
						|
          children: [
 | 
						|
            {
 | 
						|
              name: "D",
 | 
						|
              // eslint-disable-next-line @microsoft/sdl/no-insecure-url
 | 
						|
              url: `http://example.com${fullscreenPath}?different-uri=1`,
 | 
						|
              allow_fullscreen: true,
 | 
						|
              children: [
 | 
						|
                {
 | 
						|
                  name: "E",
 | 
						|
                  // eslint-disable-next-line @microsoft/sdl/no-insecure-url
 | 
						|
                  url: `http://example.org${fullscreenPath}`,
 | 
						|
                  allow_fullscreen: true,
 | 
						|
                  children: [],
 | 
						|
                },
 | 
						|
              ],
 | 
						|
            },
 | 
						|
          ],
 | 
						|
        },
 | 
						|
      ],
 | 
						|
    },
 | 
						|
    {
 | 
						|
      name: "B",
 | 
						|
      // eslint-disable-next-line @microsoft/sdl/no-insecure-url
 | 
						|
      url: `http://example.net${fullscreenPath}`,
 | 
						|
      allow_fullscreen: true,
 | 
						|
      children: [],
 | 
						|
    },
 | 
						|
  ],
 | 
						|
};
 | 
						|
 | 
						|
add_task(async function test_fullscreen_api_cross_origin_tree() {
 | 
						|
  await new Promise(r => {
 | 
						|
    SpecialPowers.pushPrefEnv(
 | 
						|
      {
 | 
						|
        set: [
 | 
						|
          ["full-screen-api.enabled", true],
 | 
						|
          ["full-screen-api.allow-trusted-requests-only", false],
 | 
						|
          ["full-screen-api.transition-duration.enter", "0 0"],
 | 
						|
          ["full-screen-api.transition-duration.leave", "0 0"],
 | 
						|
          ["dom.security.featurePolicy.header.enabled", true],
 | 
						|
          ["dom.security.featurePolicy.webidl.enabled", true],
 | 
						|
        ],
 | 
						|
      },
 | 
						|
      r
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  // Register a custom window actor to handle tracking events
 | 
						|
  // and constructing subframes
 | 
						|
  ChromeUtils.registerWindowActor(actorName, {
 | 
						|
    child: {
 | 
						|
      esModuleURI: actorModuleURI,
 | 
						|
      events: {
 | 
						|
        fullscreenchange: { mozSystemGroup: true, capture: true },
 | 
						|
        fullscreenerror: { mozSystemGroup: true, capture: true },
 | 
						|
      },
 | 
						|
    },
 | 
						|
    allFrames: true,
 | 
						|
  });
 | 
						|
 | 
						|
  let tab = await BrowserTestUtils.openNewForegroundTab({
 | 
						|
    gBrowser,
 | 
						|
    url: frameTree.url,
 | 
						|
  });
 | 
						|
 | 
						|
  let frames = new Map();
 | 
						|
  async function construct_frame_children(browsingContext, tree) {
 | 
						|
    let actor = browsingContext.currentWindowGlobal.getActor(actorName);
 | 
						|
    frames.set(tree.name, {
 | 
						|
      browsingContext,
 | 
						|
      actor,
 | 
						|
    });
 | 
						|
 | 
						|
    for (let child of tree.children) {
 | 
						|
      // Create the child IFrame and wait for it to load.
 | 
						|
      let childBC = await actor.sendQuery("CreateChild", child);
 | 
						|
      await construct_frame_children(childBC, child);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  await construct_frame_children(tab.linkedBrowser.browsingContext, frameTree);
 | 
						|
 | 
						|
  async function check_events(expected_events) {
 | 
						|
    for (let [name, expected] of expected_events) {
 | 
						|
      let actor = frames.get(name).actor;
 | 
						|
 | 
						|
      // Each content process fires the fullscreenchange
 | 
						|
      // event independently and in parallel making it
 | 
						|
      // possible for the promises returned by
 | 
						|
      // `requestFullscreen` or `exitFullscreen` to
 | 
						|
      // resolve before all events have fired. We wait
 | 
						|
      // for the number of events to match before
 | 
						|
      // continuing to ensure we don't miss an expected
 | 
						|
      // event that hasn't fired yet.
 | 
						|
      let events;
 | 
						|
      await TestUtils.waitForCondition(async () => {
 | 
						|
        events = await actor.sendQuery("GetEvents");
 | 
						|
        return events.length == expected.length;
 | 
						|
      }, `Waiting for number of events to match`);
 | 
						|
 | 
						|
      Assert.equal(events.length, expected.length, "Number of events equal");
 | 
						|
      events.forEach((value, i) => {
 | 
						|
        Assert.equal(value, expected[i], "Event type matches");
 | 
						|
      });
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  async function check_fullscreenElement(expected_elements) {
 | 
						|
    for (let [name, expected] of expected_elements) {
 | 
						|
      let element = await frames
 | 
						|
        .get(name)
 | 
						|
        .actor.sendQuery("GetFullscreenElement");
 | 
						|
      Assert.equal(element, expected, "The fullScreenElement matches");
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Trigger fullscreen from the target frame.
 | 
						|
  let target = frames.get(fullscreenTarget);
 | 
						|
  await target.actor.sendQuery("RequestFullscreen");
 | 
						|
  // true is fullscreenchange and false is fullscreenerror.
 | 
						|
  await check_events(
 | 
						|
    new Map([
 | 
						|
      ["TOP", [true]],
 | 
						|
      ["A", [true]],
 | 
						|
      ["B", []],
 | 
						|
      ["C", [true]],
 | 
						|
      ["D", [true]],
 | 
						|
      ["E", []],
 | 
						|
    ])
 | 
						|
  );
 | 
						|
  await check_fullscreenElement(
 | 
						|
    new Map([
 | 
						|
      ["TOP", "child_iframe"],
 | 
						|
      ["A", "child_iframe"],
 | 
						|
      ["B", "null"],
 | 
						|
      ["C", "child_iframe"],
 | 
						|
      ["D", "body"],
 | 
						|
      ["E", "null"],
 | 
						|
    ])
 | 
						|
  );
 | 
						|
 | 
						|
  await target.actor.sendQuery("ExitFullscreen");
 | 
						|
  // fullscreenchange should have fired on exit as well.
 | 
						|
  // true is fullscreenchange and false is fullscreenerror.
 | 
						|
  await check_events(
 | 
						|
    new Map([
 | 
						|
      ["TOP", [true, true]],
 | 
						|
      ["A", [true, true]],
 | 
						|
      ["B", []],
 | 
						|
      ["C", [true, true]],
 | 
						|
      ["D", [true, true]],
 | 
						|
      ["E", []],
 | 
						|
    ])
 | 
						|
  );
 | 
						|
  await check_fullscreenElement(
 | 
						|
    new Map([
 | 
						|
      ["TOP", "null"],
 | 
						|
      ["A", "null"],
 | 
						|
      ["B", "null"],
 | 
						|
      ["C", "null"],
 | 
						|
      ["D", "null"],
 | 
						|
      ["E", "null"],
 | 
						|
    ])
 | 
						|
  );
 | 
						|
 | 
						|
  // Clear previous events before testing exiting fullscreen with ESC.
 | 
						|
  for (const frame of frames.values()) {
 | 
						|
    frame.actor.sendQuery("ClearEvents");
 | 
						|
  }
 | 
						|
  await target.actor.sendQuery("RequestFullscreen");
 | 
						|
 | 
						|
  // Escape should cause the proper events to fire and
 | 
						|
  // document.fullscreenElement should be cleared.
 | 
						|
  let finished_exiting = target.actor.sendQuery("WaitForChange");
 | 
						|
  EventUtils.sendKey("ESCAPE");
 | 
						|
  await finished_exiting;
 | 
						|
  // true is fullscreenchange and false is fullscreenerror.
 | 
						|
  await check_events(
 | 
						|
    new Map([
 | 
						|
      ["TOP", [true, true]],
 | 
						|
      ["A", [true, true]],
 | 
						|
      ["B", []],
 | 
						|
      ["C", [true, true]],
 | 
						|
      ["D", [true, true]],
 | 
						|
      ["E", []],
 | 
						|
    ])
 | 
						|
  );
 | 
						|
  await check_fullscreenElement(
 | 
						|
    new Map([
 | 
						|
      ["TOP", "null"],
 | 
						|
      ["A", "null"],
 | 
						|
      ["B", "null"],
 | 
						|
      ["C", "null"],
 | 
						|
      ["D", "null"],
 | 
						|
      ["E", "null"],
 | 
						|
    ])
 | 
						|
  );
 | 
						|
 | 
						|
  // Remove the tests custom window actor.
 | 
						|
  ChromeUtils.unregisterWindowActor("FullscreenFrame");
 | 
						|
  BrowserTestUtils.removeTab(tab);
 | 
						|
});
 |