/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const DOC = toDataURL("
foo
");
const DOC_IFRAME_MULTI = toDataURL(`
`);
const DOC_IFRAME_NESTED = toDataURL(`
`);
// Disable bfcache to force documents to be destroyed on navigation
Services.prefs.setIntPref("browser.sessionhistory.max_total_viewers", 0);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("browser.sessionhistory.max_total_viewers");
});
add_task(async function noEventWhenPageDomainDisabled({ client }) {
info("Navigate to a page with nested iframes");
await loadURL(DOC_IFRAME_NESTED);
await runFrameDetachedTest(client, 0, async () => {
info("Navigate away from a page with an iframe");
await loadURL(DOC);
});
});
add_task(async function noEventAfterPageDomainDisabled({ client }) {
const { Page } = client;
info("Navigate to a page with nested iframes");
await loadURL(DOC_IFRAME_NESTED);
await Page.enable();
await Page.disable();
await runFrameDetachedTest(client, 0, async () => {
info("Navigate away to a page with no iframes");
await loadURL(DOC);
});
});
add_task(async function noEventWhenNavigatingWithNoFrames({ client }) {
const { Page } = client;
await Page.enable();
info("Navigate to a page with no iframes");
await loadURL(DOC);
await runFrameDetachedTest(client, 0, async () => {
info("Navigate away to a page with no iframes");
await loadURL(DOC);
});
});
add_task(async function eventWhenNavigatingWithFrames({ client }) {
const { Page } = client;
info("Navigate to a page with iframes");
await loadURL(DOC_IFRAME_MULTI);
await Page.enable();
await runFrameDetachedTest(client, 2, async () => {
info("Navigate away to a page with no iframes");
await loadURL(DOC);
});
});
add_task(async function eventWhenNavigatingWithNestedFrames({ client }) {
const { Page } = client;
info("Navigate to a page with nested iframes");
await loadURL(DOC_IFRAME_NESTED);
await Page.enable();
await runFrameDetachedTest(client, 3, async () => {
info("Navigate away to a page with no iframes");
await loadURL(DOC);
});
});
add_task(async function eventWhenDetachingFrame({ client }) {
const { Page } = client;
info("Navigate to a page with iframes");
await loadURL(DOC_IFRAME_MULTI);
await Page.enable();
await runFrameDetachedTest(client, 1, async () => {
// Remove the single frame from the page
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
const frame = content.document.getElementsByTagName("iframe")[0];
frame.remove();
});
});
});
add_task(async function eventWhenDetachingNestedFrames({ client }) {
const { Page, Runtime } = client;
info("Navigate to a page with nested iframes");
await loadURL(DOC_IFRAME_NESTED);
await Page.enable();
await Runtime.enable();
const { context } = await Runtime.executionContextCreated();
await runFrameDetachedTest(client, 3, async () => {
// Remove top-frame, which also removes any nested frames
await evaluate(client, context.id, async () => {
const frame = document.getElementsByTagName("iframe")[0];
frame.remove();
});
});
});
async function runFrameDetachedTest(client, expectedEventCount, callback) {
const { Page } = client;
const DETACHED = "Page.frameDetached";
const history = new RecordEvents(expectedEventCount);
history.addRecorder({
event: Page.frameDetached,
eventName: DETACHED,
messageFn: payload => {
return `Received ${DETACHED} for frame id ${payload.frameId}`;
},
});
const framesBefore = await getFlattenedFrameTree(client);
await callback();
const framesAfter = await getFlattenedFrameTree(client);
const frameDetachedEvents = await history.record();
if (expectedEventCount == 0) {
is(frameDetachedEvents.length, 0, "Got no frame detached event");
return;
}
// check how many frames were attached or detached
const count = Math.abs(framesBefore.size - framesAfter.size);
is(count, expectedEventCount, "Expected amount of frames detached");
is(
frameDetachedEvents.length,
count,
"Received the expected amount of frameDetached events"
);
// extract the new or removed frames
const framesAll = new Map([...framesBefore, ...framesAfter]);
const expectedFrames = new Map(
[...framesAll].filter(([key, _value]) => {
return framesBefore.has(key) && !framesAfter.has(key);
})
);
frameDetachedEvents.forEach(({ payload }) => {
const { frameId } = payload;
info(`Check frame id ${frameId}`);
const expectedFrame = expectedFrames.get(frameId);
is(
frameId,
expectedFrame.id,
"Got expected frame id for frameDetached event"
);
});
}