summaryrefslogtreecommitdiffstats
path: root/comm/suite/browser/test
diff options
context:
space:
mode:
Diffstat (limited to 'comm/suite/browser/test')
-rw-r--r--comm/suite/browser/test/browser/alltabslistener.html8
-rw-r--r--comm/suite/browser/test/browser/authenticate.sjs210
-rw-r--r--comm/suite/browser/test/browser/browser.ini38
-rw-r--r--comm/suite/browser/test/browser/browser_alltabslistener.js201
-rw-r--r--comm/suite/browser/test/browser/browser_bug329212.js42
-rw-r--r--comm/suite/browser/test/browser/browser_bug409624.js57
-rw-r--r--comm/suite/browser/test/browser/browser_bug413915.js70
-rw-r--r--comm/suite/browser/test/browser/browser_bug427559.js39
-rw-r--r--comm/suite/browser/test/browser/browser_bug435325.js56
-rw-r--r--comm/suite/browser/test/browser/browser_bug462289.js87
-rw-r--r--comm/suite/browser/test/browser/browser_bug519216.js50
-rw-r--r--comm/suite/browser/test/browser/browser_bug561636.js459
-rw-r--r--comm/suite/browser/test/browser/browser_bug562649.js26
-rw-r--r--comm/suite/browser/test/browser/browser_bug581947.js95
-rw-r--r--comm/suite/browser/test/browser/browser_bug585511.js24
-rw-r--r--comm/suite/browser/test/browser/browser_bug595507.js39
-rw-r--r--comm/suite/browser/test/browser/browser_bug623155.js136
-rw-r--r--comm/suite/browser/test/browser/browser_ctrlTab.js197
-rw-r--r--comm/suite/browser/test/browser/browser_fayt.js25
-rw-r--r--comm/suite/browser/test/browser/browser_notification_tab_switching.js95
-rw-r--r--comm/suite/browser/test/browser/browser_pageInfo.js38
-rw-r--r--comm/suite/browser/test/browser/browser_page_style_menu.js67
-rw-r--r--comm/suite/browser/test/browser/browser_popupNotification.js782
-rw-r--r--comm/suite/browser/test/browser/browser_privatebrowsing_protocolhandler.js65
-rw-r--r--comm/suite/browser/test/browser/browser_privatebrowsing_protocolhandler_page.html13
-rw-r--r--comm/suite/browser/test/browser/browser_relatedTabs.js52
-rw-r--r--comm/suite/browser/test/browser/browser_scope.js4
-rw-r--r--comm/suite/browser/test/browser/browser_selectTabAtIndex.js22
-rw-r--r--comm/suite/browser/test/browser/browser_urlbarCopying.js204
-rw-r--r--comm/suite/browser/test/browser/feed_tab.html17
-rw-r--r--comm/suite/browser/test/browser/file_dom_notifications.html40
-rw-r--r--comm/suite/browser/test/browser/head.js63
-rw-r--r--comm/suite/browser/test/browser/page_style_sample.html31
-rw-r--r--comm/suite/browser/test/browser/redirect_bug623155.sjs16
-rw-r--r--comm/suite/browser/test/browser/title_test.svg59
-rw-r--r--comm/suite/browser/test/chrome/chrome.ini3
-rw-r--r--comm/suite/browser/test/chrome/test_maxSniffing.html37
-rw-r--r--comm/suite/browser/test/mochitest/audio.oggbin0 -> 47411 bytes
-rw-r--r--comm/suite/browser/test/mochitest/bug364677-data.xml5
-rw-r--r--comm/suite/browser/test/mochitest/bug364677-data.xml^headers^1
-rw-r--r--comm/suite/browser/test/mochitest/bug395533-data.txt6
-rw-r--r--comm/suite/browser/test/mochitest/bug436801-data.xml44
-rw-r--r--comm/suite/browser/test/mochitest/ctxmenu-image.pngbin0 -> 5401 bytes
-rw-r--r--comm/suite/browser/test/mochitest/feed_discovery.html112
-rw-r--r--comm/suite/browser/test/mochitest/mochitest.ini17
-rw-r--r--comm/suite/browser/test/mochitest/subtst_contextmenu.html70
-rw-r--r--comm/suite/browser/test/mochitest/test_bug364677.html32
-rw-r--r--comm/suite/browser/test/mochitest/test_bug395533.html39
-rw-r--r--comm/suite/browser/test/mochitest/test_bug436801.html118
-rw-r--r--comm/suite/browser/test/mochitest/test_contextmenu.html931
-rw-r--r--comm/suite/browser/test/mochitest/test_feed_discovery.html56
-rw-r--r--comm/suite/browser/test/mochitest/test_registerHandler.html85
-rw-r--r--comm/suite/browser/test/mochitest/valid-feed.xml23
-rw-r--r--comm/suite/browser/test/mochitest/valid-unsniffable-feed.xml32
-rw-r--r--comm/suite/browser/test/mochitest/video.oggbin0 -> 285310 bytes
55 files changed, 5038 insertions, 0 deletions
diff --git a/comm/suite/browser/test/browser/alltabslistener.html b/comm/suite/browser/test/browser/alltabslistener.html
new file mode 100644
index 0000000000..166c31037a
--- /dev/null
+++ b/comm/suite/browser/test/browser/alltabslistener.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>Test page for bug 463387</title>
+</head>
+<body>
+<p>Test page for bug 463387</p>
+</body>
+</html>
diff --git a/comm/suite/browser/test/browser/authenticate.sjs b/comm/suite/browser/test/browser/authenticate.sjs
new file mode 100644
index 0000000000..2f8c85adc1
--- /dev/null
+++ b/comm/suite/browser/test/browser/authenticate.sjs
@@ -0,0 +1,210 @@
+function handleRequest(request, response)
+{
+ try {
+ reallyHandleRequest(request, response);
+ } catch (e) {
+ response.setStatusLine("1.0", 200, "AlmostOK");
+ response.write("Error handling request: " + e);
+ }
+}
+
+
+function reallyHandleRequest(request, response) {
+ var match;
+ var requestAuth = true, requestProxyAuth = true;
+
+ // Allow the caller to drive how authentication is processed via the query.
+ // Eg, http://localhost:8888/authenticate.sjs?user=foo&realm=bar
+ // The extra ? allows the user/pass/realm checks to succeed if the name is
+ // at the beginning of the query string.
+ var query = "?" + request.queryString;
+
+ var expected_user = "", expected_pass = "", realm = "mochitest";
+ var proxy_expected_user = "", proxy_expected_pass = "", proxy_realm = "mochi-proxy";
+ var huge = false, anonymous = false;
+ var authHeaderCount = 1;
+ // user=xxx
+ match = /[^_]user=([^&]*)/.exec(query);
+ if (match)
+ expected_user = match[1];
+
+ // pass=xxx
+ match = /[^_]pass=([^&]*)/.exec(query);
+ if (match)
+ expected_pass = match[1];
+
+ // realm=xxx
+ match = /[^_]realm=([^&]*)/.exec(query);
+ if (match)
+ realm = match[1];
+
+ // proxy_user=xxx
+ match = /proxy_user=([^&]*)/.exec(query);
+ if (match)
+ proxy_expected_user = match[1];
+
+ // proxy_pass=xxx
+ match = /proxy_pass=([^&]*)/.exec(query);
+ if (match)
+ proxy_expected_pass = match[1];
+
+ // proxy_realm=xxx
+ match = /proxy_realm=([^&]*)/.exec(query);
+ if (match)
+ proxy_realm = match[1];
+
+ // huge=1
+ match = /huge=1/.exec(query);
+ if (match)
+ huge = true;
+
+ // multiple=1
+ match = /multiple=([^&]*)/.exec(query);
+ if (match)
+ authHeaderCount = match[1]+0;
+
+ // anonymous=1
+ match = /anonymous=1/.exec(query);
+ if (match)
+ anonymous = true;
+
+ // Look for an authentication header, if any, in the request.
+ //
+ // EG: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
+ //
+ // This test only supports Basic auth. The value sent by the client is
+ // "username:password", obscured with base64 encoding.
+
+ var actual_user = "", actual_pass = "", authHeader, authPresent = false;
+ if (request.hasHeader("Authorization")) {
+ authPresent = true;
+ authHeader = request.getHeader("Authorization");
+ match = /Basic (.+)/.exec(authHeader);
+ if (match.length != 2)
+ throw "Couldn't parse auth header: " + authHeader;
+
+ var userpass = base64ToString(match[1]); // no atob() :-(
+ match = /(.*):(.*)/.exec(userpass);
+ if (match.length != 3)
+ throw "Couldn't decode auth header: " + userpass;
+ actual_user = match[1];
+ actual_pass = match[2];
+ }
+
+ var proxy_actual_user = "", proxy_actual_pass = "";
+ if (request.hasHeader("Proxy-Authorization")) {
+ authHeader = request.getHeader("Proxy-Authorization");
+ match = /Basic (.+)/.exec(authHeader);
+ if (match.length != 2)
+ throw "Couldn't parse auth header: " + authHeader;
+
+ var userpass = base64ToString(match[1]); // no atob() :-(
+ match = /(.*):(.*)/.exec(userpass);
+ if (match.length != 3)
+ throw "Couldn't decode auth header: " + userpass;
+ proxy_actual_user = match[1];
+ proxy_actual_pass = match[2];
+ }
+
+ // Don't request authentication if the credentials we got were what we
+ // expected.
+ if (expected_user == actual_user &&
+ expected_pass == actual_pass) {
+ requestAuth = false;
+ }
+ if (proxy_expected_user == proxy_actual_user &&
+ proxy_expected_pass == proxy_actual_pass) {
+ requestProxyAuth = false;
+ }
+
+ if (anonymous) {
+ if (authPresent) {
+ response.setStatusLine("1.0", 400, "Unexpected authorization header found");
+ } else {
+ response.setStatusLine("1.0", 200, "Authorization header not found");
+ }
+ } else {
+ if (requestProxyAuth) {
+ response.setStatusLine("1.0", 407, "Proxy authentication required");
+ for (i = 0; i < authHeaderCount; ++i)
+ response.setHeader("Proxy-Authenticate", "basic realm=\"" + proxy_realm + "\"", true);
+ } else if (requestAuth) {
+ response.setStatusLine("1.0", 401, "Authentication required");
+ for (i = 0; i < authHeaderCount; ++i)
+ response.setHeader("WWW-Authenticate", "basic realm=\"" + realm + "\"", true);
+ } else {
+ response.setStatusLine("1.0", 200, "OK");
+ }
+ }
+
+ response.setHeader("Content-Type", "application/xhtml+xml", false);
+ response.write("<html xmlns='http://www.w3.org/1999/xhtml'>");
+ response.write("<p>Login: <span id='ok'>" + (requestAuth ? "FAIL" : "PASS") + "</span></p>\n");
+ response.write("<p>Proxy: <span id='proxy'>" + (requestProxyAuth ? "FAIL" : "PASS") + "</span></p>\n");
+ response.write("<p>Auth: <span id='auth'>" + authHeader + "</span></p>\n");
+ response.write("<p>User: <span id='user'>" + actual_user + "</span></p>\n");
+ response.write("<p>Pass: <span id='pass'>" + actual_pass + "</span></p>\n");
+
+ if (huge) {
+ response.write("<div style='display: none'>");
+ for (i = 0; i < 100000; i++) {
+ response.write("123456789\n");
+ }
+ response.write("</div>");
+ response.write("<span id='footnote'>This is a footnote after the huge content fill</span>");
+ }
+
+ response.write("</html>");
+}
+
+
+// base64 decoder
+//
+// Yoinked from extensions/xml-rpc/src/nsXmlRpcClient.js because btoa()
+// doesn't seem to exist. :-(
+/* Convert Base64 data to a string */
+const toBinaryTable = [
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+ 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
+ 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+ -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+ 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+];
+const base64Pad = '=';
+
+function base64ToString(data) {
+
+ var result = '';
+ var leftbits = 0; // number of bits decoded, but yet to be appended
+ var leftdata = 0; // bits decoded, but yet to be appended
+
+ // Convert one by one.
+ for (var i = 0; i < data.length; i++) {
+ var c = toBinaryTable[data.charCodeAt(i) & 0x7f];
+ var padding = (data[i] == base64Pad);
+ // Skip illegal characters and whitespace
+ if (c == -1) continue;
+
+ // Collect data into leftdata, update bitcount
+ leftdata = (leftdata << 6) | c;
+ leftbits += 6;
+
+ // If we have 8 or more bits, append 8 bits to the result
+ if (leftbits >= 8) {
+ leftbits -= 8;
+ // Append if not padding.
+ if (!padding)
+ result += String.fromCharCode((leftdata >> leftbits) & 0xff);
+ leftdata &= (1 << leftbits) - 1;
+ }
+ }
+
+ // If there are any bits left, the base64 string was corrupted
+ if (leftbits)
+ throw Components.Exception('Corrupted base64 string');
+
+ return result;
+}
diff --git a/comm/suite/browser/test/browser/browser.ini b/comm/suite/browser/test/browser/browser.ini
new file mode 100644
index 0000000000..a6b00157c6
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser.ini
@@ -0,0 +1,38 @@
+[DEFAULT]
+support-files =
+ head.js
+
+[browser_alltabslistener.js]
+support-files = alltabslistener.html
+[browser_bug329212.js]
+support-files = title_test.svg
+[browser_bug409624.js]
+[browser_bug413915.js]
+[browser_bug427559.js]
+[browser_bug435325.js]
+[browser_bug462289.js]
+skip-if = toolkit == "cocoa"
+[browser_bug519216.js]
+[browser_bug561636.js]
+[browser_bug562649.js]
+[browser_bug581947.js]
+[browser_bug585511.js]
+[browser_bug595507.js]
+[browser_bug623155.js]
+support-files = redirect_bug623155.sjs
+[browser_fayt.js]
+[browser_page_style_menu.js]
+support-files = page_style_sample.html
+[browser_notification_tab_switching.js]
+support-files = file_dom_notifications.html
+[browser_pageInfo.js]
+support-files = feed_tab.html
+[browser_popupNotification.js]
+[browser_privatebrowsing_protocolhandler.js]
+support-files = browser_privatebrowsing_protocolhandler_page.html
+[browser_relatedTabs.js]
+[browser_scope.js]
+[browser_selectTabAtIndex.js]
+[browser_urlbarCopying.js]
+support-files =
+ authenticate.sjs
diff --git a/comm/suite/browser/test/browser/browser_alltabslistener.js b/comm/suite/browser/test/browser/browser_alltabslistener.js
new file mode 100644
index 0000000000..609a4e66e8
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_alltabslistener.js
@@ -0,0 +1,201 @@
+const gCompleteState = Ci.nsIWebProgressListener.STATE_STOP +
+ Ci.nsIWebProgressListener.STATE_IS_NETWORK;
+
+var gFrontProgressListener = {
+ onProgressChange: function (aWebProgress, aRequest,
+ aCurSelfProgress, aMaxSelfProgress,
+ aCurTotalProgress, aMaxTotalProgress) {
+ },
+
+ onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus) {
+ var state = "onStateChange";
+ info("FrontProgress: " + state + " 0x" + aStateFlags.toString(16));
+ ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
+ is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
+ gFrontNotificationsPos++;
+ },
+
+ onLocationChange: function (aWebProgress, aRequest, aLocationURI, aFlags) {
+ var state = "onLocationChange";
+ info("FrontProgress: " + state + " " + aLocationURI.spec);
+ ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
+ is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
+ gFrontNotificationsPos++;
+ },
+
+ onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
+ },
+
+ onSecurityChange: function (aWebProgress, aRequest, aState) {
+ var state = "onSecurityChange";
+ info("FrontProgress: " + state + " 0x" + aState.toString(16));
+ ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
+ is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
+ gFrontNotificationsPos++;
+ }
+}
+
+var gAllProgressListener = {
+ onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
+ var state = "onStateChange";
+ info("AllProgress: " + state + " 0x" + aStateFlags.toString(16));
+ is(aBrowser, gTestBrowser, state + " notification came from the correct browser");
+ ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
+ is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
+ gAllNotificationsPos++;
+
+ if ((aStateFlags & gCompleteState) == gCompleteState) {
+ is(gAllNotificationsPos, gAllNotifications.length, "Saw the expected number of notifications");
+ is(gFrontNotificationsPos, gFrontNotifications.length, "Saw the expected number of frontnotifications");
+ executeSoon(gNextTest);
+ }
+ },
+
+ onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI, aFlags) {
+ var state = "onLocationChange";
+ info("AllProgress: " + state + " " + aLocationURI.spec);
+ is(aBrowser, gTestBrowser, state + " notification came from the correct browser");
+ ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
+ is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
+ gAllNotificationsPos++;
+ },
+
+ onStatusChange: function (aBrowser, aWebProgress, aRequest, aStatus, aMessage) {
+ var state = "onStatusChange";
+ is(aBrowser, gTestBrowser, state + " notification came from the correct browser");
+ },
+
+ onSecurityChange: function (aBrowser, aWebProgress, aRequest, aState) {
+ var state = "onSecurityChange";
+ info("AllProgress: " + state + " 0x" + aState.toString(16));
+ is(aBrowser, gTestBrowser, state + " notification came from the correct browser");
+ ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
+ is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
+ gAllNotificationsPos++;
+ }
+}
+
+var gFrontNotifications, gAllNotifications, gFrontNotificationsPos, gAllNotificationsPos;
+var gBackgroundTab, gForegroundTab, gBackgroundBrowser, gForegroundBrowser, gTestBrowser;
+var gTestPage = "/browser/suite/browser/test/browser/alltabslistener.html";
+var gNextTest;
+
+function test() {
+ waitForExplicitFinish();
+
+ gBackgroundTab = getBrowser().addTab("about:blank");
+ gForegroundTab = getBrowser().addTab("about:blank");
+ gBackgroundBrowser = getBrowser().getBrowserForTab(gBackgroundTab);
+ gForegroundBrowser = getBrowser().getBrowserForTab(gForegroundTab);
+ getBrowser().selectedTab = gForegroundTab;
+
+ // We must wait until the about:blank page has completed loading before
+ // starting tests or we get notifications from that
+ gForegroundBrowser.addEventListener("load", startTests, true);
+}
+
+function runTest(browser, url, next) {
+ gFrontNotificationsPos = 0;
+ gAllNotificationsPos = 0;
+ gNextTest = next;
+ gTestBrowser = browser;
+ browser.loadURI(url);
+}
+
+function startTests() {
+ gForegroundBrowser.removeEventListener("load", startTests, true);
+ executeSoon(startTest1);
+}
+
+function startTest1() {
+ info("\nTest 1");
+ getBrowser().addProgressListener(gFrontProgressListener);
+ getBrowser().addTabsProgressListener(gAllProgressListener);
+
+ gAllNotifications = [
+ "onStateChange",
+ "onLocationChange",
+ "onSecurityChange",
+ "onStateChange"
+ ];
+ gFrontNotifications = gAllNotifications;
+ runTest(gForegroundBrowser, "http://example.org" + gTestPage, startTest2);
+}
+
+function startTest2() {
+ info("\nTest 2");
+ gAllNotifications = [
+ "onStateChange",
+ "onLocationChange",
+ "onSecurityChange",
+ "onSecurityChange",
+ "onStateChange"
+ ];
+ gFrontNotifications = gAllNotifications;
+ runTest(gForegroundBrowser, "https://example.com" + gTestPage, startTest3);
+}
+
+function startTest3() {
+ info("\nTest 3");
+ gAllNotifications = [
+ "onStateChange",
+ "onLocationChange",
+ "onSecurityChange",
+ "onStateChange"
+ ];
+ gFrontNotifications = [];
+ runTest(gBackgroundBrowser, "http://example.org" + gTestPage, startTest4);
+}
+
+function startTest4() {
+ info("\nTest 4");
+ gAllNotifications = [
+ "onStateChange",
+ "onLocationChange",
+ "onSecurityChange",
+ "onSecurityChange",
+ "onStateChange"
+ ];
+ gFrontNotifications = [];
+ runTest(gBackgroundBrowser, "https://example.com" + gTestPage, startTest5);
+}
+
+function startTest5() {
+ info("\nTest 5");
+ // Switch the foreground browser
+ [gForegroundBrowser, gBackgroundBrowser] = [gBackgroundBrowser, gForegroundBrowser];
+ [gForegroundTab, gBackgroundTab] = [gBackgroundTab, gForegroundTab];
+ // Avoid the onLocationChange this will fire
+ getBrowser().removeProgressListener(gFrontProgressListener);
+ getBrowser().selectedTab = gForegroundTab;
+ getBrowser().addProgressListener(gFrontProgressListener);
+
+ gAllNotifications = [
+ "onStateChange",
+ "onLocationChange",
+ "onSecurityChange",
+ "onStateChange"
+ ];
+ gFrontNotifications = gAllNotifications;
+ runTest(gForegroundBrowser, "http://example.org" + gTestPage, startTest6);
+}
+
+function startTest6() {
+ info("\nTest 6");
+ gAllNotifications = [
+ "onStateChange",
+ "onLocationChange",
+ "onSecurityChange",
+ "onStateChange"
+ ];
+ gFrontNotifications = [];
+ runTest(gBackgroundBrowser, "http://example.org" + gTestPage, finishTest);
+}
+
+function finishTest() {
+ getBrowser().removeProgressListener(gFrontProgressListener);
+ getBrowser().removeTabsProgressListener(gAllProgressListener);
+ getBrowser().removeTab(gBackgroundTab);
+ getBrowser().removeTab(gForegroundTab);
+ finish();
+}
diff --git a/comm/suite/browser/test/browser/browser_bug329212.js b/comm/suite/browser/test/browser/browser_bug329212.js
new file mode 100644
index 0000000000..86925a4cb8
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug329212.js
@@ -0,0 +1,42 @@
+function test() {
+ waitForExplicitFinish();
+ gBrowser.selectedTab = gBrowser.addTab();
+ gBrowser.selectedBrowser.addEventListener("load", function loadListener() {
+ gBrowser.selectedBrowser.removeEventListener("load", loadListener, true);
+
+ let doc = gBrowser.contentDocument;
+ let tooltip = document.getElementById("aHTMLTooltip");
+
+ ok(FillInHTMLTooltip(doc.getElementById("svg1")), "should get title");
+ is(tooltip.getAttribute("label"), "This is a non-root SVG element title");
+
+ ok(FillInHTMLTooltip(doc.getElementById("text1")), "should get title");
+ is(tooltip.getAttribute("label"), "\n\n\n This is a title\n\n ");
+
+ ok(!FillInHTMLTooltip(doc.getElementById("text2")), "should not get title");
+
+ ok(!FillInHTMLTooltip(doc.getElementById("text3")), "should not get title");
+
+ ok(FillInHTMLTooltip(doc.getElementById("link1")), "should get title");
+ is(tooltip.getAttribute("label"), "\n This is a title\n ");
+ ok(FillInHTMLTooltip(doc.getElementById("text4")), "should get title");
+ is(tooltip.getAttribute("label"), "\n This is a title\n ");
+
+ ok(!FillInHTMLTooltip(doc.getElementById("link2")), "should not get title");
+
+ ok(FillInHTMLTooltip(doc.getElementById("link3")), "should get title");
+ isnot(tooltip.getAttribute("label"), "");
+
+ ok(FillInHTMLTooltip(doc.getElementById("link4")), "should get title");
+ is(tooltip.getAttribute("label"), "This is an xlink:title attribute");
+
+ ok(!FillInHTMLTooltip(doc.getElementById("text5")), "should not get title");
+
+ gBrowser.removeCurrentTab();
+ finish();
+ }, true);
+
+ content.location =
+ "http://mochi.test:8888/browser/suite/browser/test/browser/title_test.svg";
+}
+
diff --git a/comm/suite/browser/test/browser/browser_bug409624.js b/comm/suite/browser/test/browser/browser_bug409624.js
new file mode 100644
index 0000000000..c3a800dffa
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug409624.js
@@ -0,0 +1,57 @@
+/* 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/. */
+ChromeUtils.defineModuleGetter(this, "FormHistory",
+ "resource://gre/modules/FormHistory.jsm");
+
+function test() {
+ waitForExplicitFinish();
+
+ // This test relies on the form history being empty to start with delete
+ // all the items first.
+ FormHistory.update({ op: "remove" },
+ { handleError: function (error) {
+ do_throw("Error occurred updating form history: " + error);
+ },
+ handleCompletion: function (reason) { if (!reason) test2(); },
+ });
+}
+
+function test2()
+{
+ let prefService = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefBranch);
+
+ let findBar = document.getElementById("FindToolbar");
+ let textbox = findBar.getElement("findbar-textbox");
+
+ let temp = {};
+ ChromeUtils.import("resource:///modules/Sanitizer.jsm", temp);
+ let s = temp.Sanitizer;
+ let prefBranch = prefService.getBranch("privacy.clearOnShutdown.");
+
+ prefBranch.setBoolPref("cache", false);
+ prefBranch.setBoolPref("cookies", false);
+ prefBranch.setBoolPref("downloads", false);
+ prefBranch.setBoolPref("formdata", true);
+ prefBranch.setBoolPref("history", false);
+ prefBranch.setBoolPref("offlineApps", false);
+ prefBranch.setBoolPref("passwords", false);
+ prefBranch.setBoolPref("sessions", false);
+ prefBranch.setBoolPref("siteSettings", false);
+
+ prefService.setBoolPref("privacy.sanitize.promptOnSanitize", false);
+
+ // Sanitize now so we can test the baseline point.
+ s.sanitize();
+ ok(!gFindBar.hasTransactions, "pre-test baseline for sanitizer");
+
+ gFindBar.getElement("findbar-textbox").value = "m";
+ ok(gFindBar.hasTransactions, "formdata can be cleared after input");
+
+ s.sanitize();
+ is(gFindBar.getElement("findbar-textbox").value, "", "findBar textbox should be empty after sanitize");
+ ok(!gFindBar.hasTransactions, "No transactions after sanitize");
+
+ finish();
+}
diff --git a/comm/suite/browser/test/browser/browser_bug413915.js b/comm/suite/browser/test/browser/browser_bug413915.js
new file mode 100644
index 0000000000..98b968a1b3
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug413915.js
@@ -0,0 +1,70 @@
+ChromeUtils.defineModuleGetter(this, "Feeds",
+ "resource:///modules/Feeds.jsm");
+
+function test() {
+ var exampleUri = Services.io.newURI("http://example.com/");
+ var secman = Cc["@mozilla.org/scriptsecuritymanager;1"]
+ .getService(Ci.nsIScriptSecurityManager);
+ var principal = secman.createCodebasePrincipal(exampleUri, {});
+
+ function testIsFeed(aTitle, aHref, aType, aKnown) {
+ var link = {
+ title: aTitle,
+ href: aHref,
+ type: aType,
+ ownerDocument: {
+ characterSet: "UTF-8"
+ }
+ };
+ return Feeds.isValidFeed(link, principal, aKnown);
+ }
+
+ var href = "http://example.com/feed/";
+ var atomType = "application/atom+xml";
+ var funkyAtomType = " aPPLICAtion/Atom+XML ";
+ var rssType = "application/rss+xml";
+ var funkyRssType = " Application/RSS+XML ";
+ var rdfType = "application/rdf+xml";
+ var texmlType = "text/xml";
+ var appxmlType = "application/xml";
+ var noRss = "Foo";
+ var rss = "RSS";
+
+ // things that should be valid
+ ok(testIsFeed(noRss, href, atomType, false) == atomType,
+ "detect Atom feed");
+ ok(testIsFeed(noRss, href, funkyAtomType, false) == atomType,
+ "clean up and detect Atom feed");
+ ok(testIsFeed(noRss, href, rssType, false) == rssType,
+ "detect RSS feed");
+ ok(testIsFeed(noRss, href, funkyRssType, false) == rssType,
+ "clean up and detect RSS feed");
+
+ // things that should not be feeds
+ ok(testIsFeed(noRss, href, rdfType, false) == null,
+ "should not detect RDF non-feed");
+ ok(testIsFeed(rss, href, rdfType, false) == null,
+ "should not detect RDF feed from type and title");
+ ok(testIsFeed(noRss, href, texmlType, false) == null,
+ "should not detect text/xml non-feed");
+ ok(testIsFeed(rss, href, texmlType, false) == null,
+ "should not detect text/xml feed from type and title");
+ ok(testIsFeed(noRss, href, appxmlType, false) == null,
+ "should not detect application/xml non-feed");
+ ok(testIsFeed(rss, href, appxmlType, false) == null,
+ "should not detect application/xml feed from type and title");
+
+ // security check only, returns cleaned up type or "application/rss+xml"
+ ok(testIsFeed(noRss, href, atomType, true) == atomType,
+ "feed security check should return Atom type");
+ ok(testIsFeed(noRss, href, funkyAtomType, true) == atomType,
+ "feed security check should return cleaned up Atom type");
+ ok(testIsFeed(noRss, href, rssType, true) == rssType,
+ "feed security check should return RSS type");
+ ok(testIsFeed(noRss, href, funkyRssType, true) == rssType,
+ "feed security check should return cleaned up RSS type");
+ ok(testIsFeed(noRss, href, "", true) == rssType,
+ "feed security check without type should return RSS type");
+ ok(testIsFeed(noRss, href, "garbage", true) == "garbage",
+ "feed security check with garbage type should return garbage");
+}
diff --git a/comm/suite/browser/test/browser/browser_bug427559.js b/comm/suite/browser/test/browser/browser_bug427559.js
new file mode 100644
index 0000000000..bd34d89f5c
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug427559.js
@@ -0,0 +1,39 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test bug 427559 to make sure focused elements that are no longer on the page
+ * will have focus transferred to the window when changing tabs back to that
+ * tab with the now-gone element.
+ */
+
+// Default focus on a button and have it kill itself on blur
+var testPage = 'data:text/html,<body><button onblur="this.remove();"><script>document.body.firstChild.focus();</script></body>';
+
+function test() {
+ waitForExplicitFinish();
+
+ gBrowser.selectedTab = gBrowser.addTab();
+
+ gBrowser.selectedBrowser.addEventListener("load", function loadListener() {
+ gBrowser.selectedBrowser.removeEventListener("load", loadListener, true);
+ executeSoon(function () {
+
+ // The test page loaded, so open an empty tab, select it, then restore
+ // the test tab. This causes the test page's focused element to be removed
+ // from its document.
+ gBrowser.selectedTab = gBrowser.addTab();
+ gBrowser.removeCurrentTab();
+
+ // Make sure focus is given to the window because the element is now gone.
+ is(document.commandDispatcher.focusedWindow, window.content,
+ "content window is focused");
+
+ gBrowser.removeCurrentTab();
+ finish();
+ });
+ }, true);
+
+ content.location = testPage;
+}
diff --git a/comm/suite/browser/test/browser/browser_bug435325.js b/comm/suite/browser/test/browser/browser_bug435325.js
new file mode 100644
index 0000000000..dca45a6001
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug435325.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* Ensure that clicking the button in the Offline mode neterror page makes the browser go online. See bug 435325. */
+
+var proxyPrefValue;
+
+function test() {
+ waitForExplicitFinish();
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ window.addEventListener("DOMContentLoaded", checkPage);
+
+
+ // Tests always connect to localhost, and per bug 87717, localhost is now
+ // reachable in offline mode. To avoid this, disable any proxy.
+ proxyPrefValue = Services.prefs.getIntPref("network.proxy.type");
+ Services.prefs.setIntPref("network.proxy.type", 0);
+
+ // Go offline and disable the proxy and cache, then try to load the test URL.
+ Services.io.offline = true;
+ Services.prefs.setBoolPref("browser.cache.disk.enable", false);
+ Services.prefs.setBoolPref("browser.cache.memory.enable", false);
+ content.location = "http://example.com/";
+}
+
+function checkPage() {
+ if(content.location == "about:blank") {
+ info("got about:blank, which is expected once, so return");
+ return;
+ }
+
+ window.removeEventListener("DOMContentLoaded", checkPage);
+
+ ok(Services.io.offline, "Setting Services.io.offline to true.");
+ is(gBrowser.contentDocument.documentURI.substring(0,27),
+ "about:neterror?e=netOffline", "Loading the Offline mode neterror page.");
+
+ // Now press the "Try Again" button
+ ok(gBrowser.contentDocument.getElementById("errorTryAgain"),
+ "The error page has got a #errorTryAgain element");
+ gBrowser.contentDocument.getElementById("errorTryAgain").click();
+
+ ok(!Services.io.offline, "After clicking the Try Again button, we're back " +
+ "online.");
+
+ finish();
+}
+
+registerCleanupFunction(function() {
+ Services.prefs.setIntPref("network.proxy.type", proxyPrefValue);
+ Services.prefs.setBoolPref("browser.cache.disk.enable", true);
+ Services.prefs.setBoolPref("browser.cache.memory.enable", true);
+ Services.io.offline = false;
+ gBrowser.removeCurrentTab();
+});
diff --git a/comm/suite/browser/test/browser/browser_bug462289.js b/comm/suite/browser/test/browser/browser_bug462289.js
new file mode 100644
index 0000000000..c61b9a0403
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug462289.js
@@ -0,0 +1,87 @@
+// Wanted delay (in ms) to let UI fully update.
+// 375: hopefully enough (on slow test environments).
+var gDelay = 375;
+
+var tab1, tab2;
+
+function focus_in_navbar()
+{
+ var parent = document.activeElement.parentNode;
+ while (parent && parent.id != "nav-bar")
+ parent = parent.parentNode;
+
+ return parent != null;
+}
+
+function test()
+{
+ waitForExplicitFinish();
+
+ // Ftr, SeaMonkey doesn't support animation (yet).
+ tab1 = gBrowser.addTab("about:blank");
+ tab2 = gBrowser.addTab("about:blank");
+
+ EventUtils.synthesizeMouseAtCenter(tab1, {});
+ setTimeout(step2, gDelay);
+}
+
+function step2()
+{
+ is(gBrowser.selectedTab, tab1, "1st click on tab1 selects tab");
+ isnot(document.activeElement, tab1, "1st click on tab1 does not activate tab");
+
+ EventUtils.synthesizeMouseAtCenter(tab1, {});
+ setTimeout(step3, gDelay);
+}
+
+function step3()
+{
+ is(gBrowser.selectedTab, tab1, "2nd click on selected tab1 keeps tab selected");
+ // SeaMonkey differs from Firefox.
+ is(document.activeElement, tab1, "2nd click on selected tab1 activates tab");
+
+ // Ftr, SeaMonkey doesn't support tabsontop (yet).
+ ok(true, "focusing URLBar then sending Tab(s) until out of nav-bar.");
+ document.getElementById("urlbar").focus();
+ while (focus_in_navbar())
+ EventUtils.synthesizeKey("VK_TAB", { });
+ is(gBrowser.selectedTab, tab1, "tab key to selected tab1 keeps tab selected");
+ is(document.activeElement, tab1, "tab key to selected tab1 activates tab");
+
+ EventUtils.synthesizeMouseAtCenter(tab1, {});
+ setTimeout(step4, gDelay);
+}
+
+function step4()
+{
+ is(gBrowser.selectedTab, tab1, "3rd click on activated tab1 keeps tab selected");
+ is(document.activeElement, tab1, "3rd click on activated tab1 keeps tab activated");
+
+ EventUtils.synthesizeMouseAtCenter(tab2, {});
+ setTimeout(step5, gDelay);
+}
+
+function step5()
+{
+ // The tabbox selects a tab within a setTimeout in a bubbling mousedown event
+ // listener, and focuses the current tab if another tab previously had focus.
+ is(gBrowser.selectedTab, tab2, "click on tab2 while tab1 is activated selects tab");
+ is(document.activeElement, tab2, "click on tab2 while tab1 is activated activates tab");
+
+ ok(true, "focusing content then sending middle-button mousedown to tab2.");
+ content.focus();
+ EventUtils.synthesizeMouseAtCenter(tab2, {button: 1, type: "mousedown"});
+ setTimeout(step6, gDelay);
+}
+
+function step6()
+{
+ is(gBrowser.selectedTab, tab2, "middle-button mousedown on selected tab2 keeps tab selected");
+ // SeaMonkey differs from Firefox.
+ is(document.activeElement, tab2, "middle-button mousedown on selected tab2 activates tab");
+
+ gBrowser.removeTab(tab2);
+ gBrowser.removeTab(tab1);
+
+ finish();
+}
diff --git a/comm/suite/browser/test/browser/browser_bug519216.js b/comm/suite/browser/test/browser/browser_bug519216.js
new file mode 100644
index 0000000000..a924f7a091
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug519216.js
@@ -0,0 +1,50 @@
+function test() {
+ waitForExplicitFinish();
+ gBrowser.stop();
+ gBrowser.addProgressListener(progressListener1);
+ gBrowser.addProgressListener(progressListener2);
+ gBrowser.addProgressListener(progressListener3);
+ gBrowser.loadURI("data:text/plain,bug519216");
+}
+
+var calledListener1 = false;
+var progressListener1 = {
+ onLocationChange: function onLocationChange() {
+ calledListener1 = true;
+ gBrowser.removeProgressListener(this);
+ }
+};
+
+var calledListener2 = false;
+var progressListener2 = {
+ onLocationChange: function onLocationChange() {
+ ok(calledListener1, "called progressListener1 before progressListener2");
+ calledListener2 = true;
+ gBrowser.removeProgressListener(this);
+ }
+};
+
+var progressListener3 = {
+ onLocationChange: function onLocationChange() {
+ ok(calledListener2, "called progressListener2 before progressListener3");
+ gBrowser.removeProgressListener(this);
+ gBrowser.addProgressListener(progressListener4);
+ executeSoon(function () {
+ expectListener4 = true;
+ gBrowser.reload();
+ });
+ }
+};
+
+var expectListener4 = false;
+var progressListener4 = {
+ onLocationChange: function onLocationChange() {
+ ok(expectListener4, "didn't call progressListener4 for the first location change");
+ gBrowser.removeProgressListener(this);
+ executeSoon(function () {
+ gBrowser.addTab();
+ gBrowser.removeCurrentTab();
+ finish();
+ });
+ }
+};
diff --git a/comm/suite/browser/test/browser/browser_bug561636.js b/comm/suite/browser/test/browser/browser_bug561636.js
new file mode 100644
index 0000000000..8f41629253
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug561636.js
@@ -0,0 +1,459 @@
+var gInvalidFormPopup = document.getElementById('invalid-form-popup');
+ok(gInvalidFormPopup,
+ "The browser should have a popup to show when a form is invalid");
+
+function checkPopupShow()
+{
+ ok(gInvalidFormPopup.state == 'showing' || gInvalidFormPopup.state == 'open',
+ "The invalid form popup should be shown");
+}
+
+function checkPopupHide()
+{
+ ok(gInvalidFormPopup.state != 'showing' && gInvalidFormPopup.state != 'open',
+ "The invalid form popup should not be shown");
+}
+
+function checkPopupMessage(doc)
+{
+ is(gInvalidFormPopup.firstChild.textContent,
+ doc.getElementById('i').validationMessage,
+ "The panel should show the message from validationMessage");
+}
+
+var gObserver = {
+ QueryInterface : XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver]),
+
+ notifyInvalidSubmit : function (aFormElement, aInvalidElements)
+ {
+ }
+};
+
+function test()
+{
+ waitForExplicitFinish();
+
+ test1();
+}
+
+/**
+ * In this test, we check that no popup appears if the form is valid.
+ */
+function test1() {
+ let uri = "data:text/html,<html><body><iframe name='t'></iframe><form target='t' action='data:text/html,'><input><input id='s' type='submit'></form></body></html>";
+ let tab = gBrowser.addTab();
+
+ tab.linkedBrowser.addEventListener("load", function test1TabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", test1TabLBLoad, true);
+ let doc = gBrowser.contentDocument;
+
+ doc.getElementById('s').click();
+
+ executeSoon(function() {
+ checkPopupHide();
+
+ // Clean-up
+ gBrowser.removeTab(gBrowser.selectedTab);
+
+ // Next test
+ executeSoon(test2);
+ });
+ }, true);
+
+ gBrowser.selectedTab = tab;
+ gBrowser.selectedTab.linkedBrowser.loadURI(uri);
+}
+
+/**
+ * In this test, we check that, when an invalid form is submitted,
+ * the invalid element is focused and a popup appears.
+ */
+function test2()
+{
+ let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input required id='i'><input id='s' type='submit'></form>";
+ let tab = gBrowser.addTab();
+
+ gInvalidFormPopup.addEventListener("popupshown", function test2gIpopupShown() {
+ gInvalidFormPopup.removeEventListener("popupshown", test2gIpopupShown);
+
+ let doc = gBrowser.contentDocument;
+ is(doc.activeElement, doc.getElementById('i'),
+ "First invalid element should be focused");
+
+ checkPopupShow();
+ checkPopupMessage(doc);
+
+ // Clean-up and next test.
+ gBrowser.removeTab(gBrowser.selectedTab);
+ executeSoon(test3);
+ });
+
+ tab.linkedBrowser.addEventListener("load", function test2TabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", test2TabLBLoad, true);
+
+ gBrowser.contentDocument.getElementById('s').click();
+ }, true);
+
+ gBrowser.selectedTab = tab;
+ gBrowser.selectedTab.linkedBrowser.loadURI(uri);
+}
+
+/**
+ * In this test, we check that, when an invalid form is submitted,
+ * the first invalid element is focused and a popup appears.
+ */
+function test3()
+{
+ let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input><input id='i' required><input required><input id='s' type='submit'></form>";
+ let tab = gBrowser.addTab();
+
+ gInvalidFormPopup.addEventListener("popupshown", function test3gIPopupShown() {
+ gInvalidFormPopup.removeEventListener("popupshown", test3gIPopupShown);
+
+ let doc = gBrowser.contentDocument;
+ is(doc.activeElement, doc.getElementById('i'),
+ "First invalid element should be focused");
+
+ checkPopupShow();
+ checkPopupMessage(doc);
+
+ // Clean-up and next test.
+ gBrowser.removeTab(gBrowser.selectedTab);
+ executeSoon(test4a);
+ });
+
+ tab.linkedBrowser.addEventListener("load", function test3TabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", test3TabLBLoad, true);
+
+ gBrowser.contentDocument.getElementById('s').click();
+ }, true);
+
+ gBrowser.selectedTab = tab;
+ gBrowser.selectedTab.linkedBrowser.loadURI(uri);
+}
+
+/**
+ * In this test, we check that, we hide the popup by interacting with the
+ * invalid element if the element becomes valid.
+ */
+function test4a()
+{
+ let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>";
+ let tab = gBrowser.addTab();
+
+ gInvalidFormPopup.addEventListener("popupshown", function test4agIPopupShown() {
+ gInvalidFormPopup.removeEventListener("popupshown", test4agIPopupShown);
+
+ let doc = gBrowser.contentDocument;
+ is(doc.activeElement, doc.getElementById('i'),
+ "First invalid element should be focused");
+
+ checkPopupShow();
+ checkPopupMessage(doc);
+
+ EventUtils.synthesizeKey("a", {});
+
+ executeSoon(function () {
+ checkPopupHide();
+
+ // Clean-up and next test.
+ gBrowser.removeTab(gBrowser.selectedTab);
+ executeSoon(test4b);
+ });
+ });
+
+ tab.linkedBrowser.addEventListener("load", function test4aTabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", test4aTabLBLoad, true);
+
+ gBrowser.contentDocument.getElementById('s').click();
+ }, true);
+
+ gBrowser.selectedTab = tab;
+ gBrowser.selectedTab.linkedBrowser.loadURI(uri);
+}
+
+/**
+ * In this test, we check that, we don't hide the popup by interacting with the
+ * invalid element if the element is still invalid.
+ */
+function test4b()
+{
+ let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input type='email' id='i' required><input id='s' type='submit'></form>";
+ let tab = gBrowser.addTab();
+
+ gInvalidFormPopup.addEventListener("popupshown", function test4bgIpopupShown() {
+ gInvalidFormPopup.removeEventListener("popupshown", test4bgIpopupShown);
+
+ let doc = gBrowser.contentDocument;
+ is(doc.activeElement, doc.getElementById('i'),
+ "First invalid element should be focused");
+
+ checkPopupShow();
+ checkPopupMessage(doc);
+
+ EventUtils.synthesizeKey("a", {});
+
+ executeSoon(function () {
+ checkPopupShow();
+
+ // Clean-up and next test.
+ gBrowser.removeTab(gBrowser.selectedTab);
+ executeSoon(test5);
+ });
+ });
+
+ tab.linkedBrowser.addEventListener("load", function test4bTabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", test4bTabLBLoad, true);
+
+ gBrowser.contentDocument.getElementById('s').click();
+ }, true);
+
+ gBrowser.selectedTab = tab;
+ gBrowser.selectedTab.linkedBrowser.loadURI(uri);
+}
+
+/**
+ * In this test, we check that we can hide the popup by blurring the invalid
+ * element.
+ */
+function test5()
+{
+ let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>";
+ let tab = gBrowser.addTab();
+
+ gInvalidFormPopup.addEventListener("popupshown", function test5gIpopupShown() {
+ gInvalidFormPopup.removeEventListener("popupshown", test5gIpopupShown);
+
+ let doc = gBrowser.contentDocument;
+ is(doc.activeElement, doc.getElementById('i'),
+ "First invalid element should be focused");
+
+ checkPopupShow();
+ checkPopupMessage(doc);
+
+ doc.getElementById('i').blur();
+
+ executeSoon(function () {
+ checkPopupHide();
+
+ // Clean-up and next test.
+ gBrowser.removeTab(gBrowser.selectedTab);
+ executeSoon(test6);
+ });
+ });
+
+ tab.linkedBrowser.addEventListener("load", function test5TabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", test5TabLBLoad, true);
+
+ gBrowser.contentDocument.getElementById('s').click();
+ }, true);
+
+ gBrowser.selectedTab = tab;
+ gBrowser.selectedTab.linkedBrowser.loadURI(uri);
+}
+
+/**
+ * In this test, we check that we can hide the popup by pressing TAB.
+ */
+function test6()
+{
+ let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>";
+ let tab = gBrowser.addTab();
+
+ gInvalidFormPopup.addEventListener("popupshown", function test6gIpopupShown() {
+ gInvalidFormPopup.removeEventListener("popupshown", test6gIpopupShown);
+
+ let doc = gBrowser.contentDocument;
+ is(doc.activeElement, doc.getElementById('i'),
+ "First invalid element should be focused");
+
+ checkPopupShow();
+ checkPopupMessage(doc);
+
+ EventUtils.synthesizeKey("VK_TAB", {});
+
+ executeSoon(function () {
+ checkPopupHide();
+
+ // Clean-up and next test.
+ gBrowser.removeTab(gBrowser.selectedTab);
+ executeSoon(test7);
+ });
+ });
+
+ tab.linkedBrowser.addEventListener("load", function test6TabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", test6TabLBLoad, true);
+
+ gBrowser.contentDocument.getElementById('s').click();
+ }, true);
+
+ gBrowser.selectedTab = tab;
+ gBrowser.selectedTab.linkedBrowser.loadURI(uri);
+}
+
+/**
+ * In this test, we check that the popup will hide if we move to another tab.
+ */
+function test7()
+{
+ let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>";
+ let tab = gBrowser.addTab();
+
+ gInvalidFormPopup.addEventListener("popupshown", function test7gIpopupShown() {
+ gInvalidFormPopup.removeEventListener("popupshown", test7gIpopupShown);
+
+ let doc = gBrowser.contentDocument;
+ is(doc.activeElement, doc.getElementById('i'),
+ "First invalid element should be focused");
+
+ checkPopupShow();
+ checkPopupMessage(doc);
+
+ // Create a new tab and move to it.
+ // Ftr, SeaMonkey doesn't support animation (yet).
+ gBrowser.selectedTab = gBrowser.addTab("about:blank");
+
+ executeSoon(function() {
+ checkPopupHide();
+
+ // Clean-up and next test.
+ gBrowser.removeTab(gBrowser.selectedTab);
+ gBrowser.removeTab(gBrowser.selectedTab);
+ executeSoon(test8);
+ });
+ });
+
+ tab.linkedBrowser.addEventListener("load", function test7TabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", test7TabLBLoad, true);
+
+ gBrowser.contentDocument.getElementById('s').click();
+ }, true);
+
+ gBrowser.selectedTab = tab;
+ gBrowser.selectedTab.linkedBrowser.loadURI(uri);
+}
+
+/**
+ * In this test, we check that nothing happen (no focus nor popup) if the
+ * invalid form is submitted in another tab than the current focused one
+ * (submitted in background).
+ */
+function test8()
+{
+ let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>";
+ let tab = gBrowser.addTab();
+
+ gObserver.notifyInvalidSubmit = function() {
+ executeSoon(function() {
+ let doc = tab.linkedBrowser.contentDocument;
+ isnot(doc.activeElement, doc.getElementById('i'),
+ "We should not focus the invalid element when the form is submitted in background");
+
+ checkPopupHide();
+
+ // Clean-up
+ Services.obs.removeObserver(gObserver, "invalidformsubmit");
+ gObserver.notifyInvalidSubmit = function () {};
+ gBrowser.removeTab(tab);
+
+ // Next test
+ executeSoon(test9);
+ });
+ };
+
+ Services.obs.addObserver(gObserver, "invalidformsubmit");
+
+ tab.linkedBrowser.addEventListener("load", function test8TabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", test8TabLBLoad, true);
+
+ isnot(gBrowser.selectedTab, tab,
+ "This tab should have been loaded in background");
+
+ tab.linkedBrowser.contentDocument.getElementById('s').click();
+ }, true);
+
+ tab.linkedBrowser.loadURI(uri);
+}
+
+/**
+ * In this test, we check that the author defined error message is shown.
+ */
+function test9()
+{
+ let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input x-moz-errormessage='foo' required id='i'><input id='s' type='submit'></form>";
+ let tab = gBrowser.addTab();
+
+ gInvalidFormPopup.addEventListener("popupshown", function test9gIpopupShown() {
+ gInvalidFormPopup.removeEventListener("popupshown", test9gIpopupShown);
+
+ let doc = gBrowser.contentDocument;
+ is(doc.activeElement, doc.getElementById('i'),
+ "First invalid element should be focused");
+
+ checkPopupShow();
+
+ is(gInvalidFormPopup.firstChild.textContent, "foo",
+ "The panel should show the author defined error message");
+
+ // Clean-up and next test.
+ gBrowser.removeTab(gBrowser.selectedTab);
+ executeSoon(test10);
+ });
+
+ tab.linkedBrowser.addEventListener("load", function test9TabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", test9TabLBLoad, true);
+
+ gBrowser.contentDocument.getElementById('s').click();
+ }, true);
+
+ gBrowser.selectedTab = tab;
+ gBrowser.selectedTab.linkedBrowser.loadURI(uri);
+}
+
+/**
+ * In this test, we check that the message is correctly updated when it changes.
+ */
+function test10()
+{
+ let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input type='email' required id='i'><input id='s' type='submit'></form>";
+ let tab = gBrowser.addTab();
+
+ gInvalidFormPopup.addEventListener("popupshown", function test10gIpopupShown() {
+ gInvalidFormPopup.removeEventListener("popupshown", test10gIpopupShown);
+
+ let doc = gBrowser.contentDocument;
+ let input = doc.getElementById('i');
+ is(doc.activeElement, input, "First invalid element should be focused");
+
+ checkPopupShow();
+
+ is(gInvalidFormPopup.firstChild.textContent, input.validationMessage,
+ "The panel should show the current validation message");
+
+ input.addEventListener('input', function test10InputInput() {
+ input.removeEventListener('input', test10InputInput);
+
+ executeSoon(function() {
+ // Now, the element suffers from another error, the message should have
+ // been updated.
+ is(gInvalidFormPopup.firstChild.textContent, input.validationMessage,
+ "The panel should show the current validation message");
+
+ // Clean-up and next test.
+ gBrowser.removeTab(gBrowser.selectedTab);
+ executeSoon(finish);
+ });
+ });
+
+ EventUtils.synthesizeKey('f', {});
+ });
+
+ tab.linkedBrowser.addEventListener("load", function test10TabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", test10TabLBLoad, true);
+
+ gBrowser.contentDocument.getElementById('s').click();
+ }, true);
+
+ gBrowser.selectedTab = tab;
+ gBrowser.selectedTab.linkedBrowser.loadURI(uri);
+}
diff --git a/comm/suite/browser/test/browser/browser_bug562649.js b/comm/suite/browser/test/browser/browser_bug562649.js
new file mode 100644
index 0000000000..57524a4b82
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug562649.js
@@ -0,0 +1,26 @@
+function test() {
+ const URI = "data:text/plain,bug562649";
+ browserDOMWindow.openURI(makeURI(URI),
+ null,
+ Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
+ Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
+
+ is(gBrowser.userTypedValue, URI, "userTypedValue matches test URI");
+ is(gURLBar.value, URI, "location bar value matches test URI");
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gBrowser.removeCurrentTab();
+ is(gBrowser.userTypedValue, URI, "userTypedValue matches test URI after switching tabs");
+ is(gURLBar.value, URI, "location bar value matches test URI after switching tabs");
+
+ waitForExplicitFinish();
+ gBrowser.selectedBrowser.addEventListener("load", function loadListener() {
+ gBrowser.selectedBrowser.removeEventListener("load", loadListener, true);
+
+ is(gBrowser.userTypedValue, null, "userTypedValue is null as the page has loaded");
+ is(gURLBar.value, URI, "location bar value matches test URI as the page has loaded");
+
+ gBrowser.removeCurrentTab();
+ finish();
+ }, true);
+}
diff --git a/comm/suite/browser/test/browser/browser_bug581947.js b/comm/suite/browser/test/browser/browser_bug581947.js
new file mode 100644
index 0000000000..5ac81b1218
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug581947.js
@@ -0,0 +1,95 @@
+function check(aElementName, aBarred, aType) {
+ let doc = gBrowser.contentDocument;
+ let tooltip = document.getElementById("aHTMLTooltip");
+ let content = doc.getElementById('content');
+
+ let e = doc.createElement(aElementName);
+ content.appendChild(e);
+
+ if (aType) {
+ e.type = aType;
+ }
+
+ ok(!FillInHTMLTooltip(e),
+ "No tooltip should be shown when the element is valid");
+
+ e.setCustomValidity('foo');
+ if (aBarred) {
+ ok(!FillInHTMLTooltip(e),
+ "No tooltip should be shown when the element is barred from constraint validation");
+ } else {
+ ok(FillInHTMLTooltip(e),
+ e.tagName + " " +"A tooltip should be shown when the element isn't valid");
+ }
+
+ e.setAttribute('title', '');
+ ok (!FillInHTMLTooltip(e),
+ "No tooltip should be shown if the title attribute is set");
+
+ e.removeAttribute('title');
+ content.setAttribute('novalidate', '');
+ ok (!FillInHTMLTooltip(e),
+ "No tooltip should be shown if the novalidate attribute is set on the form owner");
+ content.removeAttribute('novalidate');
+
+ e.remove();
+}
+
+function todo_check(aElementName, aBarred) {
+ let doc = gBrowser.contentDocument;
+ let tooltip = document.getElementById("aHTMLTooltip");
+ let content = doc.getElementById('content');
+
+ let e = doc.createElement(aElementName);
+ content.appendChild(e);
+
+ let caught = false;
+ try {
+ e.setCustomValidity('foo');
+ } catch (e) {
+ caught = true;
+ }
+
+ todo(!caught, "setCustomValidity should exist for " + aElementName);
+
+ e.remove();
+}
+
+function test() {
+ waitForExplicitFinish();
+ gBrowser.selectedTab = gBrowser.addTab();
+ gBrowser.selectedBrowser.addEventListener("load", function loadListener() {
+ gBrowser.selectedBrowser.removeEventListener("load", loadListener, true);
+
+ let testData = [
+ /* element name, barred */
+ [ 'input', false, null],
+ [ 'textarea', false, null],
+ [ 'button', true, 'button'],
+ [ 'button', false, 'submit'],
+ [ 'select', false, null],
+ [ 'output', true, null],
+ [ 'fieldset', true, null],
+ [ 'object', true, null]
+ ];
+
+ for (let data of testData) {
+ check(data[0], data[1], data[2]);
+ }
+
+ let todo_testData = [
+ [ 'keygen', 'false' ]
+ ];
+
+ for (let data of todo_testData) {
+ todo_check(data[0], data[1]);
+ }
+
+ gBrowser.removeCurrentTab();
+ finish();
+ }, true);
+
+ content.location =
+ "data:text/html,<!DOCTYPE html><html><body><form id='content'></form></body></html>";
+}
+
diff --git a/comm/suite/browser/test/browser/browser_bug585511.js b/comm/suite/browser/test/browser/browser_bug585511.js
new file mode 100644
index 0000000000..f6513cac5a
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug585511.js
@@ -0,0 +1,24 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function test() {
+ is(getBrowser().tabs.length, 1, "one tab is open initially");
+ is(getBrowser().browsers.length, getBrowser().tabs.length, ".browsers is in sync");
+
+ // Add several new tabs
+ let tab1 = getBrowser().addTab("http://mochi.test:8888/#1");
+ let tab2 = getBrowser().addTab("http://mochi.test:8888/#2");
+ let tab3 = getBrowser().addTab("http://mochi.test:8888/#3");
+ is(getBrowser().tabs.length, 4, "four tabs are open");
+ is(getBrowser().browsers.length, getBrowser().tabs.length, ".browsers is in sync");
+ getBrowser().removeTab(tab2);
+ is(getBrowser().tabs.length, 3, "three tabs are open");
+ is(getBrowser().browsers.length, getBrowser().tabs.length, ".browsers is in sync");
+ getBrowser().removeTab(tab1);
+ is(getBrowser().tabs.length, 2, "two tabs are open");
+ is(getBrowser().browsers.length, getBrowser().tabs.length, ".browsers is in sync");
+ getBrowser().removeTab(tab3);
+ is(getBrowser().tabs.length, 1, "we've closed all our tabs");
+ is(getBrowser().browsers.length, getBrowser().tabs.length, ".browsers is in sync");
+}
diff --git a/comm/suite/browser/test/browser/browser_bug595507.js b/comm/suite/browser/test/browser/browser_bug595507.js
new file mode 100644
index 0000000000..0bea8cabc6
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug595507.js
@@ -0,0 +1,39 @@
+var gInvalidFormPopup = document.getElementById('invalid-form-popup');
+ok(gInvalidFormPopup,
+ "The browser should have a popup to show when a form is invalid");
+
+/**
+ * Make sure that the form validation error message shows even if the form is in an iframe.
+ */
+function test()
+{
+ waitForExplicitFinish();
+
+ let uri = "data:text/html,<iframe src=\"data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input required id='i'><input id='s' type='submit'></form>\"</iframe>";
+ let tab = gBrowser.addTab();
+
+ gInvalidFormPopup.addEventListener("popupshown", function testgIpopupShown() {
+ gInvalidFormPopup.removeEventListener("popupshown", testgIpopupShown);
+
+ let doc = gBrowser.contentDocument.getElementsByTagName('iframe')[0].contentDocument;
+ is(doc.activeElement, doc.getElementById('i'),
+ "First invalid element should be focused");
+
+ ok(gInvalidFormPopup.state == 'showing' || gInvalidFormPopup.state == 'open',
+ "The invalid form popup should be shown");
+
+ // Clean-up and next test.
+ gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
+ executeSoon(finish);
+ });
+
+ tab.linkedBrowser.addEventListener("load", function testTabLBLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener("load", testTabLBLoad, true);
+
+ gBrowser.contentDocument.getElementsByTagName('iframe')[0].contentDocument
+ .getElementById('s').click();
+ }, true);
+
+ gBrowser.selectedTab = tab;
+ gBrowser.selectedTab.linkedBrowser.loadURI(uri);
+}
diff --git a/comm/suite/browser/test/browser/browser_bug623155.js b/comm/suite/browser/test/browser/browser_bug623155.js
new file mode 100644
index 0000000000..df8197a565
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_bug623155.js
@@ -0,0 +1,136 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const REDIRECT_FROM = "https://example.com/browser/suite/browser/test/browser/" +
+ "redirect_bug623155.sjs";
+
+const REDIRECT_TO = "https://www.bank1.com/"; // Bad-cert host.
+
+function isRedirectedURISpec(aURISpec) {
+ return isRedirectedURI(Services.io.newURI(aURISpec));
+}
+
+function isRedirectedURI(aURI) {
+ // Compare only their before-hash portion.
+ return Services.io.newURI(REDIRECT_TO)
+ .equalsExceptRef(aURI);
+}
+
+/*
+ Test.
+
+1. Load
+https://example.com/browser/browser/base/content/test/redirect_bug623155.sjs#BG
+ in a background tab.
+
+2. The redirected URI is <https://www.bank1.com/#BG>, which displayes a cert
+ error page.
+
+3. Switch the tab to foreground.
+
+4. Check the URLbar's value, expecting <https://www.bank1.com/#BG>
+
+5. Load
+https://example.com/browser/browser/base/content/test/redirect_bug623155.sjs#FG
+ in the foreground tab.
+
+6. The redirected URI is <https://www.bank1.com/#FG>. And this is also
+ a cert-error page.
+
+7. Check the URLbar's value, expecting <https://www.bank1.com/#FG>
+
+8. End.
+
+ */
+
+var gNewTab;
+
+function test() {
+ waitForExplicitFinish();
+
+ // Load a URI in the background.
+ gNewTab = gBrowser.addTab(REDIRECT_FROM + "#BG");
+ gBrowser.getBrowserForTab(gNewTab)
+ .webProgress
+ .addProgressListener(gWebProgressListener,
+ Ci.nsIWebProgress
+ .NOTIFY_LOCATION);
+}
+
+var gWebProgressListener = {
+ QueryInterface: function(aIID) {
+ if (aIID.equals(Ci.nsIWebProgressListener) ||
+ aIID.equals(Ci.nsISupportsWeakReference) ||
+ aIID.equals(Ci.nsISupports))
+ return this;
+ throw Cr.NS_NOINTERFACE;
+ },
+
+ // ---------------------------------------------------------------------------
+ // NOTIFY_LOCATION mode should work fine without these methods.
+ //
+ //onStateChange: function() {},
+ //onStatusChange: function() {},
+ //onProgressChange: function() {},
+ //onSecurityChange: function() {},
+ //----------------------------------------------------------------------------
+
+ onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
+ if (!aRequest) {
+ // This is bug 673752, or maybe initial "about:blank".
+ return;
+ }
+
+ ok(gNewTab, "There is a new tab.");
+ ok(isRedirectedURI(aLocation),
+ "onLocationChange catches only redirected URI.");
+
+ if (aLocation.ref == "BG") {
+ // This is background tab's request.
+ isnot(gNewTab, gBrowser.selectedTab, "This is a background tab.");
+ } else if (aLocation.ref == "FG") {
+ // This is foreground tab's request.
+ is(gNewTab, gBrowser.selectedTab, "This is a foreground tab.");
+ }
+ else {
+ // We shonuld not reach here.
+ ok(false, "This URI hash is not expected:" + aLocation.ref);
+ }
+
+ let isSelectedTab = (gNewTab == gBrowser.selectedTab);
+ setTimeout(delayed, 0, isSelectedTab);
+ }
+};
+
+function delayed(aIsSelectedTab) {
+ // Switch tab and confirm URL bar.
+ if (!aIsSelectedTab) {
+ gBrowser.selectedTab = gNewTab;
+ }
+
+ ok(isRedirectedURISpec(content.location.href),
+ "The content area is redirected. aIsSelectedTab:" + aIsSelectedTab);
+ is(gURLBar.value, content.location.href,
+ "The URL bar shows the content URI. aIsSelectedTab:" + aIsSelectedTab);
+
+ if (!aIsSelectedTab) {
+ // If this was a background request, go on a foreground request.
+ content.location = REDIRECT_FROM + "#FG";
+ }
+ else {
+ // Othrewise, nothing to do remains.
+ finish();
+ }
+}
+
+/* Cleanup */
+registerCleanupFunction(function() {
+ if (gNewTab) {
+ gBrowser.getBrowserForTab(gNewTab)
+ .webProgress
+ .removeProgressListener(gWebProgressListener);
+
+ gBrowser.removeTab(gNewTab);
+ }
+ gNewTab = null;
+});
diff --git a/comm/suite/browser/test/browser/browser_ctrlTab.js b/comm/suite/browser/test/browser/browser_ctrlTab.js
new file mode 100644
index 0000000000..aea07917a3
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_ctrlTab.js
@@ -0,0 +1,197 @@
+function test() {
+ waitForExplicitFinish();
+
+ gBrowser.addTab();
+ gBrowser.addTab();
+ gBrowser.addTab();
+
+ assertTabs(4);
+
+ ctrlTabTest([2] , 1, 0);
+ ctrlTabTest([2, 3, 1], 2, 2);
+ ctrlTabTest([] , 4, 2);
+
+ {
+ let selectedIndex = gBrowser.tabContainer.selectedIndex;
+ pressCtrlTab();
+ pressCtrlTab(true);
+ releaseCtrl();
+ is(gBrowser.tabContainer.selectedIndex, selectedIndex,
+ "Ctrl+Tab -> Ctrl+Shift+Tab keeps the selected tab");
+ }
+
+ { // test for bug 445369
+ let tabs = gBrowser.tabs.length;
+ pressCtrlTab();
+ EventUtils.synthesizeKey("w", { ctrlKey: true });
+ is(gBrowser.tabs.length, tabs - 1, "Ctrl+Tab -> Ctrl+W removes one tab");
+ releaseCtrl();
+ }
+ assertTabs(3);
+
+ ctrlTabTest([2, 1, 0], 7, 1);
+
+ { // test for bug 445369
+ selectTabs([1, 2, 0]);
+
+ let selectedTab = gBrowser.selectedTab;
+ let tabToRemove = gBrowser.tabs[1];
+
+ pressCtrlTab();
+ pressCtrlTab();
+ EventUtils.synthesizeKey("w", { ctrlKey: true });
+ ok(!tabToRemove.parentNode,
+ "Ctrl+Tab*2 -> Ctrl+W removes the second most recently selected tab");
+
+ pressCtrlTab(true);
+ pressCtrlTab(true);
+ releaseCtrl();
+ ok(gBrowser.selectedTab == selectedTab,
+ "Ctrl+Tab*2 -> Ctrl+W -> Ctrl+Shift+Tab*2 keeps the selected tab");
+ }
+ assertTabs(2);
+
+ ctrlTabTest([1], 1, 0);
+
+ gBrowser.removeTab(gBrowser.tabContainer.lastChild);
+
+ assertTabs(1);
+
+ { // test for bug 445768
+ let focusedWindow = document.commandDispatcher.focusedWindow;
+ let eventConsumed = true;
+ let detectKeyEvent = function (event) {
+ eventConsumed = event.defaultPrevented;
+ };
+ document.addEventListener("keypress", detectKeyEvent);
+ pressCtrlTab();
+ document.removeEventListener("keypress", detectKeyEvent);
+ ok(eventConsumed, "Ctrl+Tab consumed by the tabbed browser if one tab is open");
+ is(focusedWindow.location, document.commandDispatcher.focusedWindow.location,
+ "Ctrl+Tab doesn't change focus if one tab is open");
+ }
+
+ gBrowser.addTab();
+ gBrowser.addTab();
+ gBrowser.addTab();
+
+ assertTabs(4);
+ selectTabs([0, 1, 2, 3]);
+ pressCtrlTab();
+ ctrlTab.panel.addEventListener("popupshown", stickyTests);
+
+ function stickyTests() {
+ ctrlTab.panel.removeEventListener("popupshown", stickyTests);
+
+ EventUtils.synthesizeKey("f", { ctrlKey: true });
+ is(document.activeElement, ctrlTab.searchField.inputField,
+ "Ctrl+Tab -> Ctrl+F focuses the panel's search field");
+
+ releaseCtrl();
+ ok(isOpen(),
+ "panel is sticky after focusing the search field and releasing the Ctrl key");
+
+ EventUtils.synthesizeKey("f", {});
+ EventUtils.synthesizeKey("o", {});
+ EventUtils.synthesizeKey("o", {});
+ is(ctrlTab.searchField.value, "foo",
+ "text entered into search field");
+
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ ok(isOpen(),
+ "Enter key kicks pending search off; the panel stays open as there's no match");
+ is(ctrlTab.searchField.value, "foo",
+ "search field value persists after Enter pressed");
+
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+ is(ctrlTab.searchField.value, "",
+ "ESC key clears the search field");
+ ok(isOpen(),
+ "Clearing the search field with ESC keeps the panel open");
+
+ // blur the search field
+ EventUtils.synthesizeKey("VK_TAB", {});
+ isnot(document.activeElement, ctrlTab.searchField.inputField,
+ "Tab key blurs the panel's search field");
+
+ // advance selection and close panel
+ EventUtils.synthesizeKey("VK_TAB", {});
+ EventUtils.synthesizeKey("VK_TAB", {});
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ ok(!isOpen(),
+ "Enter key closes the panel");
+ is(gBrowser.tabContainer.selectedIndex, 1,
+ "Tab key advances the selection while the panel is sticky");
+
+ gBrowser.removeCurrentTab();
+ gBrowser.removeCurrentTab();
+ gBrowser.removeCurrentTab();
+ assertTabs(1);
+ finish();
+ }
+
+
+ /* private utility functions */
+
+ function pressCtrlTab(aShiftKey) {
+ EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true, shiftKey: !!aShiftKey });
+ }
+
+ function releaseCtrl() {
+ EventUtils.synthesizeKey("VK_CONTROL", { type: "keyup" });
+ }
+
+ function isOpen() {
+ return ctrlTab.panel.state == "showing" || ctrlTab.panel.state == "open";
+ }
+
+ function assertTabs(aTabs) {
+ var tabs = gBrowser.tabs.length;
+ if (tabs != aTabs) {
+ while (gBrowser.tabs.length > 1)
+ gBrowser.removeCurrentTab();
+ throw "expected " + aTabs + " open tabs, got " + tabs;
+ }
+ }
+
+ function selectTabs(tabs) {
+ tabs.forEach(function (index) {
+ gBrowser.selectedTab = gBrowser.tabs[index];
+ });
+ }
+
+ function ctrlTabTest(tabsToSelect, tabTimes, expectedIndex) {
+ selectTabs(tabsToSelect);
+
+ var indexStart = gBrowser.tabContainer.selectedIndex;
+ var tabCount = gBrowser.tabs.length;
+ var normalized = tabTimes % tabCount;
+ var where = normalized == 1 ? "back to the previously selected tab" :
+ normalized + " tabs back in most-recently-selected order";
+
+ for (let i = 0; i < tabTimes; i++) {
+ pressCtrlTab();
+
+ if (tabCount > 2)
+ is(gBrowser.tabContainer.selectedIndex, indexStart,
+ "Selected tab doesn't change while tabbing");
+ }
+
+ if (tabCount > 2) {
+ ok(isOpen(),
+ "With " + tabCount + " tabs open, Ctrl+Tab opens the preview panel");
+
+ releaseCtrl();
+
+ ok(!isOpen(),
+ "Releasing Ctrl closes the preview panel");
+ } else {
+ ok(!isOpen(),
+ "With " + tabCount + " tabs open, Ctrl+Tab doesn't open the preview panel");
+ }
+
+ is(gBrowser.tabContainer.selectedIndex, expectedIndex,
+ "With "+ tabCount +" tabs open and tab " + indexStart
+ + " selected, Ctrl+Tab*" + tabTimes + " goes " + where);
+ }
+}
diff --git a/comm/suite/browser/test/browser/browser_fayt.js b/comm/suite/browser/test/browser/browser_fayt.js
new file mode 100644
index 0000000000..8522bc366b
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_fayt.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function test() {
+ var tab1 = gBrowser.addTab("data:text/html;charset=utf-8,<p>this is some dummy text</p>");
+ var tab2 = gBrowser.addTab("data:text/html;charset=utf-8,<p>this is some random text</p>");
+
+ gBrowser.getBrowserForTab(tab2).addEventListener("load", runTest, true);
+ waitForExplicitFinish();
+
+ function runTest() {
+ gBrowser.getBrowserForTab(tab2).removeEventListener("load", runTest, true);
+
+ gBrowser.selectedTab = tab2;
+ is(gBrowser.fastFind.find("random", false), Ci.nsITypeAheadFind.FIND_FOUND, "FAYT found the random text");
+ gBrowser.selectedTab = tab1;
+ is(gBrowser.fastFind.find("dummy", false), Ci.nsITypeAheadFind.FIND_FOUND, "FAYT found the dummy text");
+
+ gBrowser.removeTab(tab2);
+ gBrowser.removeTab(tab1);
+ finish();
+ }
+}
+
diff --git a/comm/suite/browser/test/browser/browser_notification_tab_switching.js b/comm/suite/browser/test/browser/browser_notification_tab_switching.js
new file mode 100644
index 0000000000..2cbdaa3147
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_notification_tab_switching.js
@@ -0,0 +1,95 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+var tab;
+var notification;
+var notificationURL = "http://example.org/browser/suite/browser/test/browser/file_dom_notifications.html";
+var newWindowOpenedFromTab;
+
+function test () {
+ waitForExplicitFinish();
+
+ let pm = Services.perms;
+ registerCleanupFunction(function() {
+ pm.remove(makeURI(notificationURL), "desktop-notification");
+ gBrowser.removeTab(tab);
+ window.restore();
+ });
+
+ pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION);
+
+ tab = gBrowser.addTab(notificationURL);
+ tab.linkedBrowser.addEventListener("load", onLoad, true);
+}
+
+function onLoad() {
+ isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab");
+ tab.linkedBrowser.removeEventListener("load", onLoad, true);
+ let win = tab.linkedBrowser.contentWindow.wrappedJSObject;
+ win.newWindow = win.open("about:blank", "", "height=100,width=100");
+ newWindowOpenedFromTab = win.newWindow;
+ win.newWindow.addEventListener("load", function() {
+ info("new window loaded");
+ win.newWindow.addEventListener("blur", function b() {
+ info("new window got blur");
+ win.newWindow.removeEventListener("blur", b);
+ notification = win.showNotification1();
+ win.newWindow.addEventListener("focus", onNewWindowFocused);
+ notification.addEventListener("show", onAlertShowing);
+ });
+
+ function waitUntilNewWindowHasFocus() {
+ if (!win.newWindow.document.hasFocus()) {
+ setTimeout(waitUntilNewWindowHasFocus, 50);
+ } else {
+ // Focus another window so that new window gets blur event.
+ gBrowser.selectedBrowser.contentWindow.focus();
+ }
+ }
+ win.newWindow.focus();
+ waitUntilNewWindowHasFocus();
+ });
+}
+
+function onAlertShowing() {
+ info("Notification alert showing");
+ notification.removeEventListener("show", onAlertShowing);
+
+ let alertWindow = findChromeWindowByURI("chrome://global/content/alerts/alert.xul");
+ if (!alertWindow) {
+ todo(false, "Notifications don't use XUL windows on all platforms.");
+ notification.close();
+ newWindowOpenedFromTab.close();
+ finish();
+ return;
+ }
+ gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect);
+ EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow);
+ info("Clicked on notification");
+ alertWindow.close();
+}
+
+function onNewWindowFocused(event) {
+ event.target.close();
+ isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab");
+ // Using timeout to test that something do *not* happen!
+ setTimeout(openSecondNotification, 50);
+}
+
+function openSecondNotification() {
+ isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab");
+ let win = tab.linkedBrowser.contentWindow.wrappedJSObject;
+ notification = win.showNotification2();
+ notification.addEventListener("show", onAlertShowing);
+}
+
+function onTabSelect() {
+ gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect);
+ is(gBrowser.selectedBrowser.contentWindow.location.href, notificationURL,
+ "Notification tab should be selected.");
+
+ finish();
+}
diff --git a/comm/suite/browser/test/browser/browser_pageInfo.js b/comm/suite/browser/test/browser/browser_pageInfo.js
new file mode 100644
index 0000000000..399301a784
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_pageInfo.js
@@ -0,0 +1,38 @@
+function test() {
+ waitForExplicitFinish();
+
+ var pageInfo;
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gBrowser.selectedBrowser.addEventListener("load", function loadListener() {
+ gBrowser.selectedBrowser.removeEventListener("load", loadListener, true);
+
+ Services.obs.addObserver(observer, "page-info-dialog-loaded");
+ pageInfo = BrowserPageInfo();
+ }, true);
+ content.location =
+ "https://example.com/browser/suite/browser/test/browser/feed_tab.html";
+
+ function observer(win, topic, data) {
+ Services.obs.removeObserver(observer, "page-info-dialog-loaded");
+ handlePageInfo();
+ }
+
+ function handlePageInfo() {
+ ok(pageInfo.document.getElementById("feedPanel"), "Feed panel");
+ let feedListbox = pageInfo.document.getElementById("feedListbox");
+ ok(feedListbox, "Feed list");
+
+ var feedRowsNum = feedListbox.getRowCount();
+ is(feedRowsNum, 3, "Number of feeds listed");
+
+ for (var i = 0; i < feedRowsNum; i++) {
+ let feedItem = feedListbox.getItemAtIndex(i);
+ is(feedItem.getAttribute("name"), i + 1, "Feed name");
+ }
+
+ pageInfo.close();
+ gBrowser.removeCurrentTab();
+ finish();
+ }
+}
diff --git a/comm/suite/browser/test/browser/browser_page_style_menu.js b/comm/suite/browser/test/browser/browser_page_style_menu.js
new file mode 100644
index 0000000000..88ce97da0b
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_page_style_menu.js
@@ -0,0 +1,67 @@
+function test() {
+ waitForExplicitFinish();
+
+ var tab = gBrowser.addTab();
+ gBrowser.selectedTab = tab;
+ tab.linkedBrowser.addEventListener("load", function loadListener() {
+ tab.linkedBrowser.removeEventListener("load", loadListener, true);
+ checkPageStyleMenu();
+ }, true);
+ let rootDir = getRootDirectory(gTestPath);
+ content.location = rootDir + "page_style_sample.html";
+}
+
+function checkPageStyleMenu() {
+ var menupopup = document.getElementById("menu_UseStyleSheet")
+ .getElementsByTagName("menupopup")[0];
+ stylesheetFillPopup(menupopup);
+
+ var items = [];
+ var current = menupopup.getElementsByTagName("menuitem")[1];
+ while (current.nextSibling) {
+ current = current.nextSibling;
+ items.push(current);
+ }
+
+ var validLinks = 0;
+ Array.from(content.document.getElementsByTagName("link")).forEach(function (link) {
+ var title = link.getAttribute("title");
+ var rel = link.getAttribute("rel");
+ var media = link.getAttribute("media");
+ var idstring = "link " + (title ? title : "without title and") +
+ " with rel=\"" + rel + "\"" +
+ (media ? " and media=\"" + media + "\"" : "");
+
+ var item = items.filter(item => item.getAttribute("label") == title);
+ var found = item.length == 1;
+ var checked = found && (item[0].getAttribute("checked") == "true");
+
+ switch (link.getAttribute("data-state")) {
+ case "0":
+ ok(!found, idstring + " does not show up in page style menu");
+ break;
+ case "0-todo":
+ validLinks++;
+ todo(!found, idstring + " should not show up in page style menu");
+ ok(!checked, idstring + " is not selected");
+ break;
+ case "1":
+ validLinks++;
+ ok(found, idstring + " shows up in page style menu");
+ ok(!checked, idstring + " is not selected");
+ break;
+ case "2":
+ validLinks++;
+ ok(found, idstring + " shows up in page style menu");
+ ok(checked, idstring + " is selected");
+ break;
+ default:
+ throw "data-state attribute is missing or has invalid value";
+ }
+ });
+
+ is(validLinks, items.length, "all valid links found");
+
+ gBrowser.removeCurrentTab();
+ finish();
+}
diff --git a/comm/suite/browser/test/browser/browser_popupNotification.js b/comm/suite/browser/test/browser/browser_popupNotification.js
new file mode 100644
index 0000000000..da88243e66
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_popupNotification.js
@@ -0,0 +1,782 @@
+/* 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/. */
+
+function test() {
+ waitForExplicitFinish();
+
+ ok(PopupNotifications, "PopupNotifications object exists");
+ ok(PopupNotifications.panel, "PopupNotifications panel exists");
+
+ registerCleanupFunction(cleanUp);
+
+ runNextTest();
+}
+
+function cleanUp() {
+ for (var topic in gActiveObservers)
+ Services.obs.removeObserver(gActiveObservers[topic], topic);
+ for (var eventName in gActiveListeners)
+ PopupNotifications.panel.removeEventListener(eventName, gActiveListeners[eventName]);
+}
+
+var gActiveListeners = {};
+var gActiveObservers = {};
+var gShownState = {};
+
+function runNextTest() {
+ let nextTest = tests[gTestIndex];
+
+ function goNext() {
+ if (++gTestIndex == tests.length)
+ executeSoon(finish);
+ else
+ executeSoon(runNextTest);
+ }
+
+ function addObserver(topic) {
+ function observer() {
+ Services.obs.removeObserver(observer, "PopupNotifications-" + topic);
+ delete gActiveObservers["PopupNotifications-" + topic];
+
+ info("[Test #" + gTestIndex + "] observer for " + topic + " called");
+ nextTest[topic]();
+ goNext();
+ }
+ Services.obs.addObserver(observer, "PopupNotifications-" + topic);
+ gActiveObservers["PopupNotifications-" + topic] = observer;
+ }
+
+ if (nextTest.backgroundShow) {
+ addObserver("backgroundShow");
+ } else if (nextTest.updateNotShowing) {
+ addObserver("updateNotShowing");
+ } else {
+ doOnPopupEvent("popupshowing", function () {
+ info("[Test #" + gTestIndex + "] popup showing");
+ });
+ doOnPopupEvent("popupshown", function () {
+ gShownState[gTestIndex] = true;
+ info("[Test #" + gTestIndex + "] popup shown");
+ nextTest.onShown(this);
+ });
+
+ // We allow multiple onHidden functions to be defined in an array. They're
+ // called in the order they appear.
+ let onHiddenArray = nextTest.onHidden instanceof Array ?
+ nextTest.onHidden :
+ [nextTest.onHidden];
+ doOnPopupEvent("popuphidden", function () {
+ if (!gShownState[gTestIndex]) {
+ // This is expected to happen for test 9, so let's not treat it as a failure.
+ info("Popup from test " + gTestIndex + " was hidden before its popupshown fired");
+ }
+
+ let onHidden = onHiddenArray.shift();
+ info("[Test #" + gTestIndex + "] popup hidden (" + onHiddenArray.length + " hides remaining)");
+ executeSoon(function () {
+ onHidden.call(nextTest, this);
+ if (!onHiddenArray.length)
+ goNext();
+ });
+ }, onHiddenArray.length);
+ info("[Test #" + gTestIndex + "] added listeners; panel state: " + PopupNotifications.isPanelOpen);
+ }
+
+ info("[Test #" + gTestIndex + "] running test");
+ nextTest.run();
+}
+
+function doOnPopupEvent(eventName, callback, numExpected) {
+ gActiveListeners[eventName] = function (event) {
+ if (event.target != PopupNotifications.panel)
+ return;
+ if (typeof(numExpected) === "number")
+ numExpected--;
+ if (!numExpected) {
+ PopupNotifications.panel.removeEventListener(eventName, gActiveListeners[eventName]);
+ delete gActiveListeners[eventName];
+ }
+
+ callback.call(PopupNotifications.panel);
+ }
+ PopupNotifications.panel.addEventListener(eventName, gActiveListeners[eventName]);
+}
+
+var gTestIndex = 0;
+var gNewTab;
+
+function basicNotification() {
+ var self = this;
+ this.browser = gBrowser.selectedBrowser;
+ this.id = "test-notification-" + gTestIndex;
+ this.message = "This is popup notification " + this.id + " from test " + gTestIndex;
+ this.anchorID = null;
+ this.mainAction = {
+ label: "Main Action",
+ accessKey: "M",
+ callback: function () {
+ self.mainActionClicked = true;
+ }
+ };
+ this.secondaryActions = [
+ {
+ label: "Secondary Action",
+ accessKey: "S",
+ callback: function () {
+ self.secondaryActionClicked = true;
+ }
+ }
+ ];
+ this.options = {
+ eventCallback: function (eventName) {
+ switch (eventName) {
+ case "dismissed":
+ self.dismissalCallbackTriggered = true;
+ break;
+ case "shown":
+ self.shownCallbackTriggered = true;
+ break;
+ case "removed":
+ self.removedCallbackTriggered = true;
+ break;
+ }
+ }
+ };
+ this.addOptions = function(options) {
+ for (let [name, value] of Object.entries(options))
+ self.options[name] = value;
+ }
+}
+
+var wrongBrowserNotificationObject = new basicNotification();
+var wrongBrowserNotification;
+
+var tests = [
+ { // Test #0
+ run: function () {
+ this.notifyObj = new basicNotification();
+ showNotification(this.notifyObj);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj);
+ triggerMainCommand(popup);
+ },
+ onHidden: function (popup) {
+ ok(this.notifyObj.mainActionClicked, "mainAction was clicked");
+ ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
+ ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
+ }
+ },
+ { // Test #1
+ run: function () {
+ this.notifyObj = new basicNotification();
+ showNotification(this.notifyObj);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj);
+ triggerSecondaryCommand(popup, 0);
+ },
+ onHidden: function (popup) {
+ ok(this.notifyObj.secondaryActionClicked, "secondaryAction was clicked");
+ ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
+ ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
+ }
+ },
+ { // Test #2
+ run: function () {
+ this.notifyObj = new basicNotification();
+ this.notification = showNotification(this.notifyObj);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj);
+ dismissNotification(popup);
+ },
+ onHidden: function (popup) {
+ ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
+ this.notification.remove();
+ ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
+ }
+ },
+ // test opening a notification for a background browser
+ { // Test #3
+ run: function () {
+ gNewTab = gBrowser.addTab("about:blank");
+ isnot(gBrowser.selectedTab, gNewTab, "new tab isn't selected");
+ wrongBrowserNotificationObject.browser = gBrowser.getBrowserForTab(gNewTab);
+ wrongBrowserNotification = showNotification(wrongBrowserNotificationObject);
+ },
+ backgroundShow: function () {
+ is(PopupNotifications.isPanelOpen, false, "panel isn't open");
+ ok(!wrongBrowserNotificationObject.mainActionClicked, "main action wasn't clicked");
+ ok(!wrongBrowserNotificationObject.secondaryActionClicked, "secondary action wasn't clicked");
+ ok(!wrongBrowserNotificationObject.dismissalCallbackTriggered, "dismissal callback wasn't called");
+ }
+ },
+ // now select that browser and test to see that the notification appeared
+ { // Test #4
+ run: function () {
+ this.oldSelectedTab = gBrowser.selectedTab;
+ gBrowser.selectedTab = gNewTab;
+ },
+ onShown: function (popup) {
+ checkPopup(popup, wrongBrowserNotificationObject);
+ is(PopupNotifications.isPanelOpen, true, "isPanelOpen getter doesn't lie");
+
+ // switch back to the old browser
+ gBrowser.selectedTab = this.oldSelectedTab;
+ },
+ onHidden: function (popup) {
+ // actually remove the notification to prevent it from reappearing
+ ok(wrongBrowserNotificationObject.dismissalCallbackTriggered, "dismissal callback triggered due to tab switch");
+ wrongBrowserNotification.remove();
+ ok(wrongBrowserNotificationObject.removedCallbackTriggered, "removed callback triggered");
+ wrongBrowserNotification = null;
+ }
+ },
+ // test that the removed notification isn't shown on browser re-select
+ { // Test #5
+ run: function () {
+ gBrowser.selectedTab = gNewTab;
+ },
+ updateNotShowing: function () {
+ is(PopupNotifications.isPanelOpen, false, "panel isn't open");
+ gBrowser.removeTab(gNewTab);
+ }
+ },
+ // Test that two notifications with the same ID result in a single displayed
+ // notification.
+ { // Test #6
+ run: function () {
+ this.notifyObj = new basicNotification();
+ // Show the same notification twice
+ this.notification1 = showNotification(this.notifyObj);
+ this.notification2 = showNotification(this.notifyObj);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj);
+ this.notification2.remove();
+ },
+ onHidden: function (popup) {
+ ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
+ ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
+ }
+ },
+ // Test that two notifications with different IDs are displayed
+ { // Test #7
+ run: function () {
+ this.testNotif1 = new basicNotification();
+ this.testNotif1.message += " 1";
+ showNotification(this.testNotif1);
+ this.testNotif2 = new basicNotification();
+ this.testNotif2.message += " 2";
+ this.testNotif2.id += "-2";
+ showNotification(this.testNotif2);
+ },
+ onShown: function (popup) {
+ is(popup.childNodes.length, 2, "two notifications are shown");
+ // Trigger the main command for the first notification, and the secondary
+ // for the second. Need to do mainCommand first since the secondaryCommand
+ // triggering is async.
+ triggerMainCommand(popup);
+ is(popup.childNodes.length, 1, "only one notification left");
+ triggerSecondaryCommand(popup, 0);
+ },
+ onHidden: function (popup) {
+ ok(this.testNotif1.mainActionClicked, "main action #1 was clicked");
+ ok(!this.testNotif1.secondaryActionClicked, "secondary action #1 wasn't clicked");
+ ok(!this.testNotif1.dismissalCallbackTriggered, "dismissal callback #1 wasn't called");
+
+ ok(!this.testNotif2.mainActionClicked, "main action #2 wasn't clicked");
+ ok(this.testNotif2.secondaryActionClicked, "secondary action #2 was clicked");
+ ok(!this.testNotif2.dismissalCallbackTriggered, "dismissal callback #2 wasn't called");
+ }
+ },
+ // Test notification without mainAction
+ { // Test #8
+ run: function () {
+ this.notifyObj = new basicNotification();
+ this.notifyObj.mainAction = null;
+ this.notification = showNotification(this.notifyObj);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj);
+ dismissNotification(popup);
+ },
+ onHidden: function (popup) {
+ this.notification.remove();
+ }
+ },
+ // Test two notifications with different anchors
+ { // Test #9
+ run: function () {
+ this.notifyObj = new basicNotification();
+ this.firstNotification = showNotification(this.notifyObj);
+ this.notifyObj2 = new basicNotification();
+ this.notifyObj2.id += "-2";
+ this.notifyObj2.anchorID = "addons-notification-icon";
+ // Second showNotification() overrides the first
+ this.secondNotification = showNotification(this.notifyObj2);
+ },
+ onShown: function (popup) {
+ // This also checks that only one element is shown.
+ checkPopup(popup, this.notifyObj2);
+ is(document.getElementById("geo-notification-icon").boxObject.width, 0,
+ "geo anchor shouldn't be visible");
+ dismissNotification(popup);
+ },
+ onHidden: [
+ // The second showing triggers a popuphidden event that we should ignore.
+ function (popup) {},
+ function (popup) {
+ // Remove the notifications
+ this.firstNotification.remove();
+ this.secondNotification.remove();
+ ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
+ ok(this.notifyObj2.removedCallbackTriggered, "removed callback triggered");
+ }
+ ]
+ },
+ // Test optional params
+ { // Test #10
+ run: function () {
+ this.notifyObj = new basicNotification();
+ this.notifyObj.secondaryActions = undefined;
+ this.notification = showNotification(this.notifyObj);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj);
+ dismissNotification(popup);
+ },
+ onHidden: function (popup) {
+ ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
+ this.notification.remove();
+ ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
+ }
+ },
+ // Test that icons appear
+ { // Test #11
+ run: function () {
+ this.notifyObj = new basicNotification();
+ this.notifyObj.id = "geolocation";
+ this.notifyObj.anchorID = "geo-notification-icon";
+ // Fake these options (with arbitrary values),
+ // to avoid strict warnings in SeaMonkey notification constructor.
+ this.notifyObj.addOptions({
+ value: "Learn More...",
+ href: "http://www.seamonkey-project.org/doc/2.0/geolocation"
+ });
+ this.notification = showNotification(this.notifyObj);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj);
+ isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
+ "geo anchor should be visible");
+ dismissNotification(popup);
+ },
+ onHidden: function (popup) {
+ let icon = document.getElementById("geo-notification-icon");
+ isnot(icon.boxObject.width, 0,
+ "geo anchor should be visible after dismissal");
+ this.notification.remove();
+ is(icon.boxObject.width, 0,
+ "geo anchor should not be visible after removal");
+ }
+ },
+ // Test that persistence allows the notification to persist across reloads
+ { // Test #12
+ run: function () {
+ this.oldSelectedTab = gBrowser.selectedTab;
+ gBrowser.selectedTab = gBrowser.addTab("about:blank");
+
+ let self = this;
+ loadURI("http://example.com/", function() {
+ self.notifyObj = new basicNotification();
+ self.notifyObj.addOptions({
+ persistence: 2
+ });
+ self.notification = showNotification(self.notifyObj);
+ });
+ },
+ onShown: function (popup) {
+ this.complete = false;
+
+ let self = this;
+ loadURI("http://example.org/", function() {
+ loadURI("http://example.com/", function() {
+
+ // Next load will remove the notification
+ self.complete = true;
+
+ loadURI("http://example.org/");
+ });
+ });
+ },
+ onHidden: function (popup) {
+ ok(this.complete, "Should only have hidden the notification after 3 page loads");
+ ok(this.notifyObj.removedCallbackTriggered, "removal callback triggered");
+ gBrowser.removeTab(gBrowser.selectedTab);
+ gBrowser.selectedTab = this.oldSelectedTab;
+ }
+ },
+ // Test that a timeout allows the notification to persist across reloads
+ { // Test #13
+ run: function () {
+ this.oldSelectedTab = gBrowser.selectedTab;
+ gBrowser.selectedTab = gBrowser.addTab("about:blank");
+
+ let self = this;
+ loadURI("http://example.com/", function() {
+ self.notifyObj = new basicNotification();
+ // Set a timeout of 10 minutes that should never be hit
+ self.notifyObj.addOptions({
+ timeout: Date.now() + 600000
+ });
+ self.notification = showNotification(self.notifyObj);
+ });
+ },
+ onShown: function (popup) {
+ this.complete = false;
+
+ let self = this;
+ loadURI("http://example.org/", function() {
+ loadURI("http://example.com/", function() {
+
+ // Next load will hide the notification
+ self.notification.options.timeout = Date.now() - 1;
+ self.complete = true;
+
+ loadURI("http://example.org/");
+ });
+ });
+ },
+ onHidden: function (popup) {
+ ok(this.complete, "Should only have hidden the notification after the timeout was passed");
+ this.notification.remove();
+ gBrowser.removeTab(gBrowser.selectedTab);
+ gBrowser.selectedTab = this.oldSelectedTab;
+ }
+ },
+ // Test that setting persistWhileVisible allows a visible notification to
+ // persist across location changes
+ { // Test #14
+ run: function () {
+ this.oldSelectedTab = gBrowser.selectedTab;
+ gBrowser.selectedTab = gBrowser.addTab("about:blank");
+
+ let self = this;
+ loadURI("http://example.com/", function() {
+ self.notifyObj = new basicNotification();
+ self.notifyObj.addOptions({
+ persistWhileVisible: true
+ });
+ self.notification = showNotification(self.notifyObj);
+ });
+ },
+ onShown: function (popup) {
+ this.complete = false;
+
+ let self = this;
+ loadURI("http://example.org/", function() {
+ loadURI("http://example.com/", function() {
+
+ // Notification should persist across location changes
+ self.complete = true;
+ dismissNotification(popup);
+ });
+ });
+ },
+ onHidden: function (popup) {
+ ok(this.complete, "Should only have hidden the notification after it was dismissed");
+ this.notification.remove();
+ gBrowser.removeTab(gBrowser.selectedTab);
+ gBrowser.selectedTab = this.oldSelectedTab;
+ }
+ },
+ // Test that nested icon nodes correctly activate popups
+ { // Test #15
+ run: function() {
+ // Add a temporary box as the anchor with a button
+ this.box = document.createElement("box");
+ PopupNotifications.iconBox.appendChild(this.box);
+
+ let button = document.createElement("button");
+ button.setAttribute("label", "Please click me!");
+ this.box.appendChild(button);
+
+ // The notification should open up on the box
+ this.notifyObj = new basicNotification();
+ this.notifyObj.anchorID = this.box.id = "nested-box";
+ this.notifyObj.addOptions({dismissed: true});
+ this.notification = showNotification(this.notifyObj);
+
+ EventUtils.synthesizeMouse(button, 1, 1, {});
+ },
+ onShown: function(popup) {
+ checkPopup(popup, this.notifyObj);
+ dismissNotification(popup);
+ },
+ onHidden: function(popup) {
+ this.notification.remove();
+ this.box.remove();
+ }
+ },
+ // Test that popupnotifications without popups have anchor icons shown
+ { // Test #16
+ run: function() {
+ let notifyObj = new basicNotification();
+ notifyObj.anchorID = "geo-notification-icon";
+ notifyObj.addOptions({neverShow: true});
+ showNotification(notifyObj);
+ },
+ updateNotShowing: function() {
+ isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
+ "geo anchor should be visible");
+ }
+ },
+ // Test notification "Not Now" menu item
+ { // Test #17
+ run: function () {
+ this.notifyObj = new basicNotification();
+ this.notification = showNotification(this.notifyObj);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj);
+ triggerSecondaryCommand(popup, 1);
+ },
+ onHidden: function (popup) {
+ ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
+ this.notification.remove();
+ ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
+ }
+ },
+ // Test notification close button
+ { // Test #18
+ run: function () {
+ this.notifyObj = new basicNotification();
+ this.notification = showNotification(this.notifyObj);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj);
+ let notification = popup.childNodes[0];
+ EventUtils.synthesizeMouseAtCenter(notification.closebutton, {});
+ },
+ onHidden: function (popup) {
+ ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
+ this.notification.remove();
+ ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
+ }
+ },
+ // Test notification when chrome is hidden
+ { // Test #19
+ run: function () {
+ window.locationbar.visible = false;
+ this.notifyObj = new basicNotification();
+ this.notification = showNotification(this.notifyObj);
+ window.locationbar.visible = true;
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj);
+ is(popup.anchorNode.className, "tabbrowser-tab", "notification anchored to tab");
+ dismissNotification(popup);
+ },
+ onHidden: function (popup) {
+ ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
+ this.notification.remove();
+ ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
+ }
+ },
+ // Test notification is removed when dismissed if removeOnDismissal is true
+ { // Test #20
+ run: function () {
+ this.notifyObj = new basicNotification();
+ this.notifyObj.addOptions({
+ removeOnDismissal: true
+ });
+ this.notification = showNotification(this.notifyObj);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj);
+ dismissNotification(popup);
+ },
+ onHidden: function (popup) {
+ ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
+ ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
+ }
+ },
+ // Test multiple notification icons are shown
+ { // Test #21
+ run: function () {
+ this.notifyObj1 = new basicNotification();
+ this.notifyObj1.id += "_1";
+ this.notifyObj1.anchorID = "default-notification-icon";
+ this.notification1 = showNotification(this.notifyObj1);
+
+ this.notifyObj2 = new basicNotification();
+ this.notifyObj2.id += "_2";
+ this.notifyObj2.anchorID = "geo-notification-icon";
+ this.notification2 = showNotification(this.notifyObj2);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObj2);
+
+ // check notifyObj1 anchor icon is showing
+ isnot(document.getElementById("default-notification-icon").boxObject.width, 0,
+ "default anchor should be visible");
+ // check notifyObj2 anchor icon is showing
+ isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
+ "geo anchor should be visible");
+
+ dismissNotification(popup);
+ },
+ onHidden: [
+ function (popup) {
+ },
+ function (popup) {
+ this.notification1.remove();
+ ok(this.notifyObj1.removedCallbackTriggered, "removed callback triggered");
+
+ this.notification2.remove();
+ ok(this.notifyObj2.removedCallbackTriggered, "removed callback triggered");
+ }
+ ]
+ },
+ // Test that multiple notification icons are removed when switching tabs
+ { // Test #22
+ run: function () {
+ // show the notification on old tab.
+ this.notifyObjOld = new basicNotification();
+ this.notifyObjOld.anchorID = "default-notification-icon";
+ this.notificationOld = showNotification(this.notifyObjOld);
+
+ // switch tab
+ this.oldSelectedTab = gBrowser.selectedTab;
+ gBrowser.selectedTab = gBrowser.addTab("about:blank");
+
+ // show the notification on new tab.
+ this.notifyObjNew = new basicNotification();
+ this.notifyObjNew.anchorID = "geo-notification-icon";
+ this.notificationNew = showNotification(this.notifyObjNew);
+ },
+ onShown: function (popup) {
+ checkPopup(popup, this.notifyObjNew);
+
+ // check notifyObjOld anchor icon is removed
+ is(document.getElementById("default-notification-icon").boxObject.width, 0,
+ "default anchor shouldn't be visible");
+ // check notifyObjNew anchor icon is showing
+ isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
+ "geo anchor should be visible");
+
+ dismissNotification(popup);
+ },
+ onHidden: [
+ function (popup) {
+ },
+ function (popup) {
+ this.notificationNew.remove();
+ gBrowser.removeTab(gBrowser.selectedTab);
+
+ gBrowser.selectedTab = this.oldSelectedTab;
+ this.notificationOld.remove();
+ }
+ ]
+ }
+];
+
+function showNotification(notifyObj) {
+ return PopupNotifications.show(notifyObj.browser,
+ notifyObj.id,
+ notifyObj.message,
+ notifyObj.anchorID,
+ notifyObj.mainAction,
+ notifyObj.secondaryActions,
+ notifyObj.options);
+}
+
+function checkPopup(popup, notificationObj) {
+ info("[Test #" + gTestIndex + "] checking popup");
+
+ ok(notificationObj.shownCallbackTriggered, "shown callback was triggered");
+
+ let notifications = popup.childNodes;
+ is(notifications.length, 1, "only one notification displayed");
+ let notification = notifications[0];
+ let icon = document.getAnonymousElementByAttribute(notification, "class", "popup-notification-icon");
+ if (notificationObj.id == "geolocation") {
+ isnot(icon.boxObject.width, 0, "icon for geo displayed");
+ is(popup.anchorNode.className, "notification-anchor-icon", "notification anchored to icon");
+ }
+ is(notification.getAttribute("label"), notificationObj.message, "message matches");
+ is(notification.id, notificationObj.id + "-notification", "id matches");
+ if (notificationObj.mainAction) {
+ is(notification.getAttribute("buttonlabel"), notificationObj.mainAction.label, "main action label matches");
+ is(notification.getAttribute("buttonaccesskey"), notificationObj.mainAction.accessKey, "main action accesskey matches");
+ }
+ let actualSecondaryActions = notification.childNodes;
+ let secondaryActions = notificationObj.secondaryActions || [];
+ let actualSecondaryActionsCount = actualSecondaryActions.length;
+ if (secondaryActions.length) {
+ let lastChild = actualSecondaryActions.item(actualSecondaryActions.length - 1);
+ is(lastChild.tagName, "menuseparator", "menuseparator exists");
+ actualSecondaryActionsCount--;
+ }
+ is(actualSecondaryActionsCount, secondaryActions.length, actualSecondaryActions.length + " secondary actions");
+ secondaryActions.forEach(function (a, i) {
+ is(actualSecondaryActions[i].getAttribute("label"), a.label, "label for secondary action " + i + " matches");
+ is(actualSecondaryActions[i].getAttribute("accesskey"), a.accessKey, "accessKey for secondary action " + i + " matches");
+ });
+}
+
+function triggerMainCommand(popup) {
+ info("[Test #" + gTestIndex + "] triggering main command");
+ let notifications = popup.childNodes;
+ ok(notifications.length > 0, "at least one notification displayed");
+ let notification = notifications[0];
+ EventUtils.synthesizeMouseAtCenter(notification.button, {});
+}
+
+function triggerSecondaryCommand(popup, index) {
+ info("[Test #" + gTestIndex + "] triggering secondary command");
+ let notifications = popup.childNodes;
+ ok(notifications.length > 0, "at least one notification displayed");
+ let notification = notifications[0];
+ info("Triggering secondary command for notification " + notification.id);
+ notification.button.nextSibling.nextSibling.focus();
+
+ popup.addEventListener("popupshown", function triggerPopupShown() {
+ popup.removeEventListener("popupshown", triggerPopupShown);
+
+ // Press down until the desired command is selected
+ for (let i = 0; i <= index; i++)
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ // Activate
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ });
+
+ // One down event to open the popup
+ EventUtils.synthesizeKey("VK_DOWN", { altKey: AppConstants.platform != "macosx" });
+}
+
+function loadURI(uri, callback) {
+ if (callback) {
+ gBrowser.addEventListener("load", function loadURIgBLoad() {
+ // Ignore the about:blank load
+ if (gBrowser.currentURI.spec != uri)
+ return;
+
+ gBrowser.removeEventListener("load", loadURIgBLoad, true);
+
+ callback();
+ }, true);
+ }
+ gBrowser.loadURI(uri);
+}
+
+function dismissNotification(popup) {
+ info("[Test #" + gTestIndex + "] dismissing notification");
+ executeSoon(function () {
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+ });
+}
diff --git a/comm/suite/browser/test/browser/browser_privatebrowsing_protocolhandler.js b/comm/suite/browser/test/browser/browser_privatebrowsing_protocolhandler.js
new file mode 100644
index 0000000000..2fc5392dca
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_privatebrowsing_protocolhandler.js
@@ -0,0 +1,65 @@
+/* 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/. */
+
+// This test makes sure that the web pages can't register protocol handlers
+// inside the private browsing mode.
+
+function test() {
+ // initialization
+ waitForExplicitFinish();
+ let windowsToClose = [];
+ let notificationValue = "Protocol Registration: testprotocol";
+ let testURI = "http://example.com/browser/" +
+ "suite/browser/test/browser/browser_privatebrowsing_protocolhandler_page.html";
+
+ function doTest(aIsPrivateMode, aWindow, aCallback) {
+ aWindow.getBrowser().selectedBrowser.addEventListener("load", function onLoad() {
+ aWindow.getBrowser().selectedBrowser.removeEventListener("load", onLoad, true);
+
+ setTimeout(function() {
+ let notificationBox = aWindow.getBrowser().getNotificationBox();
+ let notification = notificationBox.getNotificationWithValue(notificationValue);
+
+ if (aIsPrivateMode) {
+ // Make sure the notification is correctly displayed without a remember control
+ ok(!notification, "Notification box should not be displayed inside of private browsing mode");
+ } else {
+ // Make sure the notification is correctly displayed with a remember control
+ ok(notification, "Notification box should be displaying outside of private browsing mode");
+ }
+
+ aCallback();
+ }, 100); // remember control is added in a setTimeout(0) call
+ }, true);
+
+ aWindow.getBrowser().selectedBrowser.loadURI(testURI);
+ }
+
+ function testOnWindow(aOptions, aCallback) {
+ whenNewWindowLoaded(aOptions, function(aWin) {
+ windowsToClose.push(aWin);
+ // execute should only be called when need, like when you are opening
+ // web pages on the test. If calling executeSoon() is not necesary, then
+ // call whenNewWindowLoaded() instead of testOnWindow() on your test.
+ executeSoon(() => aCallback(aWin));
+ });
+ };
+
+ // this function is called after calling finish() on the test.
+ registerCleanupFunction(function() {
+ windowsToClose.forEach(function(aWin) {
+ aWin.close();
+ });
+ });
+
+ // test first when not on private mode
+ testOnWindow({}, function(aWin) {
+ doTest(false, aWin, function() {
+ // then test when on private mode
+ testOnWindow({private: true}, function(aWin) {
+ doTest(true, aWin, finish);
+ });
+ });
+ });
+}
diff --git a/comm/suite/browser/test/browser/browser_privatebrowsing_protocolhandler_page.html b/comm/suite/browser/test/browser/browser_privatebrowsing_protocolhandler_page.html
new file mode 100644
index 0000000000..800476fd03
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_privatebrowsing_protocolhandler_page.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+ <head>
+ <title>Protocol registrar page</title>
+ </head>
+ <body>
+ <script>
+ navigator.registerProtocolHandler("testprotocol",
+ "https://example.com/foobar?uri=%s",
+ "Test Protocol");
+ </script>
+ </body>
+</html>
diff --git a/comm/suite/browser/test/browser/browser_relatedTabs.js b/comm/suite/browser/test/browser/browser_relatedTabs.js
new file mode 100644
index 0000000000..f93e212391
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_relatedTabs.js
@@ -0,0 +1,52 @@
+/* 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/. */
+
+function test() {
+ is(getBrowser().tabs.length, 1, "one tab is open initially");
+
+ // Add several new tabs in sequence, interrupted by selecting a
+ // different tab, moving a tab around and closing a tab,
+ // returning a list of opened tabs for verifying the expected order.
+ // The new tab behaviour is documented in bug 465673
+ let tabs = [];
+ function addTab(aURL, aReferrer) {
+ tabs.push(getBrowser().addTab(aURL, {referrerURI: aReferrer}));
+ }
+
+ addTab("http://mochi.test:8888/#0");
+ getBrowser().selectedTab = tabs[0];
+ addTab("http://mochi.test:8888/#1");
+ addTab("http://mochi.test:8888/#2", getBrowser().currentURI);
+ addTab("http://mochi.test:8888/#3", getBrowser().currentURI);
+ getBrowser().selectedTab = tabs[tabs.length - 1];
+ getBrowser().selectedTab = tabs[0];
+ addTab("http://mochi.test:8888/#4", getBrowser().currentURI);
+ getBrowser().selectedTab = tabs[3];
+ addTab("http://mochi.test:8888/#5", getBrowser().currentURI);
+ getBrowser().removeTab(tabs.pop());
+ addTab("about:blank", getBrowser().currentURI);
+ getBrowser().moveTabTo(getBrowser().selectedTab, 1);
+ addTab("http://mochi.test:8888/#6", getBrowser().currentURI);
+ addTab();
+ addTab("http://mochi.test:8888/#7");
+
+ function testPosition(tabNum, expectedPosition, msg) {
+ is(Array.from(getBrowser().tabs)
+ .indexOf(tabs[tabNum]),
+ expectedPosition,
+ msg);
+ }
+
+ testPosition(0, 3, "tab without referrer was opened to the far right");
+ testPosition(1, 7, "tab without referrer was opened to the far right");
+ testPosition(2, 5, "tab with referrer opened immediately to the right");
+ testPosition(3, 1, "next tab with referrer opened further to the right");
+ testPosition(4, 4, "tab selection changed, tab opens immediately to the right");
+ testPosition(5, 6, "blank tab with referrer opens to the right of 3rd original tab where removed tab was");
+ testPosition(6, 2, "tab has moved, new tab opens immediately to the right");
+ testPosition(7, 8, "blank tab without referrer opens at the end");
+ testPosition(8, 9, "tab without referrer opens at the end");
+
+ tabs.forEach(getBrowser().removeTab, getBrowser());
+}
diff --git a/comm/suite/browser/test/browser/browser_scope.js b/comm/suite/browser/test/browser/browser_scope.js
new file mode 100644
index 0000000000..e4edac1e04
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_scope.js
@@ -0,0 +1,4 @@
+function test() {
+ ok(!!gBrowser, "gBrowser exists");
+ is(gBrowser, getBrowser(), "both ways of getting tabbrowser work");
+}
diff --git a/comm/suite/browser/test/browser/browser_selectTabAtIndex.js b/comm/suite/browser/test/browser/browser_selectTabAtIndex.js
new file mode 100644
index 0000000000..9da6c8d489
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_selectTabAtIndex.js
@@ -0,0 +1,22 @@
+function test() {
+ for (let i = 0; i < 9; i++)
+ gBrowser.addTab();
+
+/* This part tests accel keys, which are not implemented in Seamonkey yet.
+ * Commenting out for now ...
+ * var isLinux = AppConstants.platform == "linux";
+ * for (let i = 9; i >= 1; i--) {
+ * EventUtils.synthesizeKey(i.toString(), { altKey: isLinux, accelKey: !isLinux });
+ *
+ * is(gBrowser.tabContainer.selectedIndex, (i == 9 ? gBrowser.tabs.length : i) - 1,
+ * (isLinux ? "Alt" : "Accel") + "+" + i + " selects expected tab");
+ * }
+ */
+
+ gBrowser.selectTabAtIndex(-3);
+ is(gBrowser.tabContainer.selectedIndex, gBrowser.tabs.length - 3,
+ "gBrowser.selectTabAtIndex(-3) selects expected tab");
+
+ for (let i = 0; i < 9; i++)
+ gBrowser.removeCurrentTab();
+}
diff --git a/comm/suite/browser/test/browser/browser_urlbarCopying.js b/comm/suite/browser/test/browser/browser_urlbarCopying.js
new file mode 100644
index 0000000000..cc51832996
--- /dev/null
+++ b/comm/suite/browser/test/browser/browser_urlbarCopying.js
@@ -0,0 +1,204 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const trimPref = "browser.urlbar.trimURLs";
+const phishyUserPassPref = "network.http.phishy-userpass-length";
+
+function test() {
+
+ let tab = gBrowser.selectedTab = gBrowser.addTab();
+
+ registerCleanupFunction(function () {
+ gBrowser.removeTab(tab);
+ Services.prefs.clearUserPref(trimPref);
+ Services.prefs.clearUserPref(phishyUserPassPref);
+ URLBarSetURI();
+ });
+
+ Services.prefs.setBoolPref(trimPref, true);
+ Services.prefs.setIntPref(phishyUserPassPref, 32); // avoid prompting about phishing
+
+ waitForExplicitFinish();
+
+ nextTest();
+}
+
+var tests = [
+ // pageproxystate="invalid"
+ {
+ setURL: "http://example.com/",
+ expectedURL: "example.com",
+ copyExpected: "example.com"
+ },
+ {
+ copyVal: "<e>xample.com",
+ copyExpected: "e"
+ },
+
+ // pageproxystate="valid" from this point on (due to the load)
+ {
+ loadURL: "http://example.com/",
+ expectedURL: "example.com",
+ copyExpected: "http://example.com/"
+ },
+ {
+ copyVal: "<example.co>m",
+ copyExpected: "example.co"
+ },
+ {
+ copyVal: "e<x>ample.com",
+ copyExpected: "x"
+ },
+ {
+ copyVal: "<e>xample.com",
+ copyExpected: "e"
+ },
+
+ {
+ loadURL: "http://example.com/foo",
+ expectedURL: "example.com/foo",
+ copyExpected: "http://example.com/foo"
+ },
+ {
+ copyVal: "<example.com>/foo",
+ copyExpected: "http://example.com"
+ },
+ {
+ copyVal: "<example>.com/foo",
+ copyExpected: "example"
+ },
+
+ // Test that userPass is stripped out
+ {
+ loadURL: "http://user:pass@mochi.test:8888/browser/browser/base/content/test/general/authenticate.sjs?user=user&pass=pass",
+ expectedURL: "mochi.test:8888/browser/browser/base/content/test/general/authenticate.sjs?user=user&pass=pass",
+ copyExpected: "http://mochi.test:8888/browser/browser/base/content/test/general/authenticate.sjs?user=user&pass=pass"
+ },
+
+ // Test escaping
+ {
+ loadURL: "http://example.com/()%28%29%C3%A9",
+ expectedURL: "example.com/()()\xe9",
+ copyExpected: "http://example.com/()%28%29%C3%A9"
+ },
+ {
+ copyVal: "<example.com/(>)()\xe9",
+ copyExpected: "http://example.com/("
+ },
+ {
+ copyVal: "e<xample.com/(>)()\xe9",
+ copyExpected: "xample.com/("
+ },
+
+ {
+ loadURL: "http://example.com/%C3%A9%C3%A9",
+ expectedURL: "example.com/\xe9\xe9",
+ copyExpected: "http://example.com/%C3%A9%C3%A9"
+ },
+ {
+ copyVal: "e<xample.com/\xe9>\xe9",
+ copyExpected: "xample.com/\xe9"
+ },
+ {
+ copyVal: "<example.com/\xe9>\xe9",
+ copyExpected: "http://example.com/\xe9"
+ },
+
+ {
+ loadURL: "http://example.com/?%C3%B7%C3%B7",
+ expectedURL: "example.com/?\xf7\xf7",
+ copyExpected: "http://example.com/?%C3%B7%C3%B7"
+ },
+ {
+ copyVal: "e<xample.com/?\xf7>\xf7",
+ copyExpected: "xample.com/?\xf7"
+ },
+ {
+ copyVal: "<example.com/?\xf7>\xf7",
+ copyExpected: "http://example.com/?\xf7"
+ },
+
+ // data: and javsacript: URIs shouldn't be encoded
+ {
+ loadURL: "javascript:('%C3%A9%20%25%50')",
+ expectedURL: "javascript:('%C3%A9 %25P')",
+ copyExpected: "javascript:('%C3%A9 %25P')"
+ },
+ {
+ copyVal: "<javascript:(>'%C3%A9 %25P')",
+ copyExpected: "javascript:("
+ },
+
+ {
+ loadURL: "data:text/html,(%C3%A9%20%25%50)",
+ expectedURL: "data:text/html,(%C3%A9 %25P)",
+ copyExpected: "data:text/html,(%C3%A9 %25P)",
+ },
+ {
+ copyVal: "<data:text/html,(>%C3%A9 %25P)",
+ copyExpected: "data:text/html,("
+ },
+ {
+ copyVal: "<data:text/html,(%C3%A9 %25P>)",
+ copyExpected: "data:text/html,(%C3%A9 %25P",
+ }
+];
+
+function nextTest() {
+ let test = tests.shift();
+ if (tests.length == 0)
+ runTest(test, finish);
+ else
+ runTest(test, nextTest);
+}
+
+function runTest(test, cb) {
+ function doCheck() {
+ if (test.setURL || test.loadURL) {
+ gURLBar.valueIsTyped = !!test.setURL;
+ is(gURLBar.textValue, test.expectedURL, "url bar value set");
+ }
+
+ testCopy(test.copyVal, test.copyExpected, cb);
+ }
+
+ if (test.loadURL) {
+ loadURL(test.loadURL, doCheck);
+ } else {
+ if (test.setURL)
+ gURLBar.value = test.setURL;
+ doCheck();
+ }
+}
+
+function testCopy(copyVal, targetValue, cb) {
+ info("Expecting copy of: " + targetValue);
+ waitForClipboard(targetValue, function () {
+ gURLBar.focus();
+ if (copyVal) {
+ let startBracket = copyVal.indexOf("<");
+ let endBracket = copyVal.indexOf(">");
+ if (startBracket == -1 || endBracket == -1 ||
+ startBracket > endBracket ||
+ copyVal.replace("<", "").replace(">", "") != gURLBar.textValue) {
+ ok(false, "invalid copyVal: " + copyVal);
+ }
+ gURLBar.selectionStart = startBracket;
+ gURLBar.selectionEnd = endBracket - 1;
+ } else {
+ gURLBar.select();
+ }
+
+ goDoCommand("cmd_copy");
+ }, cb, cb);
+}
+
+function loadURL(aURL, aCB) {
+ gBrowser.selectedBrowser.addEventListener("load", function () {
+ gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+ is(gBrowser.currentURI.spec, aURL, "loaded expected URL");
+ aCB();
+ }, true);
+
+ gBrowser.loadURI(aURL);
+}
diff --git a/comm/suite/browser/test/browser/feed_tab.html b/comm/suite/browser/test/browser/feed_tab.html
new file mode 100644
index 0000000000..50903f48b6
--- /dev/null
+++ b/comm/suite/browser/test/browser/feed_tab.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=458579
+-->
+ <head>
+ <title>Test for page info feeds tab</title>
+
+ <!-- Straight up standard -->
+ <link rel="alternate" type="application/atom+xml" title="1" href="/1.atom" />
+ <link rel="alternate" type="application/rss+xml" title="2" href="/2.rss" />
+ <link rel="feed" title="3" href="/3.xml" />
+
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/comm/suite/browser/test/browser/file_dom_notifications.html b/comm/suite/browser/test/browser/file_dom_notifications.html
new file mode 100644
index 0000000000..078c94a42d
--- /dev/null
+++ b/comm/suite/browser/test/browser/file_dom_notifications.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<script>
+"use strict";
+
+function showNotification1() {
+ var options = {
+ dir: undefined,
+ lang: undefined,
+ body: "Test body",
+ tag: "Test tag",
+ icon: undefined,
+ };
+ var n = new Notification("Test title", options);
+ n.addEventListener("click", function(event) {
+ event.preventDefault();
+ dump("Should focus new window.");
+ newWindow.focus();
+ });
+ return n;
+}
+
+function showNotification2() {
+ var options = {
+ dir: undefined,
+ lang: undefined,
+ body: "Test body",
+ tag: "Test tag",
+ icon: undefined,
+ };
+ return new Notification("Test title", options);
+}
+</script>
+</head>
+<body>
+<form id="notificationForm" onsubmit="showNotification();">
+ <input type="submit" value="Show notification" id="submit"/>
+</form>
+</body>
+</html>
diff --git a/comm/suite/browser/test/browser/head.js b/comm/suite/browser/test/browser/head.js
new file mode 100644
index 0000000000..9a065930a2
--- /dev/null
+++ b/comm/suite/browser/test/browser/head.js
@@ -0,0 +1,63 @@
+/* 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/. */
+
+function findChromeWindowByURI(aURI) {
+ let windows = Services.wm.getEnumerator(null);
+ while (windows.hasMoreElements()) {
+ let win = windows.getNext();
+ if (win.location.href == aURI)
+ return win;
+ }
+ return null;
+}
+
+function waitForCondition(condition, nextTest, errorMsg) {
+ var tries = 0;
+ var interval = setInterval(function() {
+ if (tries >= 30) {
+ ok(false, errorMsg);
+ moveOn();
+ }
+ if (condition()) {
+ moveOn();
+ }
+ tries++;
+ }, 100);
+ var moveOn = function() { clearInterval(interval); nextTest(); };
+}
+
+function whenNewWindowLoaded(aOptions, aCallback) {
+ var { private } = aOptions;
+ var features = private ? "private,chrome,all,dialog=no" :
+ "non-private,chrome,all,dialog=no";
+ var win = window.openDialog(getBrowserURL(), "_blank", features,
+ "about:blank");
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ aCallback(win);
+ });
+}
+
+function updateBlocklist(aCallback) {
+ var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
+ .getService(Ci.nsITimerCallback);
+ var observer = function() {
+ Services.obs.removeObserver(observer, "blocklist-updated");
+ SimpleTest.executeSoon(aCallback);
+ };
+ Services.obs.addObserver(observer, "blocklist-updated");
+ blocklistNotifier.notify(null);
+}
+
+var _originalTestBlocklistURL = null;
+function setAndUpdateBlocklist(aURL, aCallback) {
+ if (!_originalTestBlocklistURL)
+ _originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
+ Services.prefs.setCharPref("extensions.blocklist.url", aURL);
+ updateBlocklist(aCallback);
+}
+
+function resetBlocklist() {
+ Services.prefs.setCharPref("extensions.blocklist.url", _originalTestBlocklistURL);
+}
diff --git a/comm/suite/browser/test/browser/page_style_sample.html b/comm/suite/browser/test/browser/page_style_sample.html
new file mode 100644
index 0000000000..633956c4c7
--- /dev/null
+++ b/comm/suite/browser/test/browser/page_style_sample.html
@@ -0,0 +1,31 @@
+<html>
+ <head>
+ <title>Test for page style menu</title>
+ <!-- data-state values:
+ 0: should not appear in the page style menu
+ 0-todo: should not appear in the page style menu, but does
+ 1: should appear in the page style menu
+ 2: should appear in the page style menu as the selected stylesheet -->
+ <link data-state="1" href="404.css" title="1" rel="alternate stylesheet">
+ <link data-state="0" title="2" rel="alternate stylesheet">
+ <link data-state="0" href="404.css" rel="alternate stylesheet">
+ <link data-state="0" href="404.css" title="" rel="alternate stylesheet">
+ <link data-state="1" href="404.css" title="3" rel="stylesheet alternate">
+ <link data-state="1" href="404.css" title="4" rel=" alternate stylesheet ">
+ <link data-state="1" href="404.css" title="5" rel="alternate stylesheet">
+ <link data-state="2" href="404.css" title="6" rel="stylesheet">
+ <link data-state="1" href="404.css" title="7" rel="foo stylesheet">
+ <link data-state="0" href="404.css" title="8" rel="alternate">
+ <link data-state="1" href="404.css" title="9" rel="alternate STYLEsheet">
+ <link data-state="1" href="404.css" title="10" rel="alternate stylesheet" media="">
+ <link data-state="1" href="404.css" title="11" rel="alternate stylesheet" media="all">
+ <link data-state="1" href="404.css" title="12" rel="alternate stylesheet" media="ALL ">
+ <link data-state="1" href="404.css" title="13" rel="alternate stylesheet" media="screen">
+ <link data-state="1" href="404.css" title="14" rel="alternate stylesheet" media=" Screen">
+ <link data-state="1" href="404.css" title="15" rel="alternate stylesheet" media="screen foo">
+ <link data-state="1" href="404.css" title="16" rel="alternate stylesheet" media="all screen">
+ <link data-state="0-todo" href="404.css" title="17" rel="alternate stylesheet" media="allscreen">
+ <link data-state="0-todo" href="404.css" title="18" rel="alternate stylesheet" media="_all">
+ </head>
+ <body></body>
+</html>
diff --git a/comm/suite/browser/test/browser/redirect_bug623155.sjs b/comm/suite/browser/test/browser/redirect_bug623155.sjs
new file mode 100644
index 0000000000..2e4681f240
--- /dev/null
+++ b/comm/suite/browser/test/browser/redirect_bug623155.sjs
@@ -0,0 +1,16 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const REDIRECT_TO = "https://www.bank1.com/"; // Bad-cert host.
+
+function handleRequest(aRequest, aResponse) {
+ // Set HTTP Status
+ aResponse.setStatusLine(aRequest.httpVersion, 301, "Moved Permanently");
+
+ // Set redirect URI, mirroring the hash value.
+ let hash = (/\#.+/.test(aRequest.pathQueryRef))?
+ "#" + aRequest.pathQueryRef.split("#")[1]:
+ "";
+ aResponse.setHeader("Location", REDIRECT_TO + hash);
+}
diff --git a/comm/suite/browser/test/browser/title_test.svg b/comm/suite/browser/test/browser/title_test.svg
new file mode 100644
index 0000000000..6ab5b2f5c2
--- /dev/null
+++ b/comm/suite/browser/test/browser/title_test.svg
@@ -0,0 +1,59 @@
+<svg width="640px" height="480px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0">
+ <title>This is a root SVG element's title</title>
+ <foreignObject>
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <body>
+ <svg xmlns="http://www.w3.org/2000/svg" id="svg1">
+ <title>This is a non-root SVG element title</title>
+ </svg>
+ </body>
+ </html>
+ </foreignObject>
+ <text id="text1" x="10px" y="32px" font-size="24px">
+ This contains only &lt;title&gt;
+ <title>
+
+
+ This is a title
+
+ </title>
+ </text>
+ <text id="text2" x="10px" y="96px" font-size="24px">
+ This contains only &lt;desc&gt;
+ <desc>This is a desc</desc>
+ </text>
+ <text id="text3" x="10px" y="128px" font-size="24px">
+ This contains nothing.
+ </text>
+ <a id="link1" xlink:href="#">
+ This link contains &lt;title&gt;
+ <title>
+ This is a title
+ </title>
+ <text id="text4" x="10px" y="192px" font-size="24px">
+ </text>
+ </a>
+ <a id="link2" xlink:href="#">
+ <text x="10px" y="192px" font-size="24px">
+ This text contains &lt;title&gt;
+ <title>
+ This is a title
+ </title>
+ </text>
+ </a>
+ <a id="link3" xlink:href="#" xlink:title="This is an xlink:title attribute">
+ <text x="10px" y="224px" font-size="24px">
+ This link contains &lt;title&gt; &amp; xlink:title attr.
+ <title>This is a title</title>
+ </text>
+ </a>
+ <a id="link4" xlink:href="#" xlink:title="This is an xlink:title attribute">
+ <text x="10px" y="256px" font-size="24px">
+ This link contains xlink:title attr.
+ </text>
+ </a>
+ <text id="text5" x="10px" y="160px" font-size="24px"
+ xlink:title="This is an xlink:title attribute but it isn't on a link" >
+ This contains nothing.
+ </text>
+</svg>
diff --git a/comm/suite/browser/test/chrome/chrome.ini b/comm/suite/browser/test/chrome/chrome.ini
new file mode 100644
index 0000000000..05c31c161a
--- /dev/null
+++ b/comm/suite/browser/test/chrome/chrome.ini
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+[test_maxSniffing.html]
diff --git a/comm/suite/browser/test/chrome/test_maxSniffing.html b/comm/suite/browser/test/chrome/test_maxSniffing.html
new file mode 100644
index 0000000000..8fb333e523
--- /dev/null
+++ b/comm/suite/browser/test/chrome/test_maxSniffing.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=739040
+-->
+<head>
+ <title>Test that we only sniff 512 bytes</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=739040">Mozilla Bug 739040</a>
+<p id="display">
+ <iframe id="validTestFrame" src="http://mochi.test:8888/tests/suite/browser/test/mochitest/valid-feed.xml"></iframe>
+ <iframe id="unsniffableTestFrame" src="http://mochi.test:8888/tests/suite/browser/test/mochitest/valid-unsniffable-feed.xml"></iframe>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody">
+
+/** Test for Bug 739040 **/
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+ is($("validTestFrame").contentDocument.documentElement.id, "feedHandler",
+ "valid feed should be sniffed");
+ isnot($("unsniffableTestFrame").contentDocument.documentElement.id, "feedHandler",
+ "unsniffable feed should not be sniffed");
+});
+addLoadEvent(SimpleTest.finish);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/comm/suite/browser/test/mochitest/audio.ogg b/comm/suite/browser/test/mochitest/audio.ogg
new file mode 100644
index 0000000000..7e6ef77ec4
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/audio.ogg
Binary files differ
diff --git a/comm/suite/browser/test/mochitest/bug364677-data.xml b/comm/suite/browser/test/mochitest/bug364677-data.xml
new file mode 100644
index 0000000000..b48915c050
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/bug364677-data.xml
@@ -0,0 +1,5 @@
+<rss version="2.0">
+ <channel>
+ <title>t</title>
+ </channel>
+</rss>
diff --git a/comm/suite/browser/test/mochitest/bug364677-data.xml^headers^ b/comm/suite/browser/test/mochitest/bug364677-data.xml^headers^
new file mode 100644
index 0000000000..f203c6368e
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/bug364677-data.xml^headers^
@@ -0,0 +1 @@
+Content-Type: text/xml
diff --git a/comm/suite/browser/test/mochitest/bug395533-data.txt b/comm/suite/browser/test/mochitest/bug395533-data.txt
new file mode 100644
index 0000000000..e0ed39850f
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/bug395533-data.txt
@@ -0,0 +1,6 @@
+<rss version="2.0">
+ <channel>
+ <link>http://example.org/</link>
+ <title>t</title>
+ </channel>
+</rss>
diff --git a/comm/suite/browser/test/mochitest/bug436801-data.xml b/comm/suite/browser/test/mochitest/bug436801-data.xml
new file mode 100644
index 0000000000..0e45c7ed8e
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/bug436801-data.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom" xml:base="http://www.example.com/">
+
+ <title type="xhtml" xml:base="/foo/bar/">
+ <div xmlns="http://www.w3.org/1999/xhtml">Example of a <em>special</em> feed (<img height="20px" src="baz.png" alt="base test sprite"/>)</div>
+ </title>
+
+ <subtitle type="html" xml:base="/foo/bar/">
+ <![CDATA[
+ With a <em>special</em> subtitle (<img height="20px" src="baz.png" alt="base test sprite"/>)
+ ]]>
+ </subtitle>
+
+ <link href="http://example.org/"/>
+
+ <updated>2010-09-02T18:30:02Z</updated>
+
+ <author>
+ <name>John Doe</name>
+ </author>
+
+ <id>urn:uuid:22906062-ecbd-46e2-b6a7-3039506a398f</id>
+
+ <entry>
+ <title type="xhtml" xml:base="/foo/bar/">
+ <div xmlns="http://www.w3.org/1999/xhtml">Some <abbr title="Extensible Hyper-text Mark-up Language">XHTML</abbr> examples (<img height="20px" src="baz.png" alt="base test sprite"/>)</div>
+ </title>
+ <id>urn:uuid:b48083a7-71a7-4c9c-8515-b7c0d22955e7</id>
+ <updated>2010-09-02T18:30:02Z</updated>
+ <summary>Some text.</summary>
+ </entry>
+
+ <entry>
+ <title type="html" xml:base="/foo/bar/">
+ <![CDATA[
+ Some <abbr title="Hyper-text Mark-up Language">HTML</abbr> examples (<img height="20px" src="baz.png" alt="base test sprite"/>)
+ ]]>
+ </title>
+ <id>urn:uuid:1424967a-280a-414d-b0ab-8b11c4ac1bb7</id>
+ <updated>2010-09-02T18:30:02Z</updated>
+ <summary>Some text.</summary>
+ </entry>
+
+</feed>
diff --git a/comm/suite/browser/test/mochitest/ctxmenu-image.png b/comm/suite/browser/test/mochitest/ctxmenu-image.png
new file mode 100644
index 0000000000..4c3be50847
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/ctxmenu-image.png
Binary files differ
diff --git a/comm/suite/browser/test/mochitest/feed_discovery.html b/comm/suite/browser/test/mochitest/feed_discovery.html
new file mode 100644
index 0000000000..80c35d19ab
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/feed_discovery.html
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=377611
+-->
+ <head>
+ <title>Test for feed discovery</title>
+
+ <!-- Straight up standard -->
+ <link rel="alternate" type="application/atom+xml" title="1" href="/1.atom" />
+ <link rel="alternate" type="application/rss+xml" title="2" href="/2.rss" />
+ <link rel="feed" title="3" href="/3.xml" />
+
+ <!-- rel is a space-separated list -->
+ <link rel=" alternate " type="application/atom+xml" title="4" href="/4.atom" />
+ <link rel="foo alternate" type="application/atom+xml" title="5" href="/5.atom" />
+ <link rel="alternate foo" type="application/atom+xml" title="6" href="/6.atom" />
+ <link rel="foo alternate foo" type="application/atom+xml" title="7" href="/7.atom" />
+ <link rel="meat feed cake" title="8" href="/8.atom" />
+
+ <!-- rel is case-insensitive -->
+ <link rel="ALTERNate" type="application/atom+xml" title="9" href="/9.atom" />
+ <link rel="fEEd" title="10" href="/10.atom" />
+
+ <!-- type can have leading and trailing whitespace -->
+ <link rel="alternate" type=" application/atom+xml " title="11" href="/11.atom" />
+
+ <!-- type is case-insensitive -->
+ <link rel="alternate" type="aPPliCAtion/ATom+xML" title="12" href="/12.atom" />
+
+ <!-- "feed stylesheet" is a feed, though "alternate stylesheet" isn't -->
+ <link rel="feed stylesheet" title="13" href="/13.atom" />
+
+ <!-- hyphens or letters around rel not allowed -->
+ <link rel="disabled-alternate" type="application/atom+xml" title="Bogus1" href="/Bogus1" />
+ <link rel="alternates" type="application/atom+xml" title="Bogus2" href="/Bogus2" />
+ <link rel=" alternate-like" type="application/atom+xml" title="Bogus3" href="/Bogus3" />
+
+ <!-- don't tolerate text/xml if title includes 'rss' not as a word -->
+ <link rel="alternate" type="text/xml" title="Bogus4 scissorsshaped" href="/Bogus4" />
+
+ <!-- don't tolerate application/xml if title includes 'rss' not as a word -->
+ <link rel="alternate" type="application/xml" title="Bogus5 scissorsshaped" href="/Bogus5" />
+
+ <!-- don't tolerate application/rdf+xml if title includes 'rss' not as a word -->
+ <link rel="alternate" type="application/rdf+xml" title="Bogus6 scissorsshaped" href="/Bogus6" />
+
+ <!-- don't tolerate random types -->
+ <link rel="alternate" type="text/plain" title="Bogus7 rss" href="/Bogus7" />
+
+ <!-- don't find Atom by title -->
+ <link rel="foopy" type="application/atom+xml" title="Bogus8 Atom and RSS" href="/Bogus8" />
+
+ <!-- don't find application/rss+xml by title -->
+ <link rel="goats" type="application/rss+xml" title="Bogus9 RSS and Atom" href="/Bogus9" />
+
+ <!-- don't find application/rdf+xml by title -->
+ <link rel="alternate" type="application/rdf+xml" title="Bogus10 RSS and Atom" href="/Bogus10" />
+
+ <!-- don't find application/xml by title -->
+ <link rel="alternate" type="application/xml" title="Bogus11 RSS and Atom" href="/Bogus11" />
+
+ <!-- don't find text/xml by title -->
+ <link rel="alternate" type="text/xml" title="Bogus12 RSS and Atom" href="/Bogus12" />
+
+ <!-- alternate and stylesheet isn't a feed -->
+ <link rel="alternate stylesheet" type="application/rss+xml" title="Bogus13 RSS" href="/Bogus13" />
+ </head>
+ <body>
+ <script>
+ window.onload = function() {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+ var tests = new Array();
+
+ var currentWindow =
+ window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ var browserSH = currentWindow.XULBrowserWindow;
+
+ var discovered = browserSH.feeds;
+ tests.push({ check: discovered.length > 0,
+ message: "some feeds should be discovered" });
+
+ var feeds = [];
+
+ for (var aFeed of discovered) {
+ feeds[aFeed.href] = true;
+ }
+
+ for (var aLink of document.getElementsByTagName("link")) {
+ // ignore real stylesheets, and anything without an href property
+ if (aLink.type != "text/css" && aLink.href) {
+ if (/bogus/i.test(aLink.title)) {
+ tests.push({ check: !feeds[aLink.href], todo: /todo/i.test(aLink.title),
+ message: "don't discover " + aLink.href });
+ } else {
+ tests.push({ check: feeds[aLink.href], todo: /todo/i.test(aLink.title),
+ message: "should discover " + aLink.href });
+ }
+ }
+ }
+ window.arguments[0].tests = tests;
+ window.close();
+ }
+ </script>
+ </body>
+</html>
diff --git a/comm/suite/browser/test/mochitest/mochitest.ini b/comm/suite/browser/test/mochitest/mochitest.ini
new file mode 100644
index 0000000000..99b25bba9d
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/mochitest.ini
@@ -0,0 +1,17 @@
+[DEFAULT]
+support-files =
+ valid-feed.xml
+ valid-unsniffable-feed.xml
+
+[test_bug364677.html]
+support-files = bug364677-data.xml bug364677-data.xml^headers^
+[test_bug395533.html]
+support-files = bug395533-data.txt
+[test_bug436801.html]
+support-files = bug436801-data.xml
+[test_contextmenu.html]
+support-files = audio.ogg ctxmenu-image.png subtst_contextmenu.html video.ogg
+skip-if = os != "win" # disabled on Linux due to bug 513558, on Mac after 10.6 due to bug 792304
+[test_feed_discovery.html]
+support-files = feed_discovery.html
+[test_registerHandler.html]
diff --git a/comm/suite/browser/test/mochitest/subtst_contextmenu.html b/comm/suite/browser/test/mochitest/subtst_contextmenu.html
new file mode 100644
index 0000000000..63cc70c84e
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/subtst_contextmenu.html
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Subtest for browser context menu</title>
+</head>
+<body>
+Browser context menu subtest.
+
+<div id="test-text">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</div>
+<a id="test-link" href="http://mozilla.com">Click the monkey!</a>
+<a id="test-mailto" href="mailto:codemonkey@mozilla.com">Mail the monkey!</a><br>
+<input id="test-input"><br>
+<input id="test-input-select"><br>
+<img id="test-image" src="ctxmenu-image.png">
+<canvas id="test-canvas" width="100" height="100" style="background-color: blue"></canvas>
+<video controls id="test-video-ok" src="video.ogg" width="100" height="100" style="background-color: green"></video>
+<video id="test-audio-in-video" src="audio.ogg" width="100" height="100" style="background-color: red"></video>
+<video controls id="test-video-bad" src="bogus.duh" width="100" height="100" style="background-color: orange"></video>
+<video controls id="test-video-bad2" width="100" height="100" style="background-color: yellow">
+ <source src="bogus.duh" type="video/durrrr;">
+</video>
+<iframe id="test-iframe" width="98" height="98" style="border: 1px solid black"></iframe>
+<iframe id="test-video-in-iframe" src="video.ogg" width="98" height="98" style="border: 1px solid black"></iframe>
+<iframe id="test-image-in-iframe" src="ctxmenu-image.png" width="98" height="98" style="border: 1px solid black"></iframe>
+<textarea id="test-textarea">chssseesbbbie</textarea> <!-- a weird word which generates only one suggestion -->
+<textarea id="test-textarea-sel">test</textarea>
+<div id="test-contenteditable" contenteditable="true">chssseefsbbbie</div> <!-- a more weird word which generates no suggestions -->
+<input id="test-input-spellcheck" type="text" spellcheck="true" autofocus value="prodkjfgigrty"> <!-- this one also generates one suggestion -->
+<div contextmenu="myMenu">
+ <p id="test-pagemenu" hopeless="true">I've got a context menu!</p>
+ <menu id="myMenu" type="context">
+ <menuitem label="Plain item" onclick="document.getElementById('test-pagemenu').removeAttribute('hopeless');"></menuitem>
+ <menuitem label="Disabled item" disabled></menuitem>
+ <menuitem> Item w/ textContent</menuitem>
+ <menu>
+ <menuitem type="checkbox" label="Checkbox" checked></menuitem>
+ </menu>
+ <menu>
+ <menuitem type="radio" label="Radio1" checked></menuitem>
+ <menuitem type="radio" label="Radio2"></menuitem>
+ <menuitem type="radio" label="Radio3"></menuitem>
+ </menu>
+ <menu>
+ <menuitem label="Item w/ icon" icon="favicon.ico"></menuitem>
+ <menuitem label="Item w/ bad icon" icon="data://www.mozilla.org/favicon.ico"></menuitem>
+ </menu>
+ <menu label="Submenu">
+ <menuitem type="radio" label="Radio1" radiogroup="rg"></menuitem>
+ <menuitem type="radio" label="Radio2" checked radiogroup="rg"></menuitem>
+ <menuitem type="radio" label="Radio3" radiogroup="rg"></menuitem>
+ <menu>
+ <menuitem type="checkbox" label="Checkbox"></menuitem>
+ </menu>
+ </menu>
+ <menu hidden>
+ <menuitem label="Bogus item"></menuitem>
+ </menu>
+ <menu>
+ </menu>
+ <menuitem label="Hidden item" hidden></menuitem>
+ <menuitem></menuitem>
+ </menu>
+</div>
+
+<!-- SeaMonkey specific elements -->
+<a href="http://mozilla.com"><img id="test-image-link" alt="Click the monkey!" src="ctxmenu-image.png"></a>
+<a href="mailto:codemonkey@mozilla.com"><img id="test-image-mailto" alt="Mail the monkey!" src="ctxmenu-image.png"></a><br>
+
+</body>
+</html>
diff --git a/comm/suite/browser/test/mochitest/test_bug364677.html b/comm/suite/browser/test/mochitest/test_bug364677.html
new file mode 100644
index 0000000000..e08b1403f6
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/test_bug364677.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=364677
+-->
+<head>
+ <title>Test for Bug 364677</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=364677">Mozilla Bug 364677</a>
+<p id="display"><iframe id="testFrame" src="bug364677-data.xml"></iframe></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody">
+
+/** Test for Bug 364677 **/
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+ is(SpecialPowers.wrap($("testFrame")).contentDocument.documentElement.id, "feedHandler",
+ "Feed served as text/xml without a channel/link should have been sniffed");
+});
+addLoadEvent(SimpleTest.finish);
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/comm/suite/browser/test/mochitest/test_bug395533.html b/comm/suite/browser/test/mochitest/test_bug395533.html
new file mode 100644
index 0000000000..5d3cfa0121
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/test_bug395533.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=395533
+-->
+<head>
+ <title>Test for Bug 395533</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=395533">Mozilla Bug 395533</a>
+<p id="display"><iframe id="testFrame" src="bug395533-data.txt"></iframe></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody">
+
+/** Test for Bug 395533 **/
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+ // Need privs because the feed seems to have an about:feeds principal or some
+ // such. It's not same-origin with us in any case.
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ is($("testFrame").contentDocument.documentElement.id, "",
+ "Text got sniffed as a feed?");
+});
+addLoadEvent(SimpleTest.finish);
+
+
+
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/comm/suite/browser/test/mochitest/test_bug436801.html b/comm/suite/browser/test/mochitest/test_bug436801.html
new file mode 100644
index 0000000000..6ca1b83cf5
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/test_bug436801.html
@@ -0,0 +1,118 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=436801
+-->
+<head>
+ <title>Test feed preview subscribe UI</title>
+ <script src="/MochiKit/packed.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=436801">Mozilla Bug 436801</a>
+<p id="display"><iframe id="testFrame" src="bug436801-data.xml"></iframe></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody">
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function () {
+ var doc = SpecialPowers.wrap($("testFrame")).contentDocument;
+
+ checkNode(doc.getElementById("feedTitleText"), [
+ "ELEMENT", "h1", { "xml:base": "http://www.example.com/foo/bar/" }, [
+ ["TEXT", "Example of a "],
+ ["ELEMENT", "em", [
+ ["TEXT", "special"],
+ ]],
+ ["TEXT", " feed ("],
+ ["ELEMENT", "img", { "src": "baz.png" }],
+ ["TEXT", ")"],
+ ]
+ ]);
+
+ checkNode(doc.getElementById("feedSubtitleText"), [
+ "ELEMENT", "h2", { "xml:base": "http://www.example.com/foo/bar/" }, [
+ ["TEXT", "With a "],
+ ["ELEMENT", "em", [
+ ["TEXT", "special"],
+ ]],
+ ["TEXT", " subtitle ("],
+ ["ELEMENT", "img", { "src": "baz.png" }],
+ ["TEXT", ")"],
+ ]
+ ]);
+
+ checkNode(doc.querySelector(".entry").firstChild.firstChild.firstChild, [
+ "ELEMENT", "span", { "xml:base": "http://www.example.com/foo/bar/" }, [
+ ["TEXT", "Some "],
+ ["ELEMENT", "abbr", { title: "Extensible Hyper-text Mark-up Language" }, [
+ ["TEXT", "XHTML"],
+ ]],
+ ["TEXT", " examples ("],
+ ["ELEMENT", "img", { "src": "baz.png" }],
+ ["TEXT", ")"],
+ ]
+ ]);
+
+ checkNode(doc.querySelectorAll(".entry")[1].firstChild.firstChild.firstChild, [
+ "ELEMENT", "span", { "xml:base": "http://www.example.com/foo/bar/" }, [
+ ["TEXT", "Some "],
+ ["ELEMENT", "abbr", { title: "Hyper-text Mark-up Language" }, [
+ ["TEXT", "HTML"],
+ ]],
+ ["TEXT", " examples ("],
+ ["ELEMENT", "img", { "src": "baz.png" }],
+ ["TEXT", ")"],
+ ]
+ ]);
+});
+
+addLoadEvent(SimpleTest.finish);
+
+function checkNode(node, schema) {
+ var typeName = schema.shift() + "_NODE";
+ var type = Node[typeName];
+ is(node.nodeType, type, "Node should be expected type " + typeName);
+ if (type == Node.TEXT_NODE) {
+ var text = schema.shift();
+ is(node.data, text, "Text should match");
+ return;
+ }
+ // type == Node.ELEMENT_NODE
+ var tag = schema.shift();
+ is(node.localName, tag, "Element should have expected tag");
+ while (schema.length) {
+ var val = schema.shift();
+ if (Array.isArray(val))
+ var childSchema = val;
+ else
+ var attrSchema = val;
+ }
+ if (attrSchema) {
+ var nsTable = {
+ xml: "http://www.w3.org/XML/1998/namespace",
+ };
+ for (var name in attrSchema) {
+ var [ns, nsName] = name.split(":");
+ var val = nsName ? node.getAttributeNS(nsTable[ns], nsName) :
+ node.getAttribute(name);
+ is(val, attrSchema[name], "Attribute " + name + " should match");
+ }
+ }
+ if (childSchema) {
+ var numChildren = node.childNodes.length;
+ is(childSchema.length, numChildren,
+ "Element should have expected number of children");
+ for (var i = 0; i < numChildren; i++)
+ checkNode(node.childNodes[i], childSchema[i]);
+ }
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/comm/suite/browser/test/mochitest/test_contextmenu.html b/comm/suite/browser/test/mochitest/test_contextmenu.html
new file mode 100644
index 0000000000..0dea49c925
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/test_contextmenu.html
@@ -0,0 +1,931 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Tests for browser context menu</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+Browser context menu tests.
+<p id="display"></p>
+
+<div id="content">
+</div>
+
+<pre id="test">
+<script class="testbody">
+
+/** Test for Login Manager: multiple login autocomplete. **/
+
+SpecialPowers.ChromeUtils.import("resource://gre/modules/InlineSpellChecker.jsm", window);
+SpecialPowers.ChromeUtils.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", window);
+
+const Cc = SpecialPowers.Cc;
+const Ci = SpecialPowers.Ci;
+
+function openContextMenuFor(element, shiftkey, waitForSpellCheck) {
+ // Context menu should be closed before we open it again.
+ is(SpecialPowers.wrap(contextMenu).state, "closed", "checking if popup is closed");
+
+ if (lastElement)
+ lastElement.blur();
+ element.focus();
+
+ // Some elements need time to focus and spellcheck before any tests are
+ // run on them.
+ function actuallyOpenContextMenuFor() {
+ lastElement = element;
+ var eventDetails = { type : "contextmenu", button : 2, shiftKey : shiftkey };
+ synthesizeMouse(element, 2, 2, eventDetails, element.ownerDocument.defaultView);
+ }
+
+ if (waitForSpellCheck)
+ onSpellCheck(element, actuallyOpenContextMenuFor);
+ else
+ actuallyOpenContextMenuFor();
+}
+
+function closeContextMenu() {
+ contextMenu.hidePopup();
+}
+
+function executeCopyCommand(command, expectedValue)
+{
+ // Just execute the command directly rather than simulating a context menu
+ // press to avoid having to deal with its asynchronous nature
+ SpecialPowers.wrap(subwindow).controllers.getControllerForCommand(command).doCommand(command);
+
+ // The easiest way to check the clipboard is to paste the contents into a
+ // textbox
+ input.focus();
+ input.value = "";
+ SpecialPowers.wrap(input).controllers.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
+ is(input.value, expectedValue, "paste for command " + command);
+}
+
+function invokeItemAction(generatedItemId)
+{
+ var item = contextMenu.getElementsByAttribute("generateditemid",
+ generatedItemId)[0];
+ ok(item, "Got generated XUL menu item");
+ item.doCommand();
+ is(pagemenu.hasAttribute("hopeless"), false, "attribute got removed");
+}
+
+function getVisibleMenuItems(aMenu, aData) {
+ var items = [];
+ var accessKeys = {};
+ for (var i = 0; i < aMenu.childNodes.length; i++) {
+ var item = aMenu.childNodes[i];
+ if (item.hidden)
+ continue;
+
+ var key = item.accessKey;
+ if (key)
+ key = key.toLowerCase();
+
+ var isGenerated = item.hasAttribute("generateditemid");
+
+ if (item.nodeName == "menuitem") {
+ var isSpellSuggestion = item.className == "spell-suggestion";
+ if (isSpellSuggestion) {
+ is(item.id, "", "child menuitem #" + i + " is a spelling suggestion");
+ } else if (isGenerated) {
+ is(item.id, "", "child menuitem #" + i + " is a generated item");
+ } else {
+ ok(item.id, "child menuitem #" + i + " has an ID");
+ }
+ var label = item.getAttribute("label");
+ ok(label.length, "menuitem " + item.id + " has a label");
+ if (isSpellSuggestion) {
+ is(key, "", "Spell suggestions shouldn't have an access key");
+ items.push("*" + label);
+ } else if (isGenerated) {
+ items.push("+" + label);
+ } else if (item.id.indexOf("spell-check-dictionary-") != 0 &&
+ item.id != "spell-no-suggestions") {
+ ok(key, "menuitem " + item.id + " has an access key");
+ if (accessKeys[key])
+ ok(false, "menuitem " + item.id + " has same accesskey as " + accessKeys[key]);
+ else
+ accessKeys[key] = item.id;
+ }
+ if (!isSpellSuggestion && !isGenerated) {
+ items.push(item.id);
+ }
+ if (isGenerated) {
+ var p = {};
+ p.type = item.getAttribute("type");
+ p.icon = item.getAttribute("image");
+ p.checked = item.hasAttribute("checked");
+ p.disabled = item.hasAttribute("disabled");
+ items.push(p);
+ } else {
+ items.push(!item.disabled);
+ }
+ } else if (item.nodeName == "menuseparator") {
+ ok(true, "--- seperator id is " + item.id);
+ items.push("---");
+ items.push(null);
+ } else if (item.nodeName == "menu") {
+ if (isGenerated) {
+ item.id = "generated-submenu-" + aData.generatedSubmenuId++;
+ }
+ ok(item.id, "child menu #" + i + " has an ID");
+ if (!isGenerated) {
+ ok(key, "menu has an access key");
+ if (accessKeys[key])
+ ok(false, "menu " + item.id + " has same accesskey as " + accessKeys[key]);
+ else
+ accessKeys[key] = item.id;
+ }
+ items.push(item.id);
+ items.push(!item.disabled);
+ // Add a dummy item to that the indexes in checkMenu are the same
+ // for expectedItems and actualItems.
+ items.push([]);
+ items.push(null);
+ } else {
+ ok(false, "child #" + i + " of menu ID " + aMenu.id +
+ " has an unknown type (" + item.nodeName + ")");
+ }
+ }
+ return items;
+}
+
+function checkContextMenu(expectedItems) {
+ is(contextMenu.state, "open", "checking if popup is open");
+ var data = { generatedSubmenuId: 1 };
+ checkMenu(contextMenu, expectedItems, data);
+}
+
+/*
+ * checkMenu - checks to see if the specified <menupopup> contains the
+ * expected items and state.
+ * expectedItems is a array of (1) item IDs and (2) a boolean specifying if
+ * the item is enabled or not (or null to ignore it). Submenus can be checked
+ * by providing a nested array entry after the expected <menu> ID.
+ * For example: ["blah", true, // item enabled
+ * "submenu", null, // submenu
+ * ["sub1", true, // submenu contents
+ * "sub2", false], null, // submenu contents
+ * "lol", false] // item disabled
+ *
+ */
+function checkMenu(menu, expectedItems, data) {
+ var actualItems = getVisibleMenuItems(menu, data);
+ //ok(false, "Items are: " + actualItems);
+ for (var i = 0; i < expectedItems.length; i+=2) {
+ var actualItem = actualItems[i];
+ var actualEnabled = actualItems[i + 1];
+ var expectedItem = expectedItems[i];
+ var expectedEnabled = expectedItems[i + 1];
+ if (expectedItem instanceof Array) {
+ ok(true, "Checking submenu...");
+ var menuID = expectedItems[i - 2]; // The last item was the menu ID.
+ var submenu = menu.getElementsByAttribute("id", menuID)[0];
+ ok(submenu && submenu.nodeName == "menu", "got expected submenu element");
+ checkMenu(submenu.menupopup, expectedItem, data);
+ } else {
+ is(actualItem, expectedItem,
+ "checking item #" + i/2 + " (" + expectedItem + ") name");
+
+ if (typeof expectedEnabled == "object" && expectedEnabled != null ||
+ typeof actualEnabled == "object" && actualEnabled != null) {
+
+ ok(!(actualEnabled == null), "actualEnabled is not null");
+ ok(!(expectedEnabled == null), "expectedEnabled is not null");
+ is(typeof actualEnabled, typeof expectedEnabled, "checking types");
+
+ if (typeof actualEnabled != typeof expectedEnabled ||
+ actualEnabled == null || expectedEnabled == null)
+ continue;
+
+ is(actualEnabled.type, expectedEnabled.type,
+ "checking item #" + i/2 + " (" + expectedItem + ") type attr value");
+ var icon = actualEnabled.icon;
+ if (icon) {
+ var tmp = "";
+ var j = icon.length - 1;
+ while (j && icon[j] != "/") {
+ tmp = icon[j--] + tmp;
+ }
+ icon = tmp;
+ }
+ is(icon, expectedEnabled.icon,
+ "checking item #" + i/2 + " (" + expectedItem + ") icon attr value");
+ is(actualEnabled.checked, expectedEnabled.checked,
+ "checking item #" + i/2 + " (" + expectedItem + ") has checked attr");
+ is(actualEnabled.disabled, expectedEnabled.disabled,
+ "checking item #" + i/2 + " (" + expectedItem + ") has disabled attr");
+ } else if (expectedEnabled != null)
+ is(actualEnabled, expectedEnabled,
+ "checking item #" + i/2 + " (" + expectedItem + ") enabled state");
+ }
+ }
+ // Could find unexpected extra items at the end...
+ is(actualItems.length, expectedItems.length, "checking expected number of menu entries");
+}
+
+/*
+ * runTest
+ *
+ * Called by a popupshowing event handler. Each test checks for expected menu
+ * contents, closes the popup, and finally triggers the popup on a new element
+ * (thus kicking off another cycle).
+ *
+ */
+function runTest(testNum) {
+ ok(true, "Starting test #" + testNum);
+
+ switch (testNum) {
+ case 1:
+ // Invoke context menu for next test.
+ openContextMenuFor(text);
+ break;
+
+ case 2:
+ // Context menu for plain text
+ plainTextItems = ["context-back", false,
+ "context-forward", false,
+ "context-reload", true,
+ "context-stop", false,
+ "---", null,
+ "context-bookmarkpage", true,
+ "context-savepage", true,
+ "context-sendpage", true,
+ "---", null,
+ "context-viewbgimage", false,
+ "context-selectall", true,
+ "---", null,
+ "context-viewsource", true,
+ "context-viewinfo", true];
+ checkContextMenu(plainTextItems);
+ closeContextMenu();
+ openContextMenuFor(link); // Invoke context menu for next test.
+ break;
+
+ case 3:
+ // Context menu for text link
+ checkContextMenu(["context-openlinkintab", true,
+ "context-openlink", true,
+ "context-openlinkinprivatewindow", true,
+ "---", null,
+ "context-bookmarklink", true,
+ "context-savelink", true,
+ "context-sendlink", true,
+ "context-copylink", true,
+ "---", null,
+ "context-bookmarkpage", true,
+ "context-savepage", true,
+ "---", null,
+ "context-metadata", true]);
+ closeContextMenu();
+ openContextMenuFor(mailto); // Invoke context menu for next test.
+ break;
+
+ case 4:
+ // Context menu for text mailto-link
+ checkContextMenu(["context-copyemail", true,
+ "context-copylink", true,
+ "---", null,
+ "context-bookmarkpage", true,
+ "context-savepage", true,
+ "---", null,
+ "context-metadata", true]);
+ closeContextMenu();
+ openContextMenuFor(input); // Invoke context menu for next test.
+ break;
+
+ case 5:
+ // Context menu for text input field
+ checkContextMenu(["context-undo", false,
+ "context-redo", false,
+ "---", null,
+ "context-cut", false,
+ "context-copy", false,
+ "context-paste", null, // ignore clipboard state
+ "context-delete", false,
+ "---", null,
+ "context-selectall", false,
+ "---", null,
+ "spell-check-enabled", true]);
+ closeContextMenu();
+ input_sel.value = "test";
+ input_sel.select();
+ openContextMenuFor(input_sel); // Invoke context menu for next test.
+ break;
+
+ case 6:
+ // Context menu for text input field with text
+ checkContextMenu(["context-undo", false,
+ "context-redo", false,
+ "---", null,
+ "context-cut", true,
+ "context-copy", true,
+ "context-paste", null, // ignore clipboard state
+ "context-delete", true,
+ "---", null,
+ "context-selectall", true,
+ "context-searchselect", true,
+ "---", null,
+ "spell-check-enabled", true]);
+ closeContextMenu();
+ openContextMenuFor(img); // Invoke context menu for next test.
+ break;
+
+ case 7:
+ // Context menu for an image
+ checkContextMenu(["context-reloadimage", true,
+ "context-viewimage", true,
+ "context-blockimage", true,
+ "context-copyimage", true,
+ "---", null,
+ "context-saveimage", true,
+ "context-sendimage", true].concat(
+ ("@mozilla.org/suite/shell-service;1" in Cc) ?
+ ["context-setDesktopBackground", true] : []).concat(
+ ["---", null,
+ "context-bookmarkpage", true,
+ "context-savepage", true,
+ "context-sendpage", true,
+ "---", null,
+ "context-metadata", true]));
+ closeContextMenu();
+ openContextMenuFor(canvas); // Invoke context menu for next test.
+ break;
+
+ case 8:
+ // Context menu for a canvas
+ checkContextMenu(["context-viewimage", true,
+ "context-saveimage", true,
+ "context-bookmarkpage", true,
+ "context-sendpage", true,
+ "context-selectall", true]);
+ closeContextMenu();
+ openContextMenuFor(video_ok); // Invoke context menu for next test.
+ break;
+
+ case 9:
+ // Context menu for a video (with a VALID media source)
+ checkContextMenu(["context-media-play", true,
+ "context-media-mute", true,
+ "context-media-playbackrate", true,
+ ["context-media-playbackrate-050", true,
+ "context-media-playbackrate-100", true,
+ "context-media-playbackrate-150", true,
+ "context-media-playbackrate-200", true], null,
+ "context-media-hidecontrols", true,
+ "context-video-showstats", true,
+ "context-video-fullscreen", true,
+ "---", null,
+ "context-viewvideo", true,
+ "context-copyvideourl", true,
+ "---", null,
+ "context-savevideo", true,
+ "context-sendvideo", true,
+ "context-video-saveimage", true]);
+ closeContextMenu();
+ openContextMenuFor(audio_in_video); // Invoke context menu for next test.
+ break;
+
+ case 10:
+ // Context menu for a video (with an audio-only file)
+ checkContextMenu(["context-media-play", true,
+ "context-media-mute", true,
+ "context-media-playbackrate", true,
+ ["context-media-playbackrate-050", true,
+ "context-media-playbackrate-100", true,
+ "context-media-playbackrate-150", true,
+ "context-media-playbackrate-200", true], null,
+ "context-media-showcontrols", true,
+ "---", null,
+ "context-copyaudiourl", true,
+ "---", null,
+ "context-saveaudio", true,
+ "context-sendaudio", true]);
+ closeContextMenu();
+ openContextMenuFor(video_bad); // Invoke context menu for next test.
+ break;
+
+ case 11:
+ // Context menu for a video (with an INVALID media source)
+ checkContextMenu(["context-media-play", false,
+ "context-media-mute", false,
+ "context-media-playbackrate", false,
+ ["context-media-playbackrate-050", null,
+ "context-media-playbackrate-100", null,
+ "context-media-playbackrate-150", null,
+ "context-media-playbackrate-200", null], null,
+ "context-media-hidecontrols", false,
+ "context-video-showstats", false,
+ "context-video-fullscreen", false,
+ "---", null,
+ "context-viewvideo", true,
+ "context-copyvideourl", true,
+ "---", null,
+ "context-savevideo", true,
+ "context-sendvideo", true,
+ "context-video-saveimage", false]);
+ closeContextMenu();
+ openContextMenuFor(video_bad2); // Invoke context menu for next test.
+ break;
+
+ case 12:
+ // Context menu for a video (with an INVALID media source)
+ checkContextMenu(["context-media-play", false,
+ "context-media-mute", false,
+ "context-media-playbackrate", false,
+ ["context-media-playbackrate-050", null,
+ "context-media-playbackrate-100", null,
+ "context-media-playbackrate-150", null,
+ "context-media-playbackrate-200", null], null,
+ "context-media-hidecontrols", false,
+ "context-video-showstats", false,
+ "context-video-fullscreen", false,
+ "---", null,
+ "context-viewvideo", false,
+ "context-copyvideourl", false,
+ "---", null,
+ "context-savevideo", false,
+ "context-sendvideo", false,
+ "context-video-saveimage", false]);
+ closeContextMenu();
+ openContextMenuFor(iframe); // Invoke context menu for next test.
+ break;
+
+ case 13:
+ // Context menu for an iframe
+ checkContextMenu(["context-back", false,
+ "context-forward", false,
+ "context-reload", true,
+ "context-stop", false,
+ "---", null,
+ "context-bookmarkpage", true,
+ "context-savepage", true,
+ "context-sendpage", true,
+ "---", null,
+ "context-viewbgimage", false,
+ "context-selectall", true,
+ "---", null,
+ "context-viewsource", true,
+ "context-viewinfo", true,
+ "---", null,
+ "frame", null,
+ ["context-showonlythisframe", true,
+ "context-openframeintab", true,
+ "context-openframe", true,
+ "---", null,
+ "context-reloadframe", true,
+ "---", null,
+ "context-bookmarkframe", true,
+ "context-saveframe", true,
+ "context-sendframe", true,
+ "---", null,
+ "context-viewframesource", true,
+ "context-viewframeinfo", true], null]);
+ closeContextMenu();
+ openContextMenuFor(video_in_iframe); // Invoke context menu for next test.
+ break;
+
+ case 14:
+ // Context menu for a video in an iframe
+ checkContextMenu(["context-media-play", true,
+ "context-media-mute", true,
+ "context-media-playbackrate", true,
+ ["context-media-playbackrate-050", true,
+ "context-media-playbackrate-100", true,
+ "context-media-playbackrate-150", true,
+ "context-media-playbackrate-200", true], null,
+ "context-media-hidecontrols", true,
+ "context-video-showstats", true,
+ "context-video-fullscreen", true,
+ "---", null,
+ "context-viewvideo", true,
+ "context-copyvideourl", true,
+ "---", null,
+ "context-savevideo", true,
+ "context-sendvideo", true,
+ "context-video-saveimage", true,
+ "---", null,
+ "frame", null,
+ ["context-showonlythisframe", true,
+ "context-openframeintab", true,
+ "context-openframe", true,
+ "---", null,
+ "context-reloadframe", true,
+ "---", null,
+ "context-bookmarkframe", true,
+ "context-saveframe", true,
+ "context-sendframe", true,
+ "---", null,
+ "context-viewframesource", true,
+ "context-viewframeinfo", true], null]);
+ closeContextMenu();
+ openContextMenuFor(image_in_iframe); // Invoke context menu for next test.
+ break;
+
+ case 15:
+ // Context menu for an image in an iframe
+ checkContextMenu(["context-reloadimage", true,
+ "context-viewimage", true,
+ "context-blockimage", true,
+ "context-copyimage", true,
+ "---", null,
+ "context-saveimage", true,
+ "context-sendimage", true,
+ ].concat(
+ ("@mozilla.org/suite/shell-service;1" in Cc) ?
+ ["context-setDesktopBackground", true] : [])
+ .concat(
+ ["---", null,
+ "context-sendpage", true,
+ "---", null,
+ "context-metadata", true,
+ "---", null,
+ "frame", null,
+ ["context-showonlythisframe", true,
+ "context-openframeintab", true,
+ "context-openframe", true,
+ "---", null,
+ "context-reloadframe", true,
+ "---", null,
+ "context-bookmarkframe", true,
+ "context-saveframe", true,
+ "context-sendframe", true,
+ "---", null,
+ "context-viewframesource", true,
+ "context-viewframeinfo", true], null]));
+ closeContextMenu();
+ openContextMenuFor(text); // Invoke context menu for next test.
+ break;
+
+ case 16:
+ // Re-check context menu for plain text to make sure it hasn't changed
+ checkContextMenu(plainTextItems);
+ closeContextMenu();
+ textarea_sel.select();
+ openContextMenuFor(textarea_sel, false, true);
+ break;
+
+ case 17:
+ // search for text with text area's selected value
+ checkContextMenu(["context-undo", false,
+ "context-redo", false,
+ "---", null,
+ "context-cut", true,
+ "context-copy", true,
+ "context-paste", null, // ignore clipboard state
+ "context-delete", true,
+ "---", null,
+ "context-selectall", true,
+ "context-searchselect", true,
+ "---", null,
+ "spell-check-enabled", true,
+ "spell-dictionaries", true,
+ ["spell-check-dictionary-en-US", true,
+ "---", null,
+ "spell-add-dictionaries", true], null]);
+ closeContextMenu();
+ openContextMenuFor(textarea, false, true); // Invoke context menu for next test, but wait for the spellcheck.
+ break;
+
+ case 18:
+ // Context menu for textarea
+ checkContextMenu(["*chubbiness", true, // spelling suggestion
+ "---", null,
+ "spell-add-to-dictionary", true,
+ "spell-ignore-word", true,
+ "---", null,
+ "context-undo", false,
+ "context-redo", false,
+ "---", null,
+ "context-cut", false,
+ "context-copy", false,
+ "context-paste", null, // ignore clipboard state
+ "context-delete", false,
+ "---", null,
+ "context-selectall", true,
+ "---", null,
+ "spell-check-enabled", true,
+ "spell-dictionaries", true,
+ ["spell-check-dictionary-en-US", true,
+ "---", null,
+ "spell-add-dictionaries", true], null]);
+
+ contextMenu.ownerDocument.getElementById("spell-add-to-dictionary").doCommand(); // Add to dictionary
+ closeContextMenu();
+ openContextMenuFor(textarea, false, true); // Invoke context menu for next test.
+ break;
+
+ case 19:
+ // Context menu for textarea after a word has been added
+ // to the dictionary
+ checkContextMenu(["spell-undo-add-to-dictionary", true,
+ "---", null,
+ "context-undo", false,
+ "context-redo", false,
+ "---", null,
+ "context-cut", false,
+ "context-copy", false,
+ "context-paste", null, // ignore clipboard state
+ "context-delete", false,
+ "---", null,
+ "context-selectall", true,
+ "---", null,
+ "spell-check-enabled", true,
+ "spell-dictionaries", true,
+ ["spell-check-dictionary-en-US", true,
+ "---", null,
+ "spell-add-dictionaries", true], null,
+ ]);
+
+ contextMenu.ownerDocument.getElementById("spell-undo-add-to-dictionary").doCommand(); // Undo add to dictionary
+ closeContextMenu();
+ openContextMenuFor(contenteditable, false, true);
+ break;
+
+ case 20:
+ // Context menu for contenteditable
+ checkContextMenu(["spell-no-suggestions", false,
+ "---", null,
+ "spell-add-to-dictionary", true,
+ "spell-ignore-word", true,
+ "---", null,
+ "context-undo", false,
+ "context-redo", false,
+ "---", null,
+ "context-cut", false,
+ "context-copy", false,
+ "context-paste", null, // ignore clipboard state
+ "context-delete", false,
+ "---", null,
+ "context-selectall", true,
+ "---", null,
+ "spell-check-enabled", true,
+ "spell-dictionaries", true,
+ ["spell-check-dictionary-en-US", true,
+ "---", null,
+ "spell-add-dictionaries", true], null]);
+
+ closeContextMenu();
+ openContextMenuFor(inputspell, false, true); // Invoke context menu for next test.
+ break;
+
+ case 21:
+ // Context menu for spell-check input
+ checkContextMenu(["*prodigality", true, // spelling suggestion
+ "---", null,
+ "spell-add-to-dictionary", true,
+ "spell-ignore-word", true,
+ "---", null,
+ "context-undo", false,
+ "context-redo", false,
+ "---", null,
+ "context-cut", false,
+ "context-copy", false,
+ "context-paste", null, // ignore clipboard state
+ "context-delete", false,
+ "---", null,
+ "context-selectall", true,
+ "---", null,
+ "spell-check-enabled", true,
+ "spell-dictionaries", true,
+ ["spell-check-dictionary-en-US", true,
+ "---", null,
+ "spell-add-dictionaries", true], null]);
+
+ closeContextMenu();
+ openContextMenuFor(link); // Invoke context menu for next test.
+ break;
+
+ case 22:
+ executeCopyCommand("cmd_copyLink", "http://mozilla.com/");
+ closeContextMenu();
+ openContextMenuFor(pagemenu); // Invoke context menu for next test.
+ break;
+
+ case 23:
+ // Context menu for element with assigned content context menu
+ checkContextMenu(["+Plain item", {type: "", icon: "", checked: false, disabled: false},
+ "+Disabled item", {type: "", icon: "", checked: false, disabled: true},
+ "+Item w/ textContent", {type: "", icon: "", checked: false, disabled: false},
+ "---", null,
+ "+Checkbox", {type: "checkbox", icon: "", checked: true, disabled: false},
+ "---", null,
+ "+Radio1", {type: "checkbox", icon: "", checked: true, disabled: false},
+ "+Radio2", {type: "checkbox", icon: "", checked: false, disabled: false},
+ "+Radio3", {type: "checkbox", icon: "", checked: false, disabled: false},
+ "---", null,
+ "+Item w/ icon", {type: "", icon: "favicon.ico", checked: false, disabled: false},
+ "+Item w/ bad icon", {type: "", icon: "", checked: false, disabled: false},
+ "---", null,
+ "generated-submenu-1", true,
+ ["+Radio1", {type: "checkbox", icon: "", checked: false, disabled: false},
+ "+Radio2", {type: "checkbox", icon: "", checked: true, disabled: false},
+ "+Radio3", {type: "checkbox", icon: "", checked: false, disabled: false},
+ "---", null,
+ "+Checkbox", {type: "checkbox", icon: "", checked: false, disabled: false}], null,
+ "---", null,
+ "context-back", false,
+ "context-forward", false,
+ "context-reload", true,
+ "context-stop", false,
+ "---", null,
+ "context-bookmarkpage", true,
+ "context-savepage", true,
+ "context-sendpage", true,
+ "---", null,
+ "context-viewbgimage", false,
+ "context-selectall", true,
+ "---", null,
+ "context-viewsource", true,
+ "context-viewinfo", true]);
+
+ invokeItemAction("0");
+ closeContextMenu();
+ openContextMenuFor(pagemenu, true); // Invoke context menu for next test.
+ break;
+
+ case 24:
+ // Context menu for element with assigned content context menu
+ // The shift key should bypass content context menu processing
+ checkContextMenu(["context-back", false,
+ "context-forward", false,
+ "context-reload", true,
+ "context-stop", false,
+ "---", null,
+ "context-bookmarkpage", true,
+ "context-savepage", true,
+ "context-sendpage", true,
+ "---", null,
+ "context-viewbgimage", false,
+ "context-selectall", true,
+ "---", null,
+ "context-viewsource", true,
+ "context-viewinfo", true]);
+ closeContextMenu();
+
+ // Continue with SeaMonkey specific cases.
+ openContextMenuFor(img_link); // Invoke context menu for next test.
+ break;
+
+ case 25:
+ // Context menu for an image with a link
+ checkContextMenu(["context-openlinkintab", true,
+ "context-openlink", true,
+ "context-openlinkinprivatewindow", true,
+ "---", null,
+ "context-bookmarklink", true,
+ "context-savelink", true,
+ "context-sendlink", true,
+ "context-copylink", true,
+ "---", null,
+ "context-reloadimage", true,
+ "context-viewimage", true,
+ "context-blockimage", true,
+ "context-copyimage", true,
+ "---", null,
+ "context-saveimage", true,
+ "context-sendimage", true].concat(
+ ("@mozilla.org/suite/shell-service;1" in Cc) ?
+ ["context-setDesktopBackground", true] : []).concat(
+ ["---", null,
+ "context-bookmarkpage", true,
+ "---", null,
+ "context-metadata", true]));
+ closeContextMenu();
+ openContextMenuFor(img_mailto); // Invoke context menu for next test.
+ break;
+
+ case 26:
+ // Context menu for an image with a mailto: link
+ checkContextMenu(["context-copyemail", true,
+ "context-copylink", true,
+ "---", null,
+ "context-reloadimage", true,
+ "context-viewimage", true,
+ "context-blockimage", true,
+ "context-copyimage", true,
+ "---", null,
+ "context-saveimage", true,
+ "context-sendimage", true].concat(
+ ("@mozilla.org/suite/shell-service;1" in Cc) ?
+ ["context-setDesktopBackground", true] : []).concat(
+ ["---", null,
+ "context-bookmarkpage", true,
+ "---", null,
+ "context-metadata", true]));
+ closeContextMenu();
+
+ subwindow.close();
+ SimpleTest.finish();
+ return;
+
+ /*
+ * Other things that would be nice to test:
+ * - selected text
+ * - spelling / misspelled word (in text input?)
+ * - check state of disabled items
+ * - test execution of menu items (maybe as a separate test?)
+ */
+
+ default:
+ ok(false, "Unexpected invocation of test #" + testNum);
+ subwindow.close();
+ SimpleTest.finish();
+ return;
+ }
+
+}
+
+
+var testNum = 1;
+var subwindow, chromeWin, contextMenu, lastElement;
+var text, link, mailto, input, img, canvas, video_ok, video_bad, video_bad2,
+ iframe, video_in_iframe, image_in_iframe, textarea, contenteditable,
+ inputspell, pagemenu, audio_in_video;
+
+// SeaMonkey specific variables.
+var img_link, img_mailto;
+
+function startTest() {
+ chromeWin = SpecialPowers.wrap(subwindow)
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow)
+ .QueryInterface(Ci.nsIDOMChromeWindow);
+ contextMenu = chromeWin.document.getElementById("contentAreaContextMenu");
+ ok(contextMenu, "Got context menu XUL");
+
+ if (chromeWin.document.getElementById("context-stop").getAttribute("disabled") != "true") {
+ isnot(false, "Document still loading");
+ SimpleTest.executeSoon(startTest);
+ return;
+ }
+
+ lastElement = null;
+
+ text = subwindow.document.getElementById("test-text");
+ link = subwindow.document.getElementById("test-link");
+ mailto = subwindow.document.getElementById("test-mailto");
+ input = subwindow.document.getElementById("test-input");
+ input_sel = subwindow.document.getElementById("test-input-select");
+ img = subwindow.document.getElementById("test-image");
+ canvas = subwindow.document.getElementById("test-canvas");
+ video_ok = subwindow.document.getElementById("test-video-ok");
+ audio_in_video = subwindow.document.getElementById("test-audio-in-video");
+ video_bad = subwindow.document.getElementById("test-video-bad");
+ video_bad2 = subwindow.document.getElementById("test-video-bad2");
+ iframe = subwindow.document.getElementById("test-iframe");
+ video_in_iframe = subwindow.document.getElementById("test-video-in-iframe").contentDocument.getElementsByTagName("video")[0];
+ // Ensure that contextmenu has 'context-media-play' item when check runs.
+ video_in_iframe.pause();
+ image_in_iframe = subwindow.document.getElementById("test-image-in-iframe").contentDocument.getElementsByTagName("img")[0];
+ textarea = subwindow.document.getElementById("test-textarea");
+ textarea_sel = subwindow.document.getElementById("test-textarea-sel");
+ contenteditable = subwindow.document.getElementById("test-contenteditable");
+ contenteditable.focus(); // content editable needs to be focused to enable spellcheck
+ inputspell = subwindow.document.getElementById("test-input-spellcheck");
+ pagemenu = subwindow.document.getElementById("test-pagemenu");
+
+ // SeaMonkey specific elements.
+ img_link = subwindow.document.getElementById("test-image-link");
+ img_mailto = subwindow.document.getElementById("test-image-mailto");
+
+ contextMenu.addEventListener("popupshown", function() { runTest(++testNum); });
+ runTest(1);
+}
+
+// We open this in a separate window, because the Mochitests run inside a frame.
+// The frame causes an extra menu item, and prevents running the test
+// standalone (ie, clicking the test name in the Mochitest window) to see
+// success/failure messages.
+var painted = false, loaded = false;
+
+function waitForEvents(event)
+{
+ if (event.type == "MozAfterPaint")
+ painted = true;
+ else if (event.type == "load")
+ loaded = true;
+ if (painted && loaded) {
+ subwindow.removeEventListener("MozAfterPaint", waitForEvents);
+ subwindow.onload = null;
+ startTest();
+ }
+}
+
+var subwindow = window.open("./subtst_contextmenu.html", "contextmenu-subtext", "width=600,height=700");
+subwindow.addEventListener("MozAfterPaint", waitForEvents);
+subwindow.onload = waitForEvents;
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/comm/suite/browser/test/mochitest/test_feed_discovery.html b/comm/suite/browser/test/mochitest/test_feed_discovery.html
new file mode 100644
index 0000000000..2f2a0a459e
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/test_feed_discovery.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=240393
+-->
+<head>
+ <title>Test for feed discovery</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=377611">Mozilla Bug 377611</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody">
+
+/** Tests for bug 240393 (from bug 377611 on Firefox side) **/
+
+var rv = { tests: null };
+var testCheckInterval = null;
+
+function startTest() {
+ var url = window.location.href.replace(/test_feed_discovery\.html/,
+ 'feed_discovery.html');
+ SpecialPowers.openDialog(window, [url, '', 'dialog=no,width=10,height=10', rv]);
+ testCheckInterval = window.setInterval(tryIfTestIsFinished, 500);
+}
+
+function tryIfTestIsFinished() {
+ if (rv.tests) {
+ window.clearInterval(testCheckInterval);
+ checkTest();
+ }
+}
+
+function checkTest() {
+ for (var i = 0; i < rv.tests.length; ++ i) {
+ var test = rv.tests[i];
+ if (test.todo)
+ todo(test.check, test.message);
+ else
+ ok(test.check, test.message);
+ }
+ SimpleTest.finish();
+}
+
+window.onload = startTest;
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/comm/suite/browser/test/mochitest/test_registerHandler.html b/comm/suite/browser/test/mochitest/test_registerHandler.html
new file mode 100644
index 0000000000..20952ca9ee
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/test_registerHandler.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=402788
+-->
+<head>
+ <title>Test for Bug 402788</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=402788">Mozilla Bug 402788</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody">
+
+/** Test for Bug 402788 **/
+
+ // return false if an exception has been catched, true otherwise
+ function testRegisterHandler(aIsProtocol, aTxt, aUri, aTitle)
+ {
+ try {
+ if (aIsProtocol)
+ navigator.registerProtocolHandler(aTxt, aUri, aTitle);
+ else
+ navigator.registerContentHandler(aTxt, aUri, aTitle);
+ }
+ catch(e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ ok(navigator.registerProtocolHandler, "navigator.registerProtocolHandler should be defined");
+ ok(navigator.registerContentHandler, "navigator.registerContentHandler should be defined");
+
+ // testing a generic case
+ is(true, testRegisterHandler(true, "foo", "http://mochi.test:8888/%s", "Foo handler"), "registering a foo protocol handler should work");
+ is(true, testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/%s", "Foo handler"), "registering a foo content handler should work");
+
+ // testing with wrong uris
+ is(false, testRegisterHandler(true, "foo", "http://mochi.test:8888/", "Foo handler"), "a protocol handler uri should contain %s");
+ is(false, testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/", "Foo handler"), "a content handler uri should contain %s");
+
+ // the spec says we should not throw here, but it probably needs to be changed
+ is(false, testRegisterHandler(true, "foo", "foo/%s", "Foo handler"), "a protocol handler uri should be valid");
+ is(false, testRegisterHandler(false, "application/rss+xml", "foo/%s", "Foo handler"), "a content handler uri should be valid");
+
+ // we should only accept to register when the handler has the same host as the current page (bug 402287)
+ is(false, testRegisterHandler(true, "foo", "http://remotehost:8888/%s", "Foo handler"), "registering a foo protocol handler with a different host should not work");
+ is(false, testRegisterHandler(false, "application/rss+xml", "http://remotehost:8888/%s", "Foo handler"), "registering a foo content handler with a different host should not work");
+
+ // restriction to http(s) for the uri of the handler (bug 401343)
+ // https should work (http already tested in the generic case)
+ is(true, testRegisterHandler(true, "foo", "https://mochi.test:8888/%s", "Foo handler"), "registering a foo protocol handler with https scheme should work");
+ is(true, testRegisterHandler(false, "application/rss+xml", "https://mochi.test:8888/%s", "Foo handler"), "registering a foo content handler with https scheme should work");
+ // ftp should not work
+ is(false, testRegisterHandler(true, "foo", "ftp://mochi.test:8888/%s", "Foo handler"), "registering a foo protocol handler with ftp scheme should not work");
+ is(false, testRegisterHandler(false, "application/rss+xml", "ftp://mochi.test:8888/%s", "Foo handler"), "registering a foo content handler with ftp scheme should not work");
+ // chrome should not work
+ is(false, testRegisterHandler(true, "foo", "chrome://mochi.test:8888/%s", "Foo handler"), "registering a foo protocol handler with chrome scheme should not work");
+ is(false, testRegisterHandler(false, "application/rss+xml", "chrome://mochi.test:8888/%s", "Foo handler"), "registering a foo content handler with chrome scheme should not work");
+ // foo should not work
+ is(false, testRegisterHandler(true, "foo", "foo://mochi.test:8888/%s", "Foo handler"), "registering a foo protocol handler with foo scheme should not work");
+ is(false, testRegisterHandler(false, "application/rss+xml", "foo://mochi.test:8888/%s", "Foo handler"), "registering a foo content handler with foo scheme should not work");
+
+ // for security reasons, protocol handlers should never be registered for some schemes (chrome, vbscript, ...) (bug 402788)
+ is(false, testRegisterHandler(true, "chrome", "http://mochi.test:8888/%s", "chrome handler"), "registering a chrome protocol handler should not work");
+ is(false, testRegisterHandler(true, "vbscript", "http://mochi.test:8888/%s", "vbscript handler"), "registering a vbscript protocol handler should not work");
+ is(false, testRegisterHandler(true, "javascript", "http://mochi.test:8888/%s", "javascript handler"), "registering a javascript protocol handler should not work");
+ is(false, testRegisterHandler(true, "moz-icon", "http://mochi.test:8888/%s", "moz-icon handler"), "registering a moz-icon protocol handler should not work");
+
+ // for security reasons, content handlers should never be registered for some types (html, ...)
+ is(true, testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/%s", "Foo handler"), "registering rss content handlers should work");
+ is(true, testRegisterHandler(false, "application/atom+xml", "http://mochi.test:8888/%s", "Foo handler"), "registering atom content handlers should work");
+ todo(false, testRegisterHandler(false, "text/html", "http://mochi.test:8888/%s", "Foo handler"), "registering html content handlers should not work"); // bug 403798
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/comm/suite/browser/test/mochitest/valid-feed.xml b/comm/suite/browser/test/mochitest/valid-feed.xml
new file mode 100644
index 0000000000..0e700b6d8d
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/valid-feed.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+
+ <title>Example Feed</title>
+ <link href="http://example.org/"/>
+ <updated>2010-08-22T18:30:02Z</updated>
+
+ <author>
+ <name>John Doe</name>
+ </author>
+ <id>urn:uuid:e2df8375-99be-4848-b05e-b9d407555267</id>
+
+ <entry>
+
+ <title>Item</title>
+ <link href="http://example.org/first"/>
+ <id>urn:uuid:9e0f4bed-33d3-4a9d-97ab-ecaa31b3f14a</id>
+ <updated>2010-08-22T18:30:02Z</updated>
+
+ <summary>Some text.</summary>
+ </entry>
+
+</feed>
diff --git a/comm/suite/browser/test/mochitest/valid-unsniffable-feed.xml b/comm/suite/browser/test/mochitest/valid-unsniffable-feed.xml
new file mode 100644
index 0000000000..e753157395
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/valid-unsniffable-feed.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 512 bytes!
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ -->
+<feed xmlns="http://www.w3.org/2005/Atom">
+
+ <title>Example Feed</title>
+ <link href="http://example.org/"/>
+ <updated>2010-08-22T18:30:02Z</updated>
+
+ <author>
+ <name>John Doe</name>
+ </author>
+ <id>urn:uuid:e2df8375-99be-4848-b05e-b9d407555267</id>
+
+ <entry>
+
+ <title>Item</title>
+ <link href="http://example.org/first"/>
+ <id>urn:uuid:9e0f4bed-33d3-4a9d-97ab-ecaa31b3f14a</id>
+ <updated>2010-08-22T18:30:02Z</updated>
+
+ <summary>Some text.</summary>
+ </entry>
+
+</feed>
diff --git a/comm/suite/browser/test/mochitest/video.ogg b/comm/suite/browser/test/mochitest/video.ogg
new file mode 100644
index 0000000000..ac7ece3519
--- /dev/null
+++ b/comm/suite/browser/test/mochitest/video.ogg
Binary files differ