193 lines
6.8 KiB
JavaScript
193 lines
6.8 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
// Test that drag and drop events are sent at the right time.
|
|
// Supports dragging between domains, windows and iframes.
|
|
// To avoid symmetric tests, the drag source must be in the first window.
|
|
// iframe domains must match outer frame domains.
|
|
|
|
// This file should be included in DND tests that define its parameters.
|
|
// That file needs to do the following:
|
|
// 1. Call await setup(configParams), where configParams is an object that
|
|
// configures the specific test. See `setup()` below.
|
|
// 2. Use Services.scriptloader.loadSubScript to load this script.
|
|
// 3. Define runTest(testName, srcBrowsingCxt, tgtBrowsingCxt, dndOptions),
|
|
// which defaults to `runDnd` below. Other definitions will typically
|
|
// also need to delegate some functionality to runDnd.
|
|
|
|
"use strict";
|
|
|
|
const { MockRegistrar } = ChromeUtils.importESModule(
|
|
"resource://testing-common/MockRegistrar.sys.mjs"
|
|
);
|
|
|
|
// The tabs, each in their own widget.
|
|
let tab1Cxt;
|
|
let tab2Cxt;
|
|
|
|
let dragServiceCid;
|
|
|
|
// JS controller for mock drag service
|
|
let dragController;
|
|
|
|
async function runDnd(
|
|
testName,
|
|
sourceBrowsingCxt,
|
|
targetBrowsingCxt,
|
|
dndOptions = {}
|
|
) {
|
|
return EventUtils.synthesizeMockDragAndDrop({
|
|
dragController,
|
|
srcElement: "dropSource",
|
|
targetElement: "dropTarget",
|
|
sourceBrowsingCxt,
|
|
targetBrowsingCxt,
|
|
id: SpecialPowers.Ci.nsIDOMWindowUtils.DEFAULT_MOUSE_POINTER_ID,
|
|
contextLabel: testName,
|
|
info,
|
|
record,
|
|
dragAction: Ci.nsIDragService.DRAGDROP_ACTION_MOVE,
|
|
...dndOptions,
|
|
});
|
|
}
|
|
|
|
async function openWindow(tabIdx, configParams) {
|
|
let win =
|
|
tabIdx == 0 ? window : await BrowserTestUtils.openNewBrowserWindow();
|
|
const OUTER_URL_ARRAY = [configParams.outerURL1, configParams.outerURL2];
|
|
let url = OUTER_URL_ARRAY[tabIdx];
|
|
let tab = await BrowserTestUtils.openNewForegroundTab({
|
|
gBrowser: win.gBrowser,
|
|
url,
|
|
});
|
|
registerCleanupFunction(async function () {
|
|
await BrowserTestUtils.removeTab(tab);
|
|
if (tabIdx != 0) {
|
|
await BrowserTestUtils.closeWindow(win);
|
|
}
|
|
});
|
|
|
|
// Set the URL for the iframe. Also set
|
|
// neverAllowSessionIsSynthesizedForTests for both frames
|
|
// (the second is redundant if they are in the same process).
|
|
const INNER_URL_ARRAY = [configParams.innerURL1, configParams.innerURL2];
|
|
await SpecialPowers.spawn(
|
|
tab.linkedBrowser.browsingContext,
|
|
[tabIdx, INNER_URL_ARRAY[tabIdx]],
|
|
async (tabIdx, iframeUrl) => {
|
|
let iframe = content.document.getElementById("iframe");
|
|
if (!iframe && content.document.body.shadowRoot) {
|
|
iframe = content.document.body.shadowRoot.getElementById("iframe");
|
|
}
|
|
ok(iframe, `Found iframe in window ${tabIdx}`);
|
|
let loadedPromise = new Promise(res => {
|
|
iframe.addEventListener("load", res, { once: true });
|
|
});
|
|
iframe.src = iframeUrl;
|
|
await loadedPromise;
|
|
const ds = SpecialPowers.Cc[
|
|
"@mozilla.org/widget/dragservice;1"
|
|
].getService(SpecialPowers.Ci.nsIDragService);
|
|
ds.neverAllowSessionIsSynthesizedForTests = true;
|
|
}
|
|
);
|
|
|
|
await SpecialPowers.spawn(
|
|
tab.linkedBrowser.browsingContext.children[0],
|
|
[],
|
|
() => {
|
|
const ds = SpecialPowers.Cc[
|
|
"@mozilla.org/widget/dragservice;1"
|
|
].getService(SpecialPowers.Ci.nsIDragService);
|
|
ds.neverAllowSessionIsSynthesizedForTests = true;
|
|
}
|
|
);
|
|
|
|
return tab.linkedBrowser.browsingContext;
|
|
}
|
|
|
|
/**
|
|
* Configure the test. All fields are required.
|
|
*
|
|
* @param {Object} configParams
|
|
* @param {String} configParams.outerURL1
|
|
* URL of window #1's main frame's content (not iframes).
|
|
* The document must contain an iframe with ID "iframe"
|
|
* that will be used to load the iframe HTML. It also
|
|
* must contain an element with ID "dropSource" that will be
|
|
* used as the source of a drag, as well as one with ID
|
|
* "dropTarget" that will be used as the drop target.
|
|
* @param {String} configParams.outerURL2
|
|
* Like outerURL1 but for the second window. outerURL1 and
|
|
* outerURL2 may be identical. Must include "dropSource" and
|
|
* "dropTarget" elements.
|
|
* @param {String} configParams.innerURL1
|
|
* URL of the inner frame's content in window #1. Must
|
|
* include "dropSource" and "dropTarget" elements.
|
|
* @param {String} configParams.innerURL1
|
|
* URL of the inner frame's content in window #2. Must
|
|
* include "dropSource" and "dropTarget" elements.
|
|
*/
|
|
async function setup(configParams) {
|
|
const oldDragService = SpecialPowers.Cc[
|
|
"@mozilla.org/widget/dragservice;1"
|
|
].getService(SpecialPowers.Ci.nsIDragService);
|
|
dragController = oldDragService.getMockDragController();
|
|
dragServiceCid = MockRegistrar.register(
|
|
"@mozilla.org/widget/dragservice;1",
|
|
dragController.mockDragService
|
|
);
|
|
ok(dragServiceCid, "MockDragService was registered");
|
|
// If the mock failed then don't continue or else we could trigger native
|
|
// DND behavior.
|
|
if (!dragServiceCid) {
|
|
SimpleTest.finish();
|
|
}
|
|
registerCleanupFunction(async function () {
|
|
MockRegistrar.unregister(dragServiceCid);
|
|
});
|
|
dragController.mockDragService.neverAllowSessionIsSynthesizedForTests = true;
|
|
|
|
tab1Cxt = await openWindow(0, configParams);
|
|
tab2Cxt = await openWindow(1, configParams);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Test dragging between different frames and different domains
|
|
// ----------------------------------------------------------------------------
|
|
// Define runTest to establish a test between two (possibly identical) contexts.
|
|
// runTest has the same signature as runDnd.
|
|
var runTest = runDnd;
|
|
|
|
add_task(async function test_dnd_tab1_to_tab1() {
|
|
await runTest("tab1->tab1", tab1Cxt, tab1Cxt);
|
|
});
|
|
|
|
add_task(async function test_dnd_tab1_to_iframe1() {
|
|
await runTest("tab1->iframe1", tab1Cxt, tab1Cxt.children[0]);
|
|
});
|
|
|
|
add_task(async function test_dnd_tab1_to_tab2() {
|
|
await runTest("tab1->tab2", tab1Cxt, tab2Cxt);
|
|
});
|
|
|
|
add_task(async function test_dnd_tab1_to_iframe2() {
|
|
await runTest("tab1->iframe2", tab1Cxt, tab2Cxt.children[0]);
|
|
});
|
|
|
|
add_task(async function test_dnd_iframe1_to_tab1() {
|
|
await runTest("iframe1->tab1", tab1Cxt.children[0], tab1Cxt);
|
|
});
|
|
|
|
add_task(async function test_dnd_iframe1_to_iframe1() {
|
|
await runTest("iframe1->iframe1", tab1Cxt.children[0], tab1Cxt.children[0]);
|
|
});
|
|
|
|
add_task(async function test_dnd_iframe1_to_tab2() {
|
|
await runTest("iframe1->tab2", tab1Cxt.children[0], tab2Cxt);
|
|
});
|
|
|
|
add_task(async function test_dnd_iframe1_to_iframe2() {
|
|
await runTest("iframe1->iframe2", tab1Cxt.children[0], tab2Cxt.children[0]);
|
|
});
|