diff options
Diffstat (limited to 'browser/components/privatebrowsing')
60 files changed, 4253 insertions, 0 deletions
diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.css b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.css new file mode 100644 index 0000000000..26d143a7b0 --- /dev/null +++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.css @@ -0,0 +1,8 @@ +/* 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/. */ + +html.private .showNormal, +html.normal .showPrivate { + display: none !important; +} diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html new file mode 100644 index 0000000000..4d22812723 --- /dev/null +++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html @@ -0,0 +1,64 @@ +<!-- +# 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/. +--> +<!DOCTYPE html> + +<html xmlns="http://www.w3.org/1999/xhtml" class="private"> + <head> + <meta http-equiv="Content-Security-Policy" content="default-src chrome: blob:; object-src 'none'"/> + <link rel="icon" href="chrome://browser/skin/privatebrowsing/favicon.svg"/> + <link rel="stylesheet" href="chrome://browser/content/aboutPrivateBrowsing.css" media="all"/> + <link rel="stylesheet" href="chrome://browser/skin/privatebrowsing/aboutPrivateBrowsing.css" media="all"/> + <link rel="localization" href="branding/brand.ftl"/> + <link rel="localization" href="browser/branding/brandings.ftl"> + <link rel="localization" href="browser/aboutPrivateBrowsing.ftl"/> + <script src="chrome://browser/content/aboutPrivateBrowsing.js"></script> + <script src="chrome://browser/content/contentSearchHandoffUI.js"></script> + </head> + + <body> + <p class="showNormal" data-l10n-id="about-private-browsing-not-private"></p> + <button id="startPrivateBrowsing" + class="showNormal" data-l10n-id="privatebrowsingpage-open-private-window-label"></button> + <div id="search-banner" class="search-banner" + hidden="true"> + <button id="search-banner-close-button" + class="search-banner-close-button" + data-l10n-id="about-private-browsing-search-banner-close-button"> + <img class="search-banner-close-image" src="chrome://global/skin/icons/close.svg"/> + </button> + <div class="banner-body"> + <h1 id="about-private-browsing-search-banner-title" + data-l10n-id="about-private-browsing-search-banner-title" + data-l10n-args='{"engineName": ""}'></h1> + <p id="about-private-browsing-search-banner-description" + data-l10n-id="about-private-browsing-search-banner-description"> + <a href="" id="open-search-options-link" data-l10n-name="link-options"></a> + </p> + </div> + </div> + <div class="showPrivate showSearch container"> + <div class="logo-and-wordmark"> + <div class="logo"></div> + <div class="wordmark"></div> + </div> + <div class="search-inner-wrapper"> + <button id="search-handoff-button" class="search-handoff-button" tabindex="-1" data-l10n-id="about-private-browsing"> + <div class="fake-textbox" data-l10n-id="about-private-browsing-search-placeholder"></div> + <input id="fake-editable" class="fake-editable" tabindex="-1" aria-hidden="true" /> + <div class="fake-caret"></div> + </button> + </div> + <div class="info"> + <h1 data-l10n-id="about-private-browsing-info-title"></h1> + <p data-l10n-id="about-private-browsing-info-description"></p> + <a id="private-browsing-myths" data-l10n-id="about-private-browsing-info-myths"></a> + </div> + </div> + + <p id="private-browsing-vpn-text" class="vpn-promo" data-l10n-id="about-private-browsing-need-more-privacy"></p> + <a id="private-browsing-vpn-link" class="vpn-promo" data-l10n-id="about-private-browsing-turn-on-vpn"></a> + </body> +</html> diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js new file mode 100644 index 0000000000..5d9b78b902 --- /dev/null +++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js @@ -0,0 +1,141 @@ +/* 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/. */ + +/* eslint-env mozilla/frame-script */ + +document.addEventListener("DOMContentLoaded", function() { + if (!RPMIsWindowPrivate()) { + document.documentElement.classList.remove("private"); + document.documentElement.classList.add("normal"); + document + .getElementById("startPrivateBrowsing") + .addEventListener("click", function() { + RPMSendAsyncMessage("OpenPrivateWindow"); + }); + return; + } + + // Setup the private browsing myths link. + document + .getElementById("private-browsing-myths") + .setAttribute( + "href", + RPMGetFormatURLPref("app.support.baseURL") + "private-browsing-myths" + ); + + // Setup the private browsing VPN link. + const vpnPromoUrl = RPMGetFormatURLPref( + "browser.privatebrowsing.vpnpromourl" + ); + if (vpnPromoUrl) { + document + .getElementById("private-browsing-vpn-link") + .setAttribute("href", vpnPromoUrl); + } else { + // If the link is undefined, remove the promo completely + document.querySelectorAll(".vpn-promo").forEach(vpnEl => vpnEl.remove()); + } + + // Check ShouldShowVPNPromo + RPMSendQuery("ShouldShowVPNPromo", {}).then(shouldShow => { + if (!shouldShow) { + document.querySelectorAll(".vpn-promo").forEach(vpnEl => vpnEl.remove()); + } + }); + + // Set up the private search banner. + const privateSearchBanner = document.getElementById("search-banner"); + + RPMSendQuery("ShouldShowSearchBanner", {}).then(engineName => { + if (engineName) { + document.l10n.setAttributes( + document.getElementById("about-private-browsing-search-banner-title"), + "about-private-browsing-search-banner-title", + { engineName } + ); + privateSearchBanner.removeAttribute("hidden"); + document.body.classList.add("showBanner"); + } + + // We set this attribute so that tests know when we are done. + document.documentElement.setAttribute("SearchBannerInitialized", true); + }); + + function hideSearchBanner() { + privateSearchBanner.setAttribute("hidden", "true"); + document.body.classList.remove("showBanner"); + RPMSendAsyncMessage("SearchBannerDismissed"); + } + + document + .getElementById("search-banner-close-button") + .addEventListener("click", () => { + hideSearchBanner(); + }); + + let openSearchOptions = document.getElementById( + "about-private-browsing-search-banner-description" + ); + let openSearchOptionsEvtHandler = evt => { + if ( + evt.target.id == "open-search-options-link" && + (evt.keyCode == evt.DOM_VK_RETURN || evt.type == "click") + ) { + RPMSendAsyncMessage("OpenSearchPreferences"); + hideSearchBanner(); + } + }; + openSearchOptions.addEventListener("click", openSearchOptionsEvtHandler); + openSearchOptions.addEventListener("keypress", openSearchOptionsEvtHandler); + + // Setup the search hand-off box. + let btn = document.getElementById("search-handoff-button"); + let editable = document.getElementById("fake-editable"); + let HIDE_SEARCH_TOPIC = "HideSearch"; + let SHOW_SEARCH_TOPIC = "ShowSearch"; + let SEARCH_HANDOFF_TOPIC = "SearchHandoff"; + + function showSearch() { + btn.classList.remove("focused"); + btn.classList.remove("hidden"); + RPMRemoveMessageListener(SHOW_SEARCH_TOPIC, showSearch); + } + + function hideSearch() { + btn.classList.add("hidden"); + } + + function handoffSearch(text) { + RPMSendAsyncMessage(SEARCH_HANDOFF_TOPIC, { text }); + RPMAddMessageListener(SHOW_SEARCH_TOPIC, showSearch); + if (text) { + hideSearch(); + } else { + btn.classList.add("focused"); + RPMAddMessageListener(HIDE_SEARCH_TOPIC, hideSearch); + } + } + btn.addEventListener("focus", function() { + handoffSearch(); + }); + btn.addEventListener("click", function() { + handoffSearch(); + }); + + // Hand-off any text that gets dropped or pasted + editable.addEventListener("drop", function(ev) { + ev.preventDefault(); + let text = ev.dataTransfer.getData("text"); + if (text) { + handoffSearch(text); + } + }); + editable.addEventListener("paste", function(ev) { + ev.preventDefault(); + handoffSearch(ev.clipboardData.getData("Text")); + }); + + // Load contentSearchUI so it sets the search engine icon for us. + new window.ContentSearchHandoffUIController(); +}); diff --git a/browser/components/privatebrowsing/jar.mn b/browser/components/privatebrowsing/jar.mn new file mode 100644 index 0000000000..0b54263264 --- /dev/null +++ b/browser/components/privatebrowsing/jar.mn @@ -0,0 +1,8 @@ +# 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/. + +browser.jar: + content/browser/aboutPrivateBrowsing.css (content/aboutPrivateBrowsing.css) + content/browser/aboutPrivateBrowsing.html (content/aboutPrivateBrowsing.html) + content/browser/aboutPrivateBrowsing.js (content/aboutPrivateBrowsing.js) diff --git a/browser/components/privatebrowsing/moz.build b/browser/components/privatebrowsing/moz.build new file mode 100644 index 0000000000..7078f7e4db --- /dev/null +++ b/browser/components/privatebrowsing/moz.build @@ -0,0 +1,14 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +BROWSER_CHROME_MANIFESTS += [ + "test/browser/browser.ini", +] + +JAR_MANIFESTS += ["jar.mn"] + +with Files("**"): + BUG_COMPONENT = ("Firefox", "Private Browsing") diff --git a/browser/components/privatebrowsing/test/browser/browser.ini b/browser/components/privatebrowsing/test/browser/browser.ini new file mode 100644 index 0000000000..a2938f3c9e --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser.ini @@ -0,0 +1,64 @@ +[DEFAULT] +tags = openwindow +support-files = + browser_privatebrowsing_concurrent_page.html + browser_privatebrowsing_geoprompt_page.html + browser_privatebrowsing_xrprompt_page.html + browser_privatebrowsing_localStorage_before_after_page.html + browser_privatebrowsing_localStorage_before_after_page2.html + browser_privatebrowsing_localStorage_page1.html + browser_privatebrowsing_localStorage_page2.html + browser_privatebrowsing_placesTitleNoUpdate.html + browser_privatebrowsing_protocolhandler_page.html + browser_privatebrowsing_windowtitle_page.html + head.js + popup.html + title.sjs + empty_file.html + file_favicon.html + file_favicon.png + file_favicon.png^headers^ + file_triggeringprincipal_oa.html + +[browser_privatebrowsing_DownloadLastDirWithCPS.js] +[browser_privatebrowsing_about.js] +skip-if = verify +tags = trackingprotection +[browser_privatebrowsing_about_search_banner.js] +[browser_privatebrowsing_aboutSessionRestore.js] +[browser_privatebrowsing_cache.js] +[browser_privatebrowsing_certexceptionsui.js] +[browser_privatebrowsing_cleanup.js] +[browser_privatebrowsing_concurrent.js] +skip-if = release_or_beta +[browser_privatebrowsing_context_and_chromeFlags.js] +[browser_privatebrowsing_crh.js] +[browser_privatebrowsing_downloadLastDir.js] +skip-if = verify +[browser_privatebrowsing_downloadLastDir_c.js] +[browser_privatebrowsing_downloadLastDir_toggle.js] +[browser_privatebrowsing_favicon.js] +[browser_privatebrowsing_history_shift_click.js] +[browser_privatebrowsing_lastpbcontextexited.js] +[browser_privatebrowsing_localStorage.js] +[browser_privatebrowsing_localStorage_before_after.js] +[browser_privatebrowsing_noSessionRestoreMenuOption.js] +[browser_privatebrowsing_nonbrowser.js] +[browser_privatebrowsing_opendir.js] +[browser_privatebrowsing_placesTitleNoUpdate.js] +[browser_privatebrowsing_placestitle.js] +[browser_privatebrowsing_popupblocker.js] +[browser_privatebrowsing_protocolhandler.js] +[browser_privatebrowsing_rememberprompt.js] +tags = geolocation xr +[browser_privatebrowsing_sidebar.js] +[browser_privatebrowsing_theming.js] +[browser_privatebrowsing_ui.js] +[browser_privatebrowsing_urlbarfocus.js] +[browser_privatebrowsing_windowtitle.js] +[browser_privatebrowsing_zoom.js] +[browser_privatebrowsing_zoomrestore.js] +[browser_privatebrowsing_newtab_from_popup.js] +skip-if = (!e10s && os == "win" && (bits == 64)) # Bug 1354865 +[browser_privatebrowsing_blobUrl.js] +[browser_oa_private_browsing_window.js] diff --git a/browser/components/privatebrowsing/test/browser/browser_oa_private_browsing_window.js b/browser/components/privatebrowsing/test/browser/browser_oa_private_browsing_window.js new file mode 100644 index 0000000000..82ae693ce2 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_oa_private_browsing_window.js @@ -0,0 +1,64 @@ +"use strict"; + +const PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); +const TEST_PAGE = PATH + "file_triggeringprincipal_oa.html"; +const DUMMY_PAGE = PATH + "empty_file.html"; + +add_task( + async function test_principal_right_click_open_link_in_new_private_win() { + await BrowserTestUtils.withNewTab(TEST_PAGE, async function(browser) { + let promiseNewWindow = BrowserTestUtils.waitForNewWindow({ + url: DUMMY_PAGE, + }); + + // simulate right-click open link in new private window + BrowserTestUtils.waitForEvent(document, "popupshown", false, event => { + document.getElementById("context-openlinkprivate").doCommand(); + event.target.hidePopup(); + return true; + }); + BrowserTestUtils.synthesizeMouseAtCenter( + "#checkPrincipalOA", + { type: "contextmenu", button: 2 }, + gBrowser.selectedBrowser + ); + let privateWin = await promiseNewWindow; + + await SpecialPowers.spawn( + privateWin.gBrowser.selectedBrowser, + [{ DUMMY_PAGE, TEST_PAGE }], + // eslint-disable-next-line no-shadow + async function({ DUMMY_PAGE, TEST_PAGE }) { + // eslint-disable-line + + let channel = content.docShell.currentDocumentChannel; + is( + channel.URI.spec, + DUMMY_PAGE, + "sanity check to ensure we check principal for right URI" + ); + + let triggeringPrincipal = channel.loadInfo.triggeringPrincipal; + ok( + triggeringPrincipal.isContentPrincipal, + "sanity check to ensure principal is a contentPrincipal" + ); + is( + triggeringPrincipal.spec, + TEST_PAGE, + "test page must be the triggering page" + ); + is( + triggeringPrincipal.originAttributes.privateBrowsingId, + 1, + "must have correct privateBrowsingId" + ); + } + ); + await BrowserTestUtils.closeWindow(privateWin); + }); + } +); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js new file mode 100644 index 0000000000..1a406f27f9 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js @@ -0,0 +1,445 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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 gTests; +function test() { + waitForExplicitFinish(); + requestLongerTimeout(2); + runTest().catch(ex => ok(false, ex)); +} + +/* + * ================ + * Helper functions + * ================ + */ + +function createWindow(aOptions) { + return new Promise(resolve => whenNewWindowLoaded(aOptions, resolve)); +} + +function getFile(downloadLastDir, aURI) { + return new Promise(resolve => downloadLastDir.getFileAsync(aURI, resolve)); +} + +function setFile(downloadLastDir, aURI, aValue) { + downloadLastDir.setFile(aURI, aValue); + return new Promise(resolve => executeSoon(resolve)); +} + +function clearHistoryAndWait() { + clearHistory(); + return new Promise(resolve => executeSoon(_ => executeSoon(resolve))); +} + +/* + * =================== + * Function with tests + * =================== + */ + +async function runTest() { + let FileUtils = ChromeUtils.import("resource://gre/modules/FileUtils.jsm", {}) + .FileUtils; + let DownloadLastDir = ChromeUtils.import( + "resource://gre/modules/DownloadLastDir.jsm", + {} + ).DownloadLastDir; + + let tmpDir = FileUtils.getDir("TmpD", [], true); + let dir1 = newDirectory(); + let dir2 = newDirectory(); + let dir3 = newDirectory(); + + let uri1 = Services.io.newURI("http://test1.com/"); + let uri2 = Services.io.newURI("http://test2.com/"); + let uri3 = Services.io.newURI("http://test3.com/"); + let uri4 = Services.io.newURI("http://test4.com/"); + + // cleanup functions registration + registerCleanupFunction(function() { + Services.prefs.clearUserPref("browser.download.lastDir.savePerSite"); + Services.prefs.clearUserPref("browser.download.lastDir"); + [dir1, dir2, dir3].forEach(dir => dir.remove(true)); + win.close(); + pbWin.close(); + }); + + function checkDownloadLastDir(gDownloadLastDir, aLastDir) { + is( + gDownloadLastDir.file.path, + aLastDir.path, + "gDownloadLastDir should point to the expected last directory" + ); + return getFile(gDownloadLastDir, uri1); + } + + function checkDownloadLastDirNull(gDownloadLastDir) { + is(gDownloadLastDir.file, null, "gDownloadLastDir should be null"); + return getFile(gDownloadLastDir, uri1); + } + + /* + * ================================ + * Create a regular and a PB window + * ================================ + */ + + let win = await createWindow({ private: false }); + let pbWin = await createWindow({ private: true }); + + let downloadLastDir = new DownloadLastDir(win); + let pbDownloadLastDir = new DownloadLastDir(pbWin); + + /* + * ================== + * Beginning of tests + * ================== + */ + + is( + typeof downloadLastDir, + "object", + "downloadLastDir should be a valid object" + ); + is(downloadLastDir.file, null, "LastDir pref should be null to start with"); + + // set up last dir + await setFile(downloadLastDir, null, tmpDir); + is( + downloadLastDir.file.path, + tmpDir.path, + "LastDir should point to the tmpDir" + ); + isnot( + downloadLastDir.file, + tmpDir, + "downloadLastDir.file should not be pointing to tmpDir" + ); + + // set uri1 to dir1, all should now return dir1 + // also check that a new object is returned + await setFile(downloadLastDir, uri1, dir1); + is( + downloadLastDir.file.path, + dir1.path, + "downloadLastDir should return dir1" + ); + isnot( + downloadLastDir.file, + dir1, + "downloadLastDir.file should not return dir1" + ); + is( + (await getFile(downloadLastDir, uri1)).path, + dir1.path, + "uri1 should return dir1" + ); // set in CPS + isnot( + await getFile(downloadLastDir, uri1), + dir1, + "getFile on uri1 should not return dir1" + ); + is( + (await getFile(downloadLastDir, uri2)).path, + dir1.path, + "uri2 should return dir1" + ); // fallback + isnot( + await getFile(downloadLastDir, uri2), + dir1, + "getFile on uri2 should not return dir1" + ); + is( + (await getFile(downloadLastDir, uri3)).path, + dir1.path, + "uri3 should return dir1" + ); // fallback + isnot( + await getFile(downloadLastDir, uri3), + dir1, + "getFile on uri3 should not return dir1" + ); + is( + (await getFile(downloadLastDir, uri4)).path, + dir1.path, + "uri4 should return dir1" + ); // fallback + isnot( + await getFile(downloadLastDir, uri4), + dir1, + "getFile on uri4 should not return dir1" + ); + + // set uri2 to dir2, all except uri1 should now return dir2 + await setFile(downloadLastDir, uri2, dir2); + is( + downloadLastDir.file.path, + dir2.path, + "downloadLastDir should point to dir2" + ); + is( + (await getFile(downloadLastDir, uri1)).path, + dir1.path, + "uri1 should return dir1" + ); // set in CPS + is( + (await getFile(downloadLastDir, uri2)).path, + dir2.path, + "uri2 should return dir2" + ); // set in CPS + is( + (await getFile(downloadLastDir, uri3)).path, + dir2.path, + "uri3 should return dir2" + ); // fallback + is( + (await getFile(downloadLastDir, uri4)).path, + dir2.path, + "uri4 should return dir2" + ); // fallback + + // set uri3 to dir3, all except uri1 and uri2 should now return dir3 + await setFile(downloadLastDir, uri3, dir3); + is( + downloadLastDir.file.path, + dir3.path, + "downloadLastDir should point to dir3" + ); + is( + (await getFile(downloadLastDir, uri1)).path, + dir1.path, + "uri1 should return dir1" + ); // set in CPS + is( + (await getFile(downloadLastDir, uri2)).path, + dir2.path, + "uri2 should return dir2" + ); // set in CPS + is( + (await getFile(downloadLastDir, uri3)).path, + dir3.path, + "uri3 should return dir3" + ); // set in CPS + is( + (await getFile(downloadLastDir, uri4)).path, + dir3.path, + "uri4 should return dir4" + ); // fallback + + // set uri1 to dir2, all except uri3 should now return dir2 + await setFile(downloadLastDir, uri1, dir2); + is( + downloadLastDir.file.path, + dir2.path, + "downloadLastDir should point to dir2" + ); + is( + (await getFile(downloadLastDir, uri1)).path, + dir2.path, + "uri1 should return dir2" + ); // set in CPS + is( + (await getFile(downloadLastDir, uri2)).path, + dir2.path, + "uri2 should return dir2" + ); // set in CPS + is( + (await getFile(downloadLastDir, uri3)).path, + dir3.path, + "uri3 should return dir3" + ); // set in CPS + is( + (await getFile(downloadLastDir, uri4)).path, + dir2.path, + "uri4 should return dir2" + ); // fallback + + await clearHistoryAndWait(); + + // check clearHistory removes all data + is(downloadLastDir.file, null, "clearHistory removes all data"); + is(await getFile(downloadLastDir, uri1), null, "uri1 should point to null"); + is(await getFile(downloadLastDir, uri2), null, "uri2 should point to null"); + is(await getFile(downloadLastDir, uri3), null, "uri3 should point to null"); + is(await getFile(downloadLastDir, uri4), null, "uri4 should point to null"); + + await setFile(downloadLastDir, null, tmpDir); + + // check data set outside PB mode is remembered + is( + (await checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, + tmpDir.path, + "uri1 should return the expected last directory" + ); + is( + (await checkDownloadLastDir(downloadLastDir, tmpDir)).path, + tmpDir.path, + "uri1 should return the expected last directory" + ); + await clearHistoryAndWait(); + + await setFile(downloadLastDir, uri1, dir1); + + // check data set using CPS outside PB mode is remembered + is( + (await checkDownloadLastDir(pbDownloadLastDir, dir1)).path, + dir1.path, + "uri1 should return the expected last directory" + ); + is( + (await checkDownloadLastDir(downloadLastDir, dir1)).path, + dir1.path, + "uri1 should return the expected last directory" + ); + await clearHistoryAndWait(); + + // check data set inside PB mode is forgotten + await setFile(pbDownloadLastDir, null, tmpDir); + + is( + (await checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, + tmpDir.path, + "uri1 should return the expected last directory" + ); + is( + await checkDownloadLastDirNull(downloadLastDir), + null, + "uri1 should return the expected last directory" + ); + + await clearHistoryAndWait(); + + // check data set using CPS inside PB mode is forgotten + await setFile(pbDownloadLastDir, uri1, dir1); + + is( + (await checkDownloadLastDir(pbDownloadLastDir, dir1)).path, + dir1.path, + "uri1 should return the expected last directory" + ); + is( + await checkDownloadLastDirNull(downloadLastDir), + null, + "uri1 should return the expected last directory" + ); + + // check data set outside PB mode but changed inside is remembered correctly + await setFile(downloadLastDir, uri1, dir1); + await setFile(pbDownloadLastDir, uri1, dir2); + is( + (await checkDownloadLastDir(pbDownloadLastDir, dir2)).path, + dir2.path, + "uri1 should return the expected last directory" + ); + is( + (await checkDownloadLastDir(downloadLastDir, dir1)).path, + dir1.path, + "uri1 should return the expected last directory" + ); + + /* + * ==================== + * Create new PB window + * ==================== + */ + + // check that the last dir store got cleared in a new PB window + pbWin.close(); + // And give it time to close + await new Promise(resolve => executeSoon(resolve)); + + pbWin = await createWindow({ private: true }); + pbDownloadLastDir = new DownloadLastDir(pbWin); + + is( + (await checkDownloadLastDir(pbDownloadLastDir, dir1)).path, + dir1.path, + "uri1 should return the expected last directory" + ); + + await clearHistoryAndWait(); + + // check clearHistory inside PB mode clears data outside PB mode + await setFile(pbDownloadLastDir, uri1, dir2); + + await clearHistoryAndWait(); + + is( + await checkDownloadLastDirNull(downloadLastDir), + null, + "uri1 should return the expected last directory" + ); + is( + await checkDownloadLastDirNull(pbDownloadLastDir), + null, + "uri1 should return the expected last directory" + ); + + // check that disabling CPS works + Services.prefs.setBoolPref("browser.download.lastDir.savePerSite", false); + + await setFile(downloadLastDir, uri1, dir1); + is(downloadLastDir.file.path, dir1.path, "LastDir should be set to dir1"); + is( + (await getFile(downloadLastDir, uri1)).path, + dir1.path, + "uri1 should return dir1" + ); + is( + (await getFile(downloadLastDir, uri2)).path, + dir1.path, + "uri2 should return dir1" + ); + is( + (await getFile(downloadLastDir, uri3)).path, + dir1.path, + "uri3 should return dir1" + ); + is( + (await getFile(downloadLastDir, uri4)).path, + dir1.path, + "uri4 should return dir1" + ); + + downloadLastDir.setFile(uri2, dir2); + is(downloadLastDir.file.path, dir2.path, "LastDir should be set to dir2"); + is( + (await getFile(downloadLastDir, uri1)).path, + dir2.path, + "uri1 should return dir2" + ); + is( + (await getFile(downloadLastDir, uri2)).path, + dir2.path, + "uri2 should return dir2" + ); + is( + (await getFile(downloadLastDir, uri3)).path, + dir2.path, + "uri3 should return dir2" + ); + is( + (await getFile(downloadLastDir, uri4)).path, + dir2.path, + "uri4 should return dir2" + ); + + Services.prefs.clearUserPref("browser.download.lastDir.savePerSite"); + + // check that passing null to setFile clears the stored value + await setFile(downloadLastDir, uri3, dir3); + is( + (await getFile(downloadLastDir, uri3)).path, + dir3.path, + "LastDir should be set to dir3" + ); + await setFile(downloadLastDir, uri3, null); + is(await getFile(downloadLastDir, uri3), null, "uri3 should return null"); + + await clearHistoryAndWait(); + + finish(); +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js new file mode 100644 index 0000000000..5cb3de6b51 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js @@ -0,0 +1,206 @@ +/* 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/. */ + +XPCOMUtils.defineLazyModuleGetters(this, { + UrlbarUtils: "resource:///modules/UrlbarUtils.jsm", +}); + +XPCOMUtils.defineLazyGetter(this, "UrlbarTestUtils", () => { + const { UrlbarTestUtils: module } = ChromeUtils.import( + "resource://testing-common/UrlbarTestUtils.jsm" + ); + module.init(this); + return module; +}); + +/** + * Clicks the given link and checks this opens the given URI in the same tab. + * + * This function does not return to the previous page. + */ +async function testLinkOpensUrl({ win, tab, elementId, expectedUrl }) { + let loadedPromise = BrowserTestUtils.browserLoaded(tab); + await SpecialPowers.spawn(tab, [elementId], async function(elemId) { + content.document.getElementById(elemId).click(); + }); + await loadedPromise; + is( + tab.currentURI.spec, + expectedUrl, + `Clicking ${elementId} opened ${expectedUrl} in the same tab.` + ); +} + +let expectedEngineAlias; +let expectedIconURL; + +add_task(async function setup() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.search.separatePrivateDefault", true]], + }); + + const originalPrivateDefault = await Services.search.getDefaultPrivate(); + // We have to use a built-in engine as we are currently hard-coding the aliases. + const privateEngine = await Services.search.getEngineByName("DuckDuckGo"); + await Services.search.setDefaultPrivate(privateEngine); + expectedEngineAlias = privateEngine.aliases[0]; + expectedIconURL = privateEngine.iconURI.spec; + + registerCleanupFunction(async () => { + await Services.search.setDefaultPrivate(originalPrivateDefault); + }); +}); + +/** + * Tests the private-browsing-myths link in "about:privatebrowsing". + */ +add_task(async function test_myths_link() { + Services.prefs.setCharPref("app.support.baseURL", "https://example.com/"); + registerCleanupFunction(function() { + Services.prefs.clearUserPref("app.support.baseURL"); + }); + + let { win, tab } = await openAboutPrivateBrowsing(); + + await testLinkOpensUrl({ + win, + tab, + elementId: "private-browsing-myths", + expectedUrl: "https://example.com/private-browsing-myths", + }); + + await BrowserTestUtils.closeWindow(win); +}); + +function urlBarHasHiddenFocus(win) { + return win.gURLBar.focused && !win.gURLBar.hasAttribute("focused"); +} + +function urlBarHasNormalFocus(win) { + return win.gURLBar.hasAttribute("focused"); +} + +/** + * Tests that we have the correct icon displayed. + */ +add_task(async function test_search_icon() { + let { win, tab } = await openAboutPrivateBrowsing(); + + await SpecialPowers.spawn(tab, [expectedIconURL], async function(iconURL) { + is( + content.document.body.getAttribute("style"), + `--newtab-search-icon:url(${iconURL});`, + "Should have the correct icon URL for the logo" + ); + }); + + await BrowserTestUtils.closeWindow(win); +}); + +/** + * Tests the search hand-off on character keydown in "about:privatebrowsing". + */ +add_task(async function test_search_handoff_on_keydown() { + let { win, tab } = await openAboutPrivateBrowsing(); + + await SpecialPowers.spawn(tab, [], async function() { + let btn = content.document.getElementById("search-handoff-button"); + btn.click(); + ok(btn.classList.contains("focused"), "in-content search has focus styles"); + }); + ok(urlBarHasHiddenFocus(win), "url bar has hidden focused"); + + // Expect two searches, one to enter search mode and then another in search + // mode. + let searchPromise = UrlbarTestUtils.promiseSearchComplete(win); + + await new Promise(r => EventUtils.synthesizeKey("f", {}, win, r)); + await SpecialPowers.spawn(tab, [], async function() { + ok( + content.document + .getElementById("search-handoff-button") + .classList.contains("hidden"), + "in-content search is hidden" + ); + }); + await searchPromise; + ok(urlBarHasNormalFocus(win), "url bar has normal focused"); + await UrlbarTestUtils.assertSearchMode(win, { + engineName: "DuckDuckGo", + source: UrlbarUtils.RESULT_SOURCE.SEARCH, + entry: "handoff", + }); + is(win.gURLBar.value, "f", "url bar has search text"); + + // Close the popup. + await UrlbarTestUtils.exitSearchMode(win); + await UrlbarTestUtils.promisePopupClose(win); + + // Hitting ESC should reshow the in-content search + await new Promise(r => EventUtils.synthesizeKey("KEY_Escape", {}, win, r)); + await SpecialPowers.spawn(tab, [], async function() { + ok( + !content.document + .getElementById("search-handoff-button") + .classList.contains("hidden"), + "in-content search is not hidden" + ); + }); + + await BrowserTestUtils.closeWindow(win); +}); + +/** + * Tests the search hand-off on composition start in "about:privatebrowsing". + */ +add_task(async function test_search_handoff_on_composition_start() { + let { win, tab } = await openAboutPrivateBrowsing(); + + await SpecialPowers.spawn(tab, [], async function() { + content.document.getElementById("search-handoff-button").click(); + }); + ok(urlBarHasHiddenFocus(win), "url bar has hidden focused"); + await new Promise(r => + EventUtils.synthesizeComposition({ type: "compositionstart" }, win, r) + ); + ok(urlBarHasNormalFocus(win), "url bar has normal focused"); + + await BrowserTestUtils.closeWindow(win); +}); + +/** + * Tests the search hand-off on paste in "about:privatebrowsing". + */ +add_task(async function test_search_handoff_on_paste() { + let { win, tab } = await openAboutPrivateBrowsing(); + + await SpecialPowers.spawn(tab, [], async function() { + content.document.getElementById("search-handoff-button").click(); + }); + ok(urlBarHasHiddenFocus(win), "url bar has hidden focused"); + var helper = SpecialPowers.Cc[ + "@mozilla.org/widget/clipboardhelper;1" + ].getService(SpecialPowers.Ci.nsIClipboardHelper); + helper.copyString("words"); + + // Expect two searches, one to enter search mode and then another in search + // mode. + let searchPromise = UrlbarTestUtils.promiseSearchComplete(win); + + await new Promise(r => + EventUtils.synthesizeKey("v", { accelKey: true }, win, r) + ); + + await searchPromise; + + ok(urlBarHasNormalFocus(win), "url bar has normal focused"); + await UrlbarTestUtils.assertSearchMode(win, { + engineName: "DuckDuckGo", + source: UrlbarUtils.RESULT_SOURCE.SEARCH, + entry: "handoff", + }); + is(win.gURLBar.value, "words", "url bar has search text"); + + await BrowserTestUtils.closeWindow(win); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutSessionRestore.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutSessionRestore.js new file mode 100644 index 0000000000..eb19d1b1fd --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutSessionRestore.js @@ -0,0 +1,25 @@ +/* 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 checks that the session restore button from about:sessionrestore +// is disabled in private mode +add_task(async function testNoSessionRestoreButton() { + // Opening, then closing, a private window shouldn't create session data. + (await BrowserTestUtils.openNewBrowserWindow({ private: true })).close(); + + let win = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + let tab = BrowserTestUtils.addTab(win.gBrowser, "about:sessionrestore"); + let browser = tab.linkedBrowser; + + await BrowserTestUtils.browserLoaded(browser); + + await SpecialPowers.spawn(browser, [], async function() { + Assert.ok( + content.document.getElementById("errorTryAgain").disabled, + "The Restore about:sessionrestore button should be disabled" + ); + }); + + win.close(); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about_search_banner.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about_search_banner.js new file mode 100644 index 0000000000..d36f52a730 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about_search_banner.js @@ -0,0 +1,317 @@ +/* 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 about:privatebrowsing correctly shows the search +// banner. + +const { AboutPrivateBrowsingParent } = ChromeUtils.import( + "resource:///actors/AboutPrivateBrowsingParent.jsm" +); + +const PREF_UI_ENABLED = "browser.search.separatePrivateDefault.ui.enabled"; +const PREF_BANNER_SHOWN = + "browser.search.separatePrivateDefault.ui.banner.shown"; +const PREF_MAX_SEARCH_BANNER_SHOW_COUNT = + "browser.search.separatePrivateDefault.ui.banner.max"; +const MAX_SHOW_COUNT = 5; + +add_task(async function setup() { + SpecialPowers.pushPrefEnv({ + set: [ + [PREF_UI_ENABLED, false], + [PREF_BANNER_SHOWN, 0], + [PREF_MAX_SEARCH_BANNER_SHOW_COUNT, MAX_SHOW_COUNT], + ], + }); + + AboutPrivateBrowsingParent.setShownThisSession(false); +}); + +add_task(async function test_not_shown_if_pref_off() { + SpecialPowers.pushPrefEnv({ + set: [ + [PREF_UI_ENABLED, false], + [PREF_MAX_SEARCH_BANNER_SHOW_COUNT, 5], + ], + }); + + const { win, tab } = await openAboutPrivateBrowsing(); + + await SpecialPowers.spawn(tab, [], async function() { + await ContentTaskUtils.waitForCondition( + () => + content.document.documentElement.hasAttribute( + "SearchBannerInitialized" + ), + "Should have initialized" + ); + ok( + content.document.getElementById("search-banner").hasAttribute("hidden"), + "should be hiding the in-content search banner" + ); + }); + + await BrowserTestUtils.closeWindow(win); +}); + +add_task(async function test_not_shown_if_max_count_0() { + // To avoid having to restart Firefox and slow down tests, we manually reset + // the session pref. + AboutPrivateBrowsingParent.setShownThisSession(false); + + SpecialPowers.pushPrefEnv({ + set: [ + [PREF_UI_ENABLED, true], + [PREF_MAX_SEARCH_BANNER_SHOW_COUNT, 0], + ], + }); + const { win, tab } = await openAboutPrivateBrowsing(); + + await SpecialPowers.spawn(tab, [], async function() { + await ContentTaskUtils.waitForCondition( + () => + content.document.documentElement.hasAttribute( + "SearchBannerInitialized" + ), + "Should have initialized" + ); + ok( + content.document.getElementById("search-banner").hasAttribute("hidden"), + "should be hiding the in-content search banner" + ); + }); + + await BrowserTestUtils.closeWindow(win); +}); + +add_task(async function test_show_banner_first() { + // To avoid having to restart Firefox and slow down tests, we manually reset + // the session pref. + AboutPrivateBrowsingParent.setShownThisSession(false); + + SpecialPowers.pushPrefEnv({ + set: [ + [PREF_UI_ENABLED, true], + [PREF_MAX_SEARCH_BANNER_SHOW_COUNT, MAX_SHOW_COUNT], + ], + }); + + let prefChanged = TestUtils.waitForPrefChange(PREF_BANNER_SHOWN); + + const { win, tab } = await openAboutPrivateBrowsing(); + + Assert.equal( + await prefChanged, + 1, + "Should have incremented the amount of times shown." + ); + + await SpecialPowers.spawn(tab, [], async function() { + await ContentTaskUtils.waitForCondition( + () => + content.document.documentElement.hasAttribute( + "SearchBannerInitialized" + ), + "Should have initialized" + ); + + ok( + !content.document.getElementById("search-banner").hasAttribute("hidden"), + "should be showing the in-content search banner" + ); + }); + + await BrowserTestUtils.closeWindow(win); + + const { win: win1, tab: tab1 } = await openAboutPrivateBrowsing(); + + await SpecialPowers.spawn(tab1, [], async function() { + await ContentTaskUtils.waitForCondition( + () => + content.document.documentElement.hasAttribute( + "SearchBannerInitialized" + ), + "Should have initialized" + ); + + ok( + content.document.getElementById("search-banner").hasAttribute("hidden"), + "should not be showing the banner in a second window." + ); + }); + + await BrowserTestUtils.closeWindow(win1); + + Assert.equal( + Services.prefs.getIntPref(PREF_BANNER_SHOWN, -1), + 1, + "Should not have changed the preference further" + ); +}); + +add_task(async function test_show_banner_max_times() { + // We've already shown the UI once, so show it a few more times. + for (let i = 1; i < MAX_SHOW_COUNT; i++) { + // To avoid having to restart Firefox and slow down tests, we manually reset + // the session pref. + AboutPrivateBrowsingParent.setShownThisSession(false); + + let prefChanged = TestUtils.waitForPrefChange(PREF_BANNER_SHOWN); + const { win, tab } = await openAboutPrivateBrowsing(); + + Assert.equal( + await prefChanged, + i + 1, + "Should have incremented the amount of times shown." + ); + + await SpecialPowers.spawn(tab, [], async function() { + await ContentTaskUtils.waitForCondition( + () => + content.document.documentElement.hasAttribute( + "SearchBannerInitialized" + ), + "Should have initialized" + ); + + ok( + !content.document + .getElementById("search-banner") + .hasAttribute("hidden"), + "Should be showing the banner again" + ); + }); + + await BrowserTestUtils.closeWindow(win); + } + + // Final time! + + AboutPrivateBrowsingParent.setShownThisSession(false); + + const { win, tab } = await openAboutPrivateBrowsing(); + + await SpecialPowers.spawn(tab, [], async function() { + await ContentTaskUtils.waitForCondition( + () => + content.document.documentElement.hasAttribute( + "SearchBannerInitialized" + ), + "Should have initialized" + ); + + ok( + content.document.getElementById("search-banner").hasAttribute("hidden"), + "should not be showing the banner again" + ); + }); + + await BrowserTestUtils.closeWindow(win); +}); + +add_task(async function test_show_banner_close_no_more() { + SpecialPowers.pushPrefEnv({ + set: [[PREF_BANNER_SHOWN, 0]], + }); + + AboutPrivateBrowsingParent.setShownThisSession(false); + + const { win, tab } = await openAboutPrivateBrowsing(); + + await SpecialPowers.spawn(tab, [], async function() { + await ContentTaskUtils.waitForCondition( + () => + content.document.documentElement.hasAttribute( + "SearchBannerInitialized" + ), + "Should have initialized" + ); + + ok( + !content.document.getElementById("search-banner").hasAttribute("hidden"), + "should be showing the banner again before closing" + ); + + content.document.getElementById("search-banner-close-button").click(); + + await ContentTaskUtils.waitForCondition( + () => + ContentTaskUtils.is_hidden( + content.document.getElementById("search-banner") + ), + "should have closed the in-content search banner after clicking close" + ); + }); + + await BrowserTestUtils.closeWindow(win); + + Assert.equal( + Services.prefs.getIntPref(PREF_BANNER_SHOWN, -1), + MAX_SHOW_COUNT, + "Should have set the shown preference to the maximum" + ); +}); + +add_task(async function test_show_banner_open_preferences_and_no_more() { + SpecialPowers.pushPrefEnv({ + set: [[PREF_BANNER_SHOWN, 0]], + }); + + AboutPrivateBrowsingParent.setShownThisSession(false); + + const { win, tab } = await openAboutPrivateBrowsing(); + + // This is "borrowed" from the preferences test code, as waiting for the + // full preferences to load helps avoid leaking a window. + const finalPaneEvent = Services.prefs.getBoolPref( + "identity.fxaccounts.enabled" + ) + ? "sync-pane-loaded" + : "privacy-pane-loaded"; + let finalPrefPaneLoaded = TestUtils.topicObserved(finalPaneEvent, () => true); + const waitForInitialized = new Promise(resolve => { + tab.addEventListener( + "Initialized", + () => { + tab.contentWindow.addEventListener( + "load", + async function() { + await finalPrefPaneLoaded; + resolve(); + }, + { once: true } + ); + }, + { capture: true, once: true } + ); + }); + + await SpecialPowers.spawn(tab, [], async function() { + await ContentTaskUtils.waitForCondition( + () => + content.document.documentElement.hasAttribute( + "SearchBannerInitialized" + ), + "Should have initialized" + ); + + ok( + !content.document.getElementById("search-banner").hasAttribute("hidden"), + "should be showing the banner again before opening prefs" + ); + + content.document.getElementById("open-search-options-link").click(); + }); + + info("Waiting for preference window load"); + await waitForInitialized; + + await BrowserTestUtils.closeWindow(win); + + Assert.equal( + Services.prefs.getIntPref(PREF_BANNER_SHOWN, -1), + MAX_SHOW_COUNT, + "Should have set the shown preference to the maximum" + ); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_blobUrl.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_blobUrl.js new file mode 100644 index 0000000000..5988037dec --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_blobUrl.js @@ -0,0 +1,69 @@ +"use strict"; + +// Here we want to test that blob URLs are not available between private and +// non-private browsing. + +const BASE_URI = + "http://mochi.test:8888/browser/browser/components/" + + "privatebrowsing/test/browser/empty_file.html"; + +add_task(async function test() { + const loaded = BrowserTestUtils.browserLoaded( + gBrowser.selectedBrowser, + false, + BASE_URI + ); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, BASE_URI); + await loaded; + + let blobURL; + info("Creating a blob URL..."); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() { + return Promise.resolve( + content.window.URL.createObjectURL( + new Blob([123], { type: "text/plain" }) + ) + ); + }).then(newURL => { + blobURL = newURL; + }); + + info("Blob URL: " + blobURL); + + info("Creating a private window..."); + + let privateWin = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + let privateTab = privateWin.gBrowser.selectedBrowser; + + const privateTabLoaded = BrowserTestUtils.browserLoaded( + privateTab, + false, + BASE_URI + ); + BrowserTestUtils.loadURI(privateTab, BASE_URI); + await privateTabLoaded; + + await SpecialPowers.spawn(privateTab, [blobURL], function(url) { + return new Promise(resolve => { + var xhr = new content.window.XMLHttpRequest(); + xhr.onerror = function() { + resolve("SendErrored"); + }; + xhr.onload = function() { + resolve("SendLoaded"); + }; + xhr.open("GET", url); + xhr.send(); + }); + }).then(status => { + is( + status, + "SendErrored", + "Using a blob URI from one user context id in another should not work" + ); + }); + + await BrowserTestUtils.closeWindow(privateWin); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cache.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cache.js new file mode 100644 index 0000000000..7f6dd9645b --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cache.js @@ -0,0 +1,97 @@ +/* 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/. */ + +// Check about:cache after private browsing +// This test covers MozTrap test 6047 +// bug 880621 + +var tmp = {}; + +const { Sanitizer } = ChromeUtils.import("resource:///modules/Sanitizer.jsm"); + +function test() { + waitForExplicitFinish(); + + SpecialPowers.pushPrefEnv( + { + set: [["privacy.partition.network_state", false]], + }, + function() { + Sanitizer.sanitize(["cache"], { ignoreTimespan: false }); + + getStorageEntryCount("regular", function(nrEntriesR1) { + is(nrEntriesR1, 0, "Disk cache reports 0KB and has no entries"); + + get_cache_for_private_window(); + }); + } + ); +} + +function getStorageEntryCount(device, goon) { + var storage; + switch (device) { + case "private": + storage = Services.cache2.diskCacheStorage( + Services.loadContextInfo.private, + false + ); + break; + case "regular": + storage = Services.cache2.diskCacheStorage( + Services.loadContextInfo.default, + false + ); + break; + default: + throw new Error(`Unknown device ${device} at getStorageEntryCount`); + } + + var visitor = { + entryCount: 0, + onCacheStorageInfo(aEntryCount, aConsumption) {}, + onCacheEntryInfo(uri) { + var urispec = uri.asciiSpec; + info(device + ":" + urispec + "\n"); + if (urispec.match(/^http:\/\/example.org\//)) { + ++this.entryCount; + } + }, + onCacheEntryVisitCompleted() { + goon(this.entryCount); + }, + }; + + storage.asyncVisitStorage(visitor, true); +} + +function get_cache_for_private_window() { + let win = whenNewWindowLoaded({ private: true }, function() { + executeSoon(function() { + ok(true, "The private window got loaded"); + + let tab = BrowserTestUtils.addTab(win.gBrowser, "http://example.org"); + win.gBrowser.selectedTab = tab; + let newTabBrowser = win.gBrowser.getBrowserForTab(tab); + + BrowserTestUtils.browserLoaded(newTabBrowser).then(function() { + executeSoon(function() { + getStorageEntryCount("private", function(nrEntriesP) { + ok( + nrEntriesP >= 1, + "Memory cache reports some entries from example.org domain" + ); + + getStorageEntryCount("regular", function(nrEntriesR2) { + is(nrEntriesR2, 0, "Disk cache reports 0KB and has no entries"); + + win.close(); + finish(); + }); + }); + }); + }); + }); + }); +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_certexceptionsui.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_certexceptionsui.js new file mode 100644 index 0000000000..8868e66340 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_certexceptionsui.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 certificate exceptions UI behaves correctly +// in private browsing windows, based on whether it's opened from the prefs +// window or from the SSL error page (see bug 461627). + +function test() { + const EXCEPTIONS_DLG_URL = "chrome://pippki/content/exceptionDialog.xhtml"; + const EXCEPTIONS_DLG_FEATURES = "chrome,centerscreen"; + const INVALID_CERT_LOCATION = "https://nocert.example.com/"; + waitForExplicitFinish(); + + // open a private browsing window + var pbWin = OpenBrowserWindow({ private: true }); + pbWin.addEventListener( + "load", + function() { + doTest(); + }, + { once: true } + ); + + // Test the certificate exceptions dialog + function doTest() { + let params = { + exceptionAdded: false, + location: INVALID_CERT_LOCATION, + prefetchCert: true, + }; + function testCheckbox() { + win.removeEventListener("load", testCheckbox); + Services.obs.addObserver(function onCertUI(aSubject, aTopic, aData) { + Services.obs.removeObserver(onCertUI, "cert-exception-ui-ready"); + ok(win.gCert, "The certificate information should be available now"); + + let checkbox = win.document.getElementById("permanent"); + ok( + checkbox.hasAttribute("disabled"), + "the permanent checkbox should be disabled when handling the private browsing mode" + ); + ok( + !checkbox.hasAttribute("checked"), + "the permanent checkbox should not be checked when handling the private browsing mode" + ); + win.close(); + cleanup(); + }, "cert-exception-ui-ready"); + } + var win = pbWin.openDialog( + EXCEPTIONS_DLG_URL, + "", + EXCEPTIONS_DLG_FEATURES, + params + ); + win.addEventListener("load", testCheckbox); + } + + function cleanup() { + // close the private browsing window + pbWin.close(); + finish(); + } +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cleanup.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cleanup.js new file mode 100644 index 0000000000..2f1a71d110 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cleanup.js @@ -0,0 +1,46 @@ +/* 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/. */ + +"use strict"; + +const DOMAIN = "http://example.com/"; +const PATH = "browser/browser/components/privatebrowsing/test/browser/"; +const TOP_PAGE = DOMAIN + PATH + "empty_file.html"; + +add_task(async () => { + // Create a private browsing window. + let privateWindow = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + + let privateTab = privateWindow.gBrowser.selectedBrowser; + BrowserTestUtils.loadURI(privateTab, TOP_PAGE); + await BrowserTestUtils.browserLoaded(privateTab); + + let observerExited = { + observe(aSubject, aTopic, aData) { + ok(false, "Notification received!"); + }, + }; + Services.obs.addObserver(observerExited, "last-pb-context-exited"); + + let popup = BrowserTestUtils.waitForNewWindow(); + + await SpecialPowers.spawn(privateTab, [], () => { + content.window.open("empty_file.html", "_blank", "width=300,height=300"); + }); + + popup = await popup; + ok(!!popup, "Popup shown"); + + await BrowserTestUtils.closeWindow(privateWindow); + Services.obs.removeObserver(observerExited, "last-pb-context-exited"); + + let notificationPromise = TestUtils.topicObserved("last-pb-context-exited"); + + popup.close(); + + await notificationPromise; + ok(true, "Notification received!"); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent.js new file mode 100644 index 0000000000..976f02dc68 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent.js @@ -0,0 +1,101 @@ +/* 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 opening two tabs that share a localStorage, but keep one in private mode. +// Ensure that values from one don't leak into the other, and that values from +// earlier private storage sessions aren't visible later. + +// Step 1: create new tab, load a page that sets test=value in non-private storage +// Step 2: create a new tab, load a page that sets test2=value2 in private storage +// Step 3: load a page in the tab from step 1 that checks the value of test2 is value2 and the total count in non-private storage is 1 +// Step 4: load a page in the tab from step 2 that checks the value of test is value and the total count in private storage is 1 + +add_task(async function setup() { + await SpecialPowers.pushPrefEnv({ + set: [["dom.ipc.processCount", 1]], + }); +}); + +add_task(async function test() { + let prefix = + "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent_page.html"; + + function getElts(browser) { + return browser.contentTitle.split("|"); + } + + // Step 1 + let non_private_browser = gBrowser.selectedBrowser; + let url = prefix + "?action=set&name=test&value=value&initial=true"; + BrowserTestUtils.loadURI(non_private_browser, url); + await BrowserTestUtils.browserLoaded(non_private_browser, false, url); + + // Step 2 + let private_window = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + let private_browser = private_window.gBrowser.selectedBrowser; + url = prefix + "?action=set&name=test2&value=value2"; + BrowserTestUtils.loadURI(private_browser, url); + await BrowserTestUtils.browserLoaded(private_browser, false, url); + + // Step 3 + url = prefix + "?action=get&name=test2"; + BrowserTestUtils.loadURI(non_private_browser, url); + await BrowserTestUtils.browserLoaded(non_private_browser, false, url); + let elts = await getElts(non_private_browser); + isnot(elts[0], "value2", "public window shouldn't see private storage"); + is(elts[1], "1", "public window should only see public items"); + + // Step 4 + url = prefix + "?action=get&name=test"; + BrowserTestUtils.loadURI(private_browser, url); + await BrowserTestUtils.browserLoaded(private_browser, false, url); + elts = await getElts(private_browser); + isnot(elts[0], "value", "private window shouldn't see public storage"); + is(elts[1], "1", "private window should only see private items"); + + // Reopen the private window again, without privateBrowsing, which should clear the + // the private storage. + private_window.close(); + private_window = await BrowserTestUtils.openNewBrowserWindow({ + private: false, + }); + private_browser = null; + await new Promise(resolve => Cu.schedulePreciseGC(resolve)); + private_browser = private_window.gBrowser.selectedBrowser; + + url = prefix + "?action=get&name=test2"; + BrowserTestUtils.loadURI(private_browser, url); + await BrowserTestUtils.browserLoaded(private_browser, false, url); + elts = await getElts(private_browser); + isnot( + elts[0], + "value2", + "public window shouldn't see cleared private storage" + ); + is(elts[1], "1", "public window should only see public items"); + + // Making it private again should clear the storage and it shouldn't + // be able to see the old private storage as well. + private_window.close(); + private_window = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + private_browser = null; + await new Promise(resolve => Cu.schedulePreciseGC(resolve)); + private_browser = private_window.gBrowser.selectedBrowser; + + url = prefix + "?action=set&name=test3&value=value3"; + BrowserTestUtils.loadURI(private_browser, url); + await BrowserTestUtils.browserLoaded(private_browser, false, url); + elts = await getElts(private_browser); + is(elts[1], "1", "private window should only see new private items"); + + // Cleanup. + url = prefix + "?final=true"; + BrowserTestUtils.loadURI(non_private_browser, url); + await BrowserTestUtils.browserLoaded(non_private_browser, false, url); + private_window.close(); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent_page.html b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent_page.html new file mode 100644 index 0000000000..96d3b74c7c --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent_page.html @@ -0,0 +1,33 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<script type="text/javascript"> + var oGetVars = {}; + + if (window.location.search.length > 1) { + for (var aItKey, nKeyId = 0, aCouples = window.location.search.substr(1).split("&"); + nKeyId < aCouples.length; + nKeyId++) { + aItKey = aCouples[nKeyId].split("="); + oGetVars[unescape(aItKey[0])] = aItKey.length > 1 ? unescape(aItKey[1]) : ""; + } + } + + if (oGetVars.initial == "true") { + localStorage.clear(); + } + + if (oGetVars.action == "set") { + localStorage.setItem(oGetVars.name, oGetVars.value); + document.title = localStorage.getItem(oGetVars.name) + "|" + localStorage.length; + } else if (oGetVars.action == "get") { + document.title = localStorage.getItem(oGetVars.name) + "|" + localStorage.length; + } + + if (oGetVars.final == "true") { + localStorage.clear(); + } +</script> +</head> +<body> +</body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_context_and_chromeFlags.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_context_and_chromeFlags.js new file mode 100644 index 0000000000..838c199acd --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_context_and_chromeFlags.js @@ -0,0 +1,69 @@ +"use strict"; + +/** + * Given some window in the parent process, ensure that + * the nsIAppWindow has the CHROME_PRIVATE_WINDOW chromeFlag, + * and that the usePrivateBrowsing property is set to true on + * both the window's nsILoadContext, as well as on the initial + * browser's content docShell nsILoadContext. + * + * @param win (nsIDOMWindow) + * An nsIDOMWindow in the parent process. + * @return Promise + */ +function assertWindowIsPrivate(win) { + let winDocShell = win.docShell; + let chromeFlags = winDocShell.treeOwner + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIAppWindow).chromeFlags; + + if (!win.gBrowser.selectedBrowser.hasContentOpener) { + Assert.ok( + chromeFlags & Ci.nsIWebBrowserChrome.CHROME_PRIVATE_WINDOW, + "Should have the private window chrome flag" + ); + } + + let loadContext = winDocShell.QueryInterface(Ci.nsILoadContext); + Assert.ok( + loadContext.usePrivateBrowsing, + "The parent window should be using private browsing" + ); + + return SpecialPowers.spawn( + win.gBrowser.selectedBrowser, + [], + async function() { + let contentLoadContext = docShell.QueryInterface(Ci.nsILoadContext); + Assert.ok( + contentLoadContext.usePrivateBrowsing, + "Content docShell should be using private browsing" + ); + } + ); +} + +/** + * Tests that chromeFlags bits and the nsILoadContext.usePrivateBrowsing + * attribute are properly set when opening a new private browsing + * window. + */ +add_task(async function test_context_and_chromeFlags() { + let win = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + await assertWindowIsPrivate(win); + + let browser = win.gBrowser.selectedBrowser; + + let newWinPromise = BrowserTestUtils.waitForNewWindow({ + url: "http://example.com/", + }); + await SpecialPowers.spawn(browser, [], async function() { + content.open("http://example.com", "_blank", "width=100,height=100"); + }); + + let win2 = await newWinPromise; + await assertWindowIsPrivate(win2); + + await BrowserTestUtils.closeWindow(win2); + await BrowserTestUtils.closeWindow(win); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_crh.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_crh.js new file mode 100644 index 0000000000..9b532ab8eb --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_crh.js @@ -0,0 +1,48 @@ +/* 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 Clear Recent History menu item and command +// is disabled inside the private browsing mode. + +add_task(async function test() { + function checkDisableOption(aPrivateMode, aWindow) { + let crhCommand = aWindow.document.getElementById("Tools:Sanitize"); + ok(crhCommand, "The clear recent history command should exist"); + + is( + PrivateBrowsingUtils.isWindowPrivate(aWindow), + aPrivateMode, + "PrivateBrowsingUtils should report the correct per-window private browsing status" + ); + is( + crhCommand.hasAttribute("disabled"), + aPrivateMode, + "Clear Recent History command should be disabled according to the private browsing mode" + ); + } + + let testURI = "http://mochi.test:8888/"; + + let privateWin = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + let privateBrowser = privateWin.gBrowser.selectedBrowser; + BrowserTestUtils.loadURI(privateBrowser, testURI); + await BrowserTestUtils.browserLoaded(privateBrowser); + + info("Test on private window"); + checkDisableOption(true, privateWin); + + let win = await BrowserTestUtils.openNewBrowserWindow(); + let browser = win.gBrowser.selectedBrowser; + BrowserTestUtils.loadURI(browser, testURI); + await BrowserTestUtils.browserLoaded(browser); + + info("Test on public window"); + checkDisableOption(false, win); + + // Cleanup + await BrowserTestUtils.closeWindow(privateWin); + await BrowserTestUtils.closeWindow(win); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir.js new file mode 100644 index 0000000000..908c2a1d28 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir.js @@ -0,0 +1,133 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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(); + + let FileUtils = ChromeUtils.import("resource://gre/modules/FileUtils.jsm", {}) + .FileUtils; + let DownloadLastDir = ChromeUtils.import( + "resource://gre/modules/DownloadLastDir.jsm", + {} + ).DownloadLastDir; + let MockFilePicker = SpecialPowers.MockFilePicker; + let launcher = { + source: Services.io.newURI("http://test1.com/file"), + }; + + MockFilePicker.init(window); + MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK; + + let prefs = Services.prefs.getBranch("browser.download."); + let launcherDialog = Cc["@mozilla.org/helperapplauncherdialog;1"].getService( + Ci.nsIHelperAppLauncherDialog + ); + let tmpDir = FileUtils.getDir("TmpD", [], true); + let dir1 = newDirectory(); + let dir2 = newDirectory(); + let dir3 = newDirectory(); + let file1 = newFileInDirectory(dir1); + let file2 = newFileInDirectory(dir2); + let file3 = newFileInDirectory(dir3); + + // cleanup functions registration + registerCleanupFunction(function() { + Services.prefs.clearUserPref("browser.download.lastDir"); + [dir1, dir2, dir3].forEach(dir => dir.remove(true)); + MockFilePicker.cleanup(); + }); + prefs.setComplexValue("lastDir", Ci.nsIFile, tmpDir); + + function testOnWindow(aPrivate, aCallback) { + whenNewWindowLoaded({ private: aPrivate }, function(win) { + let gDownloadLastDir = new DownloadLastDir(win); + aCallback(win, gDownloadLastDir); + gDownloadLastDir.cleanupPrivateFile(); + }); + } + + function testDownloadDir( + aWin, + gDownloadLastDir, + aFile, + aDisplayDir, + aLastDir, + aGlobalLastDir, + aCallback + ) { + // Check lastDir preference. + is( + prefs.getComplexValue("lastDir", Ci.nsIFile).path, + aDisplayDir.path, + "LastDir should be the expected display dir" + ); + // Check gDownloadLastDir value. + is( + gDownloadLastDir.file.path, + aDisplayDir.path, + "gDownloadLastDir should be the expected display dir" + ); + + MockFilePicker.setFiles([aFile]); + MockFilePicker.displayDirectory = null; + + launcher.saveDestinationAvailable = function(file) { + ok(!!file, "promptForSaveToFile correctly returned a file"); + + // File picker should start with expected display dir. + is( + MockFilePicker.displayDirectory.path, + aDisplayDir.path, + "File picker should start with browser.download.lastDir" + ); + // browser.download.lastDir should be modified on not private windows + is( + prefs.getComplexValue("lastDir", Ci.nsIFile).path, + aLastDir.path, + "LastDir should be the expected last dir" + ); + // gDownloadLastDir should be usable outside of private windows + is( + gDownloadLastDir.file.path, + aGlobalLastDir.path, + "gDownloadLastDir should be the expected global last dir" + ); + + launcher.saveDestinationAvailable = null; + aWin.close(); + aCallback(); + }; + + launcherDialog.promptForSaveToFileAsync(launcher, aWin, null, null, null); + } + + testOnWindow(false, function(win, downloadDir) { + testDownloadDir(win, downloadDir, file1, tmpDir, dir1, dir1, function() { + testOnWindow(true, function(win1, downloadDir1) { + testDownloadDir( + win1, + downloadDir1, + file2, + dir1, + dir1, + dir2, + function() { + testOnWindow(false, function(win2, downloadDir2) { + testDownloadDir( + win2, + downloadDir2, + file3, + dir1, + dir3, + dir3, + finish + ); + }); + } + ); + }); + }); + }); +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_c.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_c.js new file mode 100644 index 0000000000..6e17ed9b55 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_c.js @@ -0,0 +1,146 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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(); + + let FileUtils = ChromeUtils.import("resource://gre/modules/FileUtils.jsm", {}) + .FileUtils; + let DownloadLastDir = ChromeUtils.import( + "resource://gre/modules/DownloadLastDir.jsm", + {} + ).DownloadLastDir; + let MockFilePicker = SpecialPowers.MockFilePicker; + + MockFilePicker.init(window); + MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK; + + let validateFileNameToRestore = validateFileName; + let prefs = Services.prefs.getBranch("browser.download."); + let tmpDir = FileUtils.getDir("TmpD", [], true); + let dir1 = newDirectory(); + let dir2 = newDirectory(); + let dir3 = newDirectory(); + let file1 = newFileInDirectory(dir1); + let file2 = newFileInDirectory(dir2); + let file3 = newFileInDirectory(dir3); + + // cleanup function registration + registerCleanupFunction(function() { + Services.prefs.clearUserPref("browser.download.lastDir"); + [dir1, dir2, dir3].forEach(dir => dir.remove(true)); + MockFilePicker.cleanup(); + validateFileName = validateFileNameToRestore; + }); + + // Overwrite validateFileName to validate everything + validateFileName = foo => foo; + + let params = { + fileInfo: new FileInfo( + "test.txt", + "test.txt", + "test", + "txt", + "http://mozilla.org/test.txt" + ), + contentType: "text/plain", + saveMode: SAVEMODE_FILEONLY, + saveAsType: kSaveAsType_Complete, + file: null, + }; + + prefs.setComplexValue("lastDir", Ci.nsIFile, tmpDir); + + function testOnWindow(aPrivate, aCallback) { + whenNewWindowLoaded({ private: aPrivate }, function(win) { + let gDownloadLastDir = new DownloadLastDir(win); + aCallback(win, gDownloadLastDir); + }); + } + + function testDownloadDir( + aWin, + gDownloadLastDir, + aFile, + aDisplayDir, + aLastDir, + aGlobalLastDir, + aCallback + ) { + // Check lastDir preference. + is( + prefs.getComplexValue("lastDir", Ci.nsIFile).path, + aDisplayDir.path, + "LastDir should be the expected display dir" + ); + // Check gDownloadLastDir value. + is( + gDownloadLastDir.file.path, + aDisplayDir.path, + "gDownloadLastDir should be the expected display dir" + ); + + MockFilePicker.setFiles([aFile]); + MockFilePicker.displayDirectory = null; + aWin + .promiseTargetFile(params) + .then(function() { + // File picker should start with expected display dir. + is( + MockFilePicker.displayDirectory.path, + aDisplayDir.path, + "File picker should start with browser.download.lastDir" + ); + // browser.download.lastDir should be modified on not private windows + is( + prefs.getComplexValue("lastDir", Ci.nsIFile).path, + aLastDir.path, + "LastDir should be the expected last dir" + ); + // gDownloadLastDir should be usable outside of private windows + is( + gDownloadLastDir.file.path, + aGlobalLastDir.path, + "gDownloadLastDir should be the expected global last dir" + ); + + gDownloadLastDir.cleanupPrivateFile(); + aWin.close(); + aCallback(); + }) + .catch(function() { + ok(false); + }); + } + + testOnWindow(false, function(win, downloadDir) { + testDownloadDir(win, downloadDir, file1, tmpDir, dir1, dir1, function() { + testOnWindow(true, function(win1, downloadDir1) { + testDownloadDir( + win1, + downloadDir1, + file2, + dir1, + dir1, + dir2, + function() { + testOnWindow(false, function(win2, downloadDir2) { + testDownloadDir( + win2, + downloadDir2, + file3, + dir1, + dir3, + dir3, + finish + ); + }); + } + ); + }); + }); + }); +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js new file mode 100644 index 0000000000..678781df9b --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js @@ -0,0 +1,125 @@ +const { FileUtils } = ChromeUtils.import( + "resource://gre/modules/FileUtils.jsm" +); +const { DownloadLastDir } = ChromeUtils.import( + "resource://gre/modules/DownloadLastDir.jsm" +); + +/** + * Tests how the browser remembers the last download folder + * from download to download, with a particular emphasis + * on how it behaves when private browsing windows open. + */ +add_task(async function test_downloads_last_dir_toggle() { + let tmpDir = FileUtils.getDir("TmpD", [], true); + let dir1 = newDirectory(); + + registerCleanupFunction(function() { + Services.prefs.clearUserPref("browser.download.lastDir"); + dir1.remove(true); + }); + + let win = await BrowserTestUtils.openNewBrowserWindow(); + let gDownloadLastDir = new DownloadLastDir(win); + is( + typeof gDownloadLastDir, + "object", + "gDownloadLastDir should be a valid object" + ); + is( + gDownloadLastDir.file, + null, + "gDownloadLastDir.file should be null to start with" + ); + + gDownloadLastDir.file = tmpDir; + is( + gDownloadLastDir.file.path, + tmpDir.path, + "LastDir should point to the temporary directory" + ); + isnot( + gDownloadLastDir.file, + tmpDir, + "gDownloadLastDir.file should not be pointing to the tmpDir" + ); + + gDownloadLastDir.file = 1; // not an nsIFile + is(gDownloadLastDir.file, null, "gDownloadLastDir.file should be null"); + + gDownloadLastDir.file = tmpDir; + clearHistory(); + is(gDownloadLastDir.file, null, "gDownloadLastDir.file should be null"); + + gDownloadLastDir.file = tmpDir; + await BrowserTestUtils.closeWindow(win); + + info("Opening the first private window"); + await testHelper({ private: true, expectedDir: tmpDir }); + info("Opening a non-private window"); + await testHelper({ private: false, expectedDir: tmpDir }); + info("Opening a private window and setting download directory"); + await testHelper({ private: true, setDir: dir1, expectedDir: dir1 }); + info("Opening a non-private window and checking download directory"); + await testHelper({ private: false, expectedDir: tmpDir }); + info("Opening private window and clearing history"); + await testHelper({ private: true, clearHistory: true, expectedDir: null }); + info("Opening a non-private window and checking download directory"); + await testHelper({ private: true, expectedDir: null }); +}); + +/** + * Opens a new window and performs some test actions on it based + * on the options object that have been passed in. + * + * @param options (Object) + * An object with the following properties: + * + * clearHistory (bool, optional): + * Whether or not to simulate clearing session history. + * Defaults to false. + * + * setDir (nsIFile, optional): + * An nsIFile for setting the last download directory. + * If not set, the load download directory is not changed. + * + * expectedDir (nsIFile, expectedDir): + * An nsIFile for what we expect the last download directory + * should be. The nsIFile is not compared directly - only + * paths are compared. If expectedDir is not set, then the + * last download directory is expected to be null. + * + * @returns Promise + */ +async function testHelper(options) { + let win = await BrowserTestUtils.openNewBrowserWindow(options); + let gDownloadLastDir = new DownloadLastDir(win); + + if (options.clearHistory) { + clearHistory(); + } + + if (options.setDir) { + gDownloadLastDir.file = options.setDir; + } + + let expectedDir = options.expectedDir; + + if (expectedDir) { + is( + gDownloadLastDir.file.path, + expectedDir.path, + "gDownloadLastDir should point to the expected last directory" + ); + isnot( + gDownloadLastDir.file, + expectedDir, + "gDownloadLastDir.file should not be pointing to the last directory" + ); + } else { + is(gDownloadLastDir.file, null, "gDownloadLastDir should be null"); + } + + gDownloadLastDir.cleanupPrivateFile(); + await BrowserTestUtils.closeWindow(win); +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js new file mode 100644 index 0000000000..c0e671ce34 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js @@ -0,0 +1,324 @@ +/* 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 make sure that the favicon of the private browsing is isolated. + +const TEST_SITE = "http://mochi.test:8888"; +const TEST_CACHE_SITE = "http://www.example.com"; +const TEST_DIRECTORY = + "/browser/browser/components/privatebrowsing/test/browser/"; + +const TEST_PAGE = TEST_SITE + TEST_DIRECTORY + "file_favicon.html"; +const TEST_CACHE_PAGE = TEST_CACHE_SITE + TEST_DIRECTORY + "file_favicon.html"; +const FAVICON_URI = TEST_SITE + TEST_DIRECTORY + "file_favicon.png"; +const FAVICON_CACHE_URI = TEST_CACHE_SITE + TEST_DIRECTORY + "file_favicon.png"; + +let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal(); +let makeURI = ChromeUtils.import("resource://gre/modules/BrowserUtils.jsm", {}) + .BrowserUtils.makeURI; + +function clearAllImageCaches() { + let tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"].getService( + SpecialPowers.Ci.imgITools + ); + let imageCache = tools.getImgCacheForDocument(window.document); + imageCache.clearCache(true); // true=chrome + imageCache.clearCache(false); // false=content +} + +function clearAllPlacesFavicons() { + let faviconService = Cc["@mozilla.org/browser/favicon-service;1"].getService( + Ci.nsIFaviconService + ); + + return new Promise(resolve => { + let observer = { + observe(aSubject, aTopic, aData) { + if (aTopic === "places-favicons-expired") { + resolve(); + Services.obs.removeObserver(observer, "places-favicons-expired"); + } + }, + }; + + Services.obs.addObserver(observer, "places-favicons-expired"); + faviconService.expireAllFavicons(); + }); +} + +function observeFavicon(aIsPrivate, aExpectedCookie, aPageURI) { + let attr = {}; + + if (aIsPrivate) { + attr.privateBrowsingId = 1; + } + + let expectedPrincipal = Services.scriptSecurityManager.createContentPrincipal( + aPageURI, + attr + ); + + return new Promise(resolve => { + let observer = { + observe(aSubject, aTopic, aData) { + // Make sure that the topic is 'http-on-modify-request'. + if (aTopic === "http-on-modify-request") { + // We check the privateBrowsingId for the originAttributes of the loading + // channel. All requests for the favicon should contain the correct + // privateBrowsingId. There are two requests for a favicon loading, one + // from the Places library and one from the XUL image. The difference + // of them is the loading principal. The Places will use the content + // principal and the XUL image will use the system principal. + + let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel); + let reqLoadInfo = httpChannel.loadInfo; + let loadingPrincipal = reqLoadInfo.loadingPrincipal; + + // Make sure this is a favicon request. + if (httpChannel.URI.spec !== FAVICON_URI) { + return; + } + + // Check the privateBrowsingId. + if (aIsPrivate) { + is( + reqLoadInfo.originAttributes.privateBrowsingId, + 1, + "The loadInfo has correct privateBrowsingId" + ); + } else { + is( + reqLoadInfo.originAttributes.privateBrowsingId, + 0, + "The loadInfo has correct privateBrowsingId" + ); + } + + ok( + loadingPrincipal.equals(expectedPrincipal), + "The loadingPrincipal of favicon loading from Places should be the content prinicpal" + ); + + let faviconCookie = httpChannel.getRequestHeader("cookie"); + + is( + faviconCookie, + aExpectedCookie, + "The cookie of the favicon loading is correct." + ); + } else { + ok(false, "Received unexpected topic: ", aTopic); + } + + resolve(); + Services.obs.removeObserver(observer, "http-on-modify-request"); + }, + }; + + Services.obs.addObserver(observer, "http-on-modify-request"); + }); +} + +function waitOnFaviconResponse(aFaviconURL) { + return new Promise(resolve => { + let observer = { + observe(aSubject, aTopic, aData) { + if ( + aTopic === "http-on-examine-response" || + aTopic === "http-on-examine-cached-response" + ) { + let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel); + let loadInfo = httpChannel.loadInfo; + + if (httpChannel.URI.spec !== aFaviconURL) { + return; + } + + let result = { + topic: aTopic, + privateBrowsingId: loadInfo.originAttributes.privateBrowsingId, + }; + + resolve(result); + Services.obs.removeObserver(observer, "http-on-examine-response"); + Services.obs.removeObserver( + observer, + "http-on-examine-cached-response" + ); + } + }, + }; + + Services.obs.addObserver(observer, "http-on-examine-response"); + Services.obs.addObserver(observer, "http-on-examine-cached-response"); + }); +} + +function waitOnFaviconLoaded(aFaviconURL) { + return PlacesTestUtils.waitForNotification( + "favicon-changed", + events => events.some(e => e.faviconUrl == aFaviconURL), + "places" + ); +} + +async function assignCookies(aBrowser, aURL, aCookieValue) { + let tabInfo = await openTab(aBrowser, aURL); + + await SpecialPowers.spawn(tabInfo.browser, [aCookieValue], async function( + value + ) { + content.document.cookie = value; + }); + + BrowserTestUtils.removeTab(tabInfo.tab); +} + +async function openTab(aBrowser, aURL) { + let tab = BrowserTestUtils.addTab(aBrowser, aURL); + + // Select tab and make sure its browser is focused. + aBrowser.selectedTab = tab; + tab.ownerGlobal.focus(); + + let browser = aBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + return { tab, browser }; +} + +registerCleanupFunction(async () => { + Services.cookies.removeAll(); + clearAllImageCaches(); + Services.cache2.clear(); + await PlacesUtils.history.clear(); + await PlacesUtils.bookmarks.eraseEverything(); +}); + +add_task(async function test_favicon_privateBrowsing() { + // Clear all image caches before running the test. + clearAllImageCaches(); + // Clear all favicons in Places. + await clearAllPlacesFavicons(); + + // Create a private browsing window. + let privateWindow = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + let pageURI = makeURI(TEST_PAGE); + + // Generate two random cookies for non-private window and private window + // respectively. + let cookies = []; + cookies.push(Math.random().toString()); + cookies.push(Math.random().toString()); + + // Open a tab in private window and add a cookie into it. + await assignCookies(privateWindow.gBrowser, TEST_SITE, cookies[0]); + + // Open a tab in non-private window and add a cookie into it. + await assignCookies(gBrowser, TEST_SITE, cookies[1]); + + // Add the observer earlier in case we don't capture events in time. + let promiseObserveFavicon = observeFavicon(true, cookies[0], pageURI); + + // The page must be bookmarked for favicon requests to go through in PB mode. + await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: TEST_PAGE, + }); + + // Open a tab for the private window. + let tabInfo = await openTab(privateWindow.gBrowser, TEST_PAGE); + + info("Waiting until favicon requests are all made in private window."); + await promiseObserveFavicon; + + // Close the tab. + BrowserTestUtils.removeTab(tabInfo.tab); + // FIXME: We need to wait for the next event tick here to avoid observing + // the previous tab info in the next step (bug 1446725). + await new Promise(executeSoon); + + // Add the observer earlier in case we don't capture events in time. + promiseObserveFavicon = observeFavicon(false, cookies[1], pageURI); + + // Open a tab for the non-private window. + tabInfo = await openTab(gBrowser, TEST_PAGE); + + info("Waiting until favicon requests are all made in non-private window."); + await promiseObserveFavicon; + + // Close the tab. + BrowserTestUtils.removeTab(tabInfo.tab); + await BrowserTestUtils.closeWindow(privateWindow); +}); + +add_task(async function test_favicon_cache_privateBrowsing() { + // Clear all image caches and network cache before running the test. + clearAllImageCaches(); + + Services.cache2.clear(); + + // Clear all favicons in Places. + await clearAllPlacesFavicons(); + + // Add an observer for making sure the favicon has been loaded and cached. + let promiseFaviconLoaded = waitOnFaviconLoaded(FAVICON_CACHE_URI); + let promiseFaviconResponse = waitOnFaviconResponse(FAVICON_CACHE_URI); + + // Open a tab for the non-private window. + let tabInfoNonPrivate = await openTab(gBrowser, TEST_CACHE_PAGE); + + let response = await promiseFaviconResponse; + + await promiseFaviconLoaded; + + // Check that the favicon response has come from the network and it has the + // correct privateBrowsingId. + is( + response.topic, + "http-on-examine-response", + "The favicon image should be loaded through network." + ); + is( + response.privateBrowsingId, + 0, + "We should observe the network response for the non-private tab." + ); + + // Create a private browsing window. + let privateWindow = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + + // The page must be bookmarked for favicon requests to go through in PB mode. + await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: TEST_CACHE_PAGE, + }); + + promiseFaviconResponse = waitOnFaviconResponse(FAVICON_CACHE_URI); + + // Open a tab for the private window. + let tabInfoPrivate = await openTab(privateWindow.gBrowser, TEST_CACHE_PAGE); + + // Wait for the favicon response of the private tab. + response = await promiseFaviconResponse; + + // Make sure the favicon is loaded through the network and its privateBrowsingId is correct. + is( + response.topic, + "http-on-examine-response", + "The favicon image should be loaded through the network again." + ); + is( + response.privateBrowsingId, + 1, + "We should observe the network response for the private tab." + ); + + BrowserTestUtils.removeTab(tabInfoPrivate.tab); + BrowserTestUtils.removeTab(tabInfoNonPrivate.tab); + await BrowserTestUtils.closeWindow(privateWindow); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt_page.html b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt_page.html new file mode 100644 index 0000000000..01ed3f3d2c --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt_page.html @@ -0,0 +1,13 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> +<html> + <head> + <title>Geolocation invoker</title> + </head> + <body> + <script type="text/javascript"> + navigator.geolocation.getCurrentPosition(function(pos) { + // ignore + }); + </script> + </body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_history_shift_click.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_history_shift_click.js new file mode 100644 index 0000000000..87d9e5a7c9 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_history_shift_click.js @@ -0,0 +1,69 @@ +/* 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/. */ + +add_task(async function() { + await testShiftClickOpensNewWindow("back-button"); +}); + +add_task(async function() { + await testShiftClickOpensNewWindow("forward-button"); +}); + +// Create new private browser, open new tab and set history state, then return the window +async function createPrivateWindow() { + const privateWindow = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + await BrowserTestUtils.openNewForegroundTab( + privateWindow.gBrowser, + "http://example.com" + ); + await SpecialPowers.spawn( + privateWindow.gBrowser.selectedBrowser, + [], + async function() { + content.history.pushState({}, "first item", "first-item.html"); + content.history.pushState({}, "second item", "second-item.html"); + content.history.pushState({}, "third item", "third-item.html"); + content.history.back(); + } + ); + await TestUtils.topicObserved("sessionstore-state-write-complete"); + + // Wait for the session data to be flushed before continuing the test + await new Promise(resolve => + SessionStore.getSessionHistory(privateWindow.gBrowser.selectedTab, resolve) + ); + + info("Private window created"); + + return privateWindow; +} + +async function testShiftClickOpensNewWindow(buttonId) { + const privateWindow = await createPrivateWindow(); + + const button = privateWindow.document.getElementById(buttonId); + // Wait for the new private window to be created after click + const newPrivateWindowPromise = BrowserTestUtils.waitForNewWindow(); + + EventUtils.synthesizeMouseAtCenter(button, { shiftKey: true }, privateWindow); + + info("Waiting for new private browser to open"); + + const newPrivateWindow = await newPrivateWindowPromise; + + ok( + PrivateBrowsingUtils.isBrowserPrivate(newPrivateWindow.gBrowser), + "New window is private" + ); + + // Cleanup + await Promise.all([ + BrowserTestUtils.closeWindow(privateWindow), + BrowserTestUtils.closeWindow(newPrivateWindow), + ]); + + info("Closed all windows"); +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_lastpbcontextexited.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_lastpbcontextexited.js new file mode 100644 index 0000000000..c19c53ca28 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_lastpbcontextexited.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 test() { + // We need to open a new window for this so that its docshell would get destroyed + // when clearing the PB mode flag. + function runTest(aCloseWindow, aCallback) { + let newWin = OpenBrowserWindow({ private: true }); + SimpleTest.waitForFocus(function() { + let expectedExiting = true; + let expectedExited = false; + let observerExiting = { + observe(aSubject, aTopic, aData) { + is( + aTopic, + "last-pb-context-exiting", + "Correct topic should be dispatched (exiting)" + ); + is(expectedExiting, true, "notification not expected yet (exiting)"); + expectedExited = true; + Services.obs.removeObserver( + observerExiting, + "last-pb-context-exiting" + ); + }, + }; + let observerExited = { + observe(aSubject, aTopic, aData) { + is( + aTopic, + "last-pb-context-exited", + "Correct topic should be dispatched (exited)" + ); + is(expectedExited, true, "notification not expected yet (exited)"); + Services.obs.removeObserver(observerExited, "last-pb-context-exited"); + aCallback(); + }, + }; + Services.obs.addObserver(observerExiting, "last-pb-context-exiting"); + Services.obs.addObserver(observerExited, "last-pb-context-exited"); + expectedExiting = true; + aCloseWindow(newWin); + newWin = null; + SpecialPowers.forceGC(); + }, newWin); + } + + waitForExplicitFinish(); + + runTest( + function(newWin) { + // Simulate pressing the window close button + newWin.document.getElementById("cmd_closeWindow").doCommand(); + }, + function() { + runTest(function(newWin) { + // Simulate closing the last tab + newWin.document.getElementById("cmd_close").doCommand(); + }, finish); + } + ); +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js new file mode 100644 index 0000000000..c8e212b397 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js @@ -0,0 +1,28 @@ +/* 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/. */ + +add_task(async function test() { + requestLongerTimeout(2); + const page1 = + "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/" + + "browser_privatebrowsing_localStorage_page1.html"; + + let win = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + + win.gBrowser.selectedTab = BrowserTestUtils.addTab(win.gBrowser, page1); + let browser = win.gBrowser.selectedBrowser; + await BrowserTestUtils.browserLoaded(browser); + + BrowserTestUtils.loadURI( + browser, + "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/" + + "browser_privatebrowsing_localStorage_page2.html" + ); + await BrowserTestUtils.browserLoaded(browser); + + is(browser.contentTitle, "2", "localStorage should contain 2 items"); + + // Cleanup + await BrowserTestUtils.closeWindow(win); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js new file mode 100644 index 0000000000..3537236068 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js @@ -0,0 +1,46 @@ +/* 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/. */ + +// Ensure that a storage instance used by both private and public sessions at different times does not +// allow any data to leak due to cached values. + +// Step 1: Load browser_privatebrowsing_localStorage_before_after_page.html in a private tab, causing a storage +// item to exist. Close the tab. +// Step 2: Load the same page in a non-private tab, ensuring that the storage instance reports only one item +// existing. + +add_task(async function test() { + let prefix = + "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/"; + + // Step 1. + let privateWin = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + let testURL = + prefix + "browser_privatebrowsing_localStorage_before_after_page.html"; + await BrowserTestUtils.openNewForegroundTab(privateWin.gBrowser, testURL); + + is( + privateWin.gBrowser.selectedBrowser.contentTitle, + "1", + "localStorage should contain 1 item" + ); + + // Step 2. + let win = await BrowserTestUtils.openNewBrowserWindow(); + testURL = + prefix + "browser_privatebrowsing_localStorage_before_after_page2.html"; + await BrowserTestUtils.openNewForegroundTab(win.gBrowser, testURL); + + is( + win.gBrowser.selectedBrowser.contentTitle, + "null|0", + "localStorage should contain 0 items" + ); + + // Cleanup + await BrowserTestUtils.closeWindow(privateWin); + await BrowserTestUtils.closeWindow(win); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after_page.html b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after_page.html new file mode 100644 index 0000000000..0fcb3f89be --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after_page.html @@ -0,0 +1,11 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<script type="text/javascript"> + localStorage.clear(); + localStorage.setItem("zzztest", "zzzvalue"); + document.title = localStorage.length; +</script> +</head> +<body> +</body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after_page2.html b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after_page2.html new file mode 100644 index 0000000000..4eccebdf48 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after_page2.html @@ -0,0 +1,10 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<script type="text/javascript"> + document.title = localStorage.getItem("zzztest", "zzzvalue") + "|" + localStorage.length; + localStorage.clear(); +</script> +</head> +<body> +</body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_page1.html b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_page1.html new file mode 100644 index 0000000000..ecf5507e0a --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_page1.html @@ -0,0 +1,10 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<script type="text/javascript"> + localStorage.clear(); + localStorage.setItem("test1", "value1"); +</script> +</head> +<body> +</body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_page2.html b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_page2.html new file mode 100644 index 0000000000..d49c7fea29 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_page2.html @@ -0,0 +1,10 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<script type="text/javascript"> + localStorage.setItem("test2", "value2"); + document.title = localStorage.length; +</script> +</head> +<body> +</body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js new file mode 100644 index 0000000000..d7a7b547de --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js @@ -0,0 +1,71 @@ +/** + * Tests that a popup window in private browsing window opens + * new tab links in the original private browsing window as + * new tabs. + * + * This is a regression test for bug 1202634. + */ + +// We're able to sidestep some quote-escaping issues when +// nesting data URI's by encoding the second data URI in +// base64. +const POPUP_BODY_BASE64 = btoa(`<a href="http://example.com/" target="_blank" + id="second"> + Now click this + </a>`); +const POPUP_LINK = `data:text/html;charset=utf-8;base64,${POPUP_BODY_BASE64}`; +const WINDOW_BODY = `data:text/html, + <a href="%23" id="first" + onclick="window.open('${POPUP_LINK}', '_blank', + 'width=630,height=500')"> + First click this. + </a>`; + +add_task(async function test_private_popup_window_opens_private_tabs() { + // allow top level data: URI navigations, otherwise clicking a data: link fails + await SpecialPowers.pushPrefEnv({ + set: [["security.data_uri.block_toplevel_data_uri_navigations", false]], + }); + let privWin = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + + // Sanity check - this browser better be private. + ok( + PrivateBrowsingUtils.isWindowPrivate(privWin), + "Opened a private browsing window." + ); + + // First, open a private browsing window, and load our + // testing page. + let privBrowser = privWin.gBrowser.selectedBrowser; + BrowserTestUtils.loadURI(privBrowser, WINDOW_BODY); + await BrowserTestUtils.browserLoaded(privBrowser); + + // Next, click on the link in the testing page, and ensure + // that a private popup window is opened. + let openedPromise = BrowserTestUtils.waitForNewWindow({ url: POPUP_LINK }); + + await BrowserTestUtils.synthesizeMouseAtCenter("#first", {}, privBrowser); + let popupWin = await openedPromise; + ok( + PrivateBrowsingUtils.isWindowPrivate(popupWin), + "Popup window was private." + ); + + // Now click on the link in the popup, and ensure that a new + // tab is opened in the original private browsing window. + let newTabPromise = BrowserTestUtils.waitForNewTab(privWin.gBrowser); + let popupBrowser = popupWin.gBrowser.selectedBrowser; + await BrowserTestUtils.synthesizeMouseAtCenter("#second", {}, popupBrowser); + let newPrivTab = await newTabPromise; + + // Ensure that the newly created tab's browser is private. + ok( + PrivateBrowsingUtils.isBrowserPrivate(newPrivTab.linkedBrowser), + "Newly opened tab should be private." + ); + + // Clean up + BrowserTestUtils.removeTab(newPrivTab); + await BrowserTestUtils.closeWindow(popupWin); + await BrowserTestUtils.closeWindow(privWin); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_noSessionRestoreMenuOption.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_noSessionRestoreMenuOption.js new file mode 100644 index 0000000000..17ea34d1aa --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_noSessionRestoreMenuOption.js @@ -0,0 +1,29 @@ +"use strict"; + +/** + * Tests that if we open a tab within a private browsing window, and then + * close that private browsing window, that subsequent private browsing + * windows do not allow the command for restoring the last session. + */ +add_task(async function test_no_session_restore_menu_option() { + let win = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + ok(true, "The first private window got loaded"); + BrowserTestUtils.addTab(win.gBrowser, "about:mozilla"); + await BrowserTestUtils.closeWindow(win); + + win = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + let srCommand = win.document.getElementById("Browser:RestoreLastSession"); + ok(srCommand, "The Session Restore command should exist"); + is( + PrivateBrowsingUtils.isWindowPrivate(win), + true, + "PrivateBrowsingUtils should report the correct per-window private browsing status" + ); + is( + srCommand.hasAttribute("disabled"), + true, + "The Session Restore command should be disabled in private browsing mode" + ); + + await BrowserTestUtils.closeWindow(win); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_nonbrowser.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_nonbrowser.js new file mode 100644 index 0000000000..40811292bb --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_nonbrowser.js @@ -0,0 +1,21 @@ +"use strict"; + +/** + * Tests that we fire the last-pb-context-exited observer notification + * when the last private browsing window closes, even if a chrome window + * was opened from that private browsing window. + */ +add_task(async function() { + let win = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + let chromeWin = win.open( + "chrome://browser/content/places/places.xhtml", + "_blank", + "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar" + ); + await BrowserTestUtils.waitForEvent(chromeWin, "load"); + let obsPromise = TestUtils.topicObserved("last-pb-context-exited"); + await BrowserTestUtils.closeWindow(win); + await obsPromise; + Assert.ok(true, "Got the last-pb-context-exited notification"); + chromeWin.close(); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_opendir.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_opendir.js new file mode 100644 index 0000000000..c2dbdbc596 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_opendir.js @@ -0,0 +1,175 @@ +/* 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 last open directory used inside the private +// browsing mode is not remembered after leaving that mode. + +var windowsToClose = []; +function testOnWindow(options, callback) { + var win = OpenBrowserWindow(options); + win.addEventListener( + "load", + function() { + windowsToClose.push(win); + callback(win); + }, + { once: true } + ); +} + +registerCleanupFunction(function() { + windowsToClose.forEach(function(win) { + win.close(); + }); +}); + +function test() { + // initialization + waitForExplicitFinish(); + let dir1 = Services.dirsvc.get("ProfD", Ci.nsIFile); + let dir2 = Services.dirsvc.get("TmpD", Ci.nsIFile); + let file = dir2.clone(); + file.append("pbtest.file"); + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); + + const kPrefName = "browser.open.lastDir"; + + function setupCleanSlate(win) { + win.gLastOpenDirectory.reset(); + Services.prefs.clearUserPref(kPrefName); + } + + setupCleanSlate(window); + + // open one regular and one private window + testOnWindow(undefined, function(nonPrivateWindow) { + setupCleanSlate(nonPrivateWindow); + testOnWindow({ private: true }, function(privateWindow) { + setupCleanSlate(privateWindow); + + // Test 1: general workflow test + + // initial checks + ok( + !nonPrivateWindow.gLastOpenDirectory.path, + "Last open directory path should be initially empty" + ); + nonPrivateWindow.gLastOpenDirectory.path = dir2; + is( + nonPrivateWindow.gLastOpenDirectory.path.path, + dir2.path, + "The path should be successfully set" + ); + nonPrivateWindow.gLastOpenDirectory.path = null; + is( + nonPrivateWindow.gLastOpenDirectory.path.path, + dir2.path, + "The path should be not change when assigning it to null" + ); + nonPrivateWindow.gLastOpenDirectory.path = dir1; + is( + nonPrivateWindow.gLastOpenDirectory.path.path, + dir1.path, + "The path should be successfully outside of the private browsing mode" + ); + + // test the private window + is( + privateWindow.gLastOpenDirectory.path.path, + dir1.path, + "The path should not change when entering the private browsing mode" + ); + privateWindow.gLastOpenDirectory.path = dir2; + is( + privateWindow.gLastOpenDirectory.path.path, + dir2.path, + "The path should successfully change inside the private browsing mode" + ); + + // test the non-private window + is( + nonPrivateWindow.gLastOpenDirectory.path.path, + dir1.path, + "The path should be reset to the same path as before entering the private browsing mode" + ); + + setupCleanSlate(nonPrivateWindow); + setupCleanSlate(privateWindow); + + // Test 2: the user first tries to open a file inside the private browsing mode + + // test the private window + ok( + !privateWindow.gLastOpenDirectory.path, + "No original path should exist inside the private browsing mode" + ); + privateWindow.gLastOpenDirectory.path = dir1; + is( + privateWindow.gLastOpenDirectory.path.path, + dir1.path, + "The path should be successfully set inside the private browsing mode" + ); + // test the non-private window + ok( + !nonPrivateWindow.gLastOpenDirectory.path, + "The path set inside the private browsing mode should not leak when leaving that mode" + ); + + setupCleanSlate(nonPrivateWindow); + setupCleanSlate(privateWindow); + + // Test 3: the last open directory is set from a previous session, it should be used + // in normal mode + + Services.prefs.setComplexValue(kPrefName, Ci.nsIFile, dir1); + is( + nonPrivateWindow.gLastOpenDirectory.path.path, + dir1.path, + "The pref set from last session should take effect outside the private browsing mode" + ); + + setupCleanSlate(nonPrivateWindow); + setupCleanSlate(privateWindow); + + // Test 4: the last open directory is set from a previous session, it should be used + // in private browsing mode mode + + Services.prefs.setComplexValue(kPrefName, Ci.nsIFile, dir1); + // test the private window + is( + privateWindow.gLastOpenDirectory.path.path, + dir1.path, + "The pref set from last session should take effect inside the private browsing mode" + ); + // test the non-private window + is( + nonPrivateWindow.gLastOpenDirectory.path.path, + dir1.path, + "The pref set from last session should remain in effect after leaving the private browsing mode" + ); + + setupCleanSlate(nonPrivateWindow); + setupCleanSlate(privateWindow); + + // Test 5: setting the path to a file shouldn't work + + nonPrivateWindow.gLastOpenDirectory.path = file; + ok( + !nonPrivateWindow.gLastOpenDirectory.path, + "Setting the path to a file shouldn't work when it's originally null" + ); + nonPrivateWindow.gLastOpenDirectory.path = dir1; + nonPrivateWindow.gLastOpenDirectory.path = file; + is( + nonPrivateWindow.gLastOpenDirectory.path.path, + dir1.path, + "Setting the path to a file shouldn't work when it's not originally null" + ); + + // cleanup + file.remove(false); + finish(); + }); + }); +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placesTitleNoUpdate.html b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placesTitleNoUpdate.html new file mode 100644 index 0000000000..f5bb3212f8 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placesTitleNoUpdate.html @@ -0,0 +1,8 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> +<html> + <head> + <title>Title 1</title> + </head> + <body> + </body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placesTitleNoUpdate.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placesTitleNoUpdate.js new file mode 100644 index 0000000000..94cac06158 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placesTitleNoUpdate.js @@ -0,0 +1,61 @@ +/* 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/. */ +/* eslint-disable mozilla/no-arbitrary-setTimeout */ + +// Test to make sure that the visited page titles do not get updated inside the +// private browsing mode. +"use strict"; + +add_task(async function test() { + const TEST_URL = + "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placesTitleNoUpdate.html"; + const TITLE_1 = "Title 1"; + const TITLE_2 = "Title 2"; + + await PlacesUtils.history.clear(); + + let promiseTitleChanged = PlacesTestUtils.waitForNotification( + "page-title-changed", + events => events[0].url == TEST_URL, + "places" + ); + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); + registerCleanupFunction(async () => { + BrowserTestUtils.removeTab(tab); + }); + info("Wait for a title change notification."); + await promiseTitleChanged; + await BrowserTestUtils.waitForCondition(async function() { + let entry = await PlacesUtils.history.fetch(TEST_URL); + return entry && entry.title == TITLE_1; + }, "The title matches the original title after first visit"); + + promiseTitleChanged = PlacesTestUtils.waitForNotification( + "page-title-changed", + events => events[0].url == TEST_URL, + "places" + ); + await PlacesTestUtils.addVisits({ uri: TEST_URL, title: TITLE_2 }); + info("Wait for a title change notification."); + await promiseTitleChanged; + await BrowserTestUtils.waitForCondition(async function() { + let entry = await PlacesUtils.history.fetch(TEST_URL); + return entry && entry.title == TITLE_2; + }, "The title matches the original title after updating visit"); + + let privateWin = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + registerCleanupFunction(async () => { + await BrowserTestUtils.closeWindow(privateWin); + }); + await BrowserTestUtils.openNewForegroundTab(privateWin.gBrowser, TEST_URL); + // Wait long enough to be sure history didn't set a title. + await new Promise(resolve => setTimeout(resolve, 1000)); + is( + (await PlacesUtils.history.fetch(TEST_URL)).title, + TITLE_2, + "The title remains the same after visiting in private window" + ); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js new file mode 100644 index 0000000000..8cf26b6721 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js @@ -0,0 +1,85 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* eslint-disable mozilla/no-arbitrary-setTimeout */ + +// This test makes sure that the title of existing history entries does not +// change inside a private window. + +add_task(async function test() { + const TEST_URL = + "http://mochi.test:8888/browser/browser/components/" + + "privatebrowsing/test/browser/title.sjs"; + let cm = Services.cookies; + + function cleanup() { + // delete all cookies + cm.removeAll(); + // delete all history items + return PlacesUtils.history.clear(); + } + + await cleanup(); + registerCleanupFunction(cleanup); + + let win = await BrowserTestUtils.openNewBrowserWindow(); + registerCleanupFunction(async () => { + await BrowserTestUtils.closeWindow(win); + }); + + let promiseTitleChanged = PlacesTestUtils.waitForNotification( + "page-title-changed", + events => events[0].url == TEST_URL, + "places" + ); + await BrowserTestUtils.openNewForegroundTab(win.gBrowser, TEST_URL); + await promiseTitleChanged; + await BrowserTestUtils.waitForCondition(async function() { + let entry = await PlacesUtils.history.fetch(TEST_URL); + return entry && entry.title == "No Cookie"; + }, "The page should be loaded without any cookie for the first time"); + + promiseTitleChanged = PlacesTestUtils.waitForNotification( + "page-title-changed", + events => events[0].url == TEST_URL, + "places" + ); + await BrowserTestUtils.openNewForegroundTab(win.gBrowser, TEST_URL); + await promiseTitleChanged; + await BrowserTestUtils.waitForCondition(async function() { + let entry = await PlacesUtils.history.fetch(TEST_URL); + return entry && entry.title == "Cookie"; + }, "The page should be loaded with a cookie for the second time"); + + await cleanup(); + + promiseTitleChanged = PlacesTestUtils.waitForNotification( + "page-title-changed", + events => events[0].url == TEST_URL, + "places" + ); + await BrowserTestUtils.openNewForegroundTab(win.gBrowser, TEST_URL); + await promiseTitleChanged; + await BrowserTestUtils.waitForCondition(async function() { + let entry = await PlacesUtils.history.fetch(TEST_URL); + return entry && entry.title == "No Cookie"; + }, "The page should be loaded without any cookie again"); + + // Reopen the page in a private browser window, it should not notify a title + // change. + let win2 = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + registerCleanupFunction(async () => { + let promisePBExit = TestUtils.topicObserved("last-pb-context-exited"); + await BrowserTestUtils.closeWindow(win2); + await promisePBExit; + }); + + await BrowserTestUtils.openNewForegroundTab(win2.gBrowser, TEST_URL); + // Wait long enough to be sure history didn't set a title. + await new Promise(resolve => setTimeout(resolve, 1000)); + is( + (await PlacesUtils.history.fetch(TEST_URL)).title, + "No Cookie", + "The title remains the same after visiting in private window" + ); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_popupblocker.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_popupblocker.js new file mode 100644 index 0000000000..aecf7ba999 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_popupblocker.js @@ -0,0 +1,83 @@ +/* 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 private browsing mode disables the remember option +// for the popup blocker menu. +add_task(async function test() { + let testURI = + "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/popup.html"; + let oldPopupPolicy = Services.prefs.getBoolPref( + "dom.disable_open_during_load" + ); + Services.prefs.setBoolPref("dom.disable_open_during_load", true); + + registerCleanupFunction(() => { + Services.prefs.setBoolPref("dom.disable_open_during_load", oldPopupPolicy); + }); + + function testPopupBlockerMenuItem(aExpectedDisabled, aWindow, aCallback) { + aWindow.gBrowser.addEventListener( + "DOMUpdateBlockedPopups", + function() { + executeSoon(function() { + let notification = aWindow.gBrowser + .getNotificationBox() + .getNotificationWithValue("popup-blocked"); + ok(notification, "The notification box should be displayed"); + + function checkMenuItem(callback) { + dump("CMI: in\n"); + aWindow.document.addEventListener("popupshown", function listener( + event + ) { + dump("CMI: popupshown\n"); + aWindow.document.removeEventListener("popupshown", listener); + + if (aExpectedDisabled) { + is( + aWindow.document + .getElementById("blockedPopupAllowSite") + .getAttribute("disabled"), + "true", + "The allow popups menu item should be disabled" + ); + } + + event.originalTarget.hidePopup(); + dump("CMI: calling back\n"); + callback(); + dump("CMI: called back\n"); + }); + dump("CMI: out\n"); + } + + checkMenuItem(function() { + aCallback(); + }); + notification.querySelector("button").doCommand(); + }); + }, + { once: true } + ); + + BrowserTestUtils.loadURI(aWindow.gBrowser.selectedBrowser, testURI); + } + + let win1 = await BrowserTestUtils.openNewBrowserWindow(); + await new Promise(resolve => waitForFocus(resolve, win1)); + await new Promise(resolve => testPopupBlockerMenuItem(false, win1, resolve)); + + let win2 = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + await new Promise(resolve => waitForFocus(resolve, win2)); + await new Promise(resolve => testPopupBlockerMenuItem(true, win2, resolve)); + + let win3 = await BrowserTestUtils.openNewBrowserWindow(); + await new Promise(resolve => waitForFocus(resolve, win3)); + await new Promise(resolve => testPopupBlockerMenuItem(false, win3, resolve)); + + // Cleanup + await BrowserTestUtils.closeWindow(win1); + await BrowserTestUtils.closeWindow(win2); + await BrowserTestUtils.closeWindow(win3); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_protocolhandler.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_protocolhandler.js new file mode 100644 index 0000000000..d1ace79998 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_protocolhandler.js @@ -0,0 +1,62 @@ +/* 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/. */ +/* eslint-disable mozilla/no-arbitrary-setTimeout */ + +// This test makes sure that the web pages can't register protocol handlers +// inside the private browsing mode. + +add_task(async function test() { + let notificationValue = "Protocol Registration: web+testprotocol"; + let testURI = + "https://example.com/browser/" + + "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_protocolhandler_page.html"; + + let doTest = async function(aIsPrivateMode, aWindow) { + let tab = (aWindow.gBrowser.selectedTab = BrowserTestUtils.addTab( + aWindow.gBrowser, + testURI + )); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); + + let promiseFinished = PromiseUtils.defer(); + setTimeout(function() { + let notificationBox = aWindow.gBrowser.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" + ); + } + + promiseFinished.resolve(); + }, 100); // remember control is added in a setTimeout(0) call + + await promiseFinished.promise; + }; + + // test first when not on private mode + let win = await BrowserTestUtils.openNewBrowserWindow(); + await doTest(false, win); + + // then test when on private mode + let privateWin = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + await doTest(true, privateWin); + + // Cleanup + await BrowserTestUtils.closeWindow(win); + await BrowserTestUtils.closeWindow(privateWin); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_protocolhandler_page.html b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_protocolhandler_page.html new file mode 100644 index 0000000000..200fda0d42 --- /dev/null +++ b/browser/components/privatebrowsing/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 type="text/javascript"> + navigator.registerProtocolHandler("web+testprotocol", + "https://example.com/foobar?uri=%s", + "Test Protocol"); + </script> + </body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_rememberprompt.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_rememberprompt.js new file mode 100644 index 0000000000..57c067e5a6 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_rememberprompt.js @@ -0,0 +1,90 @@ +/* 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 geolocation prompt does not show a remember +// control inside the private browsing mode. + +add_task(async function setup() { + await SpecialPowers.pushPrefEnv({ + set: [["dom.vr.always_support_vr", true]], + }); +}); + +add_task(async function test() { + function checkPrompt(aURL, aName, aPrivateMode, aWindow) { + return (async function() { + aWindow.gBrowser.selectedTab = BrowserTestUtils.addTab( + aWindow.gBrowser, + aURL + ); + await BrowserTestUtils.browserLoaded(aWindow.gBrowser.selectedBrowser); + + let notification = aWindow.PopupNotifications.getNotification(aName); + + // Wait until the notification is available. + while (!notification) { + await new Promise(resolve => { + executeSoon(resolve); + }); + notification = aWindow.PopupNotifications.getNotification(aName); + } + + if (aPrivateMode) { + // Make sure the notification is correctly displayed without a remember control + ok( + !notification.options.checkbox.show, + "Secondary actions should not exist (always/never remember)" + ); + } else { + ok( + notification.options.checkbox.show, + "Secondary actions should exist (always/never remember)" + ); + } + notification.remove(); + + aWindow.gBrowser.removeCurrentTab(); + })(); + } + + function checkPrivateBrowsingRememberPrompt(aURL, aName) { + return (async function() { + let win = await BrowserTestUtils.openNewBrowserWindow(); + let browser = win.gBrowser.selectedBrowser; + BrowserTestUtils.loadURI(browser, aURL); + await BrowserTestUtils.browserLoaded(browser); + + await checkPrompt(aURL, aName, false, win); + + let privateWin = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + let privateBrowser = privateWin.gBrowser.selectedBrowser; + BrowserTestUtils.loadURI(privateBrowser, aURL); + await BrowserTestUtils.browserLoaded(privateBrowser); + + await checkPrompt(aURL, aName, true, privateWin); + + // Cleanup + await BrowserTestUtils.closeWindow(win); + await BrowserTestUtils.closeWindow(privateWin); + })(); + } + + const geoTestPageURL = + "https://example.com/browser/" + + "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt_page.html"; + + await checkPrivateBrowsingRememberPrompt(geoTestPageURL, "geolocation"); + + const vrEnabled = Services.prefs.getBoolPref("dom.vr.enabled"); + + if (vrEnabled) { + const xrTestPageURL = + "https://example.com/browser/" + + "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_xrprompt_page.html"; + + await checkPrivateBrowsingRememberPrompt(xrTestPageURL, "xr"); + } +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_sidebar.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_sidebar.js new file mode 100644 index 0000000000..749eed9766 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_sidebar.js @@ -0,0 +1,85 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This test makes sure that Sidebars do not migrate across windows with +// different privacy states + +// See Bug 885054: https://bugzilla.mozilla.org/show_bug.cgi?id=885054 + +function test() { + waitForExplicitFinish(); + + // opens a sidebar + function openSidebar(win) { + return win.SidebarUI.show("viewBookmarksSidebar").then(() => win); + } + + let windowCache = []; + function cacheWindow(w) { + windowCache.push(w); + return w; + } + function closeCachedWindows() { + windowCache.forEach(w => w.close()); + } + + // Part 1: NON PRIVATE WINDOW -> PRIVATE WINDOW + openWindow(window, {}, 1) + .then(cacheWindow) + .then(openSidebar) + .then(win => openWindow(win, { private: true })) + .then(cacheWindow) + .then(function({ document }) { + let sidebarBox = document.getElementById("sidebar-box"); + is( + sidebarBox.hidden, + true, + "Opening a private window from reg window does not open the sidebar" + ); + }) + // Part 2: NON PRIVATE WINDOW -> NON PRIVATE WINDOW + .then(() => openWindow(window)) + .then(cacheWindow) + .then(openSidebar) + .then(win => openWindow(win)) + .then(cacheWindow) + .then(function({ document }) { + let sidebarBox = document.getElementById("sidebar-box"); + is( + sidebarBox.hidden, + false, + "Opening a reg window from reg window does open the sidebar" + ); + }) + // Part 3: PRIVATE WINDOW -> NON PRIVATE WINDOW + .then(() => openWindow(window, { private: true })) + .then(cacheWindow) + .then(openSidebar) + .then(win => openWindow(win)) + .then(cacheWindow) + .then(function({ document }) { + let sidebarBox = document.getElementById("sidebar-box"); + is( + sidebarBox.hidden, + true, + "Opening a reg window from a private window does not open the sidebar" + ); + }) + // Part 4: PRIVATE WINDOW -> PRIVATE WINDOW + .then(() => openWindow(window, { private: true })) + .then(cacheWindow) + .then(openSidebar) + .then(win => openWindow(win, { private: true })) + .then(cacheWindow) + .then(function({ document }) { + let sidebarBox = document.getElementById("sidebar-box"); + is( + sidebarBox.hidden, + false, + "Opening a private window from private window does open the sidebar" + ); + }) + .then(closeCachedWindows) + .then(finish); +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_theming.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_theming.js new file mode 100644 index 0000000000..ade1357e57 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_theming.js @@ -0,0 +1,46 @@ +/* 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 privatebrowsingmode attribute of the window is correctly +// adjusted based on whether the window is a private window. + +var windowsToClose = []; +function testOnWindow(options, callback) { + var win = OpenBrowserWindow(options); + win.addEventListener( + "load", + function() { + windowsToClose.push(win); + executeSoon(() => callback(win)); + }, + { once: true } + ); +} + +registerCleanupFunction(function() { + windowsToClose.forEach(function(win) { + win.close(); + }); +}); + +function test() { + // initialization + waitForExplicitFinish(); + + ok( + !document.documentElement.hasAttribute("privatebrowsingmode"), + "privatebrowsingmode should not be present in normal mode" + ); + + // open a private window + testOnWindow({ private: true }, function(win) { + is( + win.document.documentElement.getAttribute("privatebrowsingmode"), + "temporary", + 'privatebrowsingmode should be "temporary" inside the private browsing mode' + ); + + finish(); + }); +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_ui.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_ui.js new file mode 100644 index 0000000000..17c5833af6 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_ui.js @@ -0,0 +1,99 @@ +/* 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 gPrivateBrowsingUI object, the Private Browsing +// menu item and its XUL <command> element work correctly. + +function test() { + // initialization + waitForExplicitFinish(); + SpecialPowers.pushPrefEnv({ + set: [["security.allow_eval_with_system_principal", true]], + }); + let windowsToClose = []; + let testURI = "about:blank"; + let pbMenuItem; + let cmd; + + function doTest(aIsPrivateMode, aWindow, aCallback) { + BrowserTestUtils.browserLoaded(aWindow.gBrowser.selectedBrowser).then( + function() { + ok(aWindow.gPrivateBrowsingUI, "The gPrivateBrowsingUI object exists"); + + pbMenuItem = aWindow.document.getElementById("menu_newPrivateWindow"); + ok(pbMenuItem, "The Private Browsing menu item exists"); + + cmd = aWindow.document.getElementById("Tools:PrivateBrowsing"); + isnot( + cmd, + null, + "XUL command object for the private browsing service exists" + ); + + is( + pbMenuItem.getAttribute("label"), + "New Private Window", + 'The Private Browsing menu item should read "New Private Window"' + ); + is( + PrivateBrowsingUtils.isWindowPrivate(aWindow), + aIsPrivateMode, + "PrivateBrowsingUtils should report the correct per-window private browsing status (privateBrowsing should be " + + aIsPrivateMode + + ")" + ); + + aCallback(); + } + ); + + BrowserTestUtils.loadURI(aWindow.gBrowser.selectedBrowser, testURI); + } + + function openPrivateBrowsingModeByUI(aWindow, aCallback) { + Services.obs.addObserver(function observer(aSubject, aTopic, aData) { + aSubject.addEventListener( + "load", + function() { + Services.obs.removeObserver(observer, "domwindowopened"); + windowsToClose.push(aSubject); + aCallback(aSubject); + }, + { once: true } + ); + }, "domwindowopened"); + + cmd = aWindow.document.getElementById("Tools:PrivateBrowsing"); + var func = new Function("", cmd.getAttribute("oncommand")); + func.call(cmd); + } + + 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, opening a new private window from the + // user interface. + openPrivateBrowsingModeByUI(aWin, function(aPrivateWin) { + doTest(true, aPrivateWin, finish); + }); + }); + }); +} diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_urlbarfocus.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_urlbarfocus.js new file mode 100644 index 0000000000..9bad3fc1e2 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_urlbarfocus.js @@ -0,0 +1,48 @@ +/* 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 URL bar is focused when entering the private window. + +"use strict"; + +const { AboutNewTab } = ChromeUtils.import( + "resource:///modules/AboutNewTab.jsm" +); + +function checkUrlbarFocus(win) { + let urlbar = win.gURLBar; + is( + win.document.activeElement, + urlbar.inputField, + "URL Bar should be focused" + ); + is(urlbar.value, "", "URL Bar should be empty"); +} + +function openNewPrivateWindow() { + return new Promise(resolve => { + whenNewWindowLoaded({ private: true }, win => { + executeSoon(() => resolve(win)); + }); + }); +} + +add_task(async function() { + let win = await openNewPrivateWindow(); + checkUrlbarFocus(win); + win.close(); +}); + +add_task(async function() { + AboutNewTab.newTabURL = "about:blank"; + registerCleanupFunction(() => { + AboutNewTab.resetNewTabURL(); + }); + + let win = await openNewPrivateWindow(); + checkUrlbarFocus(win); + win.close(); + + AboutNewTab.resetNewTabURL(); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js new file mode 100644 index 0000000000..e1f72c0b39 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js @@ -0,0 +1,112 @@ +/* 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 window title changes correctly while switching +// from and to private browsing mode. + +const { AppConstants } = ChromeUtils.import( + "resource://gre/modules/AppConstants.jsm" +); + +add_task(async function test() { + const testPageURL = + "http://mochi.test:8888/browser/" + + "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle_page.html"; + requestLongerTimeout(2); + + // initialization of expected titles + let test_title = "Test title"; + let app_name = document.title; + + // XXX: Bug 1597849 - Dehardcode titles by fetching them from Fluent + // to compare with the actual values. + const isMacOS = AppConstants.platform == "macosx"; + + let pb_postfix = isMacOS ? ` — (Private Browsing)` : ` (Private Browsing)`; + let page_with_title = isMacOS ? test_title : `${test_title} — ${app_name}`; + let page_without_title = app_name; + let about_pb_title = app_name; + let pb_page_with_title = isMacOS + ? `${test_title}${pb_postfix}` + : `${test_title} — ${app_name}${pb_postfix}`; + let pb_page_without_title = `${app_name}${pb_postfix}`; + let pb_about_pb_title = `${app_name}${pb_postfix}`; + + async function testTabTitle(aWindow, url, insidePB, expected_title) { + let tab = await BrowserTestUtils.openNewForegroundTab(aWindow.gBrowser); + BrowserTestUtils.loadURI(tab.linkedBrowser, url); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); + + await BrowserTestUtils.waitForCondition(() => { + return aWindow.document.title === expected_title; + }, `Window title should be ${expected_title}, got ${aWindow.document.title}`); + + is( + aWindow.document.title, + expected_title, + "The window title for " + + url + + " is correct (" + + (insidePB ? "inside" : "outside") + + " private browsing mode)" + ); + + let win = aWindow.gBrowser.replaceTabWithWindow(tab); + await BrowserTestUtils.waitForEvent(win, "load", false); + + await BrowserTestUtils.waitForCondition(() => { + return win.document.title === expected_title; + }, `Window title should be ${expected_title}, got ${win.document.title}`); + + is( + win.document.title, + expected_title, + "The window title for " + + url + + " detached tab is correct (" + + (insidePB ? "inside" : "outside") + + " private browsing mode)" + ); + + await Promise.all([ + BrowserTestUtils.closeWindow(win), + BrowserTestUtils.closeWindow(aWindow), + ]); + } + + function openWin(private) { + return BrowserTestUtils.openNewBrowserWindow({ private }); + } + await testTabTitle( + await openWin(false), + "about:blank", + false, + page_without_title + ); + await testTabTitle(await openWin(false), testPageURL, false, page_with_title); + await testTabTitle( + await openWin(false), + "about:privatebrowsing", + false, + about_pb_title + ); + await testTabTitle( + await openWin(true), + "about:blank", + true, + pb_page_without_title + ); + await testTabTitle( + await openWin(true), + testPageURL, + true, + pb_page_with_title + ); + await testTabTitle( + await openWin(true), + "about:privatebrowsing", + true, + pb_about_pb_title + ); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle_page.html b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle_page.html new file mode 100644 index 0000000000..760bde7d14 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle_page.html @@ -0,0 +1,9 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> +<html> + <head> + <title>Test title</title> + </head> + <body> + Test page for the window title test + </body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_xrprompt_page.html b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_xrprompt_page.html new file mode 100644 index 0000000000..4330785df2 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_xrprompt_page.html @@ -0,0 +1,11 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> +<html> + <head> + <title>XR invoker</title> + </head> + <body> + <script type="text/javascript"> + navigator.getVRDisplays(); + </script> + </body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoom.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoom.js new file mode 100644 index 0000000000..048796e7d2 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoom.js @@ -0,0 +1,46 @@ +/* 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 private browsing turns off doesn't cause zoom +// settings to be reset on tab switch (bug 464962) + +add_task(async function test() { + let win = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + let tabAbout = await BrowserTestUtils.openNewForegroundTab( + win.gBrowser, + "about:mozilla" + ); + let tabMozilla = await BrowserTestUtils.openNewForegroundTab( + win.gBrowser, + "about:mozilla" + ); + + let mozillaZoom = win.ZoomManager.zoom; + + // change the zoom on the mozilla page + win.FullZoom.enlarge(); + // make sure the zoom level has been changed + isnot(win.ZoomManager.zoom, mozillaZoom, "Zoom level can be changed"); + mozillaZoom = win.ZoomManager.zoom; + + // switch to about: tab + await BrowserTestUtils.switchTab(win.gBrowser, tabAbout); + + // switch back to mozilla tab + await BrowserTestUtils.switchTab(win.gBrowser, tabMozilla); + + // make sure the zoom level has not changed + is( + win.ZoomManager.zoom, + mozillaZoom, + "Entering private browsing should not reset the zoom on a tab" + ); + + // cleanup + win.FullZoom.reset(); + BrowserTestUtils.removeTab(tabMozilla); + BrowserTestUtils.removeTab(tabAbout); + + await BrowserTestUtils.closeWindow(win); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js new file mode 100644 index 0000000000..36181041bb --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js @@ -0,0 +1,80 @@ +/* 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 about:privatebrowsing does not appear zoomed in +// if there is already a zoom site pref for about:blank (bug 487656). + +add_task(async function test() { + // initialization + let windowsToClose = []; + let windowsToReset = []; + + function promiseLocationChange() { + return new Promise(resolve => { + Services.obs.addObserver(function onLocationChange(subj, topic, data) { + Services.obs.removeObserver(onLocationChange, topic); + resolve(); + }, "browser-fullZoom:location-change"); + }); + } + + async function promiseTestReady(aIsZoomedWindow, aWindow) { + // Need to wait on two things, the ordering of which is not guaranteed: + // (1) the page load, and (2) FullZoom's update to the new page's zoom + // level. FullZoom broadcasts "browser-fullZoom:location-change" when its + // update is done. (See bug 856366 for details.) + + let browser = aWindow.gBrowser.selectedBrowser; + BrowserTestUtils.loadURI(browser, "about:blank"); + await Promise.all([ + BrowserTestUtils.browserLoaded(browser), + promiseLocationChange(), + ]); + doTest(aIsZoomedWindow, aWindow); + } + + function doTest(aIsZoomedWindow, aWindow) { + if (aIsZoomedWindow) { + is( + aWindow.ZoomManager.zoom, + 1, + "Zoom level for freshly loaded about:blank should be 1" + ); + // change the zoom on the blank page + aWindow.FullZoom.enlarge(); + isnot( + aWindow.ZoomManager.zoom, + 1, + "Zoom level for about:blank should be changed" + ); + return; + } + + // make sure the zoom level is set to 1 + is( + aWindow.ZoomManager.zoom, + 1, + "Zoom level for about:privatebrowsing should be reset" + ); + } + + function testOnWindow(options, callback) { + return BrowserTestUtils.openNewBrowserWindow(options).then(win => { + windowsToClose.push(win); + windowsToReset.push(win); + return win; + }); + } + + await testOnWindow({}).then(win => promiseTestReady(true, win)); + await testOnWindow({ private: true }).then(win => + promiseTestReady(false, win) + ); + + // cleanup + windowsToReset.forEach(win => win.FullZoom.reset()); + await Promise.all( + windowsToClose.map(win => BrowserTestUtils.closeWindow(win)) + ); +}); diff --git a/browser/components/privatebrowsing/test/browser/empty_file.html b/browser/components/privatebrowsing/test/browser/empty_file.html new file mode 100644 index 0000000000..0dc101b533 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/empty_file.html @@ -0,0 +1 @@ +<html><body></body></html> diff --git a/browser/components/privatebrowsing/test/browser/file_favicon.html b/browser/components/privatebrowsing/test/browser/file_favicon.html new file mode 100644 index 0000000000..f294b47758 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/file_favicon.html @@ -0,0 +1,11 @@ +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'> + <title>Favicon Test for originAttributes</title> + <link rel="icon" type="image/png" href="file_favicon.png" /> + </head> + <body> + Favicon!! + </body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/file_favicon.png b/browser/components/privatebrowsing/test/browser/file_favicon.png Binary files differnew file mode 100644 index 0000000000..5535363c94 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/file_favicon.png diff --git a/browser/components/privatebrowsing/test/browser/file_favicon.png^headers^ b/browser/components/privatebrowsing/test/browser/file_favicon.png^headers^ new file mode 100644 index 0000000000..9e23c73b7f --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/file_favicon.png^headers^ @@ -0,0 +1 @@ +Cache-Control: no-cache diff --git a/browser/components/privatebrowsing/test/browser/file_triggeringprincipal_oa.html b/browser/components/privatebrowsing/test/browser/file_triggeringprincipal_oa.html new file mode 100644 index 0000000000..cd05e833f3 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/file_triggeringprincipal_oa.html @@ -0,0 +1,10 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1348801</title> +</head> +<body> + <a href="empty_file.html" id="checkPrincipalOA">checkPrincipalOA</a> +</body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/head.js b/browser/components/privatebrowsing/test/browser/head.js new file mode 100644 index 0000000000..f437597512 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/head.js @@ -0,0 +1,90 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +var { PromiseUtils } = ChromeUtils.import( + "resource://gre/modules/PromiseUtils.jsm" +); +var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +ChromeUtils.defineModuleGetter( + this, + "PlacesUtils", + "resource://gre/modules/PlacesUtils.jsm" +); +ChromeUtils.defineModuleGetter( + this, + "PlacesTestUtils", + "resource://testing-common/PlacesTestUtils.jsm" +); +ChromeUtils.defineModuleGetter( + this, + "TestUtils", + "resource://testing-common/TestUtils.jsm" +); + +function whenNewWindowLoaded(aOptions, aCallback) { + let win = OpenBrowserWindow(aOptions); + let focused = SimpleTest.promiseFocus(win); + let startupFinished = TestUtils.topicObserved( + "browser-delayed-startup-finished", + subject => subject == win + ).then(() => win); + Promise.all([focused, startupFinished]).then(results => + executeSoon(() => aCallback(results[1])) + ); + + return win; +} + +function openWindow(aParent, aOptions) { + let win = aParent.OpenBrowserWindow(aOptions); + return TestUtils.topicObserved( + "browser-delayed-startup-finished", + subject => subject == win + ).then(() => win); +} + +/** + * Opens a new private window and loads "about:privatebrowsing" there. + */ +async function openAboutPrivateBrowsing() { + let win = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + waitForTabURL: "about:privatebrowsing", + }); + let tab = win.gBrowser.selectedBrowser; + return { win, tab }; +} + +function newDirectory() { + let FileUtils = ChromeUtils.import("resource://gre/modules/FileUtils.jsm", {}) + .FileUtils; + let tmpDir = FileUtils.getDir("TmpD", [], true); + let dir = tmpDir.clone(); + dir.append("testdir"); + dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + return dir; +} + +function newFileInDirectory(aDir) { + let FileUtils = ChromeUtils.import("resource://gre/modules/FileUtils.jsm", {}) + .FileUtils; + let file = aDir.clone(); + file.append("testfile"); + file.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_FILE); + return file; +} + +function clearHistory() { + // simulate clearing the private data + Services.obs.notifyObservers(null, "browser:purge-session-history"); +} + +function _initTest() { + // Don't use about:home as the homepage for new windows + Services.prefs.setIntPref("browser.startup.page", 0); + registerCleanupFunction(() => + Services.prefs.clearUserPref("browser.startup.page") + ); +} + +_initTest(); diff --git a/browser/components/privatebrowsing/test/browser/popup.html b/browser/components/privatebrowsing/test/browser/popup.html new file mode 100644 index 0000000000..68bbbfa260 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/popup.html @@ -0,0 +1,12 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> +<html> + <head> + <meta charset="utf8"> + <title>Page creating a popup</title> + </head> + <body> + <script type="text/javascript"> + window.open("data:text/plain,test", "testwin"); + </script> + </body> +</html> diff --git a/browser/components/privatebrowsing/test/browser/title.sjs b/browser/components/privatebrowsing/test/browser/title.sjs new file mode 100644 index 0000000000..568e235be1 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/title.sjs @@ -0,0 +1,22 @@ +/* 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 provides the tests with a page with different titles based on whether +// a cookie is present or not. + +function handleRequest(request, response) { + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/html", false); + + var cookie = "name=value"; + var title = "No Cookie"; + if (request.hasHeader("Cookie") && request.getHeader("Cookie") == cookie) + title = "Cookie"; + else + response.setHeader("Set-Cookie", cookie, false); + + response.write("<html><head><title>"); + response.write(title); + response.write("</title><body>test page</body></html>"); +} |