Bug 1323185 - Add window (tab) handling support for Fennec. r=ato

So far Marionette did support Fennec but not any of its tab handling
features. As such most of the commands fail because they do not take
BrowserApp into account.

This patch adds support for retrieving window handles, switching
between windows, and closing tabs.

Additionally to those changes a couple of unit tests are getting
updated, and added.

MozReview-Commit-ID: 7sbVIblm0Hw

--HG--
rename : testing/marionette/harness/marionette_harness/tests/unit/test_window_handles.py => testing/marionette/harness/marionette_harness/tests/unit/test_window_handles_content.py
extra : rebase_source : 475dd6bee446f58208192202cd4c483e2fd929dc
This commit is contained in:
Henrik Skupin 2017-01-23 08:46:50 +01:00
parent e328faf19c
commit fa96c2f9f9
8 changed files with 442 additions and 283 deletions

View File

@ -16,6 +16,59 @@ this.browser = {};
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
/**
* Get the <xul:browser> for the specified tab.
*
* @param {<xul:tab>} tab
* The tab whose browser needs to be returned.
*
* @return {<xul:browser>}
* The linked browser for the tab.
*
* @throws UnsupportedOperationError
* If tab handling for the current application isn't supported.
*/
browser.getBrowserForTab = function (tab) {
if (tab.hasOwnProperty("browser")) {
// Fennec
return tab.browser;
} else if (tab.hasOwnProperty("linkedBrowser")) {
// Firefox
return tab.linkedBrowser;
} else {
new UnsupportedOperationError("getBrowserForTab() not supported.");
}
};
/**
* Return the tab browser for the specified chrome window.
*
* @param {nsIDOMWindow} win
* The window whose tabbrowser needs to be accessed.
*
* @return {<xul:tabbrowser>}
* Tab browser or null if it's not a browser window.
*
* @throws UnsupportedOperationError
* If tab handling for the current application isn't supported.
*/
browser.getTabBrowser = function (win) {
if (win.hasOwnProperty("BrowserApp")) {
// Fennec
return win.BrowserApp;
} else if (win.hasOwnProperty("gBrowser")) {
// Firefox
return win.gBrowser;
} else {
new UnsupportedOperationError("getBrowserForTab() not supported.");
}
};
/**
* Creates a browsing context wrapper.
*
@ -41,8 +94,7 @@ browser.Context = class {
// In Firefox this is <xul:tabbrowser> (not <xul:browser>!)
// and BrowserApp in Fennec
this.browser = undefined;
this.setBrowser(win);
this.tabBrowser = browser.getTabBrowser(win);
this.knownFrames = [];
@ -78,21 +130,6 @@ browser.Context = class {
this._hasRemotenessChange = false;
}
/**
* Get the <xul:browser> for the current tab in this tab browser.
*
* @return {<xul:browser>}
* Browser linked to |this.tab| or the tab browser's
* |selectedBrowser|.
*/
get browserForTab() {
if (this.browser.getBrowserForTab) {
return this.browser.getBrowserForTab(this.tab);
} else {
return this.browser.selectedBrowser;
}
}
/**
* The current frame ID is managed per browser element on desktop in
* case the ID needs to be refreshed. The currently selected window is
@ -103,7 +140,7 @@ browser.Context = class {
if (this.driver.appName == "B2G") {
rv = this._curFrameId;
} else if (this.tab) {
rv = this.getIdForBrowser(this.browserForTab);
rv = this.getIdForBrowser(browser.getBrowserForTab(this.tab));
}
return rv;
}
@ -119,7 +156,7 @@ browser.Context = class {
* associated with the currently selected tab.
*/
getTabModalUI() {
let br = this.browserForTab;
let br = browser.getBrowserForTab(this.tab);
if (!br.hasAttribute("tabmodalPromptShowing")) {
return null;
}
@ -131,24 +168,6 @@ browser.Context = class {
return modals[0].ui;
}
/**
* Set the browser if the application is not B2G.
*
* @param {nsIDOMWindow} win
* Current window reference.
*/
setBrowser(win) {
switch (this.driver.appName) {
case "Firefox":
this.browser = win.gBrowser;
break;
case "Fennec":
this.browser = win.BrowserApp;
break;
}
}
/**
* Close the current window.
*
@ -174,20 +193,32 @@ browser.Context = class {
*
* @return {Promise}
* A promise which is resolved when the current tab has been closed.
*
* @throws UnsupportedOperationError
* If tab handling for the current application isn't supported.
*/
closeTab() {
// If the current window is not a browser then close it directly. Do the
// same if only one remaining tab is open, or no tab selected at all.
if (!this.browser || !this.tab || this.browser.browsers.length == 1) {
if (!this.tabBrowser || this.tabBrowser.tabs.length === 1 || !this.tab) {
return this.closeWindow();
}
return new Promise((resolve, reject) => {
if (this.browser.removeTab) {
if (this.tabBrowser.closeTab) {
// Fennec
this.tabBrowser.deck.addEventListener("TabClose", ev => {
resolve();
}, {once: true});
this.tabBrowser.closeTab(this.tab);
} else if (this.tabBrowser.removeTab) {
// Firefox
this.tab.addEventListener("TabClose", ev => {
resolve();
}, {once: true});
this.browser.removeTab(this.tab);
this.tabBrowser.removeTab(this.tab);
} else {
reject(new UnsupportedOperationError(
`closeTab() not supported in ${this.driver.appName}`));
@ -202,29 +233,47 @@ browser.Context = class {
* URI to open.
*/
addTab(uri) {
return this.browser.addTab(uri, true);
return this.tabBrowser.addTab(uri, true);
}
/**
* Re-sets current tab and updates remoteness tracking.
* Set the current tab and update remoteness tracking if a tabbrowser is available.
*
* If a window is provided, the internal reference is updated before
* proceeding.
* @param {number=} index
* Tab index to switch to. If the parameter is undefined,
* the currently selected tab will be used.
* @param {nsIDOMWindow=} win
* Switch to this window before selecting the tab.
*/
switchToTab(ind, win) {
switchToTab(index, win) {
if (win) {
this.window = win;
this.setBrowser(win);
this.tabBrowser = browser.getTabBrowser(win);
}
if (this.browser.selectTabAtIndex) {
this.browser.selectTabAtIndex(ind);
this.tab = this.browser.selectedTab;
this._browserWasRemote = this.browserForTab.isRemoteBrowser;
if (!this.tabBrowser) {
return;
}
else {
this.tab = this.browser.selectedTab;
if (typeof index == "undefined") {
this.tab = this.tabBrowser.selectedTab;
} else {
this.tab = this.tabBrowser.tabs[index];
if (this.tabBrowser.selectTab) {
// Fennec
this.tabBrowser.selectTab(this.tab);
} else {
// Firefox
this.tabBrowser.selectedTab = this.tab;
}
}
if (this.driver.appName == "Firefox") {
this._browserWasRemote = browser.getBrowserForTab(this.tab).isRemoteBrowser;
this._hasRemotenessChange = false;
}
this._hasRemotenessChange = false;
}
/**
@ -239,15 +288,15 @@ browser.Context = class {
register(uid, target) {
let remotenessChange = this.hasRemotenessChange();
if (this.curFrameId === null || remotenessChange) {
if (this.browser) {
if (this.tabBrowser) {
// If we're setting up a new session on Firefox, we only process the
// registration for this frame if it belongs to the current tab.
if (!this.tab) {
this.switchToTab(this.browser.selectedIndex);
this.switchToTab();
}
if (target == this.browserForTab) {
this.updateIdForBrowser(this.browserForTab, uid);
if (target == browser.getBrowserForTab(this.tab)) {
this.updateIdForBrowser(browser.getBrowserForTab(this.tab), uid);
this.mainContentId = uid;
}
} else {
@ -271,7 +320,7 @@ browser.Context = class {
// and may not apply on Fennec.
if (this.driver.appName != "Firefox" ||
this.tab === null ||
this.browserForTab === null) {
browser.getBrowserForTab(this.tab) === null) {
return false;
}
@ -279,7 +328,7 @@ browser.Context = class {
return true;
}
let currentIsRemote = this.browserForTab.isRemoteBrowser;
let currentIsRemote = browser.getBrowserForTab(this.tab).isRemoteBrowser;
this._hasRemotenessChange = this._browserWasRemote !== currentIsRemote;
this._browserWasRemote = currentIsRemote;
return this._hasRemotenessChange;

View File

@ -191,14 +191,15 @@ Object.defineProperty(GeckoDriver.prototype, "windowHandles", {
while (winEn.hasMoreElements()) {
let win = winEn.getNext();
if (win.gBrowser) {
let tabbrowser = win.gBrowser;
for (let i = 0; i < tabbrowser.browsers.length; ++i) {
let winId = this.getIdForBrowser(tabbrowser.getBrowserAtIndex(i));
let tabBrowser = browser.getTabBrowser(win);
if (tabBrowser) {
tabBrowser.tabs.forEach(tab => {
let winId = this.getIdForBrowser(browser.getBrowserForTab(tab));
if (winId !== null) {
hs.push(winId);
}
}
});
} else {
// For other chrome windows beside the browser window, only count the window itself.
let winId = win.QueryInterface(Ci.nsIInterfaceRequestor)
@ -655,7 +656,9 @@ GeckoDriver.prototype.newSession = function*(cmd, resp) {
yield registerBrowsers;
yield browserListening;
this.curBrowser.browserForTab.focus();
if (this.curBrowser.tab) {
browser.getBrowserForTab(this.curBrowser.tab).focus();
}
return {
sessionId: this.sessionId,
@ -814,7 +817,7 @@ GeckoDriver.prototype.executeScript = function*(cmd, resp) {
* @param {string=} sandbox
* Name of the sandbox to evaluate the script in. The sandbox is
* cached for later re-use on the same Window object if
* {@code newSandbox} is false. If he parameter is undefined,
* {@code newSandbox} is false. If the parameter is undefined,
* the script is evaluated in a mutable sandbox. If the parameter
* is "system", it will be evaluted in a sandbox with elevated system
* privileges, equivalent to chrome space.
@ -972,7 +975,7 @@ GeckoDriver.prototype.get = function*(cmd, resp) {
});
yield get;
this.curBrowser.browserForTab.focus();
browser.getBrowserForTab(this.curBrowser.tab).focus();
};
/**
@ -1199,7 +1202,6 @@ GeckoDriver.prototype.setWindowPosition = function (cmd, resp) {
*/
GeckoDriver.prototype.switchToWindow = function* (cmd, resp) {
let switchTo = cmd.parameters.name;
let isMobile = this.appName == "Fennec";
let found;
let getOuterWindowId = function (win) {
@ -1219,12 +1221,13 @@ GeckoDriver.prototype.switchToWindow = function* (cmd, resp) {
while (winEn.hasMoreElements()) {
let win = winEn.getNext();
let outerId = getOuterWindowId(win);
let tabbrowser = browser.getTabBrowser(win);
if (tabbrowser) {
for (let i = 0; i < tabbrowser.tabs.length; ++i) {
let contentBrowser = browser.getBrowserForTab(tabbrowser.tabs[i]);
let contentWindowId = this.getIdForBrowser(contentBrowser);
if (win.gBrowser && !isMobile) {
let tabbrowser = win.gBrowser;
for (let i = 0; i < tabbrowser.browsers.length; ++i) {
let browser = tabbrowser.getBrowserAtIndex(i);
let contentWindowId = this.getIdForBrowser(browser);
if (byNameOrId(win.name, contentWindowId, outerId)) {
found = {
win: win,
@ -2114,8 +2117,9 @@ GeckoDriver.prototype.close = function (cmd, resp) {
let win = winEn.getNext();
// For browser windows count the tabs. Otherwise take the window itself.
if (win.gBrowser) {
nwins += win.gBrowser.browsers.length;
let tabbrowser = browser.getTabBrowser(win);
if (tabbrowser) {
nwins += tabbrowser.tabs.length;
} else {
nwins++;
}

View File

@ -2,7 +2,7 @@
# 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/.
from marionette_driver.by import By
from marionette_driver import By, Wait
from marionette_driver.keys import Keys
from marionette_harness import MarionetteTestCase, skip_if_mobile, WindowManagerMixin
@ -18,45 +18,54 @@ class TestAboutPages(WindowManagerMixin, MarionetteTestCase):
else:
self.mod_key = Keys.CONTROL
self.remote_uri = self.marionette.absolute_url("javascriptPage.html")
self.marionette.navigate(self.remote_uri)
self.remote_uri = self.marionette.absolute_url("windowHandles.html")
def tearDown(self):
self.close_all_tabs()
super(TestAboutPages, self).tearDown()
@skip_if_mobile("Bug 1323185 - Add Fennec support to getWindowHandles")
def open_tab_with_link(self):
with self.marionette.using_context("content"):
self.marionette.navigate(self.remote_uri)
link = self.marionette.find_element(By.ID, "new-tab")
link.click()
@skip_if_mobile("Bug 1333209 - Process killed because of connection loss")
def test_back_forward(self):
# Bug 1311041 - Prevent changing of window handle by forcing the test
# to be run in a new tab.
new_tab = self.open_tab(trigger='menu')
new_tab = self.open_tab(trigger=self.open_tab_with_link)
self.marionette.switch_to_window(new_tab)
self.marionette.navigate("about:blank")
self.marionette.navigate(self.remote_uri)
self.marionette.navigate("about:preferences")
self.marionette.navigate("about:support")
self.marionette.go_back()
Wait(self.marionette).until(lambda mn: mn.get_url() == self.remote_uri,
message="'{}' hasn't been loaded".format(self.remote_uri))
self.wait_for_condition(
lambda mn: mn.get_url() == self.remote_uri)
# Bug 1332998 - Timeout loading the page
# self.marionette.go_forward()
# Wait(self.marionette).until(lambda mn: mn.get_url() == self.remote_uri,
# message="'about:support' hasn't been loaded")
self.marionette.close()
self.marionette.switch_to_window(self.start_tab)
@skip_if_mobile("Bug 1323185 - Add Fennec support to getWindowHandles")
@skip_if_mobile("Bug 1333209 - Process killed because of connection loss")
def test_navigate_non_remote_about_pages(self):
# Bug 1311041 - Prevent changing of window handle by forcing the test
# to be run in a new tab.
new_tab = self.open_tab(trigger='menu')
new_tab = self.open_tab(trigger=self.open_tab_with_link)
self.marionette.switch_to_window(new_tab)
self.marionette.navigate("about:blank")
self.assertEqual(self.marionette.get_url(), "about:blank")
self.marionette.navigate("about:preferences")
self.assertEqual(self.marionette.get_url(), "about:preferences")
self.marionette.navigate("about:support")
self.assertEqual(self.marionette.get_url(), "about:support")
self.marionette.close()
self.marionette.switch_to_window(self.start_tab)
@ -64,6 +73,7 @@ class TestAboutPages(WindowManagerMixin, MarionetteTestCase):
@skip_if_mobile("On Android no shortcuts are available")
def test_navigate_shortcut_key(self):
def open_with_shortcut():
self.marionette.navigate(self.remote_uri)
with self.marionette.using_context("chrome"):
main_win = self.marionette.find_element(By.ID, "main-window")
main_win.send_keys(self.mod_key, Keys.SHIFT, 'a')
@ -71,43 +81,55 @@ class TestAboutPages(WindowManagerMixin, MarionetteTestCase):
new_tab = self.open_tab(trigger=open_with_shortcut)
self.marionette.switch_to_window(new_tab)
self.wait_for_condition(lambda mn: mn.get_url() == "about:addons")
Wait(self.marionette).until(lambda mn: mn.get_url() == "about:addons",
message="'about:addons' hasn't been loaded")
self.marionette.close()
self.marionette.switch_to_window(self.start_tab)
@skip_if_mobile("Bug 1323185 - Add Fennec support to getWindowHandles")
@skip_if_mobile("Interacting with chrome elements not available for Fennec")
def test_type_to_non_remote_tab(self):
# Bug 1311041 - Prevent changing of window handle by forcing the test
# to be run in a new tab.
new_tab = self.open_tab(trigger='menu')
new_tab = self.open_tab(trigger=self.open_tab_with_link)
self.marionette.switch_to_window(new_tab)
with self.marionette.using_context("chrome"):
urlbar = self.marionette.find_element(By.ID, 'urlbar')
urlbar.send_keys(self.mod_key + 'a')
urlbar.send_keys(self.mod_key + 'x')
urlbar.send_keys('about:preferences' + Keys.ENTER)
self.wait_for_condition(lambda mn: mn.get_url() == "about:preferences")
urlbar.send_keys('about:support' + Keys.ENTER)
Wait(self.marionette).until(lambda mn: mn.get_url() == "about:support",
message="'about:support' hasn't been loaded")
self.marionette.close()
self.marionette.switch_to_window(self.start_tab)
@skip_if_mobile("Interacting with chrome elements not available for Fennec")
def test_type_to_remote_tab(self):
# Bug 1311041 - Prevent changing of window handle by forcing the test
# to be run in a new tab.
new_tab = self.open_tab(trigger=self.open_tab_with_link)
self.marionette.switch_to_window(new_tab)
# about:blank keeps remoteness from remote_uri
self.marionette.navigate("about:blank")
with self.marionette.using_context("chrome"):
urlbar = self.marionette.find_element(By.ID, 'urlbar')
urlbar.send_keys(self.mod_key + 'a')
urlbar.send_keys(self.mod_key + 'x')
urlbar.send_keys(self.remote_uri + Keys.ENTER)
self.wait_for_condition(lambda mn: mn.get_url() == self.remote_uri)
Wait(self.marionette).until(lambda mn: mn.get_url() == self.remote_uri,
message="'{}' hasn't been loaded".format(self.remote_uri))
@skip_if_mobile("Bug 1323185 - Add Fennec support to getWindowHandles")
@skip_if_mobile("Needs application independent method to open a new tab")
def test_hang(self):
# Open a new tab and close the first one
new_tab = self.open_tab(trigger="menu")
# Bug 1311041 - Prevent changing of window handle by forcing the test
# to be run in a new tab.
new_tab = self.open_tab(trigger=self.open_tab_with_link)
# Close the start tab
self.marionette.close()
self.marionette.switch_to_window(new_tab)

View File

@ -1,183 +0,0 @@
# 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/.
from marionette_driver import By, Wait
from marionette_driver.keys import Keys
from marionette_harness import MarionetteTestCase, WindowManagerMixin
class TestWindowHandles(WindowManagerMixin, MarionetteTestCase):
def setUp(self):
super(TestWindowHandles, self).setUp()
self.test_page = self.marionette.absolute_url("windowHandles.html")
self.marionette.navigate(self.test_page)
def tearDown(self):
self.close_all_windows()
self.close_all_tabs()
super(TestWindowHandles, self).tearDown()
def test_new_tab_window_handles(self):
keys = []
if self.marionette.session_capabilities['platformName'] == 'darwin':
keys.append(Keys.META)
else:
keys.append(Keys.CONTROL)
keys.append('t')
def open_with_shortcut():
with self.marionette.using_context("chrome"):
main_win = self.marionette.find_element(By.ID, "main-window")
main_win.send_keys(*keys)
new_tab = self.open_tab(trigger=open_with_shortcut)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
self.marionette.switch_to_window(new_tab)
self.assertEqual(self.marionette.get_url(), "about:newtab")
self.marionette.close()
self.marionette.switch_to_window(self.start_tab)
def test_new_tab_window_handles_no_switch(self):
"""Regression test for bug 1294456.
This test is testing the case where Marionette attempts to send a
command to a window handle when the browser has opened and selected
a new tab. Before bug 1294456 landed, the Marionette driver was getting
confused about which window handle the client cared about, and assumed
it was the window handle for the newly opened and selected tab.
This caused Marionette to think that the browser needed to do a remoteness
flip in the e10s case, since the tab opened by menu_newNavigatorTab is
about:newtab (which is currently non-remote). This meant that commands
sent to what should have been the original window handle would be
queued and never sent, since the remoteness flip in the new tab was
never going to happen.
"""
def open_with_menu():
with self.marionette.using_context("chrome"):
menu_new_tab = self.marionette.find_element(By.ID, 'menu_newNavigatorTab')
menu_new_tab.click()
new_tab = self.open_tab(trigger=open_with_menu)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
# We still have the default tab set as our window handle. This
# get_url command should be sent immediately, and not be forever-queued.
self.assertEqual(self.marionette.get_url(), self.test_page)
self.marionette.switch_to_window(new_tab)
self.marionette.close()
self.marionette.switch_to_window(self.start_tab)
def test_link_opened_tab_window_handles(self):
def open_with_link():
link = self.marionette.find_element(By.ID, "new-tab")
link.click()
new_tab = self.open_tab(trigger=open_with_link)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
self.marionette.switch_to_window(new_tab)
self.assertEqual(self.marionette.get_url(), "about:blank")
self.assertEqual(self.marionette.title, "")
self.marionette.switch_to_window(self.start_tab)
self.assertEqual(self.marionette.get_url(), self.test_page)
self.assertEqual(self.marionette.title, "Marionette New Tab Link")
self.marionette.close()
self.marionette.switch_to_window(new_tab)
self.assertEqual(self.marionette.get_url(), "about:blank")
def test_chrome_windows(self):
# We open a chrome window but are actually interested in the new tab.
new_window = self.open_window(
trigger=lambda: self.marionette.find_element(By.ID, "new-window").click())
with self.marionette.using_context("chrome"):
self.marionette.switch_to_window(new_window)
# Check that the new tab is available and wait until it has been loaded.
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
new_tab = self.marionette.current_window_handle
Wait(self.marionette).until(lambda _: self.marionette.get_url() == self.test_page,
message="Test page hasn't been loaded for newly opened tab")
link_new_tab = self.marionette.find_element(By.ID, "new-tab")
for i in range(3):
self.open_tab(trigger=lambda: link_new_tab.click())
self.marionette.switch_to_window(new_tab)
# No more chrome windows should be opened
self.assertEqual(len(self.marionette.chrome_window_handles),
len(self.start_windows) + 1)
self.marionette.close_chrome_window()
self.marionette.switch_to_window(self.start_window)
def test_chrome_window_handles_with_scopes(self):
# Ensure that we work in chrome scope so we don't have any limitations
with self.marionette.using_context("chrome"):
# Open a browser and a non-browser (about window) chrome window
self.open_window(
trigger=lambda: self.marionette.execute_script("window.open();"))
self.open_window(
trigger=lambda: self.marionette.find_element(By.ID, "aboutName").click())
handles_in_chrome_scope = self.marionette.chrome_window_handles
with self.marionette.using_context("content"):
self.assertEqual(self.marionette.chrome_window_handles,
handles_in_chrome_scope)
def test_tab_and_window_handles(self):
window_open_page = self.marionette.absolute_url("test_windows.html")
results_page = self.marionette.absolute_url("resultPage.html")
# Open a new tab and switch to it.
def open_tab_with_link():
link = self.marionette.find_element(By.ID, "new-tab")
link.click()
second_tab = self.open_tab(trigger=open_tab_with_link)
self.assertEqual(len(self.marionette.chrome_window_handles), 1)
self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
self.marionette.switch_to_window(second_tab)
self.assertEqual(self.marionette.get_url(), "about:blank")
# Open a new window from the new tab and only care about the second new tab
def open_window_with_link():
link = self.marionette.find_element(By.LINK_TEXT, "Open new window")
link.click()
# We open a new window but are actually interested in the new tab
self.marionette.navigate(window_open_page)
third_tab = self.open_tab(trigger=open_window_with_link)
self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
# Check that the new tab has the correct page loaded
self.marionette.switch_to_window(third_tab)
self.assertEqual(self.marionette.get_url(), results_page)
self.assertNotEqual(self.marionette.current_chrome_window_handle, self.start_window)
# Return to our original tab and close it.
self.marionette.switch_to_window(self.start_tab)
self.marionette.close()
self.assertEquals(len(self.marionette.window_handles), 2)
# Close the opened window and carry on in our second tab.
self.marionette.switch_to_window(third_tab)
self.marionette.close()
self.assertEqual(len(self.marionette.window_handles), 1)
self.marionette.switch_to_window(second_tab)
self.assertEqual(self.marionette.get_url(), results_page)
self.marionette.navigate("about:blank")
self.assertEqual(len(self.marionette.chrome_window_handles), 1)
self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)

View File

@ -0,0 +1,181 @@
# 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/.
from marionette_driver import By, Wait
from marionette_harness import MarionetteTestCase, WindowManagerMixin
class TestWindowHandles(WindowManagerMixin, MarionetteTestCase):
def setUp(self):
super(TestWindowHandles, self).setUp()
self.empty_page = self.marionette.absolute_url("empty.html")
self.test_page = self.marionette.absolute_url("windowHandles.html")
self.marionette.navigate(self.test_page)
self.marionette.set_context("chrome")
def tearDown(self):
self.close_all_windows()
self.close_all_tabs()
super(TestWindowHandles, self).tearDown()
def test_chrome_window_handles_with_scopes(self):
# Open a browser and a non-browser (about window) chrome window
self.open_window(
trigger=lambda: self.marionette.execute_script("window.open();"))
self.assertEqual(len(self.marionette.chrome_window_handles), len(self.start_windows) + 1)
self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
self.open_window(
trigger=lambda: self.marionette.find_element(By.ID, "aboutName").click())
self.assertEqual(len(self.marionette.chrome_window_handles), len(self.start_windows) + 2)
self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
chrome_window_handles_in_chrome_scope = self.marionette.chrome_window_handles
window_handles_in_chrome_scope = self.marionette.window_handles
with self.marionette.using_context("content"):
self.assertEqual(self.marionette.chrome_window_handles,
chrome_window_handles_in_chrome_scope)
self.assertEqual(self.marionette.window_handles,
window_handles_in_chrome_scope)
def test_chrome_window_handles_after_opening_new_window(self):
def open_with_link():
with self.marionette.using_context("content"):
link = self.marionette.find_element(By.ID, "new-window")
link.click()
# We open a new window but are actually interested in the new tab
new_win = self.open_window(trigger=open_with_link)
self.assertEqual(len(self.marionette.chrome_window_handles), len(self.start_windows) + 1)
self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
# Check that the new tab has the correct page loaded
self.marionette.switch_to_window(new_win)
self.assertEqual(self.marionette.current_chrome_window_handle, new_win)
with self.marionette.using_context("content"):
self.assertEqual(self.marionette.get_url(), self.empty_page)
# Close the opened window and carry on in our original tab.
self.marionette.close()
self.assertEqual(len(self.marionette.chrome_window_handles), len(self.start_windows))
self.marionette.switch_to_window(self.start_window)
self.assertEqual(self.marionette.current_chrome_window_handle, self.start_window)
with self.marionette.using_context("content"):
self.assertEqual(self.marionette.get_url(), self.test_page)
def test_window_handles_after_opening_new_tab(self):
def open_with_link():
with self.marionette.using_context("content"):
link = self.marionette.find_element(By.ID, "new-tab")
link.click()
new_tab = self.open_tab(trigger=open_with_link)
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
self.marionette.switch_to_window(new_tab)
self.assertEqual(self.marionette.current_window_handle, new_tab)
with self.marionette.using_context("content"):
self.assertEqual(self.marionette.get_url(), self.empty_page)
self.marionette.switch_to_window(self.start_tab)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
with self.marionette.using_context("content"):
self.assertEqual(self.marionette.get_url(), self.test_page)
self.marionette.switch_to_window(new_tab)
self.marionette.close()
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
self.marionette.switch_to_window(self.start_tab)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
def test_window_handles_after_opening_new_window(self):
def open_with_link():
with self.marionette.using_context("content"):
link = self.marionette.find_element(By.ID, "new-window")
link.click()
# We open a new window but are actually interested in the new tab
new_tab = self.open_tab(trigger=open_with_link)
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
# Check that the new tab has the correct page loaded
self.marionette.switch_to_window(new_tab)
self.assertEqual(self.marionette.current_window_handle, new_tab)
with self.marionette.using_context("content"):
self.assertEqual(self.marionette.get_url(), self.empty_page)
# Close the opened window and carry on in our original tab.
self.marionette.close()
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
self.marionette.switch_to_window(self.start_tab)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
with self.marionette.using_context("content"):
self.assertEqual(self.marionette.get_url(), self.test_page)
def test_window_handles_after_closing_original_tab(self):
def open_with_link():
with self.marionette.using_context("content"):
link = self.marionette.find_element(By.ID, "new-tab")
link.click()
new_tab = self.open_tab(trigger=open_with_link)
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
self.marionette.close()
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
self.marionette.switch_to_window(new_tab)
self.assertEqual(self.marionette.current_window_handle, new_tab)
with self.marionette.using_context("content"):
self.assertEqual(self.marionette.get_url(), self.empty_page)
def test_window_handles_no_switch(self):
"""Regression test for bug 1294456.
This test is testing the case where Marionette attempts to send a
command to a window handle when the browser has opened and selected
a new tab. Before bug 1294456 landed, the Marionette driver was getting
confused about which window handle the client cared about, and assumed
it was the window handle for the newly opened and selected tab.
This caused Marionette to think that the browser needed to do a remoteness
flip in the e10s case, since the tab opened by menu_newNavigatorTab is
about:newtab (which is currently non-remote). This meant that commands
sent to what should have been the original window handle would be
queued and never sent, since the remoteness flip in the new tab was
never going to happen.
"""
def open_with_menu():
menu_new_tab = self.marionette.find_element(By.ID, 'menu_newNavigatorTab')
menu_new_tab.click()
new_tab = self.open_tab(trigger=open_with_menu)
# We still have the default tab set as our window handle. This
# get_url command should be sent immediately, and not be forever-queued.
with self.marionette.using_context("content"):
self.assertEqual(self.marionette.get_url(), self.test_page)
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
self.marionette.switch_to_window(new_tab)
self.assertEqual(self.marionette.current_window_handle, new_tab)
self.marionette.close()
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
self.marionette.switch_to_window(self.start_tab)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)

View File

@ -0,0 +1,85 @@
# 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/.
from marionette_driver import By
from marionette_harness import MarionetteTestCase, WindowManagerMixin
class TestWindowHandles(WindowManagerMixin, MarionetteTestCase):
def setUp(self):
super(TestWindowHandles, self).setUp()
self.empty_page = self.marionette.absolute_url("empty.html")
self.test_page = self.marionette.absolute_url("windowHandles.html")
self.marionette.navigate(self.test_page)
def tearDown(self):
self.close_all_tabs()
super(TestWindowHandles, self).tearDown()
def test_window_handles_after_opening_new_tab(self):
def open_with_link():
link = self.marionette.find_element(By.ID, "new-tab")
link.click()
new_tab = self.open_tab(trigger=open_with_link)
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
self.marionette.switch_to_window(new_tab)
self.assertEqual(self.marionette.current_window_handle, new_tab)
self.assertEqual(self.marionette.get_url(), self.empty_page)
self.marionette.switch_to_window(self.start_tab)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
self.assertEqual(self.marionette.get_url(), self.test_page)
self.marionette.switch_to_window(new_tab)
self.marionette.close()
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
self.marionette.switch_to_window(self.start_tab)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
def test_window_handles_after_opening_new_window(self):
def open_with_link():
link = self.marionette.find_element(By.ID, "new-window")
link.click()
# We open a new window but are actually interested in the new tab
new_tab = self.open_tab(trigger=open_with_link)
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
# Check that the new tab has the correct page loaded
self.marionette.switch_to_window(new_tab)
self.assertEqual(self.marionette.current_window_handle, new_tab)
self.assertEqual(self.marionette.get_url(), self.empty_page)
# Close the opened window and carry on in our original tab.
self.marionette.close()
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
self.marionette.switch_to_window(self.start_tab)
self.assertEqual(self.marionette.current_window_handle, self.start_tab)
self.assertEqual(self.marionette.get_url(), self.test_page)
def test_window_handles_after_closing_original_tab(self):
def open_with_link():
link = self.marionette.find_element(By.ID, "new-tab")
link.click()
new_tab = self.open_tab(trigger=open_with_link)
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs) + 1)
self.assertNotEqual(self.marionette.current_window_handle, new_tab)
self.marionette.close()
self.assertEqual(len(self.marionette.window_handles), len(self.start_tabs))
self.marionette.switch_to_window(new_tab)
self.assertEqual(self.marionette.current_window_handle, new_tab)
self.assertEqual(self.marionette.get_url(), self.empty_page)

View File

@ -75,7 +75,8 @@ skip-if = appname == 'fennec'
[test_window_close_content.py]
[test_window_position.py]
skip-if = appname == 'fennec'
[test_window_handles.py]
[test_window_handles_content.py]
[test_window_handles_chrome.py]
skip-if = appname == 'fennec'
[test_screenshot.py]

View File

@ -8,7 +8,7 @@
<title>Marionette New Tab Link</title>
</head>
<body>
<a href="about:blank" id="new-tab" target="_blank">Click me!</a>
<a href="about:blank" id="new-window" onClick='javascript:window.open("windowHandles.html", null, "location=1,toolbar=1");'>Click me!</a>
<a href="empty.html" id="new-tab" target="_blank">Click me!</a>
<a href="" id="new-window" onClick='javascript:window.open("empty.html", null, "location=1,toolbar=1");'>Click me!</a>
</body>
</html>