diff options
Diffstat (limited to 'browser/components/privatebrowsing')
56 files changed, 3076 insertions, 0 deletions
diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.css b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.css new file mode 100644 index 000000000..29d7a843d --- /dev/null +++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.css @@ -0,0 +1,10 @@ +html.private .showNormal, +html.normal .showPrivate, +body[tpEnabled] .showTpDisabled, +body:not([tpEnabled]) .showTpEnabled { + display: none !important; +} + +.hide { + display: none; +} diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js new file mode 100644 index 000000000..31ce96347 --- /dev/null +++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js @@ -0,0 +1,98 @@ +/* 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 {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +const FAVICON_QUESTION = "chrome://global/skin/icons/question-32.png"; +const FAVICON_PRIVACY = "chrome://browser/skin/privatebrowsing/favicon.svg"; + +var stringBundle = Services.strings.createBundle( + "chrome://browser/locale/aboutPrivateBrowsing.properties"); + +var prefBranch = Services.prefs.getBranch("privacy.trackingprotection."); +var prefObserver = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, + Ci.nsISupportsWeakReference]), + observe: function () { + let tpSubHeader = document.getElementById("tpSubHeader"); + let tpToggle = document.getElementById("tpToggle"); + let tpButton = document.getElementById("tpButton"); + let title = document.getElementById("title"); + let titleTracking = document.getElementById("titleTracking"); + let globalTrackingEnabled = prefBranch.getBoolPref("enabled"); + let trackingEnabled = globalTrackingEnabled || + prefBranch.getBoolPref("pbmode.enabled"); + + tpButton.classList.toggle("hide", globalTrackingEnabled); + tpToggle.checked = trackingEnabled; + title.classList.toggle("hide", trackingEnabled); + titleTracking.classList.toggle("hide", !trackingEnabled); + tpSubHeader.classList.toggle("tp-off", !trackingEnabled); + } +}; +prefBranch.addObserver("pbmode.enabled", prefObserver, true); +prefBranch.addObserver("enabled", prefObserver, true); + +function setFavIcon(url) { + document.getElementById("favicon").setAttribute("href", url); +} + +document.addEventListener("DOMContentLoaded", function () { + if (!PrivateBrowsingUtils.isContentWindowPrivate(window)) { + document.documentElement.classList.remove("private"); + document.documentElement.classList.add("normal"); + document.title = stringBundle.GetStringFromName("title.normal"); + document.getElementById("favicon") + .setAttribute("href", FAVICON_QUESTION); + document.getElementById("startPrivateBrowsing") + .addEventListener("command", openPrivateWindow); + return; + } + + let tpToggle = document.getElementById("tpToggle"); + document.getElementById("tpButton").addEventListener('click', () => { + tpToggle.click(); + }); + + document.title = stringBundle.GetStringFromName("title.head"); + document.getElementById("favicon") + .setAttribute("href", FAVICON_PRIVACY); + tpToggle.addEventListener("change", toggleTrackingProtection); + document.getElementById("startTour") + .addEventListener("click", dontShowIntroPanelAgain); + + let formatURLPref = Cc["@mozilla.org/toolkit/URLFormatterService;1"] + .getService(Ci.nsIURLFormatter).formatURLPref; + document.getElementById("startTour").setAttribute("href", + formatURLPref("privacy.trackingprotection.introURL")); + document.getElementById("learnMore").setAttribute("href", + formatURLPref("app.support.baseURL") + "private-browsing"); + + // Update state that depends on preferences. + prefObserver.observe(); +}, false); + +function openPrivateWindow() { + // Ask chrome to open a private window + document.dispatchEvent( + new CustomEvent("AboutPrivateBrowsingOpenWindow", {bubbles:true})); +} + +function toggleTrackingProtection() { + // Ask chrome to enable tracking protection + document.dispatchEvent( + new CustomEvent("AboutPrivateBrowsingToggleTrackingProtection", + {bubbles: true})); +} + +function dontShowIntroPanelAgain() { + // Ask chrome to disable the doorhanger + document.dispatchEvent( + new CustomEvent("AboutPrivateBrowsingDontShowIntroPanelAgain", + {bubbles: true})); +} diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml new file mode 100644 index 000000000..fb5c4ac8e --- /dev/null +++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-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/. +--> +<!DOCTYPE html [ + <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> + %htmlDTD; + <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> + %globalDTD; + <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> + %brandDTD; + <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd"> + %browserDTD; + <!ENTITY % aboutPrivateBrowsingDTD SYSTEM "chrome://browser/locale/aboutPrivateBrowsing.dtd"> + %aboutPrivateBrowsingDTD; +]> + +<html xmlns="http://www.w3.org/1999/xhtml" class="private"> + <head> + <link id="favicon" rel="icon" type="image/png"/> + <link rel="stylesheet" href="chrome://browser/content/aboutPrivateBrowsing.css" type="text/css" media="all"/> + <link rel="stylesheet" href="chrome://browser/skin/privatebrowsing/aboutPrivateBrowsing.css" type="text/css" media="all"/> + <script type="application/javascript;version=1.7" src="chrome://browser/content/aboutPrivateBrowsing.js"></script> + </head> + + <body dir="&locale.dir;"> + <p class="showNormal">&aboutPrivateBrowsing.notPrivate;</p> + <button xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + id="startPrivateBrowsing" + class="showNormal" + label="&privatebrowsingpage.openPrivateWindow.label;" + accesskey="&privatebrowsingpage.openPrivateWindow.accesskey;"/> + <div class="showPrivate about-content-container"> + <h1 class="title"> + <span id="title">&privateBrowsing.title;</span> + <span id="titleTracking">&privateBrowsing.title.tracking;</span> + </h1> + <section class="section-main"> + <p>&aboutPrivateBrowsing.info.notsaved.before;<strong>&aboutPrivateBrowsing.info.notsaved.emphasize;</strong>&aboutPrivateBrowsing.info.notsaved.after;</p> + <div class="list-row"> + <ul> + <li>&aboutPrivateBrowsing.info.visited;</li> + <li>&aboutPrivateBrowsing.info.cookies;</li> + <li>&aboutPrivateBrowsing.info.searches;</li> + <li>&aboutPrivateBrowsing.info.temporaryFiles;</li> + </ul> + </div> + <p>&aboutPrivateBrowsing.info.saved.before;<strong>&aboutPrivateBrowsing.info.saved.emphasize;</strong>&aboutPrivateBrowsing.info.saved.after2;</p> + <div class="list-row"> + <ul> + <li>&aboutPrivateBrowsing.info.bookmarks;</li> + <li>&aboutPrivateBrowsing.info.downloads;</li> + </ul> + </div> + <p> + &aboutPrivateBrowsing.note.before; + <strong>&aboutPrivateBrowsing.note.emphasize;</strong> + &aboutPrivateBrowsing.note.after; + </p> + </section> + + <h2 id="tpSubHeader" class="about-subheader"> + <span class="tpTitle">&trackingProtection.title;</span> + <input id="tpToggle" class="toggle toggle-input" type="checkbox"/> + <span id="tpButton" class="toggle-btn"></span> + </h2> + + <section class="section-main"> + <p>&trackingProtection.description2;</p> + <p> + <a id="startTour" class="button">&trackingProtection.startTour1;</a> + </p> + </section> + + <section class="section-main"> + <p class="about-info">&aboutPrivateBrowsing.learnMore2; + <a id="learnMore" target="_blank">&aboutPrivateBrowsing.learnMore2.title;</a>. + </p> + </section> + + </div> + </body> +</html> diff --git a/browser/components/privatebrowsing/jar.mn b/browser/components/privatebrowsing/jar.mn new file mode 100644 index 000000000..a98d65163 --- /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.xhtml (content/aboutPrivateBrowsing.xhtml) + 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 000000000..486737a7f --- /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/.eslintrc.js b/browser/components/privatebrowsing/test/browser/.eslintrc.js new file mode 100644 index 000000000..7c8021192 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/mochitest/browser.eslintrc.js" + ] +}; diff --git a/browser/components/privatebrowsing/test/browser/browser.ini b/browser/components/privatebrowsing/test/browser/browser.ini new file mode 100644 index 000000000..5efca4c0e --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser.ini @@ -0,0 +1,54 @@ +[DEFAULT] +tags = openwindow +support-files = + browser_privatebrowsing_concurrent_page.html + browser_privatebrowsing_geoprompt_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^ + +[browser_privatebrowsing_DownloadLastDirWithCPS.js] +[browser_privatebrowsing_about.js] +tags = trackingprotection +[browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js] +[browser_privatebrowsing_aboutSessionRestore.js] +[browser_privatebrowsing_cache.js] +[browser_privatebrowsing_certexceptionsui.js] +[browser_privatebrowsing_concurrent.js] +[browser_privatebrowsing_context_and_chromeFlags.js] +[browser_privatebrowsing_crh.js] +[browser_privatebrowsing_downloadLastDir.js] +[browser_privatebrowsing_downloadLastDir_c.js] +[browser_privatebrowsing_downloadLastDir_toggle.js] +[browser_privatebrowsing_favicon.js] +[browser_privatebrowsing_geoprompt.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_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] +[browser_privatebrowsing_blobUrl.js] 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 000000000..bcd19b192 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js @@ -0,0 +1,282 @@ +/* -*- 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); + gTests = runTest(); + gTests.next(); +} + +/* + * ================ + * Helper functions + * ================ + */ + +function moveAlong(aResult) { + try { + gTests.send(aResult); + } catch (x if x instanceof StopIteration) { + finish(); + } +} + +function createWindow(aOptions) { + whenNewWindowLoaded(aOptions, function(win) { + moveAlong(win); + }); +} + +function getFile(downloadLastDir, aURI) { + downloadLastDir.getFileAsync(aURI, function(result) { + moveAlong(result); + }); +} + +function setFile(downloadLastDir, aURI, aValue) { + downloadLastDir.setFile(aURI, aValue); + executeSoon(moveAlong); +} + +function clearHistoryAndWait() { + clearHistory(); + executeSoon(() => executeSoon(moveAlong)); +} + +/* + * =================== + * Function with tests + * =================== + */ + +function runTest() { + let FileUtils = + Cu.import("resource://gre/modules/FileUtils.jsm", {}).FileUtils; + let DownloadLastDir = + Cu.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/", null, null); + let uri2 = Services.io.newURI("http://test2.com/", null, null); + let uri3 = Services.io.newURI("http://test3.com/", null, null); + let uri4 = Services.io.newURI("http://test4.com/", null, null); + + // 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"); + getFile(gDownloadLastDir, uri1); + } + + function checkDownloadLastDirNull(gDownloadLastDir) { + is(gDownloadLastDir.file, null, "gDownloadLastDir should be null"); + getFile(gDownloadLastDir, uri1); + } + + /* + * ================================ + * Create a regular and a PB window + * ================================ + */ + + let win = yield createWindow({private: false}); + let pbWin = yield 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 + yield 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 + yield 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((yield getFile(downloadLastDir, uri1)).path, dir1.path, + "uri1 should return dir1"); // set in CPS + isnot((yield getFile(downloadLastDir, uri1)), dir1, + "getFile on uri1 should not return dir1"); + is((yield getFile(downloadLastDir, uri2)).path, dir1.path, + "uri2 should return dir1"); // fallback + isnot((yield getFile(downloadLastDir, uri2)), dir1, + "getFile on uri2 should not return dir1"); + is((yield getFile(downloadLastDir, uri3)).path, dir1.path, + "uri3 should return dir1"); // fallback + isnot((yield getFile(downloadLastDir, uri3)), dir1, + "getFile on uri3 should not return dir1"); + is((yield getFile(downloadLastDir, uri4)).path, dir1.path, + "uri4 should return dir1"); // fallback + isnot((yield getFile(downloadLastDir, uri4)), dir1, + "getFile on uri4 should not return dir1"); + + // set uri2 to dir2, all except uri1 should now return dir2 + yield setFile(downloadLastDir, uri2, dir2); + is(downloadLastDir.file.path, dir2.path, + "downloadLastDir should point to dir2"); + is((yield getFile(downloadLastDir, uri1)).path, dir1.path, + "uri1 should return dir1"); // set in CPS + is((yield getFile(downloadLastDir, uri2)).path, dir2.path, + "uri2 should return dir2"); // set in CPS + is((yield getFile(downloadLastDir, uri3)).path, dir2.path, + "uri3 should return dir2"); // fallback + is((yield getFile(downloadLastDir, uri4)).path, dir2.path, + "uri4 should return dir2"); // fallback + + // set uri3 to dir3, all except uri1 and uri2 should now return dir3 + yield setFile(downloadLastDir, uri3, dir3); + is(downloadLastDir.file.path, dir3.path, + "downloadLastDir should point to dir3"); + is((yield getFile(downloadLastDir, uri1)).path, dir1.path, + "uri1 should return dir1"); // set in CPS + is((yield getFile(downloadLastDir, uri2)).path, dir2.path, + "uri2 should return dir2"); // set in CPS + is((yield getFile(downloadLastDir, uri3)).path, dir3.path, + "uri3 should return dir3"); // set in CPS + is((yield getFile(downloadLastDir, uri4)).path, dir3.path, + "uri4 should return dir4"); // fallback + + // set uri1 to dir2, all except uri3 should now return dir2 + yield setFile(downloadLastDir, uri1, dir2); + is(downloadLastDir.file.path, dir2.path, + "downloadLastDir should point to dir2"); + is((yield getFile(downloadLastDir, uri1)).path, dir2.path, + "uri1 should return dir2"); // set in CPS + is((yield getFile(downloadLastDir, uri2)).path, dir2.path, + "uri2 should return dir2"); // set in CPS + is((yield getFile(downloadLastDir, uri3)).path, dir3.path, + "uri3 should return dir3"); // set in CPS + is((yield getFile(downloadLastDir, uri4)).path, dir2.path, + "uri4 should return dir2"); // fallback + + yield clearHistoryAndWait(); + + // check clearHistory removes all data + is(downloadLastDir.file, null, "clearHistory removes all data"); + //is(Services.contentPrefs.hasPref(uri1, "browser.download.lastDir", null), + // false, "LastDir preference should be absent"); + is((yield getFile(downloadLastDir, uri1)), null, "uri1 should point to null"); + is((yield getFile(downloadLastDir, uri2)), null, "uri2 should point to null"); + is((yield getFile(downloadLastDir, uri3)), null, "uri3 should point to null"); + is((yield getFile(downloadLastDir, uri4)), null, "uri4 should point to null"); + + yield setFile(downloadLastDir, null, tmpDir); + + // check data set outside PB mode is remembered + is((yield checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory"); + is((yield checkDownloadLastDir(downloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory"); + yield clearHistoryAndWait(); + + yield setFile(downloadLastDir, uri1, dir1); + + // check data set using CPS outside PB mode is remembered + is((yield checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); + is((yield checkDownloadLastDir(downloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); + yield clearHistoryAndWait(); + + // check data set inside PB mode is forgotten + yield setFile(pbDownloadLastDir, null, tmpDir); + + is((yield checkDownloadLastDir(pbDownloadLastDir, tmpDir)).path, tmpDir.path, "uri1 should return the expected last directory"); + is((yield checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory"); + + yield clearHistoryAndWait(); + + // check data set using CPS inside PB mode is forgotten + yield setFile(pbDownloadLastDir, uri1, dir1); + + is((yield checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); + is((yield checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory"); + + // check data set outside PB mode but changed inside is remembered correctly + yield setFile(downloadLastDir, uri1, dir1); + yield setFile(pbDownloadLastDir, uri1, dir2); + is((yield checkDownloadLastDir(pbDownloadLastDir, dir2)).path, dir2.path, "uri1 should return the expected last directory"); + is((yield 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 + executeSoon(moveAlong); + yield; + pbWin = yield createWindow({private: true}); + pbDownloadLastDir = new DownloadLastDir(pbWin); + + is((yield checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); + + yield clearHistoryAndWait(); + + // check clearHistory inside PB mode clears data outside PB mode + yield setFile(pbDownloadLastDir, uri1, dir2); + + yield clearHistoryAndWait(); + + is((yield checkDownloadLastDirNull(downloadLastDir)), null, "uri1 should return the expected last directory"); + is((yield checkDownloadLastDirNull(pbDownloadLastDir)), null, "uri1 should return the expected last directory"); + + // check that disabling CPS works + Services.prefs.setBoolPref("browser.download.lastDir.savePerSite", false); + + yield setFile(downloadLastDir, uri1, dir1); + is(downloadLastDir.file.path, dir1.path, "LastDir should be set to dir1"); + is((yield getFile(downloadLastDir, uri1)).path, dir1.path, "uri1 should return dir1"); + is((yield getFile(downloadLastDir, uri2)).path, dir1.path, "uri2 should return dir1"); + is((yield getFile(downloadLastDir, uri3)).path, dir1.path, "uri3 should return dir1"); + is((yield 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((yield getFile(downloadLastDir, uri1)).path, dir2.path, "uri1 should return dir2"); + is((yield getFile(downloadLastDir, uri2)).path, dir2.path, "uri2 should return dir2"); + is((yield getFile(downloadLastDir, uri3)).path, dir2.path, "uri3 should return dir2"); + is((yield 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 + yield setFile(downloadLastDir, uri3, dir3); + is((yield getFile(downloadLastDir, uri3)).path, dir3.path, "LastDir should be set to dir3"); + yield setFile(downloadLastDir, uri3, null); + is((yield getFile(downloadLastDir, uri3)), null, "uri3 should return null"); + + yield clearHistoryAndWait(); +} 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 000000000..e00f3f67a --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js @@ -0,0 +1,115 @@ +/* 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/. */ + +/** + * Opens a new private window and loads "about:privatebrowsing" there. + */ +function* openAboutPrivateBrowsing() { + let win = yield BrowserTestUtils.openNewBrowserWindow({ private: true }); + let tab = win.gBrowser.selectedBrowser; + tab.loadURI("about:privatebrowsing"); + yield BrowserTestUtils.browserLoaded(tab); + return { win, tab }; +} + +/** + * Clicks the given link and checks this opens a new tab with the given URI. + */ +function* testLinkOpensTab({ win, tab, elementId, expectedUrl }) { + let newTabPromise = BrowserTestUtils.waitForNewTab(win.gBrowser, expectedUrl); + yield ContentTask.spawn(tab, { elementId }, function* ({ elementId }) { + content.document.getElementById(elementId).click(); + }); + let newTab = yield newTabPromise; + ok(true, `Clicking ${elementId} opened ${expectedUrl} in a new tab.`); + yield BrowserTestUtils.removeTab(newTab); +} + +/** + * Clicks the given link and checks this opens the given URI in the same tab. + * + * This function does not return to the previous page. + */ +function* testLinkOpensUrl({ win, tab, elementId, expectedUrl }) { + let loadedPromise = BrowserTestUtils.browserLoaded(tab); + yield ContentTask.spawn(tab, { elementId }, function* ({ elementId }) { + content.document.getElementById(elementId).click(); + }); + yield loadedPromise; + is(tab.currentURI.spec, expectedUrl, + `Clicking ${elementId} opened ${expectedUrl} in the same tab.`); +} + +/** + * Tests the links in "about:privatebrowsing". + */ +add_task(function* test_links() { + // Use full version and change the remote URLs to prevent network access. + Services.prefs.setCharPref("app.support.baseURL", "https://example.com/"); + Services.prefs.setCharPref("privacy.trackingprotection.introURL", + "https://example.com/tour"); + registerCleanupFunction(function () { + Services.prefs.clearUserPref("privacy.trackingprotection.introURL"); + Services.prefs.clearUserPref("app.support.baseURL"); + }); + + let { win, tab } = yield openAboutPrivateBrowsing(); + + yield testLinkOpensTab({ win, tab, + elementId: "learnMore", + expectedUrl: "https://example.com/private-browsing", + }); + + yield testLinkOpensUrl({ win, tab, + elementId: "startTour", + expectedUrl: "https://example.com/tour", + }); + + yield BrowserTestUtils.closeWindow(win); +}); + +/** + * Tests the action to disable and re-enable Tracking Protection in + * "about:privatebrowsing". + */ +add_task(function* test_toggleTrackingProtection() { + // Use tour version but disable Tracking Protection. + Services.prefs.setBoolPref("privacy.trackingprotection.pbmode.enabled", + true); + registerCleanupFunction(function () { + Services.prefs.clearUserPref("privacy.trackingprotection.pbmode.enabled"); + }); + + let { win, tab } = yield openAboutPrivateBrowsing(); + + // Set up the observer for the preference change before triggering the action. + let prefBranch = + Services.prefs.getBranch("privacy.trackingprotection.pbmode."); + let waitForPrefChanged = () => new Promise(resolve => { + let prefObserver = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), + observe: function () { + prefBranch.removeObserver("enabled", prefObserver); + resolve(); + }, + }; + prefBranch.addObserver("enabled", prefObserver, false); + }); + + let promisePrefChanged = waitForPrefChanged(); + yield ContentTask.spawn(tab, {}, function* () { + content.document.getElementById("tpButton").click(); + }); + yield promisePrefChanged; + ok(!prefBranch.getBoolPref("enabled"), "Tracking Protection is disabled."); + + promisePrefChanged = waitForPrefChanged(); + yield ContentTask.spawn(tab, {}, function* () { + content.document.getElementById("tpButton").click(); + }); + yield promisePrefChanged; + ok(prefBranch.getBoolPref("enabled"), "Tracking Protection is enabled."); + + yield BrowserTestUtils.closeWindow(win); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js new file mode 100644 index 000000000..6f52f7719 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js @@ -0,0 +1,24 @@ +/* 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 "Restore Previous Session" +// button on about:home is disabled in private mode +add_task(function* test_no_sessionrestore_button() { + // Opening, then closing, a private window shouldn't create session data. + (yield BrowserTestUtils.openNewBrowserWindow({private: true})).close(); + + let win = yield BrowserTestUtils.openNewBrowserWindow({private: true}); + let tab = win.gBrowser.addTab("about:home"); + let browser = tab.linkedBrowser; + + yield BrowserTestUtils.browserLoaded(browser); + + yield ContentTask.spawn(browser, null, function* () { + let button = content.document.getElementById("restorePreviousSession"); + Assert.equal(content.getComputedStyle(button).display, "none", + "The Session Restore about:home button should be disabled"); + }); + + win.close(); +}); 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 000000000..5f6a91836 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutSessionRestore.js @@ -0,0 +1,23 @@ +/* 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(function* testNoSessionRestoreButton() { + // Opening, then closing, a private window shouldn't create session data. + (yield BrowserTestUtils.openNewBrowserWindow({private: true})).close(); + + let win = yield BrowserTestUtils.openNewBrowserWindow({private: true}); + let tab = win.gBrowser.addTab("about:sessionrestore"); + let browser = tab.linkedBrowser; + + yield BrowserTestUtils.browserLoaded(browser); + + yield ContentTask.spawn(browser, null, 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_blobUrl.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_blobUrl.js new file mode 100644 index 000000000..2ceb1032b --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_blobUrl.js @@ -0,0 +1,45 @@ +"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(function* test() { + info("Creating a normal window..."); + let win = yield BrowserTestUtils.openNewBrowserWindow(); + let tab = win.gBrowser.selectedBrowser; + tab.loadURI(BASE_URI); + yield BrowserTestUtils.browserLoaded(tab); + + let blobURL; + + info("Creating a blob URL..."); + yield ContentTask.spawn(tab, null, function() { + return Promise.resolve(content.window.URL.createObjectURL(new content.window.Blob([123]))); + }).then(newURL => { blobURL = newURL }); + + info("Blob URL: " + blobURL); + + info("Creating a private window..."); + let privateWin = yield BrowserTestUtils.openNewBrowserWindow({ private: true }); + let privateTab = privateWin.gBrowser.selectedBrowser; + privateTab.loadURI(BASE_URI); + yield BrowserTestUtils.browserLoaded(privateTab); + + yield ContentTask.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"); + }); + + yield BrowserTestUtils.closeWindow(win); + yield 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 000000000..4990f6d3b --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cache.js @@ -0,0 +1,138 @@ +/* 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 {LoadContextInfo} = Cu.import("resource://gre/modules/LoadContextInfo.jsm", null); + +var tmp = {}; + +Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader) + .loadSubScript("chrome://browser/content/sanitize.js", tmp); + +var Sanitizer = tmp.Sanitizer; + +function test() { + + waitForExplicitFinish(); + + sanitizeCache(); + + let nrEntriesR1 = getStorageEntryCount("regular", function(nrEntriesR1) { + is(nrEntriesR1, 0, "Disk cache reports 0KB and has no entries"); + + get_cache_for_private_window(); + }); +} + +function cleanup() { + let prefs = Services.prefs.getBranch("privacy.cpd."); + + prefs.clearUserPref("history"); + prefs.clearUserPref("downloads"); + prefs.clearUserPref("cache"); + prefs.clearUserPref("cookies"); + prefs.clearUserPref("formdata"); + prefs.clearUserPref("offlineApps"); + prefs.clearUserPref("passwords"); + prefs.clearUserPref("sessions"); + prefs.clearUserPref("siteSettings"); +} + +function sanitizeCache() { + + let s = new Sanitizer(); + s.ignoreTimespan = false; + s.prefDomain = "privacy.cpd."; + + let prefs = gPrefService.getBranch(s.prefDomain); + prefs.setBoolPref("history", false); + prefs.setBoolPref("downloads", false); + prefs.setBoolPref("cache", true); + prefs.setBoolPref("cookies", false); + prefs.setBoolPref("formdata", false); + prefs.setBoolPref("offlineApps", false); + prefs.setBoolPref("passwords", false); + prefs.setBoolPref("sessions", false); + prefs.setBoolPref("siteSettings", false); + + s.sanitize(); +} + +function get_cache_service() { + return Components.classes["@mozilla.org/netwerk/cache-storage-service;1"] + .getService(Components.interfaces.nsICacheStorageService); +} + +function getStorageEntryCount(device, goon) { + var cs = get_cache_service(); + + var storage; + switch (device) { + case "private": + storage = cs.diskCacheStorage(LoadContextInfo.private, false); + break; + case "regular": + storage = cs.diskCacheStorage(LoadContextInfo.default, false); + break; + default: + throw "Unknown device " + device + " at getStorageEntryCount"; + } + + var visitor = { + entryCount: 0, + onCacheStorageInfo: function (aEntryCount, aConsumption) { + }, + onCacheEntryInfo: function(uri) + { + var urispec = uri.asciiSpec; + info(device + ":" + urispec + "\n"); + if (urispec.match(/^http:\/\/example.org\//)) + ++this.entryCount; + }, + onCacheEntryVisitCompleted: function() + { + 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 = win.gBrowser.addTab("http://example.org"); + win.gBrowser.selectedTab = tab; + let newTabBrowser = win.gBrowser.getBrowserForTab(tab); + + newTabBrowser.addEventListener("load", function eventHandler() { + newTabBrowser.removeEventListener("load", eventHandler, true); + + 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"); + + cleanup(); + + win.close(); + finish(); + }); + }); + }); + }, true); + }); + }); +} 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 000000000..519f43475 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_certexceptionsui.js @@ -0,0 +1,53 @@ +/* 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.xul'; + 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 onLoad() { + pbWin.removeEventListener("load", onLoad, false); + doTest(); + }, false); + + // Test the certificate exceptions dialog + function doTest() { + let params = { + exceptionAdded : false, + location: INVALID_CERT_LOCATION, + prefetchCert: true, + }; + function testCheckbox() { + win.removeEventListener("load", testCheckbox, false); + 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", false); + } + var win = pbWin.openDialog(EXCEPTIONS_DLG_URL, "", EXCEPTIONS_DLG_FEATURES, params); + win.addEventListener("load", testCheckbox, false); + } + + function cleanup() { + // close the private browsing window + pbWin.close(); + finish(); + } +} 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 000000000..b73bbf219 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_concurrent.js @@ -0,0 +1,88 @@ +/* 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(function* setup() { + yield SpecialPowers.pushPrefEnv({ + set: [["dom.ipc.processCount", 1]] + }); +}); + +add_task(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; + non_private_browser.loadURI(prefix + '?action=set&name=test&value=value&initial=true'); + yield BrowserTestUtils.browserLoaded(non_private_browser); + + + // Step 2 + let private_window = yield BrowserTestUtils.openNewBrowserWindow({ private : true }); + let private_browser = private_window.getBrowser().selectedBrowser; + private_browser.loadURI(prefix + '?action=set&name=test2&value=value2'); + yield BrowserTestUtils.browserLoaded(private_browser); + + + // Step 3 + non_private_browser.loadURI(prefix + '?action=get&name=test2'); + yield BrowserTestUtils.browserLoaded(non_private_browser); + let elts = yield 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 + private_browser.loadURI(prefix + '?action=get&name=test'); + yield BrowserTestUtils.browserLoaded(private_browser); + elts = yield 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 = yield BrowserTestUtils.openNewBrowserWindow({ private : false }); + private_browser = null; + yield new Promise(resolve => Cu.schedulePreciseGC(resolve)); + private_browser = private_window.getBrowser().selectedBrowser; + + private_browser.loadURI(prefix + '?action=get&name=test2'); + yield BrowserTestUtils.browserLoaded(private_browser); + elts = yield 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 = yield BrowserTestUtils.openNewBrowserWindow({ private : true }); + private_browser = null; + yield new Promise(resolve => Cu.schedulePreciseGC(resolve)); + private_browser = private_window.getBrowser().selectedBrowser; + + private_browser.loadURI(prefix + '?action=set&name=test3&value=value3'); + yield BrowserTestUtils.browserLoaded(private_browser); + elts = yield getElts(private_browser); + is(elts[1], '1', "private window should only see new private items"); + + // Cleanup. + non_private_browser.loadURI(prefix + '?final=true'); + yield BrowserTestUtils.browserLoaded(non_private_browser); + 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 000000000..db35b114d --- /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 000000000..30f7ee025 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_context_and_chromeFlags.js @@ -0,0 +1,60 @@ +"use strict"; + +/** + * Given some window in the parent process, ensure that + * the nsIXULWindow 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.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDocShell); + let chromeFlags = winDocShell.QueryInterface(Ci.nsIDocShellTreeItem) + .treeOwner + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIXULWindow) + .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 ContentTask.spawn(win.gBrowser.selectedBrowser, null, function*() { + let loadContext = docShell.QueryInterface(Ci.nsILoadContext); + Assert.ok(loadContext.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(function* test_context_and_chromeFlags() { + let win = yield BrowserTestUtils.openNewBrowserWindow({ private: true }); + yield assertWindowIsPrivate(win); + + let browser = win.gBrowser.selectedBrowser; + + let newWinPromise = BrowserTestUtils.waitForNewWindow(); + yield ContentTask.spawn(browser, null, function*() { + content.open("http://example.com", "_blank", "width=100,height=100"); + }); + + let win2 = yield newWinPromise; + yield assertWindowIsPrivate(win2); + + yield BrowserTestUtils.closeWindow(win2); + yield 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 000000000..cd316d1fb --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_crh.js @@ -0,0 +1,42 @@ +/* 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(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 = yield BrowserTestUtils.openNewBrowserWindow({private: true}); + let privateBrowser = privateWin.gBrowser.selectedBrowser; + privateBrowser.loadURI(testURI); + yield BrowserTestUtils.browserLoaded(privateBrowser); + + info("Test on private window"); + checkDisableOption(true, privateWin); + + + let win = yield BrowserTestUtils.openNewBrowserWindow(); + let browser = win.gBrowser.selectedBrowser; + browser.loadURI(testURI); + yield BrowserTestUtils.browserLoaded(browser); + + info("Test on public window"); + checkDisableOption(false, win); + + + // Cleanup + yield BrowserTestUtils.closeWindow(privateWin); + yield 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 000000000..81b2943ee --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir.js @@ -0,0 +1,93 @@ +/* -*- 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 = + Cu.import("resource://gre/modules/FileUtils.jsm", {}).FileUtils; + let DownloadLastDir = + Cu.import("resource://gre/modules/DownloadLastDir.jsm", {}).DownloadLastDir; + let MockFilePicker = SpecialPowers.MockFilePicker; + let launcher = { + source: Services.io.newURI("http://test1.com/file", null, null) + }; + + 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.returnFiles = [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(win, downloadDir) { + testDownloadDir(win, downloadDir, file2, dir1, dir1, dir2, function() { + testOnWindow(false, function(win, downloadDir) { + testDownloadDir(win, downloadDir, 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 000000000..5a04d1999 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_c.js @@ -0,0 +1,95 @@ +/* -*- 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 = + Cu.import("resource://gre/modules/FileUtils.jsm", {}).FileUtils; + let DownloadLastDir = + Cu.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.returnFiles = [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(); + }).then(null, function() { ok(false); }); + } + + testOnWindow(false, function(win, downloadDir) { + testDownloadDir(win, downloadDir, file1, tmpDir, dir1, dir1, function() { + testOnWindow(true, function(win, downloadDir) { + testDownloadDir(win, downloadDir, file2, dir1, dir1, dir2, function() { + testOnWindow(false, function(win, downloadDir) { + testDownloadDir(win, downloadDir, 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 000000000..b192c08f7 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js @@ -0,0 +1,105 @@ +Cu.import("resource://gre/modules/FileUtils.jsm"); +Cu.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(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 = yield 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; + yield BrowserTestUtils.closeWindow(win); + + info("Opening the first private window"); + yield testHelper({ private: true, expectedDir: tmpDir }); + info("Opening a non-private window"); + yield testHelper({ private: false, expectedDir: tmpDir }); + info("Opening a private window and setting download directory"); + yield testHelper({ private: true, setDir: dir1, expectedDir: dir1 }); + info("Opening a non-private window and checking download directory"); + yield testHelper({ private: false, expectedDir: tmpDir }); + info("Opening private window and clearing history"); + yield testHelper({ private: true, clearHistory: true, expectedDir: null }); + info("Opening a non-private window and checking download directory"); + yield 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 + */ +function testHelper(options) { + return new Task.spawn(function() { + let win = yield 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(); + yield 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 000000000..86f714082 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js @@ -0,0 +1,293 @@ +/* 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 { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components; + +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 = Cu.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", false); + } + } + }; + + Services.obs.addObserver(observer, "places-favicons-expired", false); + faviconService.expireAllFavicons(); + }); +} + +function observeFavicon(aIsPrivate, aExpectedCookie, aPageURI) { + let faviconReqXUL = false; + let faviconReqPlaces = false; + let attr = {}; + + if (aIsPrivate) { + attr.privateBrowsingId = 1; + } + + let expectedPrincipal = Services.scriptSecurityManager + .createCodebasePrincipal(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; + let triggeringPrincipal = reqLoadInfo.triggeringPrincipal; + + // 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"); + } + + if (loadingPrincipal.equals(systemPrincipal)) { + faviconReqXUL = true; + ok(triggeringPrincipal.equals(expectedPrincipal), + "The triggeringPrincipal of favicon loading from XUL should be the content principal."); + } else { + faviconReqPlaces = true; + 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); + } + + if (faviconReqXUL && faviconReqPlaces) { + resolve(); + Services.obs.removeObserver(observer, "http-on-modify-request", false); + } + } + }; + + Services.obs.addObserver(observer, "http-on-modify-request", false); + }); +} + +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", false); + Services.obs.removeObserver(observer, "http-on-examine-cached-response", false); + } + } + }; + + Services.obs.addObserver(observer, "http-on-examine-response", false); + Services.obs.addObserver(observer, "http-on-examine-cached-response", false); + }); +} + +function waitOnFaviconLoaded(aFaviconURL) { + return new Promise(resolve => { + let observer = { + onPageChanged(uri, attr, value, id) { + + if (attr === Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON && + value === aFaviconURL) { + resolve(); + PlacesUtils.history.removeObserver(observer, false); + } + }, + }; + + PlacesUtils.history.addObserver(observer, false); + }); +} + +function* assignCookies(aBrowser, aURL, aCookieValue){ + let tabInfo = yield openTab(aBrowser, aURL); + + yield ContentTask.spawn(tabInfo.browser, aCookieValue, function* (value) { + content.document.cookie = value; + }); + + yield BrowserTestUtils.removeTab(tabInfo.tab); +} + +function* openTab(aBrowser, aURL) { + let tab = aBrowser.addTab(aURL); + + // Select tab and make sure its browser is focused. + aBrowser.selectedTab = tab; + tab.ownerGlobal.focus(); + + let browser = aBrowser.getBrowserForTab(tab); + yield BrowserTestUtils.browserLoaded(browser); + return {tab, browser}; +} + +// A clean up function to prevent affecting other tests. +registerCleanupFunction(() => { + // Clear all cookies. + let cookieMgr = Cc["@mozilla.org/cookiemanager;1"] + .getService(Ci.nsICookieManager); + cookieMgr.removeAll(); + + // Clear all image caches and network caches. + clearAllImageCaches(); + + let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"] + .getService(Ci.nsICacheStorageService); + networkCache.clear(); +}); + +add_task(function* test_favicon_privateBrowsing() { + // Clear all image caches before running the test. + clearAllImageCaches(); + + // Clear all favicons in Places. + yield clearAllPlacesFavicons(); + + // Create a private browsing window. + let privateWindow = yield 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. + yield assignCookies(privateWindow.gBrowser, TEST_SITE, cookies[0]); + + // Open a tab in non-private window and add a cookie into it. + yield 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); + + // Open a tab for the private window. + let tabInfo = yield openTab(privateWindow.gBrowser, TEST_PAGE); + + // Waiting until favicon requests are all made. + yield promiseObserveFavicon; + + // Close the tab. + yield BrowserTestUtils.removeTab(tabInfo.tab); + + // 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 = yield openTab(gBrowser, TEST_PAGE); + + // Waiting until favicon requests are all made. + yield promiseObserveFavicon; + + // Close the tab. + yield BrowserTestUtils.removeTab(tabInfo.tab); + yield BrowserTestUtils.closeWindow(privateWindow); +}); + +add_task(function* test_favicon_cache_privateBrowsing() { + // Clear all image cahces and network cache before running the test. + clearAllImageCaches(); + + let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"] + .getService(Ci.nsICacheStorageService); + networkCache.clear(); + + // Clear all favicons in Places. + yield clearAllPlacesFavicons(); + + // Add an observer for making sure the favicon has been loaded and cached. + let promiseFaviconLoaded = waitOnFaviconLoaded(FAVICON_CACHE_URI); + + // Open a tab for the non-private window. + let tabInfoNonPrivate = yield openTab(gBrowser, TEST_CACHE_PAGE); + + let response = yield waitOnFaviconResponse(FAVICON_CACHE_URI); + + yield 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 = yield BrowserTestUtils.openNewBrowserWindow({ private: true }); + + // Open a tab for the private window. + let tabInfoPrivate = yield openTab(privateWindow.gBrowser, TEST_CACHE_PAGE); + + // Wait for the favicon response of the private tab. + response = yield waitOnFaviconResponse(FAVICON_CACHE_URI); + + // 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."); + + yield BrowserTestUtils.removeTab(tabInfoPrivate.tab); + yield BrowserTestUtils.removeTab(tabInfoNonPrivate.tab); + yield BrowserTestUtils.closeWindow(privateWindow); +}); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt.js new file mode 100644 index 000000000..3a078ffc1 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt.js @@ -0,0 +1,54 @@ +/* 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(function* test() { + const testPageURL = "http://mochi.test:8888/browser/" + + "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt_page.html"; + + function checkGeolocation(aPrivateMode, aWindow) { + return Task.spawn(function* () { + aWindow.gBrowser.selectedTab = aWindow.gBrowser.addTab(testPageURL); + yield BrowserTestUtils.browserLoaded(aWindow.gBrowser.selectedBrowser); + + let notification = aWindow.PopupNotifications.getNotification("geolocation"); + + // Wait until the notification is available. + while (!notification){ + yield new Promise(resolve => { executeSoon(resolve); }); + let notification = aWindow.PopupNotifications.getNotification("geolocation"); + } + + if (aPrivateMode) { + // Make sure the notification is correctly displayed without a remember control + is(notification.secondaryActions.length, 0, "Secondary actions shouldn't exist (always/never remember)"); + } else { + ok(notification.secondaryActions.length > 1, "Secondary actions should exist (always/never remember)"); + } + notification.remove(); + + aWindow.gBrowser.removeCurrentTab(); + }); + }; + + let win = yield BrowserTestUtils.openNewBrowserWindow(); + let browser = win.gBrowser.selectedBrowser; + browser.loadURI(testPageURL); + yield BrowserTestUtils.browserLoaded(browser); + + yield checkGeolocation(false, win); + + let privateWin = yield BrowserTestUtils.openNewBrowserWindow({private: true}); + let privateBrowser = privateWin.gBrowser.selectedBrowser; + privateBrowser.loadURI(testPageURL); + yield BrowserTestUtils.browserLoaded(privateBrowser); + + yield checkGeolocation(true, privateWin); + + // Cleanup + yield BrowserTestUtils.closeWindow(win); + yield BrowserTestUtils.closeWindow(privateWin); +}); 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 000000000..36d5e3cec --- /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_lastpbcontextexited.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_lastpbcontextexited.js new file mode 100644 index 000000000..dbe8ed060 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_lastpbcontextexited.js @@ -0,0 +1,49 @@ +/* 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: function(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: function(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", false); + Services.obs.addObserver(observerExited, "last-pb-context-exited", false); + 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 000000000..acccb5e2d --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.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/. */ + + add_task(function test() { + requestLongerTimeout(2); + const page1 = 'http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/' + + 'browser_privatebrowsing_localStorage_page1.html' + + let win = yield BrowserTestUtils.openNewBrowserWindow({private: true}); + + let tab = win.gBrowser.selectedTab = win.gBrowser.addTab(page1); + let browser = win.gBrowser.selectedBrowser; + yield BrowserTestUtils.browserLoaded(browser); + + browser.loadURI( + 'http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/' + + 'browser_privatebrowsing_localStorage_page2.html'); + yield BrowserTestUtils.browserLoaded(browser); + + is(browser.contentTitle, '2', "localStorage should contain 2 items"); + + // Cleanup + yield 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 000000000..3bcb6e5c9 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js @@ -0,0 +1,36 @@ +/* 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(function test() { + let testURI = "about:blank"; + let prefix = 'http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/'; + + // Step 1. + let privateWin = yield BrowserTestUtils.openNewBrowserWindow({private: true}); + let privateBrowser = privateWin.gBrowser.addTab( + prefix + 'browser_privatebrowsing_localStorage_before_after_page.html').linkedBrowser; + yield BrowserTestUtils.browserLoaded(privateBrowser); + + is(privateBrowser.contentTitle, '1', "localStorage should contain 1 item"); + + // Step 2. + let win = yield BrowserTestUtils.openNewBrowserWindow(); + let browser = win.gBrowser.addTab( + prefix + 'browser_privatebrowsing_localStorage_before_after_page2.html').linkedBrowser; + yield BrowserTestUtils.browserLoaded(browser); + + is(browser.contentTitle, 'null|0', 'localStorage should contain 0 items'); + + // Cleanup + yield BrowserTestUtils.closeWindow(privateWin); + yield 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 000000000..143fea4e7 --- /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 000000000..9a7e2da63 --- /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 000000000..3e79a01bf --- /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 000000000..8c9b28fd8 --- /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 000000000..b09ec0368 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js @@ -0,0 +1,61 @@ +/** + * 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(function* test_private_popup_window_opens_private_tabs() { + let privWin = yield 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; + yield BrowserTestUtils.loadURI(privBrowser, WINDOW_BODY); + yield 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(true, POPUP_LINK); + + yield BrowserTestUtils.synthesizeMouseAtCenter("#first", {}, privBrowser); + let popupWin = yield 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; + yield BrowserTestUtils.synthesizeMouseAtCenter("#second", {}, popupBrowser); + let newPrivTab = yield newTabPromise; + + // Ensure that the newly created tab's browser is private. + ok(PrivateBrowsingUtils.isBrowserPrivate(newPrivTab.linkedBrowser), + "Newly opened tab should be private."); + + // Clean up + yield BrowserTestUtils.removeTab(newPrivTab); + yield BrowserTestUtils.closeWindow(popupWin); + yield 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 000000000..ae6e8a6a3 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_noSessionRestoreMenuOption.js @@ -0,0 +1,23 @@ +"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(function* test_no_session_restore_menu_option() { + let win = yield BrowserTestUtils.openNewBrowserWindow({ private: true }); + ok(true, "The first private window got loaded"); + win.gBrowser.addTab("about:mozilla"); + yield BrowserTestUtils.closeWindow(win); + + win = yield 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"); + + yield 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 000000000..d2a69dd4e --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_nonbrowser.js @@ -0,0 +1,19 @@ +"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(function* () { + let win = yield BrowserTestUtils.openNewBrowserWindow({private: true}); + let chromeWin = win.open("chrome://browser/content/places/places.xul", "_blank", + "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar"); + yield BrowserTestUtils.waitForEvent(chromeWin, "load"); + let obsPromise = TestUtils.topicObserved("last-pb-context-exited"); + yield BrowserTestUtils.closeWindow(win); + yield 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 000000000..0b1369b11 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_opendir.js @@ -0,0 +1,133 @@ +/* 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 onLoad() { + win.removeEventListener("load", onLoad, false); + windowsToClose.push(win); + callback(win); + }, false); +} + +registerCleanupFunction(function() { + windowsToClose.forEach(function(win) { + win.close(); + }); +}); + +function test() { + // initialization + waitForExplicitFinish(); + let ds = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties); + let dir1 = ds.get("ProfD", Ci.nsIFile); + let dir2 = ds.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(); + gPrefService.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 + + gPrefService.setComplexValue(kPrefName, Ci.nsILocalFile, 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 + + gPrefService.setComplexValue(kPrefName, Ci.nsILocalFile, 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 000000000..f5bb3212f --- /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 000000000..32436b3cc --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placesTitleNoUpdate.js @@ -0,0 +1,72 @@ +/* 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 to make sure that the visited page titles do not get updated inside the +// private browsing mode. +"use strict"; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/PlacesUtils.jsm"); + +add_task(function* test() { + const TEST_URL = "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placesTitleNoUpdate.html" + const TEST_URI = Services.io.newURI(TEST_URL, null, null); + const TITLE_1 = "Title 1"; + const TITLE_2 = "Title 2"; + + function waitForTitleChanged() { + return new Promise(resolve => { + let historyObserver = { + onTitleChanged: function(uri, pageTitle) { + PlacesUtils.history.removeObserver(historyObserver, false); + resolve({uri: uri, pageTitle: pageTitle}); + }, + onBeginUpdateBatch: function () {}, + onEndUpdateBatch: function () {}, + onVisit: function () {}, + onDeleteURI: function () {}, + onClearHistory: function () {}, + onPageChanged: function () {}, + onDeleteVisits: function() {}, + QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]) + }; + + PlacesUtils.history.addObserver(historyObserver, false); + }); + }; + + yield PlacesTestUtils.clearHistory(); + + let tabToClose = gBrowser.selectedTab = gBrowser.addTab(TEST_URL); + yield waitForTitleChanged(); + is(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1, "The title matches the orignal title after first visit"); + + let place = { + uri: TEST_URI, + title: TITLE_2, + visits: [{ + visitDate: Date.now() * 1000, + transitionType: Ci.nsINavHistoryService.TRANSITION_LINK + }] + }; + PlacesUtils.asyncHistory.updatePlaces(place, { + handleError: () => ok(false, "Unexpected error in adding visit."), + handleResult: function () { }, + handleCompletion: function () {} + }); + + yield waitForTitleChanged(); + is(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_2, "The title matches the updated title after updating visit"); + + let privateWin = yield BrowserTestUtils.openNewBrowserWindow({private:true}); + yield BrowserTestUtils.browserLoaded(privateWin.gBrowser.addTab(TEST_URL).linkedBrowser); + + is(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_2, "The title remains the same after visiting in private window"); + yield PlacesTestUtils.clearHistory(); + + // Cleanup + BrowserTestUtils.closeWindow(privateWin); + gBrowser.removeTab(tabToClose); +}); + 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 000000000..a70019976 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js @@ -0,0 +1,95 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This test makes sure that the title of existing history entries does not +// change inside a private window. + +add_task(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 PlacesTestUtils.clearHistory(); + } + + yield cleanup(); + + let deferredFirst = PromiseUtils.defer(); + let deferredSecond = PromiseUtils.defer(); + let deferredThird = PromiseUtils.defer(); + + let testNumber = 0; + let historyObserver = { + onTitleChanged: function(aURI, aPageTitle) { + if (aURI.spec != TEST_URL) + return; + switch (++testNumber) { + case 1: + // The first time that the page is loaded + deferredFirst.resolve(aPageTitle); + break; + case 2: + // The second time that the page is loaded + deferredSecond.resolve(aPageTitle); + break; + case 3: + // After clean up + deferredThird.resolve(aPageTitle); + break; + default: + // Checks that opening the page in a private window should not fire a + // title change. + ok(false, "Title changed. Unexpected pass: " + testNumber); + } + }, + + onBeginUpdateBatch: function () {}, + onEndUpdateBatch: function () {}, + onVisit: function () {}, + onDeleteURI: function () {}, + onClearHistory: function () {}, + onPageChanged: function () {}, + onDeleteVisits: function() {}, + QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]) + }; + PlacesUtils.history.addObserver(historyObserver, false); + + + let win = yield BrowserTestUtils.openNewBrowserWindow(); + win.gBrowser.selectedTab = win.gBrowser.addTab(TEST_URL); + let aPageTitle = yield deferredFirst.promise; + // The first time that the page is loaded + is(aPageTitle, "No Cookie", + "The page should be loaded without any cookie for the first time"); + + win.gBrowser.selectedTab = win.gBrowser.addTab(TEST_URL); + aPageTitle = yield deferredSecond.promise; + // The second time that the page is loaded + is(aPageTitle, "Cookie", + "The page should be loaded with a cookie for the second time"); + + yield cleanup(); + + win.gBrowser.selectedTab = win.gBrowser.addTab(TEST_URL); + aPageTitle = yield deferredThird.promise; + // After clean up + is(aPageTitle, "No Cookie", + "The page should be loaded without any cookie again"); + + let win2 = yield BrowserTestUtils.openNewBrowserWindow({private: true}); + + let private_tab = win2.gBrowser.addTab(TEST_URL); + win2.gBrowser.selectedTab = private_tab; + yield BrowserTestUtils.browserLoaded(private_tab.linkedBrowser); + + // Cleanup + yield cleanup(); + PlacesUtils.history.removeObserver(historyObserver); + yield BrowserTestUtils.closeWindow(win); + yield BrowserTestUtils.closeWindow(win2); +}); 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 000000000..71d85f296 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_popupblocker.js @@ -0,0 +1,70 @@ +/* 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(function* test() { + let testURI = "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/popup.html"; + let oldPopupPolicy = gPrefService.getBoolPref("dom.disable_open_during_load"); + gPrefService.setBoolPref("dom.disable_open_during_load", true); + + registerCleanupFunction(() => { + gPrefService.setBoolPref("dom.disable_open_during_load", oldPopupPolicy); + }); + + function testPopupBlockerMenuItem(aExpectedDisabled, aWindow, aCallback) { + + aWindow.gBrowser.addEventListener("DOMUpdatePageReport", function() { + aWindow.gBrowser.removeEventListener("DOMUpdatePageReport", arguments.callee, false); + + 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(event) { + dump("CMI: popupshown\n"); + aWindow.document.removeEventListener("popupshown", arguments.callee, false); + + 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"); + }, false); + dump("CMI: out\n"); + } + + checkMenuItem(function() { + aCallback(); + }); + notification.querySelector("button").doCommand(); + }); + + }, false); + + aWindow.gBrowser.selectedBrowser.loadURI(testURI); + } + + let win1 = yield BrowserTestUtils.openNewBrowserWindow(); + yield new Promise(resolve => waitForFocus(resolve, win1)); + yield new Promise(resolve => testPopupBlockerMenuItem(false, win1, resolve)); + + let win2 = yield BrowserTestUtils.openNewBrowserWindow({private: true}); + yield new Promise(resolve => waitForFocus(resolve, win2)); + yield new Promise(resolve => testPopupBlockerMenuItem(true, win2, resolve)); + + let win3 = yield BrowserTestUtils.openNewBrowserWindow(); + yield new Promise(resolve => waitForFocus(resolve, win3)); + yield new Promise(resolve => testPopupBlockerMenuItem(false, win3, resolve)); + + // Cleanup + yield BrowserTestUtils.closeWindow(win1); + yield BrowserTestUtils.closeWindow(win2); + yield 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 000000000..fe69a2234 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_protocolhandler.js @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This test makes sure that the web pages can't register protocol handlers +// inside the private browsing mode. + +add_task(function* test() { + let notificationValue = "Protocol Registration: testprotocol"; + let testURI = "http://example.com/browser/" + + "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_protocolhandler_page.html"; + + let doTest = Task.async(function* (aIsPrivateMode, aWindow) { + let tab = aWindow.gBrowser.selectedTab = aWindow.gBrowser.addTab(testURI); + yield 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 + + yield promiseFinished.promise; + }); + + // test first when not on private mode + let win = yield BrowserTestUtils.openNewBrowserWindow(); + yield doTest(false, win); + + // then test when on private mode + let privateWin = yield BrowserTestUtils.openNewBrowserWindow({private: true}); + yield doTest(true, privateWin); + + // Cleanup + yield BrowserTestUtils.closeWindow(win); + yield 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 000000000..74f846d54 --- /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("testprotocol", + "https://example.com/foobar?uri=%s", + "Test Protocol"); + </script> + </body> +</html> 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 000000000..dbd74029d --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_sidebar.js @@ -0,0 +1,92 @@ +/* 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(); + + let { utils: Cu } = Components; + + let { Promise: { defer } } = Cu.import("resource://gre/modules/Promise.jsm", {}); + + // opens a sidebar + function openSidebar(win) { + let { promise, resolve } = defer(); + let doc = win.document; + + let sidebarID = 'viewBookmarksSidebar'; + + let sidebar = doc.getElementById('sidebar'); + + let sidebarurl = doc.getElementById(sidebarID).getAttribute('sidebarurl'); + + sidebar.addEventListener('load', function onSidebarLoad() { + if (sidebar.contentWindow.location.href != sidebarurl) + return; + sidebar.removeEventListener('load', onSidebarLoad, true); + + resolve(win); + }, true); + + win.SidebarUI.show(sidebarID); + + return promise; + } + + 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 000000000..e2b8593d6 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_theming.js @@ -0,0 +1,38 @@ +/* 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 onLoad() { + win.removeEventListener("load", onLoad, false); + windowsToClose.push(win); + executeSoon(() => callback(win)); + }, false); +} + +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 000000000..cbd2c60f8 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_ui.js @@ -0,0 +1,82 @@ +/* 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(); + let windowsToClose = []; + let testURI = "about:blank"; + let pbMenuItem; + let cmd; + + function doTest(aIsPrivateMode, aWindow, aCallback) { + aWindow.gBrowser.selectedBrowser.addEventListener("load", function onLoad() { + aWindow.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true); + + 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(); + }, true); + + aWindow.gBrowser.selectedBrowser.loadURI(testURI); + }; + + function openPrivateBrowsingModeByUI(aWindow, aCallback) { + Services.obs.addObserver(function observer(aSubject, aTopic, aData) { + aSubject.addEventListener("load", function() { + aSubject.removeEventListener("load", arguments.callee); + Services.obs.removeObserver(observer, "domwindowopened"); + windowsToClose.push(aSubject); + aCallback(aSubject); + }, false); + }, "domwindowopened", false); + + 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 000000000..2be701bcd --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_urlbarfocus.js @@ -0,0 +1,43 @@ +/* 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"; +Components.utils.import("resource://gre/modules/Promise.jsm", this); +let aboutNewTabService = Components.classes["@mozilla.org/browser/aboutnewtab-service;1"] + .getService(Components.interfaces.nsIAboutNewTabService); + +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() { + let deferred = Promise.defer(); + whenNewWindowLoaded({private: true}, win => { + executeSoon(() => deferred.resolve(win)); + }); + return deferred.promise; +} + +add_task(function* () { + let win = yield openNewPrivateWindow(); + checkUrlbarFocus(win); + win.close(); +}); + +add_task(function* () { + aboutNewTabService.newTabURL = "about:blank"; + registerCleanupFunction(() => { + aboutNewTabService.resetNewTabURL(); + }); + + let win = yield openNewPrivateWindow(); + checkUrlbarFocus(win); + win.close(); + + aboutNewTabService.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 000000000..aca8d0c7b --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js @@ -0,0 +1,77 @@ +/* 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. + +add_task(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.documentElement.getAttribute("title"); + const isOSX = ("nsILocalFileMac" in Ci); + let page_with_title; + let page_without_title; + let about_pb_title; + let pb_page_with_title; + let pb_page_without_title; + let pb_about_pb_title; + if (isOSX) { + page_with_title = test_title; + page_without_title = app_name; + about_pb_title = "Open a private window?"; + pb_page_with_title = test_title + " - (Private Browsing)"; + pb_page_without_title = app_name + " - (Private Browsing)"; + pb_about_pb_title = "Private Browsing - (Private Browsing)"; + } + else { + page_with_title = test_title + " - " + app_name; + page_without_title = app_name; + about_pb_title = "Open a private window?" + " - " + app_name; + pb_page_with_title = test_title + " - " + app_name + " (Private Browsing)"; + pb_page_without_title = app_name + " (Private Browsing)"; + pb_about_pb_title = "Private Browsing - " + app_name + " (Private Browsing)"; + } + + function* testTabTitle(aWindow, url, insidePB, expected_title) { + let tab = (yield BrowserTestUtils.openNewForegroundTab(aWindow.gBrowser)); + yield BrowserTestUtils.loadURI(tab.linkedBrowser, url); + yield BrowserTestUtils.browserLoaded(tab.linkedBrowser); + + yield 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); + yield BrowserTestUtils.waitForEvent(win, "load", false); + + yield BrowserTestUtils.waitForCondition(() => { + return win.document.title === expected_title; + }, `Window title should be ${expected_title}, got ${aWindow.document.title}`); + + is(win.document.title, expected_title, "The window title for " + url + + " detached tab is correct (" + (insidePB ? "inside" : "outside") + + " private browsing mode)"); + + yield Promise.all([ BrowserTestUtils.closeWindow(win), + BrowserTestUtils.closeWindow(aWindow) ]); + } + + function openWin(private) { + return BrowserTestUtils.openNewBrowserWindow({ private }); + } + yield Task.spawn(testTabTitle((yield openWin(false)), "about:blank", false, page_without_title)); + yield Task.spawn(testTabTitle((yield openWin(false)), testPageURL, false, page_with_title)); + yield Task.spawn(testTabTitle((yield openWin(false)), "about:privatebrowsing", false, about_pb_title)); + yield Task.spawn(testTabTitle((yield openWin(true)), "about:blank", true, pb_page_without_title)); + yield Task.spawn(testTabTitle((yield openWin(true)), testPageURL, true, pb_page_with_title)); + yield Task.spawn(testTabTitle((yield 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 000000000..760bde7d1 --- /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_zoom.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoom.js new file mode 100644 index 000000000..f5afcbd61 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoom.js @@ -0,0 +1,37 @@ +/* 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(function* test() { + let win = (yield BrowserTestUtils.openNewBrowserWindow({ private: true })); + let tabAbout = (yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:")); + let tabMozilla = (yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:")); + + 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 + yield BrowserTestUtils.switchTab(win.gBrowser, tabAbout); + + // switch back to mozilla tab + yield 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(); + yield Promise.all([ BrowserTestUtils.removeTab(tabMozilla), + BrowserTestUtils.removeTab(tabAbout) ]); + + yield 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 000000000..b67bfc229 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js @@ -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/. */ + +// 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(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", false); + }); + } + + 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; + return BrowserTestUtils.loadURI(browser, "about:blank").then(() => { + return Promise.all([ BrowserTestUtils.browserLoaded(browser), + promiseLocationChange() ]); + }).then(() => 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; + }); + } + + yield testOnWindow({}).then(win => promiseTestReady(true, win)); + yield testOnWindow({private: true}).then(win => promiseTestReady(false, win)); + + // cleanup + windowsToReset.forEach((win) => win.FullZoom.reset()); + yield 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 000000000..42682b474 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/empty_file.html @@ -0,0 +1 @@ +<html><body></body></html>
\ No newline at end of file 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 000000000..b571134e1 --- /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>
\ No newline at end of file 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 000000000..5535363c9 --- /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 000000000..9e23c73b7 --- /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/head.js b/browser/components/privatebrowsing/test/browser/head.js new file mode 100644 index 000000000..c822ba8d1 --- /dev/null +++ b/browser/components/privatebrowsing/test/browser/head.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +var {PromiseUtils} = Cu.import("resource://gre/modules/PromiseUtils.jsm", {}); +XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", + "resource://testing-common/PlacesTestUtils.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, a3) { + let { Promise: { defer } } = Components.utils.import("resource://gre/modules/Promise.jsm", {}); + let { promise, resolve } = defer(); + + let win = aParent.OpenBrowserWindow(aOptions); + + win.addEventListener("load", function onLoad() { + win.removeEventListener("load", onLoad, false); + resolve(win); + }, false); + + return promise; +} + +function newDirectory() { + let FileUtils = + Cu.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 = + Cu.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 000000000..68bbbfa26 --- /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 000000000..568e235be --- /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>"); +} |