/* 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", // eslint-disable-next-line @microsoft/sdl/no-insecure-url "http://example.com" ); const BASE2 = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", // eslint-disable-next-line @microsoft/sdl/no-insecure-url "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); } } ); });