fune/docshell/test/browser/browser_browsingContext-02.js
Kashav Madan 1a71fed80e Bug 1580766 - Add a unique ID for the BrowsingContext tree inside a browser element. r=kmag
This adds a `browserId` property to all browsing contexts. This ID is the same
for the entire tree of contexts inside a frame element. Each new top-level
context created for a given frame also inherits this ID. This allows identifying
the frame element for a given browsing context.

Originally authored by :mossop in D56245.

Differential Revision: https://phabricator.services.mozilla.com/D77911
2020-06-16 18:12:46 +00:00

231 lines
7.4 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
add_task(async function() {
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:blank" },
async function(browser) {
const BASE1 = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
);
const BASE2 = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://test1.example.com"
);
const URL = BASE1 + "onload_message.html";
let sixth = BrowserTestUtils.waitForNewTab(
gBrowser,
URL + "#sixth",
true,
true
);
let seventh = BrowserTestUtils.waitForNewTab(
gBrowser,
URL + "#seventh",
true,
true
);
let browserIds = await SpecialPowers.spawn(
browser,
[{ base1: BASE1, base2: BASE2 }],
async function({ base1, base2 }) {
let top = content;
top.name = "top";
top.location.href += "#top";
let contexts = {
top: top.location.href,
first: base1 + "dummy_page.html#first",
third: base2 + "dummy_page.html#third",
second: base1 + "dummy_page.html#second",
fourth: base2 + "dummy_page.html#fourth",
fifth: base1 + "dummy_page.html#fifth",
sixth: base1 + "onload_message.html#sixth",
seventh: base1 + "onload_message.html#seventh",
};
function addFrame(target, name) {
return content.SpecialPowers.spawn(
target,
[name, contexts[name]],
async (name, context) => {
let doc = this.content.document;
let frame = doc.createElement("iframe");
doc.body.appendChild(frame);
frame.name = name;
frame.src = context;
await new Promise(resolve => {
frame.addEventListener("load", resolve, { once: true });
});
return frame.browsingContext;
}
);
}
function addWindow(target, name, { options, resolve }) {
return content.SpecialPowers.spawn(
target,
[name, contexts[name], options, resolve],
(name, context, options, resolve) => {
let win = this.content.open(context, name, options);
let bc = win && win.docShell.browsingContext;
if (resolve) {
return new Promise(resolve =>
this.content.addEventListener("message", () => resolve(bc))
);
}
return Promise.resolve({ name });
}
);
}
// We're going to create a tree that looks like the
// following.
//
// top sixth seventh
// / \
// / \ /
// first second
// / \ /
// / \
// third fourth - - -
// /
// /
// fifth
//
// The idea is to have one top level non-auxiliary browsing
// context, five nested, one top level auxiliary with an
// opener, and one top level without an opener. Given that
// set of related and one unrelated browsing contexts we
// wish to confirm that targeting is able to find
// appropriate browsing contexts.
// BrowsingContext.findWithName requires access checks, which
// can only be performed in the process of the accessor BC's
// docShell.
function findWithName(bc, name) {
return content.SpecialPowers.spawn(bc, [bc, name], (bc, name) => {
return bc.findWithName(name);
});
}
async function reachable(start, target) {
info(start.name, target.name);
is(
await findWithName(start, target.name),
target,
[start.name, "can reach", target.name].join(" ")
);
}
async function unreachable(start, target) {
is(
await findWithName(start, target.name),
null,
[start.name, "can't reach", target.name].join(" ")
);
}
let first = await addFrame(top, "first");
info("first");
let second = await addFrame(top, "second");
info("second");
let third = await addFrame(first, "third");
info("third");
let fourth = await addFrame(first, "fourth");
info("fourth");
let fifth = await addFrame(fourth, "fifth");
info("fifth");
let sixth = await addWindow(fourth, "sixth", { resolve: true });
info("sixth");
let seventh = await addWindow(fourth, "seventh", {
options: ["noopener"],
});
info("seventh");
let origin1 = [first, second, fifth, sixth];
let origin2 = [third, fourth];
let topBC = BrowsingContext.getFromWindow(top);
let frames = new Map([
[topBC, [topBC, first, second, third, fourth, fifth, sixth]],
[first, [topBC, ...origin1, third, fourth]],
[second, [topBC, ...origin1, third, fourth]],
[third, [topBC, ...origin2, fifth, sixth]],
[fourth, [topBC, ...origin2, fifth, sixth]],
[fifth, [topBC, ...origin1, third, fourth]],
[sixth, [...origin1, third, fourth]],
]);
for (let [start, accessible] of frames) {
for (let frame of frames.keys()) {
if (accessible.includes(frame)) {
await reachable(start, frame);
} else {
await unreachable(start, frame);
}
}
await unreachable(start, seventh);
}
let topBrowserId = topBC.browserId;
ok(topBrowserId > 0, "Should have a browser ID.");
for (let [name, bc] of Object.entries({
first,
second,
third,
fourth,
fifth,
})) {
is(
bc.browserId,
topBrowserId,
`${name} frame should have the same browserId as top.`
);
}
ok(sixth.browserId > 0, "sixth should have a browserId.");
isnot(
sixth.browserId,
topBrowserId,
"sixth frame should have a different browserId to top."
);
return [topBrowserId, sixth.browserId];
}
);
[sixth, seventh] = await Promise.all([sixth, seventh]);
is(
browser.browserId,
browserIds[0],
"browser should have the right browserId."
);
is(
browser.browsingContext.browserId,
browserIds[0],
"browser's BrowsingContext should have the right browserId."
);
is(
sixth.linkedBrowser.browserId,
browserIds[1],
"sixth should have the right browserId."
);
is(
sixth.linkedBrowser.browsingContext.browserId,
browserIds[1],
"sixth's BrowsingContext should have the right browserId."
);
for (let tab of [sixth, seventh]) {
BrowserTestUtils.removeTab(tab);
}
}
);
});