summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/browser
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/tests/browser')
-rw-r--r--toolkit/content/tests/browser/.eslintrc.js7
-rw-r--r--toolkit/content/tests/browser/audio.oggbin0 -> 14290 bytes
-rw-r--r--toolkit/content/tests/browser/browser.ini75
-rw-r--r--toolkit/content/tests/browser/browser_audioCompeting.js115
-rw-r--r--toolkit/content/tests/browser/browser_audioCompeting_onlyForActiveAgent.js176
-rw-r--r--toolkit/content/tests/browser/browser_autoscroll_disabled.js67
-rw-r--r--toolkit/content/tests/browser/browser_block_autoplay_media.js87
-rw-r--r--toolkit/content/tests/browser/browser_bug1170531.js92
-rw-r--r--toolkit/content/tests/browser/browser_bug1198465.js75
-rw-r--r--toolkit/content/tests/browser/browser_bug295977_autoscroll_overflow.js214
-rw-r--r--toolkit/content/tests/browser/browser_bug451286.js152
-rw-r--r--toolkit/content/tests/browser/browser_bug594509.js9
-rw-r--r--toolkit/content/tests/browser/browser_bug982298.js70
-rw-r--r--toolkit/content/tests/browser/browser_contentTitle.js16
-rw-r--r--toolkit/content/tests/browser/browser_content_url_annotation.js73
-rw-r--r--toolkit/content/tests/browser/browser_crash_previous_frameloader.js108
-rw-r--r--toolkit/content/tests/browser/browser_default_image_filename.js45
-rw-r--r--toolkit/content/tests/browser/browser_f7_caret_browsing.js227
-rw-r--r--toolkit/content/tests/browser/browser_findbar.js249
-rw-r--r--toolkit/content/tests/browser/browser_isSynthetic.js72
-rw-r--r--toolkit/content/tests/browser/browser_keyevents_during_autoscrolling.js120
-rw-r--r--toolkit/content/tests/browser/browser_label_textlink.js38
-rw-r--r--toolkit/content/tests/browser/browser_mediaPlayback.js30
-rw-r--r--toolkit/content/tests/browser/browser_mediaPlayback_mute.js104
-rw-r--r--toolkit/content/tests/browser/browser_mediaPlayback_suspended.js191
-rw-r--r--toolkit/content/tests/browser/browser_mediaPlayback_suspended_multipleAudio.js311
-rw-r--r--toolkit/content/tests/browser/browser_mute.js16
-rw-r--r--toolkit/content/tests/browser/browser_mute2.js26
-rw-r--r--toolkit/content/tests/browser/browser_quickfind_editable.js47
-rw-r--r--toolkit/content/tests/browser/browser_saveImageURL.js68
-rw-r--r--toolkit/content/tests/browser/browser_save_resend_postdata.js145
-rw-r--r--toolkit/content/tests/browser/common/mockTransfer.js67
-rw-r--r--toolkit/content/tests/browser/data/post_form_inner.sjs31
-rw-r--r--toolkit/content/tests/browser/data/post_form_outer.sjs34
-rw-r--r--toolkit/content/tests/browser/empty.pngbin0 -> 14528 bytes
-rw-r--r--toolkit/content/tests/browser/file_contentTitle.html14
-rw-r--r--toolkit/content/tests/browser/file_mediaPlayback.html9
-rw-r--r--toolkit/content/tests/browser/file_mediaPlayback2.html12
-rw-r--r--toolkit/content/tests/browser/file_mediaPlaybackFrame.html2
-rw-r--r--toolkit/content/tests/browser/file_mediaPlaybackFrame2.html2
-rw-r--r--toolkit/content/tests/browser/file_multipleAudio.html19
-rw-r--r--toolkit/content/tests/browser/file_multiplePlayingAudio.html23
-rw-r--r--toolkit/content/tests/browser/file_redirect.html13
-rw-r--r--toolkit/content/tests/browser/file_redirect_to.html15
-rw-r--r--toolkit/content/tests/browser/head.js33
-rw-r--r--toolkit/content/tests/browser/image.jpgbin0 -> 24204 bytes
-rw-r--r--toolkit/content/tests/browser/image_page.html9
47 files changed, 3308 insertions, 0 deletions
diff --git a/toolkit/content/tests/browser/.eslintrc.js b/toolkit/content/tests/browser/.eslintrc.js
new file mode 100644
index 000000000..c764b133d
--- /dev/null
+++ b/toolkit/content/tests/browser/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ "extends": [
+ "../../../../testing/mochitest/browser.eslintrc.js"
+ ]
+};
diff --git a/toolkit/content/tests/browser/audio.ogg b/toolkit/content/tests/browser/audio.ogg
new file mode 100644
index 000000000..7f1833508
--- /dev/null
+++ b/toolkit/content/tests/browser/audio.ogg
Binary files differ
diff --git a/toolkit/content/tests/browser/browser.ini b/toolkit/content/tests/browser/browser.ini
new file mode 100644
index 000000000..278b2ffe0
--- /dev/null
+++ b/toolkit/content/tests/browser/browser.ini
@@ -0,0 +1,75 @@
+[DEFAULT]
+support-files =
+ head.js
+ file_contentTitle.html
+ audio.ogg
+
+[browser_audioCompeting.js]
+tags = audiochannel
+support-files =
+ file_multipleAudio.html
+[browser_audioCompeting_onlyForActiveAgent.js]
+tags = audiochannel
+support-files =
+ file_multiplePlayingAudio.html
+[browser_autoscroll_disabled.js]
+[browser_block_autoplay_media.js]
+tags = audiochannel
+support-files =
+ file_multipleAudio.html
+[browser_bug295977_autoscroll_overflow.js]
+[browser_bug451286.js]
+skip-if = !e10s
+[browser_bug594509.js]
+[browser_bug982298.js]
+[browser_bug1198465.js]
+[browser_contentTitle.js]
+[browser_crash_previous_frameloader.js]
+run-if = e10s && crashreporter
+[browser_default_image_filename.js]
+[browser_f7_caret_browsing.js]
+[browser_findbar.js]
+[browser_label_textlink.js]
+[browser_isSynthetic.js]
+support-files =
+ empty.png
+[browser_keyevents_during_autoscrolling.js]
+[browser_save_resend_postdata.js]
+support-files =
+ common/mockTransfer.js
+ data/post_form_inner.sjs
+ data/post_form_outer.sjs
+skip-if = e10s # Bug ?????? - test directly manipulates content (gBrowser.contentDocument.getElementById("postForm").submit();)
+[browser_content_url_annotation.js]
+skip-if = !e10s || !crashreporter
+support-files =
+ file_redirect.html
+ file_redirect_to.html
+[browser_bug1170531.js]
+[browser_mediaPlayback.js]
+tags = audiochannel
+support-files =
+ file_mediaPlayback.html
+ file_mediaPlaybackFrame.html
+[browser_mediaPlayback_mute.js]
+tags = audiochannel
+support-files =
+ file_mediaPlayback2.html
+ file_mediaPlaybackFrame2.html
+[browser_mediaPlayback_suspended.js]
+tags = audiochannel
+support-files =
+ file_mediaPlayback2.html
+[browser_mediaPlayback_suspended_multipleAudio.js]
+tags = audiochannel
+support-files =
+ file_multipleAudio.html
+[browser_mute.js]
+tags = audiochannel
+[browser_mute2.js]
+tags = audiochannel
+[browser_quickfind_editable.js]
+[browser_saveImageURL.js]
+support-files =
+ image.jpg
+ image_page.html
diff --git a/toolkit/content/tests/browser/browser_audioCompeting.js b/toolkit/content/tests/browser/browser_audioCompeting.js
new file mode 100644
index 000000000..7b6a76c1d
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_audioCompeting.js
@@ -0,0 +1,115 @@
+const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_multipleAudio.html";
+
+function* wait_for_tab_playing_event(tab, expectPlaying) {
+ if (tab.soundPlaying == expectPlaying) {
+ ok(true, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
+ } else {
+ yield BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
+ if (event.detail.changed.indexOf("soundplaying") >= 0) {
+ is(tab.soundPlaying, expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
+ return true;
+ }
+ return false;
+ });
+ }
+}
+
+function play_audio_from_invisible_tab () {
+ return new Promise(resolve => {
+ var autoPlay = content.document.getElementById('autoplay');
+ if (!autoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(autoPlay.paused, true, "Audio in tab 1 was paused by audio competing.");
+ autoPlay.play();
+ autoPlay.onpause = function() {
+ autoPlay.onpause = null;
+ ok(true, "Audio in tab 1 can't playback when other tab is playing in foreground.");
+ resolve();
+ };
+ });
+}
+
+function audio_should_keep_playing_even_go_to_background () {
+ var autoPlay = content.document.getElementById('autoplay');
+ if (!autoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(autoPlay.paused, false, "Audio in tab 2 is still playing in the background.");
+}
+
+function play_non_autoplay_audio () {
+ return new Promise(resolve => {
+ var autoPlay = content.document.getElementById('autoplay');
+ var nonAutoPlay = content.document.getElementById('nonautoplay');
+ if (!autoPlay || !nonAutoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(nonAutoPlay.paused, true, "Non-autoplay audio isn't started playing yet.");
+ nonAutoPlay.play();
+
+ nonAutoPlay.onplay = function() {
+ nonAutoPlay.onplay = null;
+ is(nonAutoPlay.paused, false, "Start Non-autoplay audio.");
+ is(autoPlay.paused, false, "Autoplay audio is still playing.");
+ resolve();
+ };
+ });
+}
+
+add_task(function* setup_test_preference() {
+ yield new Promise(resolve => {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["dom.audiochannel.audioCompeting", true],
+ ["dom.ipc.processCount", 1]
+ ]}, resolve);
+ });
+});
+
+add_task(function* cross_tabs_audio_competing () {
+ info("- open tab 1 in foreground -");
+ let tab1 = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser,
+ "about:blank");
+ tab1.linkedBrowser.loadURI(PAGE);
+ yield wait_for_tab_playing_event(tab1, true);
+
+ info("- open tab 2 in foreground -");
+ let tab2 = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser,
+ "about:blank");
+ tab2.linkedBrowser.loadURI(PAGE);
+ yield wait_for_tab_playing_event(tab1, false);
+
+ info("- open tab 3 in foreground -");
+ let tab3 = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser,
+ "about:blank");
+ yield ContentTask.spawn(tab2.linkedBrowser, null,
+ audio_should_keep_playing_even_go_to_background);
+
+ info("- play audio from background tab 1 -");
+ yield ContentTask.spawn(tab1.linkedBrowser, null,
+ play_audio_from_invisible_tab);
+
+ info("- remove tabs -");
+ yield BrowserTestUtils.removeTab(tab1);
+ yield BrowserTestUtils.removeTab(tab2);
+ yield BrowserTestUtils.removeTab(tab3);
+});
+
+add_task(function* within_one_tab_audio_competing () {
+ info("- open tab and play audio1 -");
+ let tab = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser,
+ "about:blank");
+ tab.linkedBrowser.loadURI(PAGE);
+ yield wait_for_tab_playing_event(tab, true);
+
+ info("- play audio2 in the same tab -");
+ yield ContentTask.spawn(tab.linkedBrowser, null,
+ play_non_autoplay_audio);
+
+ info("- remove tab -");
+ yield BrowserTestUtils.removeTab(tab);
+});
+
diff --git a/toolkit/content/tests/browser/browser_audioCompeting_onlyForActiveAgent.js b/toolkit/content/tests/browser/browser_audioCompeting_onlyForActiveAgent.js
new file mode 100644
index 000000000..31cd3f624
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_audioCompeting_onlyForActiveAgent.js
@@ -0,0 +1,176 @@
+const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_multiplePlayingAudio.html";
+
+var SuspendedType = {
+ NONE_SUSPENDED : 0,
+ SUSPENDED_PAUSE : 1,
+ SUSPENDED_BLOCK : 2,
+ SUSPENDED_PAUSE_DISPOSABLE : 3
+};
+
+function wait_for_event(browser, event) {
+ return BrowserTestUtils.waitForEvent(browser, event, false, (event) => {
+ is(event.originalTarget, browser, "Event must be dispatched to correct browser.");
+ return true;
+ });
+}
+
+function check_all_audio_suspended(suspendedType) {
+ var audio1 = content.document.getElementById("audio1");
+ var audio2 = content.document.getElementById("audio2");
+ if (!audio1 || !audio2) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(audio1.computedSuspended, suspendedType,
+ "The suspeded state of audio1 is correct.");
+ is(audio2.computedSuspended, suspendedType,
+ "The suspeded state of audio2 is correct.");
+}
+
+function check_audio1_suspended(suspendedType) {
+ var audio1 = content.document.getElementById("audio1");
+ if (!audio1) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(audio1.computedSuspended, suspendedType,
+ "The suspeded state of audio1 is correct.");
+}
+
+function check_audio2_suspended(suspendedType) {
+ var audio2 = content.document.getElementById("audio2");
+ if (!audio2) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(audio2.computedSuspended, suspendedType,
+ "The suspeded state of audio2 is correct.");
+}
+
+function check_all_audio_pause_state(expectedPauseState) {
+ var audio1 = content.document.getElementById("audio1");
+ var audio2 = content.document.getElementById("audio2");
+ if (!audio1 | !audio2) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(audio1.paused, expectedPauseState,
+ "The pause state of audio1 is correct.");
+ is(audio2.paused, expectedPauseState,
+ "The pause state of audio2 is correct.");
+}
+
+function check_audio1_pause_state(expectedPauseState) {
+ var audio1 = content.document.getElementById("audio1");
+ if (!audio1) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(audio1.paused, expectedPauseState,
+ "The pause state of audio1 is correct.");
+}
+
+function check_audio2_pause_state(expectedPauseState) {
+ var audio2 = content.document.getElementById("audio2");
+ if (!audio2) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(audio2.paused, expectedPauseState,
+ "The pause state of audio2 is correct.");
+}
+
+function play_audio1_from_page() {
+ var audio1 = content.document.getElementById("audio1");
+ if (!audio1) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(audio1.paused, true, "Audio1 is paused.");
+ audio1.play();
+ return new Promise(resolve => {
+ audio1.onplay = function() {
+ audio1.onplay = null;
+ ok(true, "Audio1 started playing.");
+ resolve();
+ }
+ });
+}
+
+function stop_audio1_from_page() {
+ var audio1 = content.document.getElementById("audio1");
+ if (!audio1) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(audio1.paused, false, "Audio1 is playing.");
+ audio1.pause();
+ return new Promise(resolve => {
+ audio1.onpause = function() {
+ audio1.onpause = null;
+ ok(true, "Audio1 stopped playing.");
+ resolve();
+ }
+ });
+}
+
+function* audio_competing_for_active_agent(url, browser) {
+ browser.loadURI(url);
+
+ info("- page should have playing audio -");
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+
+ info("- the default suspended state of all audio should be non-suspened -");
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_all_audio_suspended);
+
+ info("- only pause playing audio in the page -");
+ browser.pauseMedia(true /* disposable */);
+
+ info("- page shouldn't have any playing audio -");
+ yield wait_for_event(browser, "DOMAudioPlaybackStopped");
+ yield ContentTask.spawn(browser, true /* expect for pause */,
+ check_all_audio_pause_state);
+ yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE,
+ check_all_audio_suspended);
+
+ info("- resume audio1 from page -");
+ yield ContentTask.spawn(browser, null,
+ play_audio1_from_page);
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_audio1_suspended);
+
+ info("- audio2 should still be suspended -");
+ yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE,
+ check_audio2_suspended);
+ yield ContentTask.spawn(browser, true /* expect for pause */,
+ check_audio2_pause_state);
+
+ info("- stop audio1 from page -");
+ yield ContentTask.spawn(browser, null,
+ stop_audio1_from_page);
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_audio1_suspended);
+
+ info("- audio2 should still be suspended -");
+ yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE,
+ check_audio2_suspended);
+ yield ContentTask.spawn(browser, true /* expect for pause */,
+ check_audio2_pause_state);
+
+}
+
+add_task(function* setup_test_preference() {
+ yield SpecialPowers.pushPrefEnv({"set": [
+ ["media.useAudioChannelService.testing", true],
+ ["dom.audiochannel.audioCompeting", true],
+ ["dom.audiochannel.audioCompeting.allAgents", true]
+ ]});
+});
+
+add_task(function* test_suspended_pause_disposable() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank"
+ }, audio_competing_for_active_agent.bind(this, PAGE));
+});
diff --git a/toolkit/content/tests/browser/browser_autoscroll_disabled.js b/toolkit/content/tests/browser/browser_autoscroll_disabled.js
new file mode 100644
index 000000000..07c6174ab
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_autoscroll_disabled.js
@@ -0,0 +1,67 @@
+add_task(function* ()
+{
+ const kPrefName_AutoScroll = "general.autoScroll";
+ Services.prefs.setBoolPref(kPrefName_AutoScroll, false);
+
+ let dataUri = 'data:text/html,<html><body id="i" style="overflow-y: scroll"><div style="height: 2000px"></div>\
+ <iframe id="iframe" style="display: none;"></iframe>\
+</body></html>';
+
+ let loadedPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ gBrowser.loadURI(dataUri);
+ yield loadedPromise;
+
+ yield BrowserTestUtils.synthesizeMouse("#i", 50, 50, { button: 1 },
+ gBrowser.selectedBrowser);
+
+ yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () {
+ var iframe = content.document.getElementById("iframe");
+
+ if (iframe) {
+ var e = new iframe.contentWindow.PageTransitionEvent("pagehide",
+ { bubbles: true,
+ cancelable: true,
+ persisted: false });
+ iframe.contentDocument.dispatchEvent(e);
+ iframe.contentDocument.documentElement.dispatchEvent(e);
+ }
+ });
+
+ yield BrowserTestUtils.synthesizeMouse("#i", 100, 100,
+ { type: "mousemove", clickCount: "0" },
+ gBrowser.selectedBrowser);
+
+ // If scrolling didn't work, we wouldn't do any redraws and thus time out, so
+ // request and force redraws to get the chance to check for scrolling at all.
+ yield new Promise(resolve => window.requestAnimationFrame(resolve));
+
+ let msg = yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () {
+ // Skip the first animation frame callback as it's the same callback that
+ // the browser uses to kick off the scrolling.
+ return new Promise(resolve => {
+ function checkScroll() {
+ let msg = "";
+ let elem = content.document.getElementById('i');
+ if (elem.scrollTop != 0) {
+ msg += "element should not have scrolled vertically";
+ }
+ if (elem.scrollLeft != 0) {
+ msg += "element should not have scrolled horizontally";
+ }
+
+ resolve(msg);
+ }
+
+ content.requestAnimationFrame(checkScroll);
+ });
+ });
+
+ ok(!msg, "element scroll " + msg);
+
+ // restore the changed prefs
+ if (Services.prefs.prefHasUserValue(kPrefName_AutoScroll))
+ Services.prefs.clearUserPref(kPrefName_AutoScroll);
+
+ // wait for focus to fix a failure in the next test if the latter runs too soon.
+ yield SimpleTest.promiseFocus();
+});
diff --git a/toolkit/content/tests/browser/browser_block_autoplay_media.js b/toolkit/content/tests/browser/browser_block_autoplay_media.js
new file mode 100644
index 000000000..3b2a309b9
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_block_autoplay_media.js
@@ -0,0 +1,87 @@
+const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_multipleAudio.html";
+
+var SuspendedType = {
+ NONE_SUSPENDED : 0,
+ SUSPENDED_PAUSE : 1,
+ SUSPENDED_BLOCK : 2,
+ SUSPENDED_PAUSE_DISPOSABLE : 3
+};
+
+function* wait_for_tab_playing_event(tab, expectPlaying) {
+ if (tab.soundPlaying == expectPlaying) {
+ ok(true, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
+ } else {
+ yield BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
+ if (event.detail.changed.indexOf("soundplaying") >= 0) {
+ is(tab.soundPlaying, expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
+ return true;
+ }
+ return false;
+ });
+ }
+}
+
+function check_audio_suspended(suspendedType) {
+ var autoPlay = content.document.getElementById('autoplay');
+ if (!autoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(autoPlay.computedSuspended, suspendedType,
+ "The suspeded state of autoplay audio is correct.");
+}
+
+add_task(function* setup_test_preference() {
+ yield new Promise(resolve => {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["media.useAudioChannelService.testing", true],
+ ["media.block-autoplay-until-in-foreground", true]
+ ]}, resolve);
+ });
+});
+
+add_task(function* block_autoplay_media() {
+ info("- open new background tab1 -");
+ let tab1 = window.gBrowser.addTab("about:blank");
+ tab1.linkedBrowser.loadURI(PAGE);
+ yield BrowserTestUtils.browserLoaded(tab1.linkedBrowser);
+
+ info("- should block autoplay media for non-visited tab1 -");
+ yield ContentTask.spawn(tab1.linkedBrowser, SuspendedType.SUSPENDED_BLOCK,
+ check_audio_suspended);
+
+ info("- open new background tab2 -");
+ let tab2 = window.gBrowser.addTab("about:blank");
+ tab2.linkedBrowser.loadURI(PAGE);
+ yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser);
+
+ info("- should block autoplay for non-visited tab2 -");
+ yield ContentTask.spawn(tab2.linkedBrowser, SuspendedType.SUSPENDED_BLOCK,
+ check_audio_suspended);
+
+ info("- select tab1 as foreground tab -");
+ yield BrowserTestUtils.switchTab(window.gBrowser, tab1);
+
+ info("- media should be unblocked because the tab was visited -");
+ yield wait_for_tab_playing_event(tab1, true);
+ yield ContentTask.spawn(tab1.linkedBrowser, SuspendedType.NONE_SUSPENDED,
+ check_audio_suspended);
+
+ info("- open another new foreground tab3 -");
+ let tab3 = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser,
+ "about:blank");
+ info("- should still play media from tab1 -");
+ yield wait_for_tab_playing_event(tab1, true);
+ yield ContentTask.spawn(tab1.linkedBrowser, SuspendedType.NONE_SUSPENDED,
+ check_audio_suspended);
+
+ info("- should still block media from tab2 -");
+ yield wait_for_tab_playing_event(tab2, false);
+ yield ContentTask.spawn(tab2.linkedBrowser, SuspendedType.SUSPENDED_BLOCK,
+ check_audio_suspended);
+
+ info("- remove tabs -");
+ yield BrowserTestUtils.removeTab(tab1);
+ yield BrowserTestUtils.removeTab(tab2);
+ yield BrowserTestUtils.removeTab(tab3);
+});
diff --git a/toolkit/content/tests/browser/browser_bug1170531.js b/toolkit/content/tests/browser/browser_bug1170531.js
new file mode 100644
index 000000000..49df5661a
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_bug1170531.js
@@ -0,0 +1,92 @@
+// Test for bug 1170531
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1170531
+
+add_task(function* () {
+ // Get a bunch of DOM nodes
+ let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).
+ getInterface(Ci.nsIDOMWindowUtils);
+
+ let editMenu = document.getElementById("edit-menu");
+ let menubar = editMenu.parentNode;
+ let menuPopup = editMenu.menupopup;
+ let editMenuIndex = -1;
+ for (let i = 0; i < menubar.children.length; i++) {
+ if (menubar.children[i] === editMenu) {
+ editMenuIndex = i;
+ break;
+ }
+ }
+
+ let closeMenu = function(aCallback) {
+ if (OS.Constants.Sys.Name == "Darwin") {
+ executeSoon(aCallback);
+ return;
+ }
+
+ menuPopup.addEventListener("popuphidden", function onPopupHidden() {
+ menuPopup.removeEventListener("popuphidden", onPopupHidden, false);
+ executeSoon(aCallback);
+ }, false);
+
+ executeSoon(function() {
+ editMenu.open = false;
+ });
+ };
+
+ let openMenu = function(aCallback) {
+ if (OS.Constants.Sys.Name == "Darwin") {
+ goUpdateGlobalEditMenuItems();
+ // On OSX, we have a native menu, so it has to be updated. In single process browsers,
+ // this happens synchronously, but in e10s, we have to wait for the main thread
+ // to deal with it for us. 1 second should be plenty of time.
+ setTimeout(aCallback, 1000);
+ return;
+ }
+
+ menuPopup.addEventListener("popupshown", function onPopupShown() {
+ menuPopup.removeEventListener("popupshown", onPopupShown, false);
+ executeSoon(aCallback);
+ }, false);
+
+ executeSoon(function() {
+ editMenu.open = true;
+ });
+ };
+
+ yield BrowserTestUtils.withNewTab({ gBrowser: gBrowser, url: "about:blank" }, function* (browser) {
+ let menu_cut_disabled, menu_copy_disabled;
+
+ yield BrowserTestUtils.loadURI(browser, "data:text/html,<div>hello!</div>");
+ yield BrowserTestUtils.browserLoaded(browser);
+ browser.focus();
+ yield new Promise(resolve => waitForFocus(resolve, window));
+ yield new Promise(openMenu);
+ menu_cut_disabled = menuPopup.querySelector("#menu_cut").getAttribute('disabled') == "true";
+ is(menu_cut_disabled, false, "menu_cut should be enabled");
+ menu_copy_disabled = menuPopup.querySelector("#menu_copy").getAttribute('disabled') == "true";
+ is(menu_copy_disabled, false, "menu_copy should be enabled");
+ yield new Promise(closeMenu);
+
+ yield BrowserTestUtils.loadURI(browser, "data:text/html,<div contentEditable='true'>hello!</div>");
+ yield BrowserTestUtils.browserLoaded(browser);
+ browser.focus();
+ yield new Promise(resolve => waitForFocus(resolve, window));
+ yield new Promise(openMenu);
+ menu_cut_disabled = menuPopup.querySelector("#menu_cut").getAttribute('disabled') == "true";
+ is(menu_cut_disabled, false, "menu_cut should be enabled");
+ menu_copy_disabled = menuPopup.querySelector("#menu_copy").getAttribute('disabled') == "true";
+ is(menu_copy_disabled, false, "menu_copy should be enabled");
+ yield new Promise(closeMenu);
+
+ yield BrowserTestUtils.loadURI(browser, "about:preferences");
+ yield BrowserTestUtils.browserLoaded(browser);
+ browser.focus();
+ yield new Promise(resolve => waitForFocus(resolve, window));
+ yield new Promise(openMenu);
+ menu_cut_disabled = menuPopup.querySelector("#menu_cut").getAttribute('disabled') == "true";
+ is(menu_cut_disabled, true, "menu_cut should be disabled");
+ menu_copy_disabled = menuPopup.querySelector("#menu_copy").getAttribute('disabled') == "true";
+ is(menu_copy_disabled, true, "menu_copy should be disabled");
+ yield new Promise(closeMenu);
+ });
+});
diff --git a/toolkit/content/tests/browser/browser_bug1198465.js b/toolkit/content/tests/browser/browser_bug1198465.js
new file mode 100644
index 000000000..a9cc83e12
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_bug1198465.js
@@ -0,0 +1,75 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var kPrefName = "accessibility.typeaheadfind.prefillwithselection";
+var kEmptyURI = "data:text/html,";
+
+// This pref is false by default in OSX; ensure the test still works there.
+Services.prefs.setBoolPref(kPrefName, true);
+
+registerCleanupFunction(function() {
+ Services.prefs.clearUserPref(kPrefName);
+});
+
+add_task(function* () {
+ let aTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, kEmptyURI);
+ ok(!gFindBarInitialized, "findbar isn't initialized yet");
+
+ // Note: the use case here is when the user types directly in the findbar
+ // _before_ it's prefilled with a text selection in the page.
+
+ // So `yield BrowserTestUtils.sendChar()` can't be used here:
+ // - synthesizing a key in the browser won't actually send it to the
+ // findbar; the findbar isn't part of the browser content.
+ // - we need to _not_ wait for _startFindDeferred to be resolved; yielding
+ // a synthesized keypress on the browser implicitely happens after the
+ // browser has dispatched its return message with the prefill value for
+ // the findbar, which essentially nulls these tests.
+
+ let findBar = gFindBar;
+ is(findBar._findField.value, "", "findbar is empty");
+
+ // Test 1
+ // Any input in the findbar should erase a previous search.
+
+ findBar._findField.value = "xy";
+ findBar.startFind();
+ is(findBar._findField.value, "xy", "findbar should have xy initial query");
+ is(findBar._findField.mInputField,
+ document.activeElement,
+ "findbar is now focused");
+
+ EventUtils.sendChar("z", window);
+ is(findBar._findField.value, "z", "z erases xy");
+
+ findBar._findField.value = "";
+ ok(!findBar._findField.value, "erase findbar after first test");
+
+ // Test 2
+ // Prefilling the findbar should be ignored if a search has been run.
+
+ findBar.startFind();
+ ok(findBar._startFindDeferred, "prefilled value hasn't been fetched yet");
+ is(findBar._findField.mInputField,
+ document.activeElement,
+ "findbar is still focused");
+
+ EventUtils.sendChar("a", window);
+ EventUtils.sendChar("b", window);
+ is(findBar._findField.value, "ab", "initial ab typed in the findbar");
+
+ // This resolves _startFindDeferred if it's still pending; let's just skip
+ // over waiting for the browser's return message that should do this as it
+ // doesn't really matter.
+ findBar.onCurrentSelection("foo", true);
+ ok(!findBar._startFindDeferred, "prefilled value fetched");
+ is(findBar._findField.value, "ab", "ab kept instead of prefill value");
+
+ EventUtils.sendChar("c", window);
+ is(findBar._findField.value, "abc", "c is appended after ab");
+
+ // Clear the findField value to make the test run successfully
+ // for multiple runs in the same browser session.
+ findBar._findField.value = "";
+ yield BrowserTestUtils.removeTab(aTab);
+});
diff --git a/toolkit/content/tests/browser/browser_bug295977_autoscroll_overflow.js b/toolkit/content/tests/browser/browser_bug295977_autoscroll_overflow.js
new file mode 100644
index 000000000..958afc868
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_bug295977_autoscroll_overflow.js
@@ -0,0 +1,214 @@
+requestLongerTimeout(2);
+add_task(function* ()
+{
+ function pushPref(name, value) {
+ return new Promise(resolve => SpecialPowers.pushPrefEnv({"set": [[name, value]]}, resolve));
+ }
+
+ yield pushPref("general.autoScroll", true);
+
+ const expectScrollNone = 0;
+ const expectScrollVert = 1;
+ const expectScrollHori = 2;
+ const expectScrollBoth = 3;
+
+ var allTests = [
+ {dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body><style type="text/css">div { display: inline-block; }</style>\
+ <div id="a" style="width: 100px; height: 100px; overflow: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
+ <div id="b" style="width: 100px; height: 100px; overflow: auto;"><div style="width: 200px; height: 200px;"></div></div>\
+ <div id="c" style="width: 100px; height: 100px; overflow-x: auto; overflow-y: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
+ <div id="d" style="width: 100px; height: 100px; overflow-y: auto; overflow-x: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
+ <select id="e" style="width: 100px; height: 100px;" multiple="multiple"><option>aaaaaaaaaaaaaaaaaaaaaaaa</option><option>a</option><option>a</option>\
+ <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option>\
+ <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option></select>\
+ <select id="f" style="width: 100px; height: 100px;"><option>a</option><option>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</option><option>a</option>\
+ <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option>\
+ <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option></select>\
+ <div id="g" style="width: 99px; height: 99px; border: 10px solid black; margin: 10px; overflow: auto;"><div style="width: 100px; height: 100px;"></div></div>\
+ <div id="h" style="width: 100px; height: 100px; overflow: -moz-hidden-unscrollable;"><div style="width: 200px; height: 200px;"></div></div>\
+ <iframe id="iframe" style="display: none;"></iframe>\
+ </body></html>'},
+ {elem: 'a', expected: expectScrollNone},
+ {elem: 'b', expected: expectScrollBoth},
+ {elem: 'c', expected: expectScrollHori},
+ {elem: 'd', expected: expectScrollVert},
+ {elem: 'e', expected: expectScrollVert},
+ {elem: 'f', expected: expectScrollNone},
+ {elem: 'g', expected: expectScrollBoth},
+ {elem: 'h', expected: expectScrollNone},
+ {dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body id="i" style="overflow-y: scroll"><div style="height: 2000px"></div>\
+ <iframe id="iframe" style="display: none;"></iframe>\
+ </body></html>'},
+ {elem: 'i', expected: expectScrollVert}, // bug 695121
+ {dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><style>html, body { width: 100%; height: 100%; overflow-x: hidden; overflow-y: scroll; }</style>\
+ <body id="j"><div style="height: 2000px"></div>\
+ <iframe id="iframe" style="display: none;"></iframe>\
+ </body></html>'},
+ {elem: 'j', expected: expectScrollVert}, // bug 914251
+ {dataUri: 'data:text/html,<html><head><meta charset="utf-8">\
+<style>\
+body > div {scroll-behavior: smooth;width: 300px;height: 300px;overflow: scroll;}\
+body > div > div {width: 1000px;height: 1000px;}\
+</style>\
+</head><body><div id="t"><div></div></div></body></html>'},
+ {elem: 't', expected: expectScrollBoth}, // bug 1308775
+ {dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body>\
+<div id="k" style="height: 150px; width: 200px; overflow: scroll; border: 1px solid black;">\
+<iframe style="height: 200px; width: 300px;"></iframe>\
+</div>\
+<div id="l" style="height: 150px; width: 300px; overflow: scroll; border: 1px dashed black;">\
+<iframe style="height: 200px; width: 200px;" src="data:text/html,<div style=\'border: 5px solid blue; height: 200%; width: 200%;\'></div>"></iframe>\
+</div>\
+<iframe id="m"></iframe>\
+<div style="height: 200%; border: 5px dashed black;">filler to make document overflow: scroll;</div>\
+</body></html>'},
+ {elem: 'k', expected: expectScrollBoth},
+ {elem: 'k', expected: expectScrollNone, testwindow: true},
+ {elem: 'l', expected: expectScrollNone},
+ {elem: 'm', expected: expectScrollVert, testwindow: true},
+ {dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body>\
+<img width="100" height="100" alt="image map" usemap="%23planetmap">\
+<map name="planetmap">\
+ <area id="n" shape="rect" coords="0,0,100,100" href="javascript:void(null)">\
+</map>\
+<a href="javascript:void(null)" id="o" style="width: 100px; height: 100px; border: 1px solid black; display: inline-block; vertical-align: top;">link</a>\
+<input id="p" style="width: 100px; height: 100px; vertical-align: top;">\
+<textarea id="q" style="width: 100px; height: 100px; vertical-align: top;"></textarea>\
+<div style="height: 200%; border: 1px solid black;"></div>\
+</body></html>'},
+ {elem: 'n', expected: expectScrollNone, testwindow: true},
+ {elem: 'o', expected: expectScrollNone, testwindow: true},
+ {elem: 'p', expected: expectScrollVert, testwindow: true, middlemousepastepref: false},
+ {elem: 'q', expected: expectScrollVert, testwindow: true, middlemousepastepref: false},
+ {dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body>\
+<input id="r" style="width: 100px; height: 100px; vertical-align: top;">\
+<textarea id="s" style="width: 100px; height: 100px; vertical-align: top;"></textarea>\
+<div style="height: 200%; border: 1px solid black;"></div>\
+</body></html>'},
+ {elem: 'r', expected: expectScrollNone, testwindow: true, middlemousepastepref: true},
+ {elem: 's', expected: expectScrollNone, testwindow: true, middlemousepastepref: true}
+ ];
+
+ for (let test of allTests) {
+ if (test.dataUri) {
+ let loadedPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ gBrowser.loadURI(test.dataUri);
+ yield loadedPromise;
+ continue;
+ }
+
+ let prefsChanged = (test.middlemousepastepref == false || test.middlemousepastepref == true);
+ if (prefsChanged) {
+ yield pushPref("middlemouse.paste", test.middlemousepastepref);
+ }
+
+ yield BrowserTestUtils.synthesizeMouse("#" + test.elem, 50, 80, { button: 1 },
+ gBrowser.selectedBrowser);
+
+ // This ensures bug 605127 is fixed: pagehide in an unrelated document
+ // should not cancel the autoscroll.
+ yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () {
+ var iframe = content.document.getElementById("iframe");
+
+ if (iframe) {
+ var e = new iframe.contentWindow.PageTransitionEvent("pagehide",
+ { bubbles: true,
+ cancelable: true,
+ persisted: false });
+ iframe.contentDocument.dispatchEvent(e);
+ iframe.contentDocument.documentElement.dispatchEvent(e);
+ }
+ });
+
+ is(document.activeElement, gBrowser.selectedBrowser, "Browser still focused after autoscroll started");
+
+ yield BrowserTestUtils.synthesizeMouse("#" + test.elem, 100, 100,
+ { type: "mousemove", clickCount: "0" },
+ gBrowser.selectedBrowser);
+
+ if (prefsChanged) {
+ yield new Promise(resolve => SpecialPowers.popPrefEnv(resolve));
+ }
+
+ // Start checking for the scroll.
+ let firstTimestamp = undefined;
+ let timeCompensation;
+ do {
+ let timestamp = yield new Promise(resolve => window.requestAnimationFrame(resolve));
+ if (firstTimestamp === undefined) {
+ firstTimestamp = timestamp;
+ }
+
+ // This value is calculated similarly to the value of the same name in
+ // ClickEventHandler.autoscrollLoop, except here it's cumulative across
+ // all frames after the first one instead of being based only on the
+ // current frame.
+ timeCompensation = (timestamp - firstTimestamp) / 20;
+ info("timestamp=" + timestamp + " firstTimestamp=" + firstTimestamp +
+ " timeCompensation=" + timeCompensation);
+
+ // Try to wait until enough time has passed to allow the scroll to happen.
+ // autoscrollLoop incrementally scrolls during each animation frame, but
+ // due to how its calculations work, when a frame is very close to the
+ // previous frame, no scrolling may actually occur during that frame.
+ // After 100ms's worth of frames, timeCompensation will be 1, making it
+ // more likely that the accumulated scroll in autoscrollLoop will be >= 1,
+ // although it also depends on acceleration, which here in this test
+ // should be > 1 due to how it synthesizes mouse events below.
+ } while (timeCompensation < 5);
+
+ // Close the autoscroll popup by synthesizing Esc.
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+ let scrollVert = test.expected & expectScrollVert;
+ let scrollHori = test.expected & expectScrollHori;
+
+ yield ContentTask.spawn(gBrowser.selectedBrowser,
+ { scrollVert : scrollVert,
+ scrollHori: scrollHori,
+ elemid : test.elem,
+ checkWindow: test.testwindow },
+ function* (args) {
+ let msg = "";
+ if (args.checkWindow) {
+ if (!((args.scrollVert && content.scrollY > 0) ||
+ (!args.scrollVert && content.scrollY == 0))) {
+ msg += "Failed: ";
+ }
+ msg += 'Window for ' + args.elemid + ' should' + (args.scrollVert ? '' : ' not') + ' have scrolled vertically\n';
+
+ if (!((args.scrollHori && content.scrollX > 0) ||
+ (!args.scrollHori && content.scrollX == 0))) {
+ msg += "Failed: ";
+ }
+ msg += ' Window for ' + args.elemid + ' should' + (args.scrollHori ? '' : ' not') + ' have scrolled horizontally\n';
+ } else {
+ let elem = content.document.getElementById(args.elemid);
+ if (!((args.scrollVert && elem.scrollTop > 0) ||
+ (!args.scrollVert && elem.scrollTop == 0))) {
+ msg += "Failed: ";
+ }
+ msg += ' ' + args.elemid + ' should' + (args.scrollVert ? '' : ' not') + ' have scrolled vertically\n';
+ if (!((args.scrollHori && elem.scrollLeft > 0) ||
+ (!args.scrollHori && elem.scrollLeft == 0))) {
+ msg += "Failed: ";
+ }
+ msg += args.elemid + ' should' + (args.scrollHori ? '' : ' not') + ' have scrolled horizontally';
+ }
+
+ Assert.ok(msg.indexOf("Failed") == -1, msg);
+ }
+ );
+
+ // Before continuing the test, we need to ensure that the IPC
+ // message that stops autoscrolling has had time to arrive.
+ yield new Promise(resolve => executeSoon(resolve));
+ }
+
+ // remove 2 tabs that were opened by middle-click on links
+ while (gBrowser.visibleTabs.length > 1) {
+ gBrowser.removeTab(gBrowser.visibleTabs[gBrowser.visibleTabs.length - 1]);
+ }
+
+ // wait for focus to fix a failure in the next test if the latter runs too soon.
+ yield SimpleTest.promiseFocus();
+});
diff --git a/toolkit/content/tests/browser/browser_bug451286.js b/toolkit/content/tests/browser/browser_bug451286.js
new file mode 100644
index 000000000..a5dadeb84
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_bug451286.js
@@ -0,0 +1,152 @@
+Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js", this);
+
+add_task(function*() {
+ const SEARCH_TEXT = "text";
+ const DATAURI = "data:text/html," + SEARCH_TEXT;
+
+ // Bug 451286. An iframe that should be highlighted
+ let visible = "<iframe id='visible' src='" + DATAURI + "'></iframe>";
+
+ // Bug 493658. An invisible iframe that shouldn't interfere with
+ // highlighting matches lying after it in the document
+ let invisible = "<iframe id='invisible' style='display: none;' " +
+ "src='" + DATAURI + "'></iframe>";
+
+ let uri = DATAURI + invisible + SEARCH_TEXT + visible + SEARCH_TEXT;
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, uri);
+ let contentRect = tab.linkedBrowser.getBoundingClientRect();
+ let noHighlightSnapshot = snapshotRect(window, contentRect);
+ ok(noHighlightSnapshot, "Got noHighlightSnapshot");
+
+ yield openFindBarAndWait();
+ gFindBar._findField.value = SEARCH_TEXT;
+ yield findAgainAndWait();
+ var matchCase = gFindBar.getElement("find-case-sensitive");
+ if (matchCase.checked)
+ matchCase.doCommand();
+
+ // Turn on highlighting
+ yield toggleHighlightAndWait(true);
+ yield closeFindBarAndWait();
+
+ // Take snapshot of highlighting
+ let findSnapshot = snapshotRect(window, contentRect);
+ ok(findSnapshot, "Got findSnapshot");
+
+ // Now, remove the highlighting, and take a snapshot to compare
+ // to our original state
+ yield openFindBarAndWait();
+ yield toggleHighlightAndWait(false);
+ yield closeFindBarAndWait();
+
+ let unhighlightSnapshot = snapshotRect(window, contentRect);
+ ok(unhighlightSnapshot, "Got unhighlightSnapshot");
+
+ // Select the matches that should have been highlighted manually
+ yield ContentTask.spawn(tab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let win = doc.defaultView;
+
+ // Create a manual highlight in the visible iframe to test bug 451286
+ let iframe = doc.getElementById("visible");
+ let ifBody = iframe.contentDocument.body;
+ let range = iframe.contentDocument.createRange();
+ range.selectNodeContents(ifBody.childNodes[0]);
+ let ifWindow = iframe.contentWindow;
+ let ifDocShell = ifWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell);
+
+ let ifController = ifDocShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsISelectionDisplay)
+ .QueryInterface(Ci.nsISelectionController);
+
+ let frameFindSelection =
+ ifController.getSelection(ifController.SELECTION_FIND);
+ frameFindSelection.addRange(range);
+
+ // Create manual highlights in the main document (the matches that lie
+ // before/after the iframes
+ let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell);
+
+ let controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsISelectionDisplay)
+ .QueryInterface(Ci.nsISelectionController);
+
+ let docFindSelection =
+ controller.getSelection(ifController.SELECTION_FIND);
+
+ range = doc.createRange();
+ range.selectNodeContents(doc.body.childNodes[0]);
+ docFindSelection.addRange(range);
+ range = doc.createRange();
+ range.selectNodeContents(doc.body.childNodes[2]);
+ docFindSelection.addRange(range);
+ range = doc.createRange();
+ range.selectNodeContents(doc.body.childNodes[4]);
+ docFindSelection.addRange(range);
+ });
+
+ // Take snapshot of manual highlighting
+ let manualSnapshot = snapshotRect(window, contentRect);
+ ok(manualSnapshot, "Got manualSnapshot");
+
+ // Test 1: Were the matches in iframe correctly highlighted?
+ let res = compareSnapshots(findSnapshot, manualSnapshot, true);
+ ok(res[0], "Matches found in iframe correctly highlighted");
+
+ // Test 2: Were the matches in iframe correctly unhighlighted?
+ res = compareSnapshots(noHighlightSnapshot, unhighlightSnapshot, true);
+ ok(res[0], "Highlighting in iframe correctly removed");
+
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+function toggleHighlightAndWait(shouldHighlight) {
+ return new Promise((resolve) => {
+ let listener = {
+ onFindResult() {},
+ onHighlightFinished() {
+ gFindBar.browser.finder.removeResultListener(listener);
+ resolve();
+ },
+ onMatchesCountResult() {}
+ };
+ gFindBar.browser.finder.addResultListener(listener);
+ gFindBar.toggleHighlight(shouldHighlight);
+ });
+}
+
+function findAgainAndWait() {
+ return new Promise(resolve => {
+ let listener = {
+ onFindResult() {
+ gFindBar.browser.finder.removeResultListener(listener);
+ resolve();
+ },
+ onHighlightFinished() {},
+ onMatchesCountResult() {}
+ };
+ gFindBar.browser.finder.addResultListener(listener);
+ gFindBar.onFindAgainCommand();
+ });
+}
+
+function* openFindBarAndWait() {
+ let awaitTransitionEnd = BrowserTestUtils.waitForEvent(gFindBar, "transitionend");
+ gFindBar.open();
+ yield awaitTransitionEnd;
+}
+
+// This test is comparing snapshots. It is necessary to wait for the gFindBar
+// to close before taking the snapshot so the gFindBar does not take up space
+// on the new snapshot.
+function* closeFindBarAndWait() {
+ let awaitTransitionEnd = BrowserTestUtils.waitForEvent(gFindBar, "transitionend", false, event => {
+ return event.propertyName == "visibility";
+ });
+ gFindBar.close();
+ yield awaitTransitionEnd;
+}
diff --git a/toolkit/content/tests/browser/browser_bug594509.js b/toolkit/content/tests/browser/browser_bug594509.js
new file mode 100644
index 000000000..e67b05f85
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_bug594509.js
@@ -0,0 +1,9 @@
+add_task(function* () {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:rights");
+
+ yield ContentTask.spawn(tab.linkedBrowser, null, function* () {
+ Assert.ok(content.document.getElementById("your-rights"), "about:rights content loaded");
+ });
+
+ yield BrowserTestUtils.removeTab(tab);
+});
diff --git a/toolkit/content/tests/browser/browser_bug982298.js b/toolkit/content/tests/browser/browser_bug982298.js
new file mode 100644
index 000000000..047340c5c
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_bug982298.js
@@ -0,0 +1,70 @@
+const scrollHtml =
+ "<textarea id=\"textarea1\" row=2>Firefox\n\nFirefox\n\n\n\n\n\n\n\n\n\n" +
+ "</textarea><a href=\"about:blank\">blank</a>";
+
+add_task(function*() {
+ let url = "data:text/html;base64," + btoa(scrollHtml);
+ yield BrowserTestUtils.withNewTab({gBrowser, url}, function*(browser) {
+ let awaitFindResult = new Promise(resolve => {
+ let listener = {
+ onFindResult(aData) {
+ info("got find result");
+ browser.finder.removeResultListener(listener);
+
+ ok(aData.result == Ci.nsITypeAheadFind.FIND_FOUND, "should find string");
+ resolve();
+ },
+ onCurrentSelection() {},
+ onMatchesCountResult() {}
+ };
+ info("about to add results listener, open find bar, and send 'F' string");
+ browser.finder.addResultListener(listener);
+ });
+ gFindBar.onFindCommand();
+ EventUtils.sendString("F");
+ info("added result listener and sent string 'F'");
+ yield awaitFindResult;
+
+ let awaitScrollDone = BrowserTestUtils.waitForMessage(browser.messageManager, "ScrollDone");
+ // scroll textarea to bottom
+ const scrollTest =
+ "var textarea = content.document.getElementById(\"textarea1\");" +
+ "textarea.scrollTop = textarea.scrollHeight;" +
+ "sendAsyncMessage(\"ScrollDone\", { });"
+ browser.messageManager.loadFrameScript("data:text/javascript;base64," +
+ btoa(scrollTest), false);
+ yield awaitScrollDone;
+ info("got ScrollDone event");
+ yield BrowserTestUtils.loadURI(browser, "about:blank");
+ yield BrowserTestUtils.browserLoaded(browser);
+
+ ok(browser.currentURI.spec == "about:blank", "got load event for about:blank");
+
+ let awaitFindResult2 = new Promise(resolve => {
+ let listener = {
+ onFindResult(aData) {
+ info("got find result #2");
+ browser.finder.removeResultListener(listener);
+ resolve();
+ },
+ onCurrentSelection() {},
+ onMatchesCountResult() {}
+ };
+
+ browser.finder.addResultListener(listener);
+ info("added result listener");
+ });
+ // find again needs delay for crash test
+ setTimeout(function() {
+ // ignore exception if occured
+ try {
+ info("about to send find again command");
+ gFindBar.onFindAgainCommand(false);
+ info("sent find again command");
+ } catch (e) {
+ info("got exception from onFindAgainCommand: " + e);
+ }
+ }, 0);
+ yield awaitFindResult2;
+ });
+});
diff --git a/toolkit/content/tests/browser/browser_contentTitle.js b/toolkit/content/tests/browser/browser_contentTitle.js
new file mode 100644
index 000000000..e7966e565
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_contentTitle.js
@@ -0,0 +1,16 @@
+var url = "https://example.com/browser/toolkit/content/tests/browser/file_contentTitle.html";
+
+add_task(function*() {
+ let tab = gBrowser.selectedTab = gBrowser.addTab(url);
+ let browser = tab.linkedBrowser;
+ yield new Promise((resolve) => {
+ addEventListener("TestLocationChange", function listener() {
+ removeEventListener("TestLocationChange", listener);
+ resolve();
+ }, true, true);
+ });
+
+ is(gBrowser.contentTitle, "Test Page", "Should have the right title.");
+
+ gBrowser.removeTab(tab);
+});
diff --git a/toolkit/content/tests/browser/browser_content_url_annotation.js b/toolkit/content/tests/browser/browser_content_url_annotation.js
new file mode 100644
index 000000000..1a4cee4c6
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_content_url_annotation.js
@@ -0,0 +1,73 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+/* global Services, requestLongerTimeout, TestUtils, BrowserTestUtils,
+ ok, info, dump, is, Ci, Cu, Components, ctypes, privateNoteIntentionalCrash,
+ gBrowser, add_task, addEventListener, removeEventListener, ContentTask */
+
+"use strict";
+
+// Running this test in ASAN is slow.
+requestLongerTimeout(2);
+
+/**
+ * Removes a file from a directory. This is a no-op if the file does not
+ * exist.
+ *
+ * @param directory
+ * The nsIFile representing the directory to remove from.
+ * @param filename
+ * A string for the file to remove from the directory.
+ */
+function removeFile(directory, filename) {
+ let file = directory.clone();
+ file.append(filename);
+ if (file.exists()) {
+ file.remove(false);
+ }
+}
+
+/**
+ * Returns the directory where crash dumps are stored.
+ *
+ * @return nsIFile
+ */
+function getMinidumpDirectory() {
+ let dir = Services.dirsvc.get('ProfD', Ci.nsIFile);
+ dir.append("minidumps");
+ return dir;
+}
+
+/**
+ * Checks that the URL is correctly annotated on a content process crash.
+ */
+add_task(function* test_content_url_annotation() {
+ let url = "https://example.com/browser/toolkit/content/tests/browser/file_redirect.html";
+ let redirect_url = "https://example.com/browser/toolkit/content/tests/browser/file_redirect_to.html";
+
+ yield BrowserTestUtils.withNewTab({
+ gBrowser: gBrowser
+ }, function* (browser) {
+ ok(browser.isRemoteBrowser, "Should be a remote browser");
+
+ // file_redirect.html should send us to file_redirect_to.html
+ let promise = ContentTask.spawn(browser, {}, function* () {
+ dump('ContentTask starting...\n');
+ yield new Promise((resolve) => {
+ addEventListener("RedirectDone", function listener() {
+ dump('Got RedirectDone\n');
+ removeEventListener("RedirectDone", listener);
+ resolve();
+ }, true, true);
+ });
+ });
+ browser.loadURI(url);
+ yield promise;
+
+ // Crash the tab
+ let annotations = yield BrowserTestUtils.crashBrowser(browser);
+
+ ok("URL" in annotations, "annotated a URL");
+ is(annotations.URL, redirect_url,
+ "Should have annotated the URL after redirect");
+ });
+});
diff --git a/toolkit/content/tests/browser/browser_crash_previous_frameloader.js b/toolkit/content/tests/browser/browser_crash_previous_frameloader.js
new file mode 100644
index 000000000..bd50c6ffd
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_crash_previous_frameloader.js
@@ -0,0 +1,108 @@
+"use strict";
+
+/**
+ * Cleans up the .dmp and .extra file from a crash.
+ *
+ * @param subject (nsISupports)
+ * The subject passed through the ipc:content-shutdown
+ * observer notification when a content process crash has
+ * occurred.
+ */
+function cleanUpMinidump(subject) {
+ Assert.ok(subject instanceof Ci.nsIPropertyBag2,
+ "Subject needs to be a nsIPropertyBag2 to clean up properly");
+ let dumpID = subject.getPropertyAsAString("dumpID");
+
+ Assert.ok(dumpID, "There should be a dumpID");
+ if (dumpID) {
+ let dir = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ dir.append("minidumps");
+
+ let file = dir.clone();
+ file.append(dumpID + ".dmp");
+ file.remove(true);
+
+ file = dir.clone();
+ file.append(dumpID + ".extra");
+ file.remove(true);
+ }
+}
+
+/**
+ * This test ensures that if a remote frameloader crashes after
+ * the frameloader owner swaps it out for a new frameloader,
+ * that a oop-browser-crashed event is not sent to the new
+ * frameloader's browser element.
+ */
+add_task(function* test_crash_in_previous_frameloader() {
+ // On debug builds, crashing tabs results in much thinking, which
+ // slows down the test and results in intermittent test timeouts,
+ // so we'll pump up the expected timeout for this test.
+ requestLongerTimeout(2);
+
+ if (!gMultiProcessBrowser) {
+ Assert.ok(false, "This test should only be run in multi-process mode.");
+ return;
+ }
+
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "http://example.com",
+ }, function*(browser) {
+ // First, sanity check...
+ Assert.ok(browser.isRemoteBrowser,
+ "This browser needs to be remote if this test is going to " +
+ "work properly.");
+
+ // We will wait for the oop-browser-crashed event to have
+ // a chance to appear. That event is fired when TabParents
+ // are destroyed, and that occurs _before_ ContentParents
+ // are destroyed, so we'll wait on the ipc:content-shutdown
+ // observer notification, which is fired when a ContentParent
+ // goes away. After we see this notification, oop-browser-crashed
+ // events should have fired.
+ let contentProcessGone = TestUtils.topicObserved("ipc:content-shutdown");
+ let sawTabCrashed = false;
+ let onTabCrashed = () => {
+ sawTabCrashed = true;
+ };
+
+ browser.addEventListener("oop-browser-crashed", onTabCrashed);
+
+ // The name of the game is to cause a crash in a remote browser,
+ // and then immediately swap out the browser for a non-remote one.
+ yield ContentTask.spawn(browser, null, function() {
+ const Cu = Components.utils;
+ Cu.import("resource://gre/modules/ctypes.jsm");
+ Cu.import("resource://gre/modules/Timer.jsm");
+
+ let dies = function() {
+ privateNoteIntentionalCrash();
+ let zero = new ctypes.intptr_t(8);
+ let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
+ badptr.contents
+ };
+
+ // When the parent flips the remoteness of the browser, the
+ // page should receive the pagehide event, which we'll then
+ // use to crash the frameloader.
+ addEventListener("pagehide", function() {
+ dump("\nEt tu, Brute?\n");
+ dies();
+ });
+ });
+
+ gBrowser.updateBrowserRemoteness(browser, false);
+ info("Waiting for content process to go away.");
+ let [subject, data] = yield contentProcessGone;
+
+ // If we don't clean up the minidump, the harness will
+ // complain.
+ cleanUpMinidump(subject);
+
+ info("Content process is gone!");
+ Assert.ok(!sawTabCrashed,
+ "Should not have seen the oop-browser-crashed event.");
+ browser.removeEventListener("oop-browser-crashed", onTabCrashed);
+ });
+});
diff --git a/toolkit/content/tests/browser/browser_default_image_filename.js b/toolkit/content/tests/browser/browser_default_image_filename.js
new file mode 100644
index 000000000..2859d486f
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_default_image_filename.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.init(window);
+
+/**
+ * TestCase for bug 564387
+ * <https://bugzilla.mozilla.org/show_bug.cgi?id=564387>
+ */
+add_task(function* () {
+ let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ gBrowser.loadURI("data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7");
+ yield loadPromise;
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(document, "popupshown");
+
+ yield BrowserTestUtils.synthesizeMouseAtCenter("img",
+ { type: "contextmenu", button: 2 },
+ gBrowser.selectedBrowser);
+
+ yield popupShownPromise;
+
+ let showFilePickerPromise = new Promise(resolve => {
+ MockFilePicker.showCallback = function(fp) {
+ is(fp.defaultString, "index.gif");
+ resolve();
+ }
+ });
+
+ registerCleanupFunction(function () {
+ MockFilePicker.cleanup();
+ });
+
+ // Select "Save Image As" option from context menu
+ var saveImageAsCommand = document.getElementById("context-saveimage");
+ saveImageAsCommand.doCommand();
+
+ yield showFilePickerPromise;
+
+ let contextMenu = document.getElementById("contentAreaContextMenu");
+ let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
+ contextMenu.hidePopup();
+ yield popupHiddenPromise;
+});
diff --git a/toolkit/content/tests/browser/browser_f7_caret_browsing.js b/toolkit/content/tests/browser/browser_f7_caret_browsing.js
new file mode 100644
index 000000000..c4b6823d4
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_f7_caret_browsing.js
@@ -0,0 +1,227 @@
+var gListener = null;
+const kURL = "data:text/html;charset=utf-8,Caret browsing is fun.<input id='in'>";
+
+const kPrefShortcutEnabled = "accessibility.browsewithcaret_shortcut.enabled";
+const kPrefWarnOnEnable = "accessibility.warn_on_browsewithcaret";
+const kPrefCaretBrowsingOn = "accessibility.browsewithcaret";
+
+var oldPrefs = {};
+for (let pref of [kPrefShortcutEnabled, kPrefWarnOnEnable, kPrefCaretBrowsingOn]) {
+ oldPrefs[pref] = Services.prefs.getBoolPref(pref);
+}
+
+Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
+Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
+Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
+
+registerCleanupFunction(function() {
+ for (let pref of [kPrefShortcutEnabled, kPrefWarnOnEnable, kPrefCaretBrowsingOn]) {
+ Services.prefs.setBoolPref(pref, oldPrefs[pref]);
+ }
+});
+
+// NB: not using BrowserTestUtils.domWindowOpened here because there's no way to
+// undo waiting for a window open. If we don't want the window to be opened, and
+// wait for it to verify that it indeed does not open, we need to be able to
+// then "stop" waiting so that when we next *do* want it to open, our "old"
+// listener doesn't fire and do things we don't want (like close the window...).
+let gCaretPromptOpeningObserver;
+function promiseCaretPromptOpened() {
+ return new Promise(resolve => {
+ function observer(subject, topic, data) {
+ if (topic == "domwindowopened") {
+ Services.ww.unregisterNotification(observer);
+ let win = subject.QueryInterface(Ci.nsIDOMWindow);
+ BrowserTestUtils.waitForEvent(win, "load", false, e => e.target.location.href != "about:blank").then(() => resolve(win));
+ gCaretPromptOpeningObserver = null;
+ }
+ }
+ Services.ww.registerNotification(observer);
+ gCaretPromptOpeningObserver = observer;
+ });
+}
+
+function hitF7(async = true) {
+ let f7 = () => EventUtils.sendKey("F7");
+ // Need to not stop execution inside this task:
+ if (async) {
+ executeSoon(f7);
+ } else {
+ f7();
+ }
+}
+
+function syncToggleCaretNoDialog(expected) {
+ let openedDialog = false;
+ promiseCaretPromptOpened().then(function(win) {
+ openedDialog = true;
+ win.close(); // This will eventually return focus here and allow the test to continue...
+ });
+ // Cause the dialog to appear sync, if it still does.
+ hitF7(false);
+
+ let expectedStr = expected ? "on." : "off.";
+ ok(!openedDialog, "Shouldn't open a dialog to turn caret browsing " + expectedStr);
+ // Need to clean up if the dialog wasn't opened, so the observer doesn't get
+ // re-triggered later on causing "issues".
+ if (!openedDialog) {
+ Services.ww.unregisterNotification(gCaretPromptOpeningObserver);
+ gCaretPromptOpeningObserver = null;
+ }
+ let prefVal = Services.prefs.getBoolPref(kPrefCaretBrowsingOn);
+ is(prefVal, expected, "Caret browsing should now be " + expectedStr);
+}
+
+function waitForFocusOnInput(browser)
+{
+ return ContentTask.spawn(browser, null, function* () {
+ let textEl = content.document.getElementById("in");
+ return ContentTaskUtils.waitForCondition(() => {
+ return content.document.activeElement == textEl;
+ }, "Input should get focused.");
+ });
+}
+
+function focusInput(browser)
+{
+ return ContentTask.spawn(browser, null, function* () {
+ let textEl = content.document.getElementById("in");
+ textEl.focus();
+ });
+}
+
+add_task(function* checkTogglingCaretBrowsing() {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, kURL);
+ yield focusInput(tab.linkedBrowser);
+
+ let promiseGotKey = promiseCaretPromptOpened();
+ hitF7();
+ let prompt = yield promiseGotKey;
+ let doc = prompt.document;
+ is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
+ ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
+ let promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload");
+
+ doc.documentElement.cancelDialog();
+ yield promiseDialogUnloaded;
+ info("Dialog unloaded");
+ yield waitForFocusOnInput(tab.linkedBrowser);
+ ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off after cancelling the dialog.");
+
+ promiseGotKey = promiseCaretPromptOpened();
+ hitF7();
+ prompt = yield promiseGotKey;
+
+ doc = prompt.document;
+ is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
+ ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
+ promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload");
+
+ doc.documentElement.acceptDialog();
+ yield promiseDialogUnloaded;
+ info("Dialog unloaded");
+ yield waitForFocusOnInput(tab.linkedBrowser);
+ ok(Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should be on after accepting the dialog.");
+
+ syncToggleCaretNoDialog(false);
+
+ promiseGotKey = promiseCaretPromptOpened();
+ hitF7();
+ prompt = yield promiseGotKey;
+ doc = prompt.document;
+
+ is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
+ ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
+
+ promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload");
+ doc.documentElement.cancelDialog();
+ yield promiseDialogUnloaded;
+ info("Dialog unloaded");
+ yield waitForFocusOnInput(tab.linkedBrowser);
+
+ ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off after cancelling the dialog.");
+
+ Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
+ Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
+ Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
+
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+add_task(function* toggleCheckboxNoCaretBrowsing() {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, kURL);
+ yield focusInput(tab.linkedBrowser);
+
+ let promiseGotKey = promiseCaretPromptOpened();
+ hitF7();
+ let prompt = yield promiseGotKey;
+ let doc = prompt.document;
+ is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
+ let checkbox = doc.getElementById("checkbox");
+ ok(!checkbox.checked, "Checkbox shouldn't be checked by default.");
+
+ // Check the box:
+ checkbox.click();
+
+ let promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload");
+
+ // Say no:
+ doc.documentElement.getButton("cancel").click();
+
+ yield promiseDialogUnloaded;
+ info("Dialog unloaded");
+ yield waitForFocusOnInput(tab.linkedBrowser);
+ ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off.");
+ ok(!Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should now be disabled.");
+
+ syncToggleCaretNoDialog(false);
+ ok(!Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should still be disabled.");
+
+ Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
+ Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
+ Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
+
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+
+add_task(function* toggleCheckboxWantCaretBrowsing() {
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, kURL);
+ yield focusInput(tab.linkedBrowser);
+
+ let promiseGotKey = promiseCaretPromptOpened();
+ hitF7();
+ let prompt = yield promiseGotKey;
+ let doc = prompt.document;
+ is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
+ let checkbox = doc.getElementById("checkbox");
+ ok(!checkbox.checked, "Checkbox shouldn't be checked by default.");
+
+ // Check the box:
+ checkbox.click();
+
+ let promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload");
+
+ // Say yes:
+ doc.documentElement.acceptDialog();
+ yield promiseDialogUnloaded;
+ info("Dialog unloaded");
+ yield waitForFocusOnInput(tab.linkedBrowser);
+ ok(Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should now be on.");
+ ok(Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should still be enabled.");
+ ok(!Services.prefs.getBoolPref(kPrefWarnOnEnable), "Should no longer warn when enabling.");
+
+ syncToggleCaretNoDialog(false);
+ syncToggleCaretNoDialog(true);
+ syncToggleCaretNoDialog(false);
+
+ Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
+ Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
+ Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
+
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+
+
+
diff --git a/toolkit/content/tests/browser/browser_findbar.js b/toolkit/content/tests/browser/browser_findbar.js
new file mode 100644
index 000000000..1ab06f632
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_findbar.js
@@ -0,0 +1,249 @@
+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.";
+// Using 'javascript' schema to bypass E10SUtils.canLoadURIInProcess, because
+// it does not allow 'data:' URI to be loaded in the parent process.
+const E10S_PARENT_TEST_PAGE_URI = "javascript:document.write('The letter s.');";
+
+/**
+ * Makes sure that the findbar hotkeys (' and /) event listeners
+ * are added to the system event group and do not get blocked
+ * by calling stopPropagation on a keypress event on a page.
+ */
+add_task(function* test_hotkey_event_propagation() {
+ info("Ensure hotkeys are not affected by stopPropagation.");
+
+ // Opening new tab
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
+ let browser = gBrowser.getBrowserForTab(tab);
+ let findbar = gBrowser.getFindBar();
+
+ // Pressing these keys open the findbar.
+ const HOTKEYS = ["/", "'"];
+
+ // Checking if findbar appears when any hotkey is pressed.
+ for (let key of HOTKEYS) {
+ is(findbar.hidden, true, "Findbar is hidden now.");
+ gBrowser.selectedTab = tab;
+ yield SimpleTest.promiseFocus(gBrowser.selectedBrowser);
+ yield BrowserTestUtils.sendChar(key, browser);
+ is(findbar.hidden, false, "Findbar should not be hidden.");
+ yield closeFindbarAndWait(findbar);
+ }
+
+ // Stop propagation for all keyboard events.
+ 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 SimpleTest.promiseFocus(gBrowser.selectedBrowser);
+ yield BrowserTestUtils.sendChar(key, browser);
+ is(findbar.hidden, false, "Findbar should not be hidden.");
+ yield closeFindbarAndWait(findbar);
+ }
+
+ gBrowser.removeTab(tab);
+});
+
+add_task(function* test_not_found() {
+ info("Check correct 'Phrase not found' on new tab");
+
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
+
+ // Search for the first word.
+ yield promiseFindFinished("--- THIS SHOULD NEVER MATCH ---", false);
+ let findbar = gBrowser.getFindBar();
+ is(findbar._findStatusDesc.textContent, findbar._notFoundStr,
+ "Findbar status text should be 'Phrase not found'");
+
+ gBrowser.removeTab(tab);
+});
+
+add_task(function* test_found() {
+ 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);
+ ok(!gBrowser.getFindBar()._findStatusDesc.textContent,
+ "Findbar status should be empty");
+
+ gBrowser.removeTab(tab);
+});
+
+// Setting first findbar to case-sensitive mode should not affect
+// new tab find bar.
+add_task(function* test_tabwise_case_sensitive() {
+ let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
+ let findbar1 = gBrowser.getFindBar();
+
+ let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
+ let findbar2 = gBrowser.getFindBar();
+
+ // Toggle case sensitivity for first findbar
+ findbar1.getElement("find-case-sensitive").click();
+
+ gBrowser.selectedTab = tab1;
+
+ // Not found for first tab.
+ yield promiseFindFinished("S", true);
+ is(findbar1._findStatusDesc.textContent, findbar1._notFoundStr,
+ "Findbar status text should be 'Phrase not found'");
+
+ gBrowser.selectedTab = tab2;
+
+ // But it didn't affect the second findbar.
+ yield promiseFindFinished("S", true);
+ ok(!findbar2._findStatusDesc.textContent, "Findbar status should be empty");
+
+ gBrowser.removeTab(tab1);
+ gBrowser.removeTab(tab2);
+});
+
+/**
+ * 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() {
+ // This test only makes sence in e10s evironment.
+ if (!gMultiProcessBrowser) {
+ info("Skipping this test because of non-e10s environment.");
+ return;
+ }
+
+ info("Ensure findbar re-initialization at remoteness change.");
+
+ // 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();
+
+ // Findbar should operate normally.
+ yield promiseFindFinished("z", false);
+ is(findbar._findStatusDesc.textContent, findbar._notFoundStr,
+ "Findbar status text should be 'Phrase not found'");
+
+ yield promiseFindFinished("s", false);
+ ok(!findbar._findStatusDesc.textContent, "Findbar status should be empty");
+
+ // Moving browser into the parent process and reloading sample data.
+ ok(browser.isRemoteBrowser, "Browser should be remote now.");
+ yield promiseRemotenessChange(tab, false);
+ yield BrowserTestUtils.loadURI(browser, E10S_PARENT_TEST_PAGE_URI);
+ ok(!browser.isRemoteBrowser, "Browser should not be remote any more.");
+
+ // Findbar should keep operating normally after remoteness change.
+ yield promiseFindFinished("z", false);
+ is(findbar._findStatusDesc.textContent, findbar._notFoundStr,
+ "Findbar status text should be 'Phrase not found'");
+
+ yield promiseFindFinished("s", false);
+ ok(!findbar._findStatusDesc.textContent, "Findbar status should be empty");
+
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+/**
+ * Ensure that the initial typed characters aren't lost immediately after
+ * opening the find bar.
+ */
+add_task(function* () {
+ // This test only makes sence in e10s evironment.
+ if (!gMultiProcessBrowser) {
+ info("Skipping this test because of non-e10s environment.");
+ return;
+ }
+
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
+ let browser = tab.linkedBrowser;
+
+ ok(!gFindBarInitialized, "findbar isn't initialized yet");
+
+ let findBar = gFindBar;
+ let initialValue = findBar._findField.value;
+
+ EventUtils.synthesizeKey("f", { accelKey: true }, window);
+
+ let promises = [
+ BrowserTestUtils.sendChar("a", browser),
+ BrowserTestUtils.sendChar("b", browser),
+ BrowserTestUtils.sendChar("c", browser)
+ ];
+
+ isnot(document.activeElement, findBar._findField.inputField,
+ "findbar is not yet focused");
+ is(findBar._findField.value, initialValue, "still has initial find query");
+
+ yield Promise.all(promises);
+ is(document.activeElement, findBar._findField.inputField,
+ "findbar is now focused");
+ is(findBar._findField.value, "abc", "abc fully entered as find query");
+
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+function promiseFindFinished(searchText, highlightOn) {
+ let deferred = Promise.defer();
+
+ let findbar = gBrowser.getFindBar();
+ findbar.startFind(findbar.FIND_NORMAL);
+ let highlightElement = findbar.getElement("highlight");
+ if (highlightElement.checked != highlightOn)
+ highlightElement.click();
+ executeSoon(() => {
+ 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);
+ findbar.browser.finder.removeResultListener(resultListener);
+ deferred.resolve();
+ }
+
+ resultListener = {
+ onFindResult: foundOrTimedout
+ };
+ findbar.browser.finder.addResultListener(resultListener);
+ findbar._find();
+ });
+
+ return deferred.promise;
+}
+
+function promiseRemotenessChange(tab, shouldBeRemote) {
+ return new Promise((resolve) => {
+ let browser = gBrowser.getBrowserForTab(tab);
+ tab.addEventListener("TabRemotenessChange", function listener() {
+ tab.removeEventListener("TabRemotenessChange", listener);
+ resolve();
+ });
+ gBrowser.updateBrowserRemoteness(browser, shouldBeRemote);
+ });
+}
diff --git a/toolkit/content/tests/browser/browser_isSynthetic.js b/toolkit/content/tests/browser/browser_isSynthetic.js
new file mode 100644
index 000000000..15a341461
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_isSynthetic.js
@@ -0,0 +1,72 @@
+function LocationChangeListener(browser) {
+ this.browser = browser;
+ browser.addProgressListener(this);
+}
+
+LocationChangeListener.prototype = {
+ wasSynthetic: false,
+ browser: null,
+
+ destroy: function() {
+ this.browser.removeProgressListener(this);
+ },
+
+ onLocationChange: function(webProgress, request, location, flags) {
+ this.wasSynthetic = this.browser.isSyntheticDocument;
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+ Ci.nsISupportsWeakReference])
+}
+
+const FILES = gTestPath.replace("browser_isSynthetic.js", "")
+ .replace("chrome://mochitests/content/", "http://example.com/");
+
+function waitForPageShow(browser) {
+ return ContentTask.spawn(browser, null, function*() {
+ Cu.import("resource://gre/modules/PromiseUtils.jsm");
+ yield new Promise(resolve => {
+ let listener = () => {
+ removeEventListener("pageshow", listener, true);
+ resolve();
+ }
+ addEventListener("pageshow", listener, true);
+ });
+ });
+}
+
+add_task(function*() {
+ let tab = gBrowser.addTab("about:blank");
+ let browser = tab.linkedBrowser;
+ yield BrowserTestUtils.browserLoaded(browser);
+ let listener = new LocationChangeListener(browser);
+
+ is(browser.isSyntheticDocument, false, "Should not be synthetic");
+
+ let loadPromise = waitForPageShow(browser);
+ browser.loadURI("data:text/html;charset=utf-8,<html/>");
+ yield loadPromise;
+ is(listener.wasSynthetic, false, "Should not be synthetic");
+ is(browser.isSyntheticDocument, false, "Should not be synthetic");
+
+ loadPromise = waitForPageShow(browser);
+ browser.loadURI(FILES + "empty.png");
+ yield loadPromise;
+ is(listener.wasSynthetic, true, "Should be synthetic");
+ is(browser.isSyntheticDocument, true, "Should be synthetic");
+
+ loadPromise = waitForPageShow(browser);
+ browser.goBack();
+ yield loadPromise;
+ is(listener.wasSynthetic, false, "Should not be synthetic");
+ is(browser.isSyntheticDocument, false, "Should not be synthetic");
+
+ loadPromise = waitForPageShow(browser);
+ browser.goForward();
+ yield loadPromise;
+ is(listener.wasSynthetic, true, "Should be synthetic");
+ is(browser.isSyntheticDocument, true, "Should be synthetic");
+
+ listener.destroy();
+ gBrowser.removeTab(tab);
+});
diff --git a/toolkit/content/tests/browser/browser_keyevents_during_autoscrolling.js b/toolkit/content/tests/browser/browser_keyevents_during_autoscrolling.js
new file mode 100644
index 000000000..3fce47114
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_keyevents_during_autoscrolling.js
@@ -0,0 +1,120 @@
+add_task(function * ()
+{
+ const kPrefName_AutoScroll = "general.autoScroll";
+ Services.prefs.setBoolPref(kPrefName_AutoScroll, true);
+
+ const kNoKeyEvents = 0;
+ const kKeyDownEvent = 1;
+ const kKeyPressEvent = 2;
+ const kKeyUpEvent = 4;
+ const kAllKeyEvents = 7;
+
+ var expectedKeyEvents;
+ var dispatchedKeyEvents;
+ var key;
+ var root;
+
+ /**
+ * Encapsulates EventUtils.sendChar().
+ */
+ function sendChar(aChar)
+ {
+ key = aChar;
+ dispatchedKeyEvents = kNoKeyEvents;
+ EventUtils.sendChar(key);
+ is(dispatchedKeyEvents, expectedKeyEvents,
+ "unexpected key events were dispatched or not dispatched: " + key);
+ }
+
+ /**
+ * Encapsulates EventUtils.sendKey().
+ */
+ function sendKey(aKey)
+ {
+ key = aKey;
+ dispatchedKeyEvents = kNoKeyEvents;
+ EventUtils.sendKey(key);
+ is(dispatchedKeyEvents, expectedKeyEvents,
+ "unexpected key events were dispatched or not dispatched: " + key);
+ }
+
+ function onKey(aEvent)
+ {
+// if (aEvent.target != root && aEvent.target != root.ownerDocument.body) {
+// ok(false, "unknown target: " + aEvent.target.tagName);
+// return;
+// }
+
+ var keyFlag;
+ switch (aEvent.type) {
+ case "keydown":
+ keyFlag = kKeyDownEvent;
+ break;
+ case "keypress":
+ keyFlag = kKeyPressEvent;
+ break;
+ case "keyup":
+ keyFlag = kKeyUpEvent;
+ break;
+ default:
+ ok(false, "Unknown events: " + aEvent.type);
+ return;
+ }
+ dispatchedKeyEvents |= keyFlag;
+ is(keyFlag, expectedKeyEvents & keyFlag, aEvent.type + " fired: " + key);
+ }
+
+ var dataUri = 'data:text/html,<body style="height:10000px;"></body>';
+
+ let loadedPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ gBrowser.loadURI(dataUri);
+ yield loadedPromise;
+
+ yield SimpleTest.promiseFocus(gBrowser.selectedBrowser);
+
+ window.addEventListener("keydown", onKey, false);
+ window.addEventListener("keypress", onKey, false);
+ window.addEventListener("keyup", onKey, false);
+
+ // Test whether the key events are handled correctly under normal condition
+ expectedKeyEvents = kAllKeyEvents;
+ sendChar("A");
+
+ // Start autoscrolling by middle button click on the page
+ let shownPromise = BrowserTestUtils.waitForEvent(window, "popupshown", false,
+ event => event.originalTarget.className == "autoscroller");
+ yield BrowserTestUtils.synthesizeMouseAtPoint(10, 10, { button: 1 },
+ gBrowser.selectedBrowser);
+ yield shownPromise;
+
+ // Most key events should be eaten by the browser.
+ expectedKeyEvents = kNoKeyEvents;
+ sendChar("A");
+ sendKey("DOWN");
+ sendKey("RETURN");
+ sendKey("RETURN");
+ sendKey("HOME");
+ sendKey("END");
+ sendKey("TAB");
+ sendKey("RETURN");
+
+ // Finish autoscrolling by ESC key. Note that only keydown and keypress
+ // events are eaten because keyup event is fired *after* the autoscrolling
+ // is finished.
+ expectedKeyEvents = kKeyUpEvent;
+ sendKey("ESCAPE");
+
+ // Test whether the key events are handled correctly under normal condition
+ expectedKeyEvents = kAllKeyEvents;
+ sendChar("A");
+
+ window.removeEventListener("keydown", onKey, false);
+ window.removeEventListener("keypress", onKey, false);
+ window.removeEventListener("keyup", onKey, false);
+
+ // restore the changed prefs
+ if (Services.prefs.prefHasUserValue(kPrefName_AutoScroll))
+ Services.prefs.clearUserPref(kPrefName_AutoScroll);
+
+ finish();
+});
diff --git a/toolkit/content/tests/browser/browser_label_textlink.js b/toolkit/content/tests/browser/browser_label_textlink.js
new file mode 100644
index 000000000..861086707
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_label_textlink.js
@@ -0,0 +1,38 @@
+add_task(function* () {
+ yield BrowserTestUtils.withNewTab({gBrowser, url: "about:config"}, function*(browser) {
+ let newTabURL = "http://www.example.com/";
+ yield ContentTask.spawn(browser, newTabURL, function*(newTabURL) {
+ let doc = content.document;
+ let label = doc.createElement("label");
+ label.href = newTabURL;
+ label.id = "textlink-test";
+ label.className = "text-link";
+ label.textContent = "click me";
+ doc.documentElement.append(label);
+ });
+
+ // Test that click will open tab in foreground.
+ let awaitNewTab = BrowserTestUtils.waitForNewTab(gBrowser, newTabURL);
+ yield BrowserTestUtils.synthesizeMouseAtCenter("#textlink-test", {}, browser);
+ let newTab = yield awaitNewTab;
+ is(newTab.linkedBrowser, gBrowser.selectedBrowser, "selected tab should be example page");
+ yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+ // Test that ctrl+shift+click/meta+shift+click will open tab in background.
+ awaitNewTab = BrowserTestUtils.waitForNewTab(gBrowser, newTabURL);
+ yield BrowserTestUtils.synthesizeMouseAtCenter("#textlink-test",
+ {ctrlKey: true, metaKey: true, shiftKey: true},
+ browser);
+ yield awaitNewTab;
+ is(gBrowser.selectedBrowser, browser, "selected tab should be original tab");
+ yield BrowserTestUtils.removeTab(gBrowser.tabs[gBrowser.tabs.length - 1]);
+
+ // Middle-clicking should open tab in foreground.
+ awaitNewTab = BrowserTestUtils.waitForNewTab(gBrowser, newTabURL);
+ yield BrowserTestUtils.synthesizeMouseAtCenter("#textlink-test",
+ {button: 1}, browser);
+ newTab = yield awaitNewTab;
+ is(newTab.linkedBrowser, gBrowser.selectedBrowser, "selected tab should be example page");
+ yield BrowserTestUtils.removeTab(gBrowser.tabs[gBrowser.tabs.length - 1]);
+ });
+});
diff --git a/toolkit/content/tests/browser/browser_mediaPlayback.js b/toolkit/content/tests/browser/browser_mediaPlayback.js
new file mode 100644
index 000000000..1a6ebfcb8
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_mediaPlayback.js
@@ -0,0 +1,30 @@
+const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlayback.html";
+const FRAME = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlaybackFrame.html";
+
+function wait_for_event(browser, event) {
+ return BrowserTestUtils.waitForEvent(browser, event, false, (event) => {
+ is(event.originalTarget, browser, "Event must be dispatched to correct browser.");
+ ok(!event.cancelable, "The event should not be cancelable");
+ return true;
+ });
+}
+
+function* test_on_browser(url, browser) {
+ browser.loadURI(url);
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+ yield wait_for_event(browser, "DOMAudioPlaybackStopped");
+}
+
+add_task(function* test_page() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank",
+ }, test_on_browser.bind(undefined, PAGE));
+});
+
+add_task(function* test_frame() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank",
+ }, test_on_browser.bind(undefined, FRAME));
+});
diff --git a/toolkit/content/tests/browser/browser_mediaPlayback_mute.js b/toolkit/content/tests/browser/browser_mediaPlayback_mute.js
new file mode 100644
index 000000000..852fc56fb
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_mediaPlayback_mute.js
@@ -0,0 +1,104 @@
+const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlayback2.html";
+const FRAME = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlaybackFrame2.html";
+
+function wait_for_event(browser, event) {
+ return BrowserTestUtils.waitForEvent(browser, event, false, (event) => {
+ is(event.originalTarget, browser, "Event must be dispatched to correct browser.");
+ return true;
+ });
+}
+
+function* test_audio_in_browser() {
+ function get_audio_element() {
+ var doc = content.document;
+ var list = doc.getElementsByTagName('audio');
+ if (list.length == 1) {
+ return list[0];
+ }
+
+ // iframe?
+ list = doc.getElementsByTagName('iframe');
+
+ var iframe = list[0];
+ list = iframe.contentDocument.getElementsByTagName('audio');
+ return list[0];
+ }
+
+ var audio = get_audio_element();
+ return {
+ computedVolume: audio.computedVolume,
+ computedMuted: audio.computedMuted
+ }
+}
+
+function* test_on_browser(url, browser) {
+ browser.loadURI(url);
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+
+ var result = yield ContentTask.spawn(browser, null, test_audio_in_browser);
+ is(result.computedVolume, 1, "Audio volume is 1");
+ is(result.computedMuted, false, "Audio is not muted");
+
+ ok(!browser.audioMuted, "Audio should not be muted by default");
+ browser.mute();
+ ok(browser.audioMuted, "Audio should be muted now");
+
+ yield wait_for_event(browser, "DOMAudioPlaybackStopped");
+
+ result = yield ContentTask.spawn(browser, null, test_audio_in_browser);
+ is(result.computedVolume, 0, "Audio volume is 0 when muted");
+ is(result.computedMuted, true, "Audio is muted");
+}
+
+function* test_visibility(url, browser) {
+ browser.loadURI(url);
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+
+ var result = yield ContentTask.spawn(browser, null, test_audio_in_browser);
+ is(result.computedVolume, 1, "Audio volume is 1");
+ is(result.computedMuted, false, "Audio is not muted");
+
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank",
+ }, function() {});
+
+ ok(!browser.audioMuted, "Audio should not be muted by default");
+ browser.mute();
+ ok(browser.audioMuted, "Audio should be muted now");
+
+ yield wait_for_event(browser, "DOMAudioPlaybackStopped");
+
+ result = yield ContentTask.spawn(browser, null, test_audio_in_browser);
+ is(result.computedVolume, 0, "Audio volume is 0 when muted");
+ is(result.computedMuted, true, "Audio is muted");
+}
+
+add_task(function*() {
+ yield new Promise((resolve) => {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["media.useAudioChannelService.testing", true]
+ ]}, resolve);
+ });
+});
+
+add_task(function* test_page() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank",
+ }, test_on_browser.bind(undefined, PAGE));
+});
+
+add_task(function* test_frame() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank",
+ }, test_on_browser.bind(undefined, FRAME));
+});
+
+add_task(function* test_frame() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank",
+ }, test_visibility.bind(undefined, PAGE));
+});
diff --git a/toolkit/content/tests/browser/browser_mediaPlayback_suspended.js b/toolkit/content/tests/browser/browser_mediaPlayback_suspended.js
new file mode 100644
index 000000000..ef8bb9dc8
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_mediaPlayback_suspended.js
@@ -0,0 +1,191 @@
+const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlayback2.html";
+
+var SuspendedType = {
+ NONE_SUSPENDED : 0,
+ SUSPENDED_PAUSE : 1,
+ SUSPENDED_BLOCK : 2,
+ SUSPENDED_PAUSE_DISPOSABLE : 3
+};
+
+function wait_for_event(browser, event) {
+ return BrowserTestUtils.waitForEvent(browser, event, false, (event) => {
+ is(event.originalTarget, browser, "Event must be dispatched to correct browser.");
+ return true;
+ });
+}
+
+function check_audio_onplay() {
+ var list = content.document.getElementsByTagName('audio');
+ if (list.length != 1) {
+ ok(false, "There should be only one audio element in page!")
+ }
+
+ var audio = list[0];
+ return new Promise((resolve, reject) => {
+ audio.onplay = () => {
+ ok(needToReceiveOnPlay, "Should not receive play event!");
+ this.onplay = null;
+ reject();
+ };
+
+ audio.pause();
+ audio.play();
+
+ setTimeout(() => {
+ ok(true, "Doesn't receive play event when media was blocked.");
+ audio.onplay = null;
+ resolve();
+ }, 1000)
+ });
+}
+
+function check_audio_suspended(suspendedType) {
+ var list = content.document.getElementsByTagName('audio');
+ if (list.length != 1) {
+ ok(false, "There should be only one audio element in page!")
+ }
+
+ var audio = list[0];
+ is(audio.computedSuspended, suspendedType,
+ "The suspended state of MediaElement is correct.");
+}
+
+function check_audio_pause_state(expectedPauseState) {
+ var list = content.document.getElementsByTagName('audio');
+ if (list.length != 1) {
+ ok(false, "There should be only one audio element in page!")
+ }
+
+ var audio = list[0];
+ if (expectedPauseState) {
+ is(audio.paused, true, "Audio is paused correctly.");
+ } else {
+ is(audio.paused, false, "Audio is resumed correctly.");
+ }
+}
+
+function* suspended_pause(url, browser) {
+ info("### Start test for suspended-pause ###");
+ browser.loadURI(url);
+
+ info("- page should have playing audio -");
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+
+ info("- the suspended state of audio should be non-suspened -");
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_audio_suspended);
+
+ info("- pause playing audio -");
+ browser.pauseMedia(false /* non-disposable */);
+ yield ContentTask.spawn(browser, true /* expect for pause */,
+ check_audio_pause_state);
+ yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE,
+ check_audio_suspended);
+
+ info("- resume paused audio -");
+ browser.resumeMedia();
+ yield ContentTask.spawn(browser, false /* expect for playing */,
+ check_audio_pause_state);
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_audio_suspended);
+}
+
+function* suspended_pause_disposable(url, browser) {
+ info("### Start test for suspended-pause-disposable ###");
+ browser.loadURI(url);
+
+ info("- page should have playing audio -");
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+
+ info("- the suspended state of audio should be non-suspened -");
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_audio_suspended);
+
+ info("- pause playing audio -");
+ browser.pauseMedia(true /* disposable */);
+ yield ContentTask.spawn(browser, true /* expect for pause */,
+ check_audio_pause_state);
+ yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE,
+ check_audio_suspended);
+
+ info("- resume paused audio -");
+ browser.resumeMedia();
+ yield ContentTask.spawn(browser, false /* expect for playing */,
+ check_audio_pause_state);
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_audio_suspended);
+}
+
+function* suspended_stop_disposable(url, browser) {
+ info("### Start test for suspended-stop-disposable ###");
+ browser.loadURI(url);
+
+ info("- page should have playing audio -");
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+
+ info("- the suspended state of audio should be non-suspened -");
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_audio_suspended);
+
+ info("- stop playing audio -");
+ browser.stopMedia();
+ yield wait_for_event(browser, "DOMAudioPlaybackStopped");
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_audio_suspended);
+}
+
+function* suspended_block(url, browser) {
+ info("### Start test for suspended-block ###");
+ browser.loadURI(url);
+
+ info("- page should have playing audio -");
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+
+ info("- block playing audio -");
+ browser.blockMedia();
+ yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_BLOCK,
+ check_audio_suspended);
+ yield ContentTask.spawn(browser, null,
+ check_audio_onplay);
+
+ info("- resume blocked audio -");
+ browser.resumeMedia();
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_audio_suspended);
+}
+
+add_task(function* setup_test_preference() {
+ yield new Promise(resolve => {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["media.useAudioChannelService.testing", true]
+ ]}, resolve);
+ });
+});
+
+add_task(function* test_suspended_pause() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank"
+ }, suspended_pause.bind(this, PAGE));
+});
+
+add_task(function* test_suspended_pause_disposable() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank"
+ }, suspended_pause_disposable.bind(this, PAGE));
+});
+
+add_task(function* test_suspended_stop_disposable() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank"
+ }, suspended_stop_disposable.bind(this, PAGE));
+});
+
+add_task(function* test_suspended_block() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank"
+ }, suspended_block.bind(this, PAGE));
+});
diff --git a/toolkit/content/tests/browser/browser_mediaPlayback_suspended_multipleAudio.js b/toolkit/content/tests/browser/browser_mediaPlayback_suspended_multipleAudio.js
new file mode 100644
index 000000000..12e2ec077
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_mediaPlayback_suspended_multipleAudio.js
@@ -0,0 +1,311 @@
+const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_multipleAudio.html";
+
+var SuspendedType = {
+ NONE_SUSPENDED : 0,
+ SUSPENDED_PAUSE : 1,
+ SUSPENDED_BLOCK : 2,
+ SUSPENDED_PAUSE_DISPOSABLE : 3
+};
+
+function wait_for_event(browser, event) {
+ return BrowserTestUtils.waitForEvent(browser, event, false, (event) => {
+ is(event.originalTarget, browser, "Event must be dispatched to correct browser.");
+ return true;
+ });
+}
+
+function check_all_audio_suspended(suspendedType) {
+ var autoPlay = content.document.getElementById('autoplay');
+ var nonAutoPlay = content.document.getElementById('nonautoplay');
+ if (!autoPlay || !nonAutoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(autoPlay.computedSuspended, suspendedType,
+ "The suspeded state of autoplay audio is correct.");
+ is(nonAutoPlay.computedSuspended, suspendedType,
+ "The suspeded state of non-autoplay audio is correct.");
+}
+
+function check_autoplay_audio_suspended(suspendedType) {
+ var autoPlay = content.document.getElementById('autoplay');
+ if (!autoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(autoPlay.computedSuspended, suspendedType,
+ "The suspeded state of autoplay audio is correct.");
+}
+
+function check_nonautoplay_audio_suspended(suspendedType) {
+ var nonAutoPlay = content.document.getElementById('nonautoplay');
+ if (!nonAutoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(nonAutoPlay.computedSuspended, suspendedType,
+ "The suspeded state of non-autoplay audio is correct.");
+}
+
+function check_autoplay_audio_pause_state(expectedPauseState) {
+ var autoPlay = content.document.getElementById('autoplay');
+ if (!autoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ if (autoPlay.paused == expectedPauseState) {
+ if (expectedPauseState) {
+ ok(true, "Audio is paused correctly.");
+ } else {
+ ok(true, "Audio is resumed correctly.");
+ }
+ } else if (expectedPauseState) {
+ autoPlay.onpause = function () {
+ autoPlay.onpause = null;
+ ok(true, "Audio is paused correctly, checking from onpause.");
+ }
+ } else {
+ autoPlay.onplay = function () {
+ autoPlay.onplay = null;
+ ok(true, "Audio is resumed correctly, checking from onplay.");
+ }
+ }
+}
+
+function play_nonautoplay_audio_should_be_paused() {
+ var nonAutoPlay = content.document.getElementById('nonautoplay');
+ if (!nonAutoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ nonAutoPlay.play();
+ return new Promise(resolve => {
+ nonAutoPlay.onpause = function () {
+ nonAutoPlay.onpause = null;
+ is(nonAutoPlay.ended, false, "Audio can't be playback.");
+ resolve();
+ }
+ });
+}
+
+function all_audio_onresume() {
+ var autoPlay = content.document.getElementById('autoplay');
+ var nonAutoPlay = content.document.getElementById('nonautoplay');
+ if (!autoPlay || !nonAutoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(autoPlay.paused, false, "Autoplay audio is resumed.");
+ is(nonAutoPlay.paused, false, "Non-AutoPlay audio is resumed.");
+}
+
+function all_audio_onpause() {
+ var autoPlay = content.document.getElementById('autoplay');
+ var nonAutoPlay = content.document.getElementById('nonautoplay');
+ if (!autoPlay || !nonAutoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(autoPlay.paused, true, "Autoplay audio is paused.");
+ is(nonAutoPlay.paused, true, "Non-AutoPlay audio is paused.");
+}
+
+function play_nonautoplay_audio_should_play_until_ended() {
+ var nonAutoPlay = content.document.getElementById('nonautoplay');
+ if (!nonAutoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ nonAutoPlay.play();
+ return new Promise(resolve => {
+ nonAutoPlay.onended = function () {
+ nonAutoPlay.onended = null;
+ ok(true, "Audio can be playback until ended.");
+ resolve();
+ }
+ });
+}
+
+function no_audio_resumed() {
+ var autoPlay = content.document.getElementById('autoplay');
+ var nonAutoPlay = content.document.getElementById('nonautoplay');
+ if (!autoPlay || !nonAutoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ is(autoPlay.paused && nonAutoPlay.paused, true, "No audio was resumed.");
+}
+
+function play_nonautoplay_audio_should_be_blocked(suspendedType) {
+ var nonAutoPlay = content.document.getElementById('nonautoplay');
+ if (!nonAutoPlay) {
+ ok(false, "Can't get the audio element!");
+ }
+
+ nonAutoPlay.play();
+ ok(nonAutoPlay.paused, "The blocked audio can't be playback.");
+}
+
+function* suspended_pause(url, browser) {
+ info("### Start test for suspended-pause ###");
+ browser.loadURI(url);
+
+ info("- page should have playing audio -");
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+
+ info("- the default suspended state of all audio should be non-suspened-");
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_all_audio_suspended);
+
+ info("- pause all audio in the page -");
+ browser.pauseMedia(false /* non-disposable */);
+ yield ContentTask.spawn(browser, true /* expect for pause */,
+ check_autoplay_audio_pause_state);
+ yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE,
+ check_autoplay_audio_suspended);
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_nonautoplay_audio_suspended);
+
+ info("- no audio can be playback during suspended-paused -");
+ yield ContentTask.spawn(browser, null,
+ play_nonautoplay_audio_should_be_paused);
+ yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE,
+ check_nonautoplay_audio_suspended);
+
+ info("- both audio should be resumed at the same time -");
+ browser.resumeMedia();
+ yield ContentTask.spawn(browser, null,
+ all_audio_onresume);
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_all_audio_suspended);
+
+ info("- both audio should be paused at the same time -");
+ browser.pauseMedia(false /* non-disposable */);
+ yield ContentTask.spawn(browser, null, all_audio_onpause);
+}
+
+function* suspended_pause_disposable(url, browser) {
+ info("### Start test for suspended-pause-disposable ###");
+ browser.loadURI(url);
+
+ info("- page should have playing audio -");
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+
+ info("- the default suspended state of all audio should be non-suspened -");
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_all_audio_suspended);
+
+ info("- only pause playing audio in the page -");
+ browser.pauseMedia(true /* non-disposable */);
+ yield ContentTask.spawn(browser, true /* expect for pause */,
+ check_autoplay_audio_pause_state);
+ yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE,
+ check_autoplay_audio_suspended);
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_nonautoplay_audio_suspended);
+
+ info("- new playing audio should be playback correctly -");
+ yield ContentTask.spawn(browser, null,
+ play_nonautoplay_audio_should_play_until_ended);
+
+ info("- should only resume one audio -");
+ browser.resumeMedia();
+ yield ContentTask.spawn(browser, false /* expect for playing */,
+ check_autoplay_audio_pause_state);
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_all_audio_suspended);
+}
+
+function* suspended_stop_disposable(url, browser) {
+ info("### Start test for suspended-stop-disposable ###");
+ browser.loadURI(url);
+
+ info("- page should have playing audio -");
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+
+ info("- the default suspended state of all audio should be non-suspened -");
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_all_audio_suspended);
+
+ info("- only stop playing audio in the page -");
+ browser.stopMedia();
+ yield wait_for_event(browser, "DOMAudioPlaybackStopped");
+ yield ContentTask.spawn(browser, true /* expect for pause */,
+ check_autoplay_audio_pause_state);
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_all_audio_suspended);
+
+ info("- new playing audio should be playback correctly -");
+ yield ContentTask.spawn(browser, null,
+ play_nonautoplay_audio_should_play_until_ended);
+
+ info("- no any audio can be resumed by page -");
+ browser.resumeMedia();
+ yield ContentTask.spawn(browser, null, no_audio_resumed);
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_all_audio_suspended);
+}
+
+function* suspended_block(url, browser) {
+ info("### Start test for suspended-block ###");
+ browser.loadURI(url);
+
+ info("- page should have playing audio -");
+ yield wait_for_event(browser, "DOMAudioPlaybackStarted");
+
+ info("- the default suspended state of all audio should be non-suspened-");
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_all_audio_suspended);
+
+ info("- block autoplay audio -");
+ browser.blockMedia();
+ yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_BLOCK,
+ check_autoplay_audio_suspended);
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_nonautoplay_audio_suspended);
+
+ info("- no audio can be playback during suspended-block -");
+ yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_BLOCK,
+ play_nonautoplay_audio_should_be_blocked);
+
+ info("- both audio should be resumed at the same time -");
+ browser.resumeMedia();
+ yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
+ check_all_audio_suspended);
+}
+
+add_task(function* setup_test_preference() {
+ yield new Promise(resolve => {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["media.useAudioChannelService.testing", true]
+ ]}, resolve);
+ });
+});
+
+add_task(function* test_suspended_pause() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank"
+ }, suspended_pause.bind(this, PAGE));
+});
+
+add_task(function* test_suspended_pause_disposable() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank"
+ }, suspended_pause_disposable.bind(this, PAGE));
+});
+
+add_task(function* test_suspended_stop_disposable() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank"
+ }, suspended_stop_disposable.bind(this, PAGE));
+});
+
+add_task(function* test_suspended_block() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: "about:blank"
+ }, suspended_block.bind(this, PAGE));
+});
diff --git a/toolkit/content/tests/browser/browser_mute.js b/toolkit/content/tests/browser/browser_mute.js
new file mode 100644
index 000000000..f4829b808
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_mute.js
@@ -0,0 +1,16 @@
+const PAGE = "data:text/html,page";
+
+function* test_on_browser(browser) {
+ ok(!browser.audioMuted, "Audio should not be muted by default");
+ browser.mute();
+ ok(browser.audioMuted, "Audio should be muted now");
+ browser.unmute();
+ ok(!browser.audioMuted, "Audio should be unmuted now");
+}
+
+add_task(function*() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: PAGE,
+ }, test_on_browser);
+});
diff --git a/toolkit/content/tests/browser/browser_mute2.js b/toolkit/content/tests/browser/browser_mute2.js
new file mode 100644
index 000000000..38f415b71
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_mute2.js
@@ -0,0 +1,26 @@
+const PAGE = "data:text/html,page";
+
+function* test_on_browser(browser) {
+ ok(!browser.audioMuted, "Audio should not be muted by default");
+ browser.mute();
+ ok(browser.audioMuted, "Audio should be muted now");
+
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: PAGE,
+ }, test_on_browser2);
+
+ browser.unmute();
+ ok(!browser.audioMuted, "Audio should be unmuted now");
+}
+
+function* test_on_browser2(browser) {
+ ok(!browser.audioMuted, "Audio should not be muted by default");
+}
+
+add_task(function*() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: PAGE,
+ }, test_on_browser);
+});
diff --git a/toolkit/content/tests/browser/browser_quickfind_editable.js b/toolkit/content/tests/browser/browser_quickfind_editable.js
new file mode 100644
index 000000000..d4ab59744
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_quickfind_editable.js
@@ -0,0 +1,47 @@
+const PAGE = "data:text/html,<div contenteditable>foo</div><input><textarea></textarea>";
+const DESIGNMODE_PAGE = "data:text/html,<body onload='document.designMode=\"on\";'>";
+const HOTKEYS = ["/", "'"];
+
+function* test_hotkeys(browser, expected) {
+ let findbar = gBrowser.getFindBar();
+ for (let key of HOTKEYS) {
+ is(findbar.hidden, true, "findbar is hidden");
+ yield BrowserTestUtils.sendChar(key, gBrowser.selectedBrowser);
+ is(findbar.hidden, expected, "findbar should" + (expected ? "" : " not") + " be hidden");
+ if (!expected) {
+ yield closeFindbarAndWait(findbar);
+ }
+ }
+}
+
+function* focus_element(browser, query) {
+ yield ContentTask.spawn(browser, query, function* focus(query) {
+ let element = content.document.querySelector(query);
+ element.focus();
+ });
+}
+
+add_task(function* test_hotkey_on_editable_element() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: PAGE
+ }, function* do_tests(browser) {
+ yield test_hotkeys(browser, false);
+ const ELEMENTS = ["div", "input", "textarea"];
+ for (let elem of ELEMENTS) {
+ yield focus_element(browser, elem);
+ yield test_hotkeys(browser, true);
+ yield focus_element(browser, ":root");
+ yield test_hotkeys(browser, false);
+ }
+ });
+});
+
+add_task(function* test_hotkey_on_designMode_document() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: DESIGNMODE_PAGE
+ }, function* do_tests(browser) {
+ yield test_hotkeys(browser, true);
+ });
+});
diff --git a/toolkit/content/tests/browser/browser_saveImageURL.js b/toolkit/content/tests/browser/browser_saveImageURL.js
new file mode 100644
index 000000000..75e1cfdcd
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_saveImageURL.js
@@ -0,0 +1,68 @@
+"use strict";
+
+const IMAGE_PAGE = "https://example.com/browser/toolkit/content/tests/browser/image_page.html";
+const PREF_UNSAFE_FORBIDDEN = "dom.ipc.cpows.forbid-unsafe-from-browser";
+
+MockFilePicker.init(window);
+MockFilePicker.returnValue = MockFilePicker.returnCancel;
+
+registerCleanupFunction(function() {
+ MockFilePicker.cleanup();
+});
+
+function waitForFilePicker() {
+ return new Promise((resolve) => {
+ MockFilePicker.showCallback = () => {
+ MockFilePicker.showCallback = null;
+ ok(true, "Saw the file picker");
+ resolve();
+ }
+ })
+}
+
+/**
+ * Test that saveImageURL works when we pass in the aIsContentWindowPrivate
+ * argument instead of a document. This is the preferred API.
+ */
+add_task(function* preferred_API() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: IMAGE_PAGE,
+ }, function*(browser) {
+ let url = yield ContentTask.spawn(browser, null, function*() {
+ let image = content.document.getElementById("image");
+ return image.href;
+ });
+
+ saveImageURL(url, "image.jpg", null, true, false, null, null, null, null, false);
+ yield waitForFilePicker();
+ });
+});
+
+/**
+ * Test that saveImageURL will still work when passed a document instead
+ * of the aIsContentWindowPrivate argument. This is the deprecated API, and
+ * will not work in apps using remote browsers having PREF_UNSAFE_FORBIDDEN
+ * set to true.
+ */
+add_task(function* deprecated_API() {
+ yield BrowserTestUtils.withNewTab({
+ gBrowser,
+ url: IMAGE_PAGE,
+ }, function*(browser) {
+ yield pushPrefs([PREF_UNSAFE_FORBIDDEN, false]);
+
+ let url = yield ContentTask.spawn(browser, null, function*() {
+ let image = content.document.getElementById("image");
+ return image.href;
+ });
+
+ // Now get the document directly from content. If we run this test with
+ // e10s-enabled, this will be a CPOW, which is forbidden. We'll just
+ // pass the XUL document instead to test this interface.
+ let doc = document;
+
+ saveImageURL(url, "image.jpg", null, true, false, null, doc, null, null);
+ yield waitForFilePicker();
+ });
+});
diff --git a/toolkit/content/tests/browser/browser_save_resend_postdata.js b/toolkit/content/tests/browser/browser_save_resend_postdata.js
new file mode 100644
index 000000000..602a13d22
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_save_resend_postdata.js
@@ -0,0 +1,145 @@
+/* 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/. */
+
+var MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.init(window);
+
+/**
+ * Test for bug 471962 <https://bugzilla.mozilla.org/show_bug.cgi?id=471962>:
+ * When saving an inner frame as file only, the POST data of the outer page is
+ * sent to the address of the inner page.
+ *
+ * Test for bug 485196 <https://bugzilla.mozilla.org/show_bug.cgi?id=485196>:
+ * Web page generated by POST is retried as GET when Save Frame As used, and the
+ * page is no longer in the cache.
+ */
+function test() {
+ waitForExplicitFinish();
+
+ gBrowser.loadURI("http://mochi.test:8888/browser/toolkit/content/tests/browser/data/post_form_outer.sjs");
+
+ gBrowser.addEventListener("pageshow", function pageShown(event) {
+ if (event.target.location == "about:blank")
+ return;
+ gBrowser.removeEventListener("pageshow", pageShown);
+
+ // Submit the form in the outer page, then wait for both the outer
+ // document and the inner frame to be loaded again.
+ gBrowser.addEventListener("DOMContentLoaded", handleOuterSubmit);
+ gBrowser.contentDocument.getElementById("postForm").submit();
+ });
+
+ var framesLoaded = 0;
+ var innerFrame;
+
+ function handleOuterSubmit() {
+ if (++framesLoaded < 2)
+ return;
+
+ gBrowser.removeEventListener("DOMContentLoaded", handleOuterSubmit);
+
+ innerFrame = gBrowser.contentDocument.getElementById("innerFrame");
+
+ // Submit the form in the inner page.
+ gBrowser.addEventListener("DOMContentLoaded", handleInnerSubmit);
+ innerFrame.contentDocument.getElementById("postForm").submit();
+ }
+
+ function handleInnerSubmit() {
+ gBrowser.removeEventListener("DOMContentLoaded", handleInnerSubmit);
+
+ // Create the folder the page will be saved into.
+ var destDir = createTemporarySaveDirectory();
+ var file = destDir.clone();
+ file.append("no_default_file_name");
+ MockFilePicker.returnFiles = [file];
+ MockFilePicker.showCallback = function(fp) {
+ MockFilePicker.filterIndex = 1; // kSaveAsType_URL
+ };
+
+ mockTransferCallback = onTransferComplete;
+ mockTransferRegisterer.register();
+
+ registerCleanupFunction(function () {
+ mockTransferRegisterer.unregister();
+ MockFilePicker.cleanup();
+ destDir.remove(true);
+ });
+
+ var docToSave = innerFrame.contentDocument;
+ // We call internalSave instead of saveDocument to bypass the history
+ // cache.
+ internalSave(docToSave.location.href, docToSave, null, null,
+ docToSave.contentType, false, null, null,
+ docToSave.referrer ? makeURI(docToSave.referrer) : null,
+ docToSave, false, null);
+ }
+
+ function onTransferComplete(downloadSuccess) {
+ ok(downloadSuccess, "The inner frame should have been downloaded successfully");
+
+ // Read the entire saved file.
+ var file = MockFilePicker.returnFiles[0];
+ var fileContents = readShortFile(file);
+
+ // Check if outer POST data is found (bug 471962).
+ is(fileContents.indexOf("inputfield=outer"), -1,
+ "The saved inner frame does not contain outer POST data");
+
+ // Check if inner POST data is found (bug 485196).
+ isnot(fileContents.indexOf("inputfield=inner"), -1,
+ "The saved inner frame was generated using the correct POST data");
+
+ finish();
+ }
+}
+
+Cc["@mozilla.org/moz/jssubscript-loader;1"]
+ .getService(Ci.mozIJSSubScriptLoader)
+ .loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js",
+ this);
+
+function createTemporarySaveDirectory() {
+ var saveDir = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties)
+ .get("TmpD", Ci.nsIFile);
+ saveDir.append("testsavedir");
+ if (!saveDir.exists())
+ saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
+ return saveDir;
+}
+
+/**
+ * Reads the contents of the provided short file (up to 1 MiB).
+ *
+ * @param aFile
+ * nsIFile object pointing to the file to be read.
+ *
+ * @return
+ * String containing the raw octets read from the file.
+ */
+function readShortFile(aFile) {
+ var inputStream = Cc["@mozilla.org/network/file-input-stream;1"]
+ .createInstance(Ci.nsIFileInputStream);
+ inputStream.init(aFile, -1, 0, 0);
+ try {
+ var scrInputStream = Cc["@mozilla.org/scriptableinputstream;1"]
+ .createInstance(Ci.nsIScriptableInputStream);
+ scrInputStream.init(inputStream);
+ try {
+ // Assume that the file is much shorter than 1 MiB.
+ return scrInputStream.read(1048576);
+ }
+ finally {
+ // Close the scriptable stream after reading, even if the operation
+ // failed.
+ scrInputStream.close();
+ }
+ }
+ finally {
+ // Close the stream after reading, if it is still open, even if the read
+ // operation failed.
+ inputStream.close();
+ }
+}
diff --git a/toolkit/content/tests/browser/common/mockTransfer.js b/toolkit/content/tests/browser/common/mockTransfer.js
new file mode 100644
index 000000000..c8b8fc161
--- /dev/null
+++ b/toolkit/content/tests/browser/common/mockTransfer.js
@@ -0,0 +1,67 @@
+/* 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/. */
+
+Cc["@mozilla.org/moz/jssubscript-loader;1"]
+ .getService(Ci.mozIJSSubScriptLoader)
+ .loadSubScript("chrome://mochikit/content/tests/SimpleTest/MockObjects.js", this);
+
+var mockTransferCallback;
+
+/**
+ * This "transfer" object implementation continues the currently running test
+ * when the download is completed, reporting true for success or false for
+ * failure as the first argument of the testRunner.continueTest function.
+ */
+function MockTransfer() {
+ this._downloadIsSuccessful = true;
+}
+
+MockTransfer.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([
+ Ci.nsIWebProgressListener,
+ Ci.nsIWebProgressListener2,
+ Ci.nsITransfer,
+ ]),
+
+ /* nsIWebProgressListener */
+ onStateChange: function MTFC_onStateChange(aWebProgress, aRequest,
+ aStateFlags, aStatus) {
+ // If at least one notification reported an error, the download failed.
+ if (!Components.isSuccessCode(aStatus))
+ this._downloadIsSuccessful = false;
+
+ // If the download is finished
+ if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
+ (aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK))
+ // Continue the test, reporting the success or failure condition.
+ mockTransferCallback(this._downloadIsSuccessful);
+ },
+ onProgressChange: function () {},
+ onLocationChange: function () {},
+ onStatusChange: function MTFC_onStatusChange(aWebProgress, aRequest, aStatus,
+ aMessage) {
+ // If at least one notification reported an error, the download failed.
+ if (!Components.isSuccessCode(aStatus))
+ this._downloadIsSuccessful = false;
+ },
+ onSecurityChange: function () {},
+
+ /* nsIWebProgressListener2 */
+ onProgressChange64: function () {},
+ onRefreshAttempted: function () {},
+
+ /* nsITransfer */
+ init: function() {},
+ setSha256Hash: function() {},
+ setSignatureInfo: function() {}
+};
+
+// Create an instance of a MockObjectRegisterer whose methods can be used to
+// temporarily replace the default "@mozilla.org/transfer;1" object factory with
+// one that provides the mock implementation above. To activate the mock object
+// factory, call the "register" method. Starting from that moment, all the
+// transfer objects that are requested will be mock objects, until the
+// "unregister" method is called.
+var mockTransferRegisterer =
+ new MockObjectRegisterer("@mozilla.org/transfer;1", MockTransfer);
diff --git a/toolkit/content/tests/browser/data/post_form_inner.sjs b/toolkit/content/tests/browser/data/post_form_inner.sjs
new file mode 100644
index 000000000..ce72159d8
--- /dev/null
+++ b/toolkit/content/tests/browser/data/post_form_inner.sjs
@@ -0,0 +1,31 @@
+/* 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/. */
+
+const CC = Components.Constructor;
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream");
+
+function handleRequest(request, response)
+{
+ var body =
+ '<html>\
+ <body>\
+ Inner POST data: ';
+
+ var bodyStream = new BinaryInputStream(request.bodyInputStream);
+ var bytes = [], avail = 0;
+ while ((avail = bodyStream.available()) > 0)
+ body += String.fromCharCode.apply(String, bodyStream.readByteArray(avail));
+
+ body +=
+ '<form id="postForm" action="post_form_inner.sjs" method="post">\
+ <input type="text" name="inputfield" value="inner">\
+ <input type="submit">\
+ </form>\
+ </body>\
+ </html>';
+
+ response.bodyOutputStream.write(body, body.length);
+}
diff --git a/toolkit/content/tests/browser/data/post_form_outer.sjs b/toolkit/content/tests/browser/data/post_form_outer.sjs
new file mode 100644
index 000000000..89256fcfb
--- /dev/null
+++ b/toolkit/content/tests/browser/data/post_form_outer.sjs
@@ -0,0 +1,34 @@
+/* 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/. */
+
+const CC = Components.Constructor;
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream");
+
+function handleRequest(request, response)
+{
+ var body =
+ '<html>\
+ <body>\
+ Outer POST data: ';
+
+ var bodyStream = new BinaryInputStream(request.bodyInputStream);
+ var bytes = [], avail = 0;
+ while ((avail = bodyStream.available()) > 0)
+ body += String.fromCharCode.apply(String, bodyStream.readByteArray(avail));
+
+ body +=
+ '<form id="postForm" action="post_form_outer.sjs" method="post">\
+ <input type="text" name="inputfield" value="outer">\
+ <input type="submit">\
+ </form>\
+ \
+ <iframe id="innerFrame" src="post_form_inner.sjs" width="400" height="200">\
+ \
+ </body>\
+ </html>';
+
+ response.bodyOutputStream.write(body, body.length);
+}
diff --git a/toolkit/content/tests/browser/empty.png b/toolkit/content/tests/browser/empty.png
new file mode 100644
index 000000000..17ddf0c3e
--- /dev/null
+++ b/toolkit/content/tests/browser/empty.png
Binary files differ
diff --git a/toolkit/content/tests/browser/file_contentTitle.html b/toolkit/content/tests/browser/file_contentTitle.html
new file mode 100644
index 000000000..8d330aa0f
--- /dev/null
+++ b/toolkit/content/tests/browser/file_contentTitle.html
@@ -0,0 +1,14 @@
+<html>
+<head><title>Test Page</title></head>
+<body>
+<script type="text/javascript">
+dump("Script!\n");
+addEventListener("load", () => {
+ // Trigger an onLocationChange event. We want to make sure the title is still correct afterwards.
+ location.hash = "#x2";
+ var event = new Event("TestLocationChange");
+ document.dispatchEvent(event);
+}, false);
+</script>
+</body>
+</html>
diff --git a/toolkit/content/tests/browser/file_mediaPlayback.html b/toolkit/content/tests/browser/file_mediaPlayback.html
new file mode 100644
index 000000000..5df0bc154
--- /dev/null
+++ b/toolkit/content/tests/browser/file_mediaPlayback.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script type="text/javascript">
+var audio = new Audio();
+audio.oncanplay = function() {
+ audio.oncanplay = null;
+ audio.play();
+};
+audio.src = "audio.ogg";
+</script>
diff --git a/toolkit/content/tests/browser/file_mediaPlayback2.html b/toolkit/content/tests/browser/file_mediaPlayback2.html
new file mode 100644
index 000000000..dffbd299b
--- /dev/null
+++ b/toolkit/content/tests/browser/file_mediaPlayback2.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<body>
+<script type="text/javascript">
+var audio = new Audio();
+audio.oncanplay = function() {
+ audio.oncanplay = null;
+ audio.play();
+};
+audio.src = "audio.ogg";
+document.body.appendChild(audio);
+</script>
+</body>
diff --git a/toolkit/content/tests/browser/file_mediaPlaybackFrame.html b/toolkit/content/tests/browser/file_mediaPlaybackFrame.html
new file mode 100644
index 000000000..119db62ec
--- /dev/null
+++ b/toolkit/content/tests/browser/file_mediaPlaybackFrame.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<iframe src="file_mediaPlayback.html"></iframe>
diff --git a/toolkit/content/tests/browser/file_mediaPlaybackFrame2.html b/toolkit/content/tests/browser/file_mediaPlaybackFrame2.html
new file mode 100644
index 000000000..d96a4cd4e
--- /dev/null
+++ b/toolkit/content/tests/browser/file_mediaPlaybackFrame2.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<iframe src="file_mediaPlayback2.html"></iframe>
diff --git a/toolkit/content/tests/browser/file_multipleAudio.html b/toolkit/content/tests/browser/file_multipleAudio.html
new file mode 100644
index 000000000..5dc37febb
--- /dev/null
+++ b/toolkit/content/tests/browser/file_multipleAudio.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<head>
+ <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+ <meta content="utf-8" http-equiv="encoding">
+</head>
+<body>
+<audio id="autoplay" src="audio.ogg"></audio>
+<audio id="nonautoplay" src="audio.ogg"></audio>
+<script type="text/javascript">
+
+// In linux debug on try server, sometimes the download process would fail, so
+// we can't activate the "auto-play" or playing after receving "oncanplay".
+// Therefore, we just call play here.
+var audio = document.getElementById("autoplay");
+audio.loop = true;
+audio.play();
+
+</script>
+</body>
diff --git a/toolkit/content/tests/browser/file_multiplePlayingAudio.html b/toolkit/content/tests/browser/file_multiplePlayingAudio.html
new file mode 100644
index 000000000..ae122506f
--- /dev/null
+++ b/toolkit/content/tests/browser/file_multiplePlayingAudio.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<head>
+ <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+ <meta content="utf-8" http-equiv="encoding">
+</head>
+<body>
+<audio id="audio1" src="audio.ogg" controls></audio>
+<audio id="audio2" src="audio.ogg" controls></audio>
+<script type="text/javascript">
+
+// In linux debug on try server, sometimes the download process would fail, so
+// we can't activate the "auto-play" or playing after receving "oncanplay".
+// Therefore, we just call play here.
+var audio1 = document.getElementById("audio1");
+audio1.loop = true;
+audio1.play();
+
+var audio2 = document.getElementById("audio2");
+audio2.loop = true;
+audio2.play();
+
+</script>
+</body>
diff --git a/toolkit/content/tests/browser/file_redirect.html b/toolkit/content/tests/browser/file_redirect.html
new file mode 100644
index 000000000..4d5fa9dfd
--- /dev/null
+++ b/toolkit/content/tests/browser/file_redirect.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>redirecting...</title>
+<script>
+window.addEventListener("load",
+ () => window.location = "file_redirect_to.html");
+</script>
+<body>
+redirectin u bro
+</body>
+</html>
diff --git a/toolkit/content/tests/browser/file_redirect_to.html b/toolkit/content/tests/browser/file_redirect_to.html
new file mode 100644
index 000000000..28c0b5371
--- /dev/null
+++ b/toolkit/content/tests/browser/file_redirect_to.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>redirected!</title>
+<script>
+window.addEventListener("load", () => {
+ var event = new Event("RedirectDone");
+ document.dispatchEvent(event);
+});
+</script>
+<body>
+u got redirected, bro
+</body>
+</html>
diff --git a/toolkit/content/tests/browser/head.js b/toolkit/content/tests/browser/head.js
new file mode 100644
index 000000000..1c6c2b54f
--- /dev/null
+++ b/toolkit/content/tests/browser/head.js
@@ -0,0 +1,33 @@
+"use strict";
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+ "resource://gre/modules/Promise.jsm");
+
+/**
+ * A wrapper for the findbar's method "close", which is not synchronous
+ * because of animation.
+ */
+function closeFindbarAndWait(findbar) {
+ return new Promise((resolve) => {
+ if (findbar.hidden) {
+ resolve();
+ return;
+ }
+ findbar.addEventListener("transitionend", function cont(aEvent) {
+ if (aEvent.propertyName != "visibility") {
+ return;
+ }
+ findbar.removeEventListener("transitionend", cont);
+ resolve();
+ });
+ findbar.close();
+ });
+}
+
+function pushPrefs(...aPrefs) {
+ let deferred = Promise.defer();
+ SpecialPowers.pushPrefEnv({"set": aPrefs}, deferred.resolve);
+ return deferred.promise;
+}
diff --git a/toolkit/content/tests/browser/image.jpg b/toolkit/content/tests/browser/image.jpg
new file mode 100644
index 000000000..5031808ad
--- /dev/null
+++ b/toolkit/content/tests/browser/image.jpg
Binary files differ
diff --git a/toolkit/content/tests/browser/image_page.html b/toolkit/content/tests/browser/image_page.html
new file mode 100644
index 000000000..522a1d8cf
--- /dev/null
+++ b/toolkit/content/tests/browser/image_page.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>OHAI</title>
+<body>
+<img id="image" src="image.jpg" />
+</body>
+</html>