summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/general/browser_tab_dragdrop.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/test/general/browser_tab_dragdrop.js')
-rw-r--r--browser/base/content/test/general/browser_tab_dragdrop.js256
1 files changed, 256 insertions, 0 deletions
diff --git a/browser/base/content/test/general/browser_tab_dragdrop.js b/browser/base/content/test/general/browser_tab_dragdrop.js
new file mode 100644
index 0000000000..2cf52572ec
--- /dev/null
+++ b/browser/base/content/test/general/browser_tab_dragdrop.js
@@ -0,0 +1,256 @@
+// Swaps the content of tab a into tab b and then closes tab a.
+function swapTabsAndCloseOther(a, b) {
+ gBrowser.swapBrowsersAndCloseOther(gBrowser.tabs[b], gBrowser.tabs[a]);
+}
+
+// Mirrors the effect of the above function on an array.
+function swapArrayContentsAndRemoveOther(arr, a, b) {
+ arr[b] = arr[a];
+ arr.splice(a, 1);
+}
+
+function checkBrowserIds(expected) {
+ is(
+ gBrowser.tabs.length,
+ expected.length,
+ "Should have the right number of tabs."
+ );
+
+ for (let [i, tab] of gBrowser.tabs.entries()) {
+ is(
+ tab.linkedBrowser.browserId,
+ expected[i],
+ `Tab ${i} should have the right browser ID.`
+ );
+ is(
+ tab.linkedBrowser.browserId,
+ tab.linkedBrowser.browsingContext.browserId,
+ `Browser for tab ${i} has the same browserId as its BrowsingContext`
+ );
+ }
+}
+
+var getClicks = function(tab) {
+ return SpecialPowers.spawn(tab.linkedBrowser, [], function() {
+ return content.wrappedJSObject.clicks;
+ });
+};
+
+var clickTest = async function(tab) {
+ let clicks = await getClicks(tab);
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], function() {
+ let target = content.document.body;
+ let rect = target.getBoundingClientRect();
+ let left = (rect.left + rect.right) / 2;
+ let top = (rect.top + rect.bottom) / 2;
+
+ let utils = content.windowUtils;
+ utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
+ utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+ });
+
+ let newClicks = await getClicks(tab);
+ is(newClicks, clicks + 1, "adding 1 more click on BODY");
+};
+
+function loadURI(tab, url) {
+ BrowserTestUtils.loadURI(tab.linkedBrowser, url);
+ return BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+}
+
+// Creates a framescript which caches the current object value from the plugin
+// in the page. checkObjectValue below verifies that the framescript is still
+// active for the browser and that the cached value matches that from the plugin
+// in the page which tells us the plugin hasn't been reinitialized.
+async function cacheObjectValue(browser) {
+ await SpecialPowers.spawn(browser, [], () => {
+ let plugin = content.document.getElementById("p").wrappedJSObject;
+ info(`plugin is ${plugin}`);
+ let win = content.document.defaultView;
+ info(`win is ${win}`);
+ win.objectValue = plugin.getObjectValue();
+ info(`got objectValue: ${win.objectValue}`);
+ });
+}
+
+// Note, can't run this via registerCleanupFunction because it needs the
+// browser to still be alive and have a messageManager.
+async function cleanupObjectValue(browser) {
+ info("entered cleanupObjectValue");
+ await SpecialPowers.spawn(browser, [], () => {
+ info("in cleanup function");
+ let win = content.document.defaultView;
+ info(`about to delete objectValue: ${win.objectValue}`);
+ delete win.objectValue;
+ });
+ info("exiting cleanupObjectValue");
+}
+
+// See the notes for cacheObjectValue above.
+async function checkObjectValue(browser) {
+ let data = await SpecialPowers.spawn(browser, [], () => {
+ let plugin = content.document.getElementById("p").wrappedJSObject;
+ let win = content.document.defaultView;
+ let result, exception;
+ try {
+ result = plugin.checkObjectValue(win.objectValue);
+ } catch (e) {
+ exception = e.toString();
+ }
+ return {
+ result,
+ exception,
+ };
+ });
+
+ if (data.result === null) {
+ ok(false, "checkObjectValue threw an exception: " + data.exception);
+ throw new Error(data.exception);
+ } else {
+ return data.result;
+ }
+}
+
+add_task(async function() {
+ // create a few tabs
+ let tabs = [
+ gBrowser.tabs[0],
+ BrowserTestUtils.addTab(gBrowser, "about:blank", { skipAnimation: true }),
+ BrowserTestUtils.addTab(gBrowser, "about:blank", { skipAnimation: true }),
+ BrowserTestUtils.addTab(gBrowser, "about:blank", { skipAnimation: true }),
+ BrowserTestUtils.addTab(gBrowser, "about:blank", { skipAnimation: true }),
+ ];
+
+ // Initially 0 1 2 3 4
+ await loadURI(
+ tabs[1],
+ "data:text/html;charset=utf-8,<title>tab1</title><body>tab1<iframe>"
+ );
+ await loadURI(tabs[2], "data:text/plain;charset=utf-8,tab2");
+ await loadURI(
+ tabs[3],
+ "data:text/html;charset=utf-8,<title>tab3</title><body>tab3<iframe>"
+ );
+ await loadURI(
+ tabs[4],
+ "http://example.com/browser/browser/base/content/test/general/browser_tab_dragdrop_embed.html"
+ );
+ await BrowserTestUtils.switchTab(gBrowser, tabs[3]);
+
+ let browserIds = tabs.map(t => t.linkedBrowser.browserId);
+ checkBrowserIds(browserIds);
+
+ is(gBrowser.tabs[1], tabs[1], "tab1");
+ is(gBrowser.tabs[2], tabs[2], "tab2");
+ is(gBrowser.tabs[3], tabs[3], "tab3");
+ is(gBrowser.tabs[4], tabs[4], "tab4");
+
+ swapTabsAndCloseOther(2, 3); // now: 0 1 2 4
+ // Tab 2 is gone (what was tab 3 is displaying its content).
+ tabs.splice(2, 1);
+ swapArrayContentsAndRemoveOther(browserIds, 2, 3);
+
+ is(gBrowser.tabs[1], tabs[1], "tab1");
+ is(gBrowser.tabs[2], tabs[2], "tab2");
+ is(gBrowser.tabs[3], tabs[3], "tab4");
+
+ checkBrowserIds(browserIds);
+
+ info("about to cacheObjectValue");
+ await cacheObjectValue(tabs[3].linkedBrowser);
+ info("just finished cacheObjectValue");
+
+ swapTabsAndCloseOther(3, 2); // now: 0 1 4
+ tabs.splice(3, 1);
+ swapArrayContentsAndRemoveOther(browserIds, 3, 2);
+
+ is(
+ Array.prototype.indexOf.call(gBrowser.tabs, gBrowser.selectedTab),
+ 2,
+ "The third tab should be selected"
+ );
+
+ checkBrowserIds(browserIds);
+
+ ok(
+ await checkObjectValue(gBrowser.tabs[2].linkedBrowser),
+ "same plugin instance"
+ );
+
+ is(gBrowser.tabs[1], tabs[1], "tab1");
+ is(gBrowser.tabs[2], tabs[2], "tab4");
+
+ let clicks = await getClicks(gBrowser.tabs[2]);
+ is(clicks, 0, "no click on BODY so far");
+ await clickTest(gBrowser.tabs[2]);
+
+ swapTabsAndCloseOther(2, 1); // now: 0 4
+ tabs.splice(2, 1);
+ swapArrayContentsAndRemoveOther(browserIds, 2, 1);
+
+ is(gBrowser.tabs[1], tabs[1], "tab4");
+
+ checkBrowserIds(browserIds);
+
+ ok(
+ await checkObjectValue(gBrowser.tabs[1].linkedBrowser),
+ "same plugin instance"
+ );
+ await cleanupObjectValue(gBrowser.tabs[1].linkedBrowser);
+
+ await clickTest(gBrowser.tabs[1]);
+
+ // Load a new document (about:blank) in tab4, then detach that tab into a new window.
+ // In the new window, navigate back to the original document and click on its <body>,
+ // verify that its onclick was called.
+ is(
+ Array.prototype.indexOf.call(gBrowser.tabs, gBrowser.selectedTab),
+ 1,
+ "The second tab should be selected"
+ );
+ is(
+ gBrowser.tabs[1],
+ tabs[1],
+ "The second tab in gBrowser.tabs should be equal to the second tab in our array"
+ );
+ is(
+ gBrowser.selectedTab,
+ tabs[1],
+ "The second tab in our array is the selected tab"
+ );
+ await loadURI(tabs[1], "about:blank");
+ let key = tabs[1].linkedBrowser.permanentKey;
+
+ checkBrowserIds(browserIds);
+
+ let win = gBrowser.replaceTabWithWindow(tabs[1]);
+ await new Promise(resolve => whenDelayedStartupFinished(win, resolve));
+
+ let newWinBrowserId = browserIds[1];
+ browserIds.splice(1, 1);
+ checkBrowserIds(browserIds);
+
+ // Verify that the original window now only has the initial tab left in it.
+ is(gBrowser.tabs[0], tabs[0], "tab0");
+ is(gBrowser.tabs[0].linkedBrowser.currentURI.spec, "about:blank", "tab0 uri");
+
+ let tab = win.gBrowser.tabs[0];
+ is(tab.linkedBrowser.permanentKey, key, "Should have kept the key");
+ is(tab.linkedBrowser.browserId, newWinBrowserId, "Should have kept the ID");
+ is(
+ tab.linkedBrowser.browserId,
+ tab.linkedBrowser.browsingContext.browserId,
+ "Should have kept the ID"
+ );
+
+ let awaitPageShow = BrowserTestUtils.waitForContentEvent(
+ tab.linkedBrowser,
+ "pageshow"
+ );
+ win.gBrowser.goBack();
+ await awaitPageShow;
+
+ await clickTest(tab);
+ promiseWindowClosed(win);
+});