summaryrefslogtreecommitdiffstats
path: root/docshell/test/unit
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /docshell/test/unit
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'docshell/test/unit')
-rw-r--r--docshell/test/unit/head_docshell.js95
-rw-r--r--docshell/test/unit/test_URIFixup.js123
-rw-r--r--docshell/test/unit/test_URIFixup_info.js932
-rw-r--r--docshell/test/unit/test_URIFixup_search.js142
-rw-r--r--docshell/test/unit/test_browsing_context_structured_clone.js68
-rw-r--r--docshell/test/unit/test_bug442584.js35
-rw-r--r--docshell/test/unit/test_pb_notification.js18
-rw-r--r--docshell/test/unit/test_privacy_transition.js21
-rw-r--r--docshell/test/unit/xpcshell.ini16
9 files changed, 1450 insertions, 0 deletions
diff --git a/docshell/test/unit/head_docshell.js b/docshell/test/unit/head_docshell.js
new file mode 100644
index 0000000000..1b6595b8b8
--- /dev/null
+++ b/docshell/test/unit/head_docshell.js
@@ -0,0 +1,95 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var { XPCOMUtils } = ChromeUtils.import(
+ "resource://gre/modules/XPCOMUtils.jsm"
+);
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ AddonTestUtils: "resource://testing-common/AddonTestUtils.jsm",
+ NetUtil: "resource://gre/modules/NetUtil.jsm",
+ SearchUtils: "resource://gre/modules/SearchUtils.jsm",
+ SearchTestUtils: "resource://testing-common/SearchTestUtils.jsm",
+ Services: "resource://gre/modules/Services.jsm",
+});
+
+var dirSvc = Services.dirSvc;
+var profileDir = do_get_profile();
+
+const kSearchEngineID = "test_urifixup_search_engine";
+const kSearchEngineURL = "https://www.example.org/?search={searchTerms}";
+const kPrivateSearchEngineID = "test_urifixup_search_engine_private";
+const kPrivateSearchEngineURL =
+ "https://www.example.org/?private={searchTerms}";
+const kPostSearchEngineID = "test_urifixup_search_engine_post";
+const kPostSearchEngineURL = "https://www.example.org/";
+const kPostSearchEngineData = "q={searchTerms}";
+
+const SEARCH_CONFIG = [
+ {
+ appliesTo: [
+ {
+ included: {
+ everywhere: true,
+ },
+ },
+ ],
+ default: "yes",
+ webExtension: {
+ id: "fixup_search@search.mozilla.org",
+ },
+ },
+];
+
+async function setupSearchService() {
+ SearchTestUtils.init(this);
+
+ Services.prefs.setBoolPref("browser.search.modernConfig", true);
+ AddonTestUtils.init(this);
+ AddonTestUtils.overrideCertDB();
+ AddonTestUtils.createAppInfo(
+ "xpcshell@tests.mozilla.org",
+ "XPCShell",
+ "1",
+ "42"
+ );
+
+ await SearchTestUtils.useTestEngines(".", null, SEARCH_CONFIG);
+ await AddonTestUtils.promiseStartupManager();
+ await Services.search.init();
+}
+
+async function addTestEngines() {
+ // This is a hack, ideally we should be setting up a configuration with
+ // built-in engines, but the `chrome_settings_overrides` section that
+ // WebExtensions need is only defined for browser/
+ await Services.search.addPolicyEngine({
+ description: "urifixup search engine",
+ chrome_settings_overrides: {
+ search_provider: {
+ name: kSearchEngineID,
+ search_url: kSearchEngineURL,
+ },
+ },
+ });
+ await Services.search.addPolicyEngine({
+ description: "urifixup private search engine",
+ chrome_settings_overrides: {
+ search_provider: {
+ name: kPrivateSearchEngineID,
+ search_url: kPrivateSearchEngineURL,
+ },
+ },
+ });
+ await Services.search.addPolicyEngine({
+ description: "urifixup POST search engine",
+ chrome_settings_overrides: {
+ search_provider: {
+ name: kPostSearchEngineID,
+ search_url: kPostSearchEngineURL,
+ search_url_post_params: kPostSearchEngineData,
+ },
+ },
+ });
+}
diff --git a/docshell/test/unit/test_URIFixup.js b/docshell/test/unit/test_URIFixup.js
new file mode 100644
index 0000000000..7967933b56
--- /dev/null
+++ b/docshell/test/unit/test_URIFixup.js
@@ -0,0 +1,123 @@
+var pref = "browser.fixup.typo.scheme";
+
+var data = [
+ {
+ // ttp -> http.
+ wrong: "ttp://www.example.com/",
+ fixed: "http://www.example.com/",
+ },
+ {
+ // htp -> http.
+ wrong: "htp://www.example.com/",
+ fixed: "http://www.example.com/",
+ },
+ {
+ // ttps -> https.
+ wrong: "ttps://www.example.com/",
+ fixed: "https://www.example.com/",
+ },
+ {
+ // tps -> https.
+ wrong: "tps://www.example.com/",
+ fixed: "https://www.example.com/",
+ },
+ {
+ // ps -> https.
+ wrong: "ps://www.example.com/",
+ fixed: "https://www.example.com/",
+ },
+ {
+ // htps -> https.
+ wrong: "htps://www.example.com/",
+ fixed: "https://www.example.com/",
+ },
+ {
+ // ile -> file.
+ wrong: "ile:///this/is/a/test.html",
+ fixed: "file:///this/is/a/test.html",
+ },
+ {
+ // le -> file.
+ wrong: "le:///this/is/a/test.html",
+ fixed: "file:///this/is/a/test.html",
+ },
+ {
+ // Replace ';' with ':'.
+ wrong: "http;//www.example.com/",
+ fixed: "http://www.example.com/",
+ noPrefValue: "http://http;//www.example.com/",
+ },
+ {
+ // Missing ':'.
+ wrong: "https//www.example.com/",
+ fixed: "https://www.example.com/",
+ noPrefValue: "http://https//www.example.com/",
+ },
+ {
+ // Missing ':' for file scheme.
+ wrong: "file///this/is/a/test.html",
+ fixed: "file:///this/is/a/test.html",
+ noPrefValue: "http://file///this/is/a/test.html",
+ },
+ {
+ // Valid should not be changed.
+ wrong: "https://example.com/this/is/a/test.html",
+ fixed: "https://example.com/this/is/a/test.html",
+ },
+ {
+ // Unmatched should not be changed.
+ wrong: "whatever://this/is/a/test.html",
+ fixed: "whatever://this/is/a/test.html",
+ },
+];
+
+var len = data.length;
+
+add_task(async function setup() {
+ await setupSearchService();
+ // Now we've initialised the search service, we force remove the engines
+ // it has, so they don't interfere with this test.
+ // Search engine integration is tested in test_URIFixup_search.js.
+ Services.search.wrappedJSObject._engines.clear();
+});
+
+// Make sure we fix what needs fixing when there is no pref set.
+add_task(function test_unset_pref_fixes_typos() {
+ Services.prefs.clearUserPref(pref);
+ for (let i = 0; i < len; ++i) {
+ let item = data[i];
+ let { preferredURI } = Services.uriFixup.getFixupURIInfo(
+ item.wrong,
+ Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS
+ );
+ Assert.equal(preferredURI.spec, item.fixed);
+ }
+});
+
+// Make sure we don't do anything when the pref is explicitly
+// set to false.
+add_task(function test_false_pref_keeps_typos() {
+ Services.prefs.setBoolPref(pref, false);
+ for (let i = 0; i < len; ++i) {
+ let item = data[i];
+ let { preferredURI } = Services.uriFixup.getFixupURIInfo(
+ item.wrong,
+ Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS
+ );
+ Assert.equal(preferredURI.spec, item.noPrefValue || item.wrong);
+ }
+});
+
+// Finally, make sure we still fix what needs fixing if the pref is
+// explicitly set to true.
+add_task(function test_true_pref_fixes_typos() {
+ Services.prefs.setBoolPref(pref, true);
+ for (let i = 0; i < len; ++i) {
+ let item = data[i];
+ let { preferredURI } = Services.uriFixup.getFixupURIInfo(
+ item.wrong,
+ Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS
+ );
+ Assert.equal(preferredURI.spec, item.fixed);
+ }
+});
diff --git a/docshell/test/unit/test_URIFixup_info.js b/docshell/test/unit/test_URIFixup_info.js
new file mode 100644
index 0000000000..f2dc18f54e
--- /dev/null
+++ b/docshell/test/unit/test_URIFixup_info.js
@@ -0,0 +1,932 @@
+const { AppConstants } = ChromeUtils.import(
+ "resource://gre/modules/AppConstants.jsm"
+);
+
+const kForceDNSLookup = "browser.fixup.dns_first_for_single_words";
+
+// TODO(bug 1522134), this test should also use
+// combinations of the following flags.
+var flagInputs = [
+ Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
+ Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
+ Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT,
+ Services.uriFixup.FIXUP_FLAGS_MAKE_ALTERNATE_URI,
+ Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS,
+ // This should not really generate a search, but it does, see Bug 1588118.
+ Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
+ Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT,
+];
+
+/*
+ The following properties are supported for these test cases:
+ {
+ input: "", // Input string, required
+ fixedURI: "", // Expected fixedURI
+ alternateURI: "", // Expected alternateURI
+ keywordLookup: false, // Whether a keyword lookup is expected
+ protocolChange: false, // Whether a protocol change is expected
+ inWhitelist: false, // Whether the input host is in the whitelist
+ affectedByDNSForSingleWordHosts: false, // Whether the input host could be a host, but is normally assumed to be a keyword query
+ }
+*/
+var testcases = [
+ {
+ input: "about:home",
+ fixedURI: "about:home",
+ },
+ {
+ input: "http://www.mozilla.org",
+ fixedURI: "http://www.mozilla.org/",
+ },
+ {
+ input: "http://127.0.0.1/",
+ fixedURI: "http://127.0.0.1/",
+ },
+ {
+ input: "file:///foo/bar",
+ fixedURI: "file:///foo/bar",
+ },
+ {
+ input: "://www.mozilla.org",
+ fixedURI: "http://www.mozilla.org/",
+ protocolChange: true,
+ },
+ {
+ input: "www.mozilla.org",
+ fixedURI: "http://www.mozilla.org/",
+ protocolChange: true,
+ },
+ {
+ input: "http://mozilla/",
+ fixedURI: "http://mozilla/",
+ alternateURI: "https://www.mozilla.com/",
+ },
+ {
+ input: "http://test./",
+ fixedURI: "http://test./",
+ alternateURI: "https://www.test./",
+ },
+ {
+ input: "127.0.0.1",
+ fixedURI: "http://127.0.0.1/",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3.4/",
+ fixedURI: "http://1.2.3.4/",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3.4/foo",
+ fixedURI: "http://1.2.3.4/foo",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3.4:8000",
+ fixedURI: "http://1.2.3.4:8000/",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3.4:8000/",
+ fixedURI: "http://1.2.3.4:8000/",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3.4:8000/foo",
+ fixedURI: "http://1.2.3.4:8000/foo",
+ protocolChange: true,
+ },
+ {
+ input: "192.168.10.110",
+ fixedURI: "http://192.168.10.110/",
+ protocolChange: true,
+ },
+ {
+ input: "192.168.10.110/123",
+ fixedURI: "http://192.168.10.110/123",
+ protocolChange: true,
+ },
+ {
+ input: "192.168.10.110/123foo",
+ fixedURI: "http://192.168.10.110/123foo",
+ protocolChange: true,
+ },
+ {
+ input: "192.168.10.110:1234/123",
+ fixedURI: "http://192.168.10.110:1234/123",
+ protocolChange: true,
+ },
+ {
+ input: "192.168.10.110:1234/123foo",
+ fixedURI: "http://192.168.10.110:1234/123foo",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3",
+ fixedURI: "http://1.2.0.3/",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3/",
+ fixedURI: "http://1.2.0.3/",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3/foo",
+ fixedURI: "http://1.2.0.3/foo",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3/123",
+ fixedURI: "http://1.2.0.3/123",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3:8000",
+ fixedURI: "http://1.2.0.3:8000/",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3:8000/",
+ fixedURI: "http://1.2.0.3:8000/",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3:8000/foo",
+ fixedURI: "http://1.2.0.3:8000/foo",
+ protocolChange: true,
+ },
+ {
+ input: "1.2.3:8000/123",
+ fixedURI: "http://1.2.0.3:8000/123",
+ protocolChange: true,
+ },
+ {
+ input: "http://1.2.3",
+ fixedURI: "http://1.2.0.3/",
+ },
+ {
+ input: "http://1.2.3/",
+ fixedURI: "http://1.2.0.3/",
+ },
+ {
+ input: "http://1.2.3/foo",
+ fixedURI: "http://1.2.0.3/foo",
+ },
+ {
+ input: "[::1]",
+ fixedURI: "http://[::1]/",
+ protocolChange: true,
+ },
+ {
+ input: "[::1]/",
+ fixedURI: "http://[::1]/",
+ protocolChange: true,
+ },
+ {
+ input: "[::1]:8000",
+ fixedURI: "http://[::1]:8000/",
+ protocolChange: true,
+ },
+ {
+ input: "[::1]:8000/",
+ fixedURI: "http://[::1]:8000/",
+ protocolChange: true,
+ },
+ {
+ input: "[[::1]]/",
+ keywordLookup: true,
+ },
+ {
+ input: "[fe80:cd00:0:cde:1257:0:211e:729c]",
+ fixedURI: "http://[fe80:cd00:0:cde:1257:0:211e:729c]/",
+ protocolChange: true,
+ },
+ {
+ input: "[64:ff9b::8.8.8.8]",
+ fixedURI: "http://[64:ff9b::808:808]/",
+ protocolChange: true,
+ },
+ {
+ input: "[64:ff9b::8.8.8.8]/~moz",
+ fixedURI: "http://[64:ff9b::808:808]/~moz",
+ protocolChange: true,
+ },
+ {
+ input: "[::1][::1]",
+ keywordLookup: true,
+ },
+ {
+ input: "[::1][100",
+ keywordLookup: true,
+ },
+ {
+ input: "[::1]]",
+ keywordLookup: true,
+ },
+ {
+ input: "1234",
+ fixedURI: "http://0.0.4.210/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "whitelisted/foo.txt",
+ fixedURI: "http://whitelisted/foo.txt",
+ alternateURI: "https://www.whitelisted.com/foo.txt",
+ protocolChange: true,
+ },
+ {
+ input: "mozilla",
+ fixedURI: "http://mozilla/",
+ alternateURI: "https://www.mozilla.com/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "test.",
+ fixedURI: "http://test./",
+ alternateURI: "https://www.test./",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: ".test",
+ fixedURI: "http://.test/",
+ alternateURI: "https://www..test/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "mozilla is amazing",
+ keywordLookup: true,
+ },
+ {
+ input: "search ?mozilla",
+ keywordLookup: true,
+ },
+ {
+ input: "mozilla .com",
+ keywordLookup: true,
+ },
+ {
+ input: "what if firefox?",
+ keywordLookup: true,
+ },
+ {
+ input: "london's map",
+ keywordLookup: true,
+ },
+ {
+ input: "mozilla ",
+ fixedURI: "http://mozilla/",
+ alternateURI: "https://www.mozilla.com/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: " mozilla ",
+ fixedURI: "http://mozilla/",
+ alternateURI: "https://www.mozilla.com/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "mozilla \\",
+ keywordLookup: true,
+ },
+ {
+ input: "mozilla \\ foo.txt",
+ keywordLookup: true,
+ },
+ {
+ input: "mozilla \\\r foo.txt",
+ keywordLookup: true,
+ },
+ {
+ input: "mozilla\n",
+ fixedURI: "http://mozilla/",
+ alternateURI: "https://www.mozilla.com/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "mozilla \r\n",
+ fixedURI: "http://mozilla/",
+ alternateURI: "https://www.mozilla.com/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "moz\r\nfirefox\nos\r",
+ fixedURI: "http://mozfirefoxos/",
+ alternateURI: "https://www.mozfirefoxos.com/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "moz\r\n firefox\n",
+ keywordLookup: true,
+ },
+ {
+ input: "",
+ keywordLookup: true,
+ },
+ {
+ input: "[]",
+ keywordLookup: true,
+ },
+ {
+ input: "http://whitelisted/",
+ fixedURI: "http://whitelisted/",
+ alternateURI: "https://www.whitelisted.com/",
+ inWhitelist: true,
+ },
+ {
+ input: "whitelisted",
+ fixedURI: "http://whitelisted/",
+ alternateURI: "https://www.whitelisted.com/",
+ protocolChange: true,
+ inWhitelist: true,
+ },
+ {
+ input: "whitelisted.",
+ fixedURI: "http://whitelisted./",
+ alternateURI: "https://www.whitelisted./",
+ protocolChange: true,
+ inWhitelist: true,
+ },
+ {
+ input: "mochi.test",
+ fixedURI: "http://mochi.test/",
+ alternateURI: "https://www.mochi.test/",
+ protocolChange: true,
+ inWhitelist: true,
+ },
+ // local.domain is a whitelisted suffix...
+ {
+ input: "some.local.domain",
+ fixedURI: "http://some.local.domain/",
+ protocolChange: true,
+ inWhitelist: true,
+ },
+ // ...but .domain is not.
+ {
+ input: "some.domain",
+ fixedURI: "http://some.domain/",
+ alternateURI: "https://www.some.domain/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "café.com",
+ fixedURI: "http://xn--caf-dma.com/",
+ alternateURI: "https://www.xn--caf-dma.com/",
+ protocolChange: true,
+ },
+ {
+ input: "mozilla.nonexistent",
+ fixedURI: "http://mozilla.nonexistent/",
+ alternateURI: "https://www.mozilla.nonexistent/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "mochi.ocm",
+ fixedURI: "http://mochi.com/",
+ alternateURI: "https://www.mochi.com/",
+ protocolChange: true,
+ },
+ {
+ input: "47.6182,-122.830",
+ fixedURI: "http://47.6182,-122.830/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "-47.6182,-23.51",
+ fixedURI: "http://-47.6182,-23.51/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "-22.14,23.51-",
+ fixedURI: "http://-22.14,23.51-/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "32.7",
+ fixedURI: "http://32.0.0.7/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "5+2",
+ fixedURI: "http://5+2/",
+ alternateURI: "https://www.5+2.com/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "5/2",
+ fixedURI: "http://0.0.0.5/2",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "moz ?.::%27",
+ keywordLookup: true,
+ },
+ {
+ input: "mozilla.com/?q=search",
+ fixedURI: "http://mozilla.com/?q=search",
+ alternateURI: "https://www.mozilla.com/?q=search",
+ protocolChange: true,
+ },
+ {
+ input: "mozilla.com?q=search",
+ fixedURI: "http://mozilla.com/?q=search",
+ alternateURI: "https://www.mozilla.com/?q=search",
+ protocolChange: true,
+ },
+ {
+ input: "mozilla.com ?q=search",
+ keywordLookup: true,
+ },
+ {
+ input: "mozilla.com.?q=search",
+ fixedURI: "http://mozilla.com./?q=search",
+ protocolChange: true,
+ },
+ {
+ input: "mozilla.com'?q=search",
+ fixedURI: "http://mozilla.com/?q=search",
+ alternateURI: "https://www.mozilla.com/?q=search",
+ protocolChange: true,
+ },
+ {
+ input: "mozilla.com':search",
+ keywordLookup: true,
+ },
+ {
+ input: "[mozilla]",
+ keywordLookup: true,
+ },
+ {
+ input: "':?",
+ fixedURI: "http://'/?",
+ alternateURI: "https://www.'.com/?",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "whitelisted?.com",
+ fixedURI: "http://whitelisted/?.com",
+ alternateURI: "https://www.whitelisted.com/?.com",
+ protocolChange: true,
+ },
+ {
+ input: "?'.com",
+ keywordLookup: true,
+ },
+ {
+ input: "' ?.com",
+ keywordLookup: true,
+ },
+ {
+ input: "?mozilla",
+ keywordLookup: true,
+ },
+ {
+ input: "??mozilla",
+ keywordLookup: true,
+ },
+ {
+ input: "mozilla/",
+ fixedURI: "http://mozilla/",
+ alternateURI: "https://www.mozilla.com/",
+ protocolChange: true,
+ },
+ {
+ input: "mozilla",
+ fixedURI: "http://mozilla/",
+ alternateURI: "https://www.mozilla.com/",
+ protocolChange: true,
+ keywordLookup: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "mozilla5/2",
+ fixedURI: "http://mozilla5/2",
+ alternateURI: "https://www.mozilla5.com/2",
+ protocolChange: true,
+ keywordLookup: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "mozilla/foo",
+ fixedURI: "http://mozilla/foo",
+ alternateURI: "https://www.mozilla.com/foo",
+ protocolChange: true,
+ keywordLookup: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "mozilla\\",
+ fixedURI: "http://mozilla/",
+ alternateURI: "https://www.mozilla.com/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "localhost",
+ fixedURI: "http://localhost/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "localhost:8080",
+ fixedURI: "http://localhost:8080/",
+ protocolChange: true,
+ },
+ {
+ input: "plonk:8080",
+ fixedURI: "http://plonk:8080/",
+ protocolChange: true,
+ },
+ {
+ input: "plonk:8080?test",
+ fixedURI: "http://plonk:8080/?test",
+ protocolChange: true,
+ },
+ {
+ input: "plonk:8080#test",
+ fixedURI: "http://plonk:8080/#test",
+ protocolChange: true,
+ },
+ {
+ input: "plonk/ #",
+ fixedURI: "http://plonk/%20#",
+ alternateURI: "https://www.plonk.com/%20#",
+ protocolChange: true,
+ keywordLookup: false,
+ },
+ {
+ input: "blah.com.",
+ fixedURI: "http://blah.com./",
+ protocolChange: true,
+ },
+ {
+ input:
+ "\u10E0\u10D4\u10D2\u10D8\u10E1\u10E2\u10E0\u10D0\u10EA\u10D8\u10D0.\u10D2\u10D4",
+ fixedURI: "http://xn--lodaehvb5cdik4g.xn--node/",
+ alternateURI: "https://www.xn--lodaehvb5cdik4g.xn--node/",
+ protocolChange: true,
+ },
+ {
+ input: " \t mozilla.org/\t \t ",
+ fixedURI: "http://mozilla.org/",
+ alternateURI: "https://www.mozilla.org/",
+ protocolChange: true,
+ },
+ {
+ input: " moz\ti\tlla.org ",
+ keywordLookup: true,
+ },
+ {
+ input: "mozilla/",
+ fixedURI: "http://mozilla/",
+ alternateURI: "https://www.mozilla.com/",
+ protocolChange: true,
+ },
+ {
+ input: "mozilla/ test /",
+ fixedURI: "http://mozilla/%20test%20/",
+ alternateURI: "https://www.mozilla.com/%20test%20/",
+ protocolChange: true,
+ },
+ {
+ input: "mozilla /test/",
+ keywordLookup: true,
+ },
+ {
+ input: "pserver:8080",
+ fixedURI: "http://pserver:8080/",
+ protocolChange: true,
+ },
+ {
+ input: "http;mozilla",
+ fixedURI: "http://http;mozilla/",
+ alternateURI: "https://www.http;mozilla.com/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ },
+ {
+ input: "http//mozilla.org",
+ fixedURI: "http://mozilla.org/",
+ shouldRunTest: flags =>
+ flags & Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS,
+ },
+ {
+ input: "http//mozilla.org",
+ fixedURI: "http://http//mozilla.org",
+ alternateURI: "https://www.http.com//mozilla.org",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ shouldRunTest: flags =>
+ !(flags & Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS),
+ },
+ {
+ input: "www.mozilla",
+ fixedURI: "http://www.mozilla/",
+ protocolChange: true,
+ },
+];
+
+if (AppConstants.platform == "win") {
+ testcases.push({
+ input: "C:\\some\\file.txt",
+ fixedURI: "file:///C:/some/file.txt",
+ protocolChange: true,
+ });
+ testcases.push({
+ input: "//mozilla",
+ fixedURI: "http://mozilla/",
+ alternateURI: "https://www.mozilla.com/",
+ protocolChange: true,
+ });
+ testcases.push({
+ input: "/a",
+ fixedURI: "http://a/",
+ alternateURI: "https://www.a.com/",
+ keywordLookup: true,
+ protocolChange: true,
+ affectedByDNSForSingleWordHosts: true,
+ });
+} else {
+ testcases.push({
+ input: "/some/file.txt",
+ fixedURI: "file:///some/file.txt",
+ protocolChange: true,
+ });
+ testcases.push({
+ input: "//mozilla",
+ fixedURI: "file:////mozilla",
+ protocolChange: true,
+ });
+ testcases.push({
+ input: "/a",
+ fixedURI: "file:///a",
+ protocolChange: true,
+ });
+}
+
+function sanitize(input) {
+ return input.replace(/\r|\n/g, "").trim();
+}
+
+add_task(async function setup() {
+ var prefList = [
+ "browser.fixup.typo.scheme",
+ "keyword.enabled",
+ "browser.fixup.domainwhitelist.whitelisted",
+ "browser.fixup.domainsuffixwhitelist.test",
+ "browser.fixup.domainsuffixwhitelist.local.domain",
+ "browser.search.separatePrivateDefault",
+ "browser.search.separatePrivateDefault.ui.enabled",
+ ];
+ for (let pref of prefList) {
+ Services.prefs.setBoolPref(pref, true);
+ }
+
+ await setupSearchService();
+ await addTestEngines();
+
+ await Services.search.setDefault(
+ Services.search.getEngineByName(kSearchEngineID)
+ );
+ await Services.search.setDefaultPrivate(
+ Services.search.getEngineByName(kPrivateSearchEngineID)
+ );
+});
+
+var gSingleWordDNSLookup = false;
+add_task(async function run_test() {
+ // Only keywordlookup things should be affected by requiring a DNS lookup for single-word hosts:
+ info(
+ "Check only keyword lookup testcases should be affected by requiring DNS for single hosts"
+ );
+ let affectedTests = testcases.filter(
+ t => !t.keywordLookup && t.affectedByDNSForSingleWordHosts
+ );
+ if (affectedTests.length) {
+ for (let testcase of affectedTests) {
+ info("Affected: " + testcase.input);
+ }
+ }
+ Assert.equal(affectedTests.length, 0);
+ await do_single_test_run();
+ gSingleWordDNSLookup = true;
+ await do_single_test_run();
+ gSingleWordDNSLookup = false;
+ await Services.search.setDefault(
+ Services.search.getEngineByName(kPostSearchEngineID)
+ );
+ await do_single_test_run();
+});
+
+async function do_single_test_run() {
+ Services.prefs.setBoolPref(kForceDNSLookup, gSingleWordDNSLookup);
+
+ let relevantTests = gSingleWordDNSLookup
+ ? testcases.filter(t => t.keywordLookup)
+ : testcases;
+
+ let engine = await Services.search.getDefault();
+ let engineUrl =
+ engine.name == kPostSearchEngineID
+ ? kPostSearchEngineURL
+ : kSearchEngineURL;
+ let privateEngine = await Services.search.getDefaultPrivate();
+ let privateEngineUrl = kPrivateSearchEngineURL;
+
+ for (let {
+ input: testInput,
+ fixedURI: expectedFixedURI,
+ alternateURI: alternativeURI,
+ keywordLookup: expectKeywordLookup,
+ protocolChange: expectProtocolChange,
+ inWhitelist: inWhitelist,
+ affectedByDNSForSingleWordHosts: affectedByDNSForSingleWordHosts,
+ shouldRunTest,
+ } of relevantTests) {
+ // Explicitly force these into a boolean
+ expectKeywordLookup = !!expectKeywordLookup;
+ expectProtocolChange = !!expectProtocolChange;
+ inWhitelist = !!inWhitelist;
+ affectedByDNSForSingleWordHosts = !!affectedByDNSForSingleWordHosts;
+
+ expectKeywordLookup =
+ expectKeywordLookup &&
+ (!affectedByDNSForSingleWordHosts || !gSingleWordDNSLookup);
+
+ for (let flags of flagInputs) {
+ info(
+ 'Checking "' +
+ testInput +
+ '" with flags ' +
+ flags +
+ " (DNS lookup for single words: " +
+ (gSingleWordDNSLookup ? "yes" : "no") +
+ ")"
+ );
+
+ if (shouldRunTest && !shouldRunTest(flags)) {
+ continue;
+ }
+
+ let URIInfo;
+ try {
+ URIInfo = Services.uriFixup.getFixupURIInfo(testInput, flags);
+ } catch (ex) {
+ // Both APIs should return an error in the same cases.
+ info("Caught exception: " + ex);
+ Assert.equal(expectedFixedURI, null);
+ continue;
+ }
+
+ // Check the fixedURI:
+ let makeAlternativeURI =
+ flags & Services.uriFixup.FIXUP_FLAGS_MAKE_ALTERNATE_URI;
+ if (makeAlternativeURI && alternativeURI != null) {
+ Assert.equal(
+ URIInfo.fixedURI.spec,
+ alternativeURI,
+ "should have gotten alternate URI"
+ );
+ } else {
+ Assert.equal(
+ URIInfo.fixedURI && URIInfo.fixedURI.spec,
+ expectedFixedURI,
+ "should get correct fixed URI"
+ );
+ }
+
+ // Check booleans on input:
+ let couldDoKeywordLookup =
+ flags & Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
+ Assert.equal(
+ !!URIInfo.keywordProviderName,
+ couldDoKeywordLookup && expectKeywordLookup,
+ "keyword lookup as expected"
+ );
+ Assert.equal(
+ URIInfo.fixupChangedProtocol,
+ expectProtocolChange,
+ "protocol change as expected"
+ );
+ Assert.equal(
+ URIInfo.fixupCreatedAlternateURI,
+ makeAlternativeURI && alternativeURI != null,
+ "alternative URI as expected"
+ );
+
+ // Check the preferred URI
+ if (couldDoKeywordLookup) {
+ if (expectKeywordLookup) {
+ if (!inWhitelist) {
+ let urlparamInput = encodeURIComponent(sanitize(testInput)).replace(
+ /%20/g,
+ "+"
+ );
+ // If the input starts with `?`, then URIInfo.preferredURI.spec will omit it
+ // In order to test this behaviour, remove `?` only if it is the first character
+ if (urlparamInput.startsWith("%3F")) {
+ urlparamInput = urlparamInput.replace("%3F", "");
+ }
+ let isPrivate =
+ flags & Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
+ let searchEngineUrl = isPrivate ? privateEngineUrl : engineUrl;
+ let searchURL = searchEngineUrl.replace(
+ "{searchTerms}",
+ urlparamInput
+ );
+ let spec = URIInfo.preferredURI.spec.replace(/%27/g, "'");
+ Assert.equal(spec, searchURL, "should get correct search URI");
+ let providerName = isPrivate ? privateEngine.name : engine.name;
+ Assert.equal(
+ URIInfo.keywordProviderName,
+ providerName,
+ "should get correct provider name"
+ );
+ // Also check keywordToURI() uses the right engine.
+ let kwInfo = Services.uriFixup.keywordToURI(
+ urlparamInput,
+ isPrivate
+ );
+ Assert.equal(kwInfo.providerName, URIInfo.providerName);
+ if (providerName == kPostSearchEngineID) {
+ Assert.ok(kwInfo.postData);
+ let submission = engine.getSubmission(urlparamInput);
+ let enginePostData = NetUtil.readInputStreamToString(
+ submission.postData,
+ submission.postData.available()
+ );
+ let postData = NetUtil.readInputStreamToString(
+ kwInfo.postData,
+ kwInfo.postData.available()
+ );
+ Assert.equal(postData, enginePostData);
+ }
+ } else {
+ Assert.equal(
+ URIInfo.preferredURI,
+ null,
+ "not expecting a preferred URI"
+ );
+ }
+ } else {
+ Assert.equal(
+ URIInfo.preferredURI.spec,
+ URIInfo.fixedURI.spec,
+ "fixed URI should match"
+ );
+ }
+ } else {
+ // In these cases, we should never be doing a keyword lookup and
+ // the fixed URI should be preferred:
+ let prefURI = URIInfo.preferredURI && URIInfo.preferredURI.spec;
+ let fixedURI = URIInfo.fixedURI && URIInfo.fixedURI.spec;
+ Assert.equal(prefURI, fixedURI, "fixed URI should be same as expected");
+ }
+ Assert.equal(
+ sanitize(testInput),
+ URIInfo.originalInput,
+ "should mirror original input"
+ );
+ }
+ }
+}
diff --git a/docshell/test/unit/test_URIFixup_search.js b/docshell/test/unit/test_URIFixup_search.js
new file mode 100644
index 0000000000..05a7b2e0b3
--- /dev/null
+++ b/docshell/test/unit/test_URIFixup_search.js
@@ -0,0 +1,142 @@
+const { AppConstants } = ChromeUtils.import(
+ "resource://gre/modules/AppConstants.jsm"
+);
+
+var isWin = AppConstants.platform == "win";
+
+var data = [
+ {
+ // Valid should not be changed.
+ wrong: "https://example.com/this/is/a/test.html",
+ fixed: "https://example.com/this/is/a/test.html",
+ },
+ {
+ // Unrecognized protocols should be changed.
+ wrong: "whatever://this/is/a/test.html",
+ fixed: kSearchEngineURL.replace(
+ "{searchTerms}",
+ encodeURIComponent("whatever://this/is/a/test.html")
+ ),
+ },
+
+ {
+ // Unrecognized protocols should be changed.
+ wrong: "whatever://this/is/a/test.html",
+ fixed: kPrivateSearchEngineURL.replace(
+ "{searchTerms}",
+ encodeURIComponent("whatever://this/is/a/test.html")
+ ),
+ inPrivateBrowsing: true,
+ },
+
+ // The following tests check that when a user:password is present in the URL
+ // `user:` isn't treated as an unknown protocol thus leaking the user and
+ // password to the search engine.
+ {
+ wrong: "user:pass@example.com/this/is/a/test.html",
+ fixed: "http://user:pass@example.com/this/is/a/test.html",
+ },
+ {
+ wrong: "user@example.com:8080/this/is/a/test.html",
+ fixed: "http://user@example.com:8080/this/is/a/test.html",
+ },
+ {
+ wrong: "https:pass@example.com/this/is/a/test.html",
+ fixed: "https://pass@example.com/this/is/a/test.html",
+ },
+ {
+ wrong: "user:pass@example.com:8080/this/is/a/test.html",
+ fixed: "http://user:pass@example.com:8080/this/is/a/test.html",
+ },
+ {
+ wrong: "http:user:pass@example.com:8080/this/is/a/test.html",
+ fixed: "http://user:pass@example.com:8080/this/is/a/test.html",
+ },
+ {
+ wrong: "ttp:user:pass@example.com:8080/this/is/a/test.html",
+ fixed: "http://user:pass@example.com:8080/this/is/a/test.html",
+ },
+ {
+ wrong: "gobbledygook:user:pass@example.com:8080/this/is/a/test.html",
+ fixed:
+ "http://gobbledygook:user%3Apass@example.com:8080/this/is/a/test.html",
+ },
+ {
+ wrong: "user:@example.com:8080/this/is/a/test.html",
+ fixed: "http://user@example.com:8080/this/is/a/test.html",
+ },
+ {
+ wrong: "//user:pass@example.com:8080/this/is/a/test.html",
+ fixed:
+ (isWin ? "http:" : "file://") +
+ "//user:pass@example.com:8080/this/is/a/test.html",
+ },
+ {
+ wrong: "://user:pass@example.com:8080/this/is/a/test.html",
+ fixed: "http://user:pass@example.com:8080/this/is/a/test.html",
+ },
+ {
+ wrong: "localhost:8080/?param=1",
+ fixed: "http://localhost:8080/?param=1",
+ },
+ {
+ wrong: "localhost:8080?param=1",
+ fixed: "http://localhost:8080/?param=1",
+ },
+ {
+ wrong: "localhost:8080#somewhere",
+ fixed: "http://localhost:8080/#somewhere",
+ },
+ {
+ wrong: "whatever://this/is/a@b/test.html",
+ fixed: kSearchEngineURL.replace(
+ "{searchTerms}",
+ encodeURIComponent("whatever://this/is/a@b/test.html")
+ ),
+ },
+];
+
+var extProtocolSvc = Cc[
+ "@mozilla.org/uriloader/external-protocol-service;1"
+].getService(Ci.nsIExternalProtocolService);
+
+if (extProtocolSvc && extProtocolSvc.externalProtocolHandlerExists("mailto")) {
+ data.push({
+ wrong: "mailto:foo@bar.com",
+ fixed: "mailto:foo@bar.com",
+ });
+}
+
+var len = data.length;
+
+add_task(async function setup() {
+ await setupSearchService();
+ await addTestEngines();
+
+ Services.prefs.setBoolPref("keyword.enabled", true);
+ Services.prefs.setBoolPref("browser.search.separatePrivateDefault", true);
+ Services.prefs.setBoolPref(
+ "browser.search.separatePrivateDefault.ui.enabled",
+ true
+ );
+
+ await Services.search.setDefault(
+ Services.search.getEngineByName(kSearchEngineID)
+ );
+ await Services.search.setDefaultPrivate(
+ Services.search.getEngineByName(kPrivateSearchEngineID)
+ );
+});
+
+// Make sure we fix what needs fixing
+add_task(function test_fix_unknown_schemes() {
+ for (let i = 0; i < len; ++i) {
+ let item = data[i];
+ let flags = Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS;
+ if (item.inPrivateBrowsing) {
+ flags |= Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
+ }
+ let { preferredURI } = Services.uriFixup.getFixupURIInfo(item.wrong, flags);
+ Assert.equal(preferredURI.spec, item.fixed);
+ }
+});
diff --git a/docshell/test/unit/test_browsing_context_structured_clone.js b/docshell/test/unit/test_browsing_context_structured_clone.js
new file mode 100644
index 0000000000..d06f7aecf6
--- /dev/null
+++ b/docshell/test/unit/test_browsing_context_structured_clone.js
@@ -0,0 +1,68 @@
+"use strict";
+
+add_task(async function test_BrowsingContext_structured_clone() {
+ let browser = Services.appShell.createWindowlessBrowser(false);
+
+ let frame = browser.document.createElement("iframe");
+
+ await new Promise(r => {
+ frame.onload = () => r();
+ browser.document.body.appendChild(frame);
+ });
+
+ let { browsingContext } = frame;
+
+ let sch = new StructuredCloneHolder({ browsingContext });
+
+ let deserialize = () => sch.deserialize({}, true);
+
+ // Check that decoding a live browsing context produces the correct
+ // object.
+ equal(
+ deserialize().browsingContext,
+ browsingContext,
+ "Got correct browsing context from StructuredClone deserialize"
+ );
+
+ // Check that decoding a second time still succeeds.
+ equal(
+ deserialize().browsingContext,
+ browsingContext,
+ "Got correct browsing context from second StructuredClone deserialize"
+ );
+
+ // Destroy the browsing context and make sure that the decode fails
+ // with a DataCloneError.
+ //
+ // Making sure the BrowsingContext is actually destroyed by the time
+ // we do the second decode is a bit tricky. We obviously have clear
+ // our local references to it, and give the GC a chance to reap them.
+ // And we also, of course, have to destroy the frame that it belongs
+ // to, or its frame loader and window global would hold it alive.
+ //
+ // Beyond that, we don't *have* to reload or destroy the parent
+ // document, but we do anyway just to be safe.
+ //
+
+ frame.remove();
+ frame = null;
+ browsingContext = null;
+
+ browser.document.location.reload();
+ browser.close();
+
+ // We will schedule a precise GC and do both GC and CC a few times, to make
+ // sure we have completely destroyed the WindowGlobal actors (which keep
+ // references to their BrowsingContexts) in order
+ // to allow their (now snow-white) references to be collected.
+ await schedulePreciseGCAndForceCC(3);
+
+ // OK. We can be fairly confident that the BrowsingContext object
+ // stored in our structured clone data has been destroyed. Make sure
+ // that attempting to decode it again leads to the appropriate error.
+ Assert.throws(
+ deserialize,
+ e => e.name === "DataCloneError",
+ "Should get a DataCloneError when trying to decode a dead BrowsingContext"
+ );
+});
diff --git a/docshell/test/unit/test_bug442584.js b/docshell/test/unit/test_bug442584.js
new file mode 100644
index 0000000000..c109557f50
--- /dev/null
+++ b/docshell/test/unit/test_bug442584.js
@@ -0,0 +1,35 @@
+var prefetch = Cc["@mozilla.org/prefetch-service;1"].getService(
+ Ci.nsIPrefetchService
+);
+
+var ReferrerInfo = Components.Constructor(
+ "@mozilla.org/referrer-info;1",
+ "nsIReferrerInfo",
+ "init"
+);
+
+function run_test() {
+ // Fill up the queue
+ Services.prefs.setBoolPref("network.prefetch-next", true);
+ for (var i = 0; i < 5; i++) {
+ var uri = Services.io.newURI("http://localhost/" + i);
+ var referrerInfo = new ReferrerInfo(Ci.nsIReferrerInfo.EMPTY, true, uri);
+ prefetch.prefetchURI(uri, referrerInfo, null, true);
+ }
+
+ // Make sure the queue has items in it...
+ Assert.ok(prefetch.hasMoreElements());
+
+ // Now disable the pref to force the queue to empty...
+ Services.prefs.setBoolPref("network.prefetch-next", false);
+ Assert.ok(!prefetch.hasMoreElements());
+
+ // Now reenable the pref, and add more items to the queue.
+ Services.prefs.setBoolPref("network.prefetch-next", true);
+ for (var k = 0; k < 5; k++) {
+ var uri2 = Services.io.newURI("http://localhost/" + k);
+ var referrerInfo2 = new ReferrerInfo(Ci.nsIReferrerInfo.EMPTY, true, uri2);
+ prefetch.prefetchURI(uri2, referrerInfo2, null, true);
+ }
+ Assert.ok(prefetch.hasMoreElements());
+}
diff --git a/docshell/test/unit/test_pb_notification.js b/docshell/test/unit/test_pb_notification.js
new file mode 100644
index 0000000000..51cd3b95ff
--- /dev/null
+++ b/docshell/test/unit/test_pb_notification.js
@@ -0,0 +1,18 @@
+function destroy_transient_docshell() {
+ let windowlessBrowser = Services.appShell.createWindowlessBrowser(true);
+ windowlessBrowser.docShell.setOriginAttributes({ privateBrowsingId: 1 });
+ windowlessBrowser.close();
+ do_test_pending();
+ do_timeout(0, Cu.forceGC);
+}
+
+function run_test() {
+ var obs = {
+ observe(aSubject, aTopic, aData) {
+ Assert.equal(aTopic, "last-pb-context-exited");
+ do_test_finished();
+ },
+ };
+ Services.obs.addObserver(obs, "last-pb-context-exited");
+ destroy_transient_docshell();
+}
diff --git a/docshell/test/unit/test_privacy_transition.js b/docshell/test/unit/test_privacy_transition.js
new file mode 100644
index 0000000000..ae1bf71284
--- /dev/null
+++ b/docshell/test/unit/test_privacy_transition.js
@@ -0,0 +1,21 @@
+var gNotifications = 0;
+
+var observer = {
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIPrivacyTransitionObserver",
+ "nsISupportsWeakReference",
+ ]),
+
+ privateModeChanged(enabled) {
+ gNotifications++;
+ },
+};
+
+function run_test() {
+ let windowlessBrowser = Services.appShell.createWindowlessBrowser(true);
+ windowlessBrowser.docShell.addWeakPrivacyTransitionObserver(observer);
+ windowlessBrowser.docShell.setOriginAttributes({ privateBrowsingId: 1 });
+ windowlessBrowser.docShell.setOriginAttributes({ privateBrowsingId: 0 });
+ windowlessBrowser.close();
+ Assert.equal(gNotifications, 2);
+}
diff --git a/docshell/test/unit/xpcshell.ini b/docshell/test/unit/xpcshell.ini
new file mode 100644
index 0000000000..9052267bfa
--- /dev/null
+++ b/docshell/test/unit/xpcshell.ini
@@ -0,0 +1,16 @@
+[DEFAULT]
+head = head_docshell.js
+
+[test_bug442584.js]
+[test_browsing_context_structured_clone.js]
+[test_URIFixup.js]
+# Disabled for 1563343 -- URI fixup should be done at the app level in GV.
+skip-if = os == 'android'
+[test_URIFixup_search.js]
+skip-if = os == 'android'
+[test_URIFixup_info.js]
+skip-if = os == 'android'
+[test_pb_notification.js]
+# Bug 751575: unrelated JS changes cause timeouts on random platforms
+skip-if = true
+[test_privacy_transition.js]