Bug 1140512 - Ensure FindBar communicates properly with content after remoteness change. r=mikedeboer

This commit is contained in:
Iaroslav (yarik) Sheptykin 2015-09-19 20:22:21 +02:00
parent f252d4ca30
commit 79d7095e90
5 changed files with 106 additions and 26 deletions

View File

@ -451,5 +451,31 @@ this.BrowserTestUtils = {
tab.ownerDocument.defaultView.gBrowser.removeTab(tab);
}
});
},
/**
* Version of EventUtils' `sendChar` function; it will synthesize a keypress
* event in a child process and returns a Promise that will result when the
* event was fired. Instead of a Window, a Browser object is required to be
* passed to this function.
*
* @param {String} char
* A character for the keypress event that is sent to the browser.
* @param {Browser} browser
* Browser element, must not be null.
*
* @returns {Promise}
* @resolves True if the keypress event was synthesized.
*/
sendChar(char, browser) {
return new Promise(resolve => {
let mm = browser.messageManager;
mm.addMessageListener("Test:SendCharDone", function charMsg(message) {
mm.removeMessageListener("Test:SendCharDone", charMsg);
resolve(message.data.sendCharResult);
});
mm.sendAsyncMessage("Test:SendChar", { char: char });
});
}
};

View File

@ -11,6 +11,10 @@ EventUtils.window = {};
EventUtils.parent = EventUtils.window;
EventUtils._EU_Ci = Components.interfaces;
EventUtils._EU_Cc = Components.classes;
// EventUtils' `sendChar` function relies on the navigator to synthetize events.
EventUtils.navigator = content.document.defaultView.navigator;
EventUtils.KeyboardEvent = content.document.defaultView.KeyboardEvent;
Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
addMessageListener("Test:SynthesizeMouse", (message) => {
@ -39,3 +43,8 @@ addMessageListener("Test:SynthesizeMouse", (message) => {
let result = EventUtils.synthesizeMouseAtPoint(left, top, data.event, content);
sendAsyncMessage("Test:SynthesizeMouseDone", { defaultPrevented: result });
});
addMessageListener("Test:SendChar", message => {
let result = EventUtils.sendChar(message.data.char, content);
sendAsyncMessage("Test:SendCharDone", { sendCharResult: result });
});

View File

@ -18,7 +18,6 @@ skip-if = e10s # Bug 1064580
[browser_f7_caret_browsing.js]
skip-if = e10s
[browser_findbar.js]
skip-if = e10s # Disabled for e10s: Bug ?????? - seems to be a timing issue with RemoteFinder.jsm messages coming later than the tests expect.
[browser_input_file_tooltips.js]
skip-if = e10s # Bug ?????? - test directly manipulates content (TypeError: doc.createElement is not a function)
[browser_isSynthetic.js]

View File

@ -2,6 +2,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
Components.utils.import("resource://gre/modules/Timer.jsm", this);
const TEST_PAGE_URI = "data:text/html;charset=utf-8,The letter s.";
/**
* Makes sure that the findbar hotkeys (' and /) event listeners
* are added to the system event group and do not get blocked
@ -11,7 +13,7 @@ add_task(function* test_hotkey_event_propagation() {
info("Ensure hotkeys are not affected by stopPropagation.");
// Opening new tab
let tab = yield promiseTestPageLoad();
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let browser = gBrowser.getBrowserForTab(tab);
let findbar = gBrowser.getFindBar();
@ -23,24 +25,29 @@ add_task(function* test_hotkey_event_propagation() {
is(findbar.hidden, true, "Findbar is hidden now.");
gBrowser.selectedTab = tab;
yield promiseFocus();
EventUtils.sendChar(key, browser.contentWindow);
yield BrowserTestUtils.sendChar(key, browser);
is(findbar.hidden, false, "Findbar should not be hidden.");
yield closeFindbarAndWait(findbar);
}
// Stop propagation for all keyboard events.
let window = browser.contentWindow;
let stopPropagation = function(e) { e.stopImmediatePropagation(); };
window.addEventListener("keydown", stopPropagation, true);
window.addEventListener("keypress", stopPropagation, true);
window.addEventListener("keyup", stopPropagation, true);
let frameScript = () => {
const stopPropagation = e => e.stopImmediatePropagation();
let window = content.document.defaultView;
window.removeEventListener("keydown", stopPropagation);
window.removeEventListener("keypress", stopPropagation);
window.removeEventListener("keyup", stopPropagation);
};
let mm = browser.messageManager;
mm.loadFrameScript("data:,(" + frameScript.toString() + ")();", false);
// Checking if findbar still appears when any hotkey is pressed.
for (let key of HOTKEYS) {
is(findbar.hidden, true, "Findbar is hidden now.");
gBrowser.selectedTab = tab;
yield promiseFocus();
EventUtils.sendChar(key, browser.contentWindow);
yield BrowserTestUtils.sendChar(key, browser);
is(findbar.hidden, false, "Findbar should not be hidden.");
yield closeFindbarAndWait(findbar);
}
@ -51,7 +58,7 @@ add_task(function* test_hotkey_event_propagation() {
add_task(function* test_not_found() {
info("Check correct 'Phrase not found' on new tab");
let tab = yield promiseTestPageLoad();
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
// Search for the first word.
yield promiseFindFinished("--- THIS SHOULD NEVER MATCH ---", false);
@ -63,7 +70,7 @@ add_task(function* test_not_found() {
});
add_task(function* test_found() {
let tab = yield promiseTestPageLoad();
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
// Search for a string that WILL be found, with 'Highlight All' on
yield promiseFindFinished("S", true);
@ -76,10 +83,10 @@ add_task(function* test_found() {
// Setting first findbar to case-sensitive mode should not affect
// new tab find bar.
add_task(function* test_tabwise_case_sensitive() {
let tab1 = yield promiseTestPageLoad();
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let findbar1 = gBrowser.getFindBar();
let tab2 = yield promiseTestPageLoad();
let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let findbar2 = gBrowser.getFindBar();
// Toggle case sensitivity for first findbar
@ -102,22 +109,33 @@ add_task(function* test_tabwise_case_sensitive() {
gBrowser.removeTab(tab2);
});
function promiseTestPageLoad() {
let deferred = Promise.defer();
/**
* Navigating from a web page (for example mozilla.org) to an internal page
* (like about:addons) might trigger a change of browser's remoteness.
* 'Remoteness change' means that rendering page content moves from child
* process into the parent process or the other way around.
* This test ensures that findbar properly handles such a change.
*/
add_task(function * test_reinitialization_at_remoteness_change() {
info("Ensure findbar re-initialization at remoteness change.");
let tab = gBrowser.selectedTab = gBrowser.addTab("data:text/html;charset=utf-8,The letter s.");
let browser = gBrowser.selectedBrowser;
browser.addEventListener("load", function listener() {
if (browser.currentURI.spec == "about:blank")
return;
info("Page loaded: " + browser.currentURI.spec);
browser.removeEventListener("load", listener, true);
// Load a remote page and trigger findbar construction.
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let browser = gBrowser.getBrowserForTab(tab);
let findbar = gBrowser.getFindBar();
deferred.resolve(tab);
}, true);
// Findbar should operate normally.
yield promiseFindFinished("s", false);
ok(!findbar._findStatusDesc.textContent, "Findbar status should be empty");
return deferred.promise;
}
gBrowser.updateBrowserRemoteness(browser, false);
// Findbar should keep operating normally.
yield promiseFindFinished("s", false);
ok(!findbar._findStatusDesc.textContent, "Findbar status should be empty");
yield BrowserTestUtils.removeTab(tab);
});
function promiseFindFinished(searchText, highlightOn) {
let deferred = Promise.defer();
@ -131,8 +149,17 @@ function promiseFindFinished(searchText, highlightOn) {
findbar._findField.value = searchText;
let resultListener;
// When highlighting is on the finder sends a second "FOUND" message after
// the search wraps. This causes timing problems with e10s. waitMore
// forces foundOrTimeout wait for the second "FOUND" message before
// resolving the promise.
let waitMore = highlightOn;
let findTimeout = setTimeout(() => foundOrTimedout(null), 2000);
let foundOrTimedout = function(aData) {
if (aData !== null && waitMore) {
waitMore = false;
return;
}
if (aData === null)
info("Result listener not called, timeout reached.");
clearTimeout(findTimeout);

View File

@ -373,12 +373,28 @@
// browser property
if (this.getAttribute("browserid"))
setTimeout(function(aSelf) { aSelf.browser = aSelf.browser; }, 0, this);
if (typeof gBrowser !== 'undefined')
gBrowser.tabContainer.addEventListener("TabRemotenessChange", this);
]]></constructor>
<destructor><![CDATA[
this.destroy();
]]></destructor>
<method name="handleEvent">
<parameter name="aEvent"/>
<body><![CDATA[
switch(aEvent.type) {
case "onRemotenessChange":
// Reinitializing browser to re-attach listeners.
this.browser._lastSearchString = this._findField.value;
this.browser = this.browser;
break;
}
]]></body>
</method>
<!-- This is necessary because the destructor isn't called when
we are removed from a document that is not destroyed. This
needs to be explicitly called in this case -->
@ -402,6 +418,9 @@
// Clear all timers that might still be running.
this._cancelTimers();
if (typeof gBrowser !== 'undefined')
gBrowser.tabContainer.removeEventListener("TabRemotenessChange", this);
]]></body>
</method>