mirror of
https://github.com/zen-browser/desktop.git
synced 2026-08-26 00:11:35 +00:00
gh-14990: Prevent policyContainer from bloating the session file (gh-15098)
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -5,4 +5,4 @@
|
||||
*.patch linguist-language=C++
|
||||
*.d.ts linguist-language=TypeScript
|
||||
|
||||
src/zen/tests/* linguist-language=C++
|
||||
src/zen/tests/** linguist-language=C++
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/.prettierignore b/.prettierignore
|
||||
index 949896ff064ae0b54b6a657ea074bc88e12820f7..5249f420972667bece4d85fe8d35073afaebeb8a 100644
|
||||
index bd8ab46ff7175f5039b69b04c1afe53ab8efe746..7ae12a1ff3724e99aeec2e93518640a2fa9611e6 100644
|
||||
--- a/.prettierignore
|
||||
+++ b/.prettierignore
|
||||
@@ -1803,3 +1803,12 @@ tools/ts/test/baselines/
|
||||
@@ -1807,3 +1807,12 @@ tools/ts/test/baselines/
|
||||
try_task_config.json
|
||||
xpcom/idl-parser/xpidl/fixtures/xpctest.d.json
|
||||
**/package-lock.json
|
||||
@@ -12,6 +12,6 @@ index 949896ff064ae0b54b6a657ea074bc88e12820f7..5249f420972667bece4d85fe8d35073a
|
||||
+*.min.js
|
||||
+*.min.mjs
|
||||
+*.inc
|
||||
+*/mochitests/*
|
||||
+**/mochitests/**
|
||||
+*.svg
|
||||
+
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
diff --git a/browser/components/urlbar/UrlbarPrefs.sys.mjs b/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||
index 2d21248256c6c2bfb8dac958133c10e3251ef564..f788bd10ec2c08e4b27b77cd3bb0489fb04e8b7a 100644
|
||||
index 89f0d44d462de3d7d0f581d6371606f475443822..0d45ce5f6455e9c7276c54f504906bade5b3d286 100644
|
||||
--- a/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||
+++ b/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||
@@ -462,6 +462,7 @@ const PREF_URLBAR_DEFAULTS = /** @type {PreferenceDefinition[]} */ ([
|
||||
@@ -163,6 +163,9 @@ const PREF_URLBAR_DEFAULTS = /** @type {PreferenceDefinition[]} */ ([
|
||||
// Feature gate pref for flight status suggestions in the urlbar.
|
||||
["flightStatus.featureGate", false],
|
||||
|
||||
+ // Whether to close the urlbar when blurring the window while the urlbar is focused.
|
||||
+ ["closeOnWindowBlur", true],
|
||||
+
|
||||
// The minimum prefix length of a flight status keyword the user must type to
|
||||
// trigger the suggestion. 0 means the min length should be taken from Nimbus
|
||||
// or remote settings.
|
||||
@@ -482,6 +485,7 @@ const PREF_URLBAR_DEFAULTS = /** @type {PreferenceDefinition[]} */ ([
|
||||
["shortcuts.tabs", true],
|
||||
["shortcuts.history", true],
|
||||
["shortcuts.actions", true],
|
||||
@@ -10,7 +20,7 @@ index 2d21248256c6c2bfb8dac958133c10e3251ef564..f788bd10ec2c08e4b27b77cd3bb0489f
|
||||
|
||||
// Boolean to determine if the providers defined in `exposureResults`
|
||||
// should be displayed in search results. This can be set by a
|
||||
@@ -799,6 +800,8 @@ function makeDefaultResultGroups({ showSearchSuggestionsFirst }) {
|
||||
@@ -840,6 +844,8 @@ function makeDefaultResultGroups({
|
||||
*/
|
||||
let rootGroup = {
|
||||
children: [
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
index e7e9495e56076cd112beafb8297dece4ae4cea58..330104d245ddd0956b95377082a6182579cbaf4d 100644
|
||||
index e7e9495e56076cd112beafb8297dece4ae4cea58..95e4333866a5f0d41fbdbe23910c396406a247e9 100644
|
||||
--- a/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
+++ b/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
@@ -101,6 +101,13 @@ const lazy = XPCOMUtils.declareLazy({
|
||||
@@ -280,7 +280,20 @@ index e7e9495e56076cd112beafb8297dece4ae4cea58..330104d245ddd0956b95377082a61825
|
||||
l10nId,
|
||||
l10nId == "urlbar-placeholder-with-name"
|
||||
? { name: engineName }
|
||||
@@ -5424,6 +5540,11 @@ ${
|
||||
@@ -5347,6 +5463,12 @@ ${
|
||||
}
|
||||
|
||||
lazy.logger.debug("Blur Event");
|
||||
+ if (
|
||||
+ this.document.commandDispatcher.focusedElement == this.inputField &&
|
||||
+ !lazy.UrlbarPrefs.get("closeOnWindowBlur")
|
||||
+ ) {
|
||||
+ return;
|
||||
+ }
|
||||
// We cannot count every blur events after a missed engagement as abandoment
|
||||
// because the user may have clicked on some view element that executes
|
||||
// a command causing a focus change. For example opening preferences from
|
||||
@@ -5424,6 +5546,11 @@ ${
|
||||
}
|
||||
|
||||
_on_click(event) {
|
||||
@@ -292,7 +305,7 @@ index e7e9495e56076cd112beafb8297dece4ae4cea58..330104d245ddd0956b95377082a61825
|
||||
switch (event.target) {
|
||||
case this.inputField:
|
||||
case this._inputContainer:
|
||||
@@ -5513,10 +5634,11 @@ ${
|
||||
@@ -5513,10 +5640,11 @@ ${
|
||||
}
|
||||
if (untrim) {
|
||||
this.setValue(this._untrimmedValue);
|
||||
@@ -305,7 +318,7 @@ index e7e9495e56076cd112beafb8297dece4ae4cea58..330104d245ddd0956b95377082a61825
|
||||
this.view.autoOpen({ event });
|
||||
} else {
|
||||
if (this._untrimOnFocusAfterKeydown) {
|
||||
@@ -5556,9 +5678,16 @@ ${
|
||||
@@ -5556,9 +5684,16 @@ ${
|
||||
}
|
||||
|
||||
_on_mousedown(event) {
|
||||
@@ -323,7 +336,7 @@ index e7e9495e56076cd112beafb8297dece4ae4cea58..330104d245ddd0956b95377082a61825
|
||||
if (
|
||||
event.composedTarget != this.inputField &&
|
||||
event.composedTarget != this._inputContainer
|
||||
@@ -5568,6 +5697,10 @@ ${
|
||||
@@ -5568,6 +5703,10 @@ ${
|
||||
|
||||
this.focusedViaMousedown = !this.focused;
|
||||
this.#preventClickSelectsAll = this.focused;
|
||||
@@ -334,7 +347,7 @@ index e7e9495e56076cd112beafb8297dece4ae4cea58..330104d245ddd0956b95377082a61825
|
||||
|
||||
// Keep the focus status, since the attribute may be changed
|
||||
// upon calling this.focus().
|
||||
@@ -5605,7 +5738,7 @@ ${
|
||||
@@ -5605,7 +5744,7 @@ ${
|
||||
// view open on tab switch, and the TabSelect event arrived earlier.
|
||||
// Also ignore mousedown on the urlbarView context menu: opening/closing the
|
||||
// view is already handled by the result opening flow.
|
||||
@@ -343,7 +356,7 @@ index e7e9495e56076cd112beafb8297dece4ae4cea58..330104d245ddd0956b95377082a61825
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5894,7 +6027,7 @@ ${
|
||||
@@ -5894,7 +6033,7 @@ ${
|
||||
// When we are in actions search mode we can show more results so
|
||||
// increase the limit.
|
||||
let maxResults =
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/browser/components/urlbar/content/UrlbarView.mjs b/browser/components/urlbar/content/UrlbarView.mjs
|
||||
index 8afb2bf4a757b3ef7902f5a6e6eed6b70ca2845e..440dea1e66540ca1998cb7464b6695ac823fedcb 100644
|
||||
index e465806c4ae4fc372d9aa2b71aa7f0e74c65d026..c0b3781901298bedee2736819a93edbf545507a7 100644
|
||||
--- a/browser/components/urlbar/content/UrlbarView.mjs
|
||||
+++ b/browser/components/urlbar/content/UrlbarView.mjs
|
||||
@@ -674,7 +674,7 @@ export class UrlbarView {
|
||||
@@ -803,7 +803,7 @@ export class UrlbarView {
|
||||
!this.input.value ||
|
||||
this.input.getAttribute("pageproxystate") == "valid"
|
||||
) {
|
||||
@@ -11,7 +11,7 @@ index 8afb2bf4a757b3ef7902f5a6e6eed6b70ca2845e..440dea1e66540ca1998cb7464b6695ac
|
||||
// Try to reuse the cached top-sites context. If it's not cached, then
|
||||
// there will be a gap of time between when the input is focused and
|
||||
// when the view opens that can be perceived as flicker.
|
||||
@@ -812,10 +812,6 @@ export class UrlbarView {
|
||||
@@ -941,10 +941,6 @@ export class UrlbarView {
|
||||
}
|
||||
|
||||
// If search mode isn't active, close the view.
|
||||
@@ -22,7 +22,7 @@ index 8afb2bf4a757b3ef7902f5a6e6eed6b70ca2845e..440dea1e66540ca1998cb7464b6695ac
|
||||
|
||||
// Search mode is active. If the one-offs should be shown, make sure they
|
||||
// are enabled and show the view.
|
||||
@@ -3031,6 +3027,8 @@ export class UrlbarView {
|
||||
@@ -3203,6 +3199,8 @@ export class UrlbarView {
|
||||
if (row?.hasAttribute("row-selectable")) {
|
||||
row?.toggleAttribute("selected", true);
|
||||
}
|
||||
@@ -31,7 +31,7 @@ index 8afb2bf4a757b3ef7902f5a6e6eed6b70ca2845e..440dea1e66540ca1998cb7464b6695ac
|
||||
if (element != row) {
|
||||
row?.toggleAttribute("descendant-selected", true);
|
||||
}
|
||||
@@ -3544,7 +3542,7 @@ export class UrlbarView {
|
||||
@@ -3715,7 +3713,7 @@ export class UrlbarView {
|
||||
}
|
||||
|
||||
#enableOrDisableRowWrap() {
|
||||
@@ -40,3 +40,16 @@ index 8afb2bf4a757b3ef7902f5a6e6eed6b70ca2845e..440dea1e66540ca1998cb7464b6695ac
|
||||
this.#rows.toggleAttribute("wrap", wrap);
|
||||
this.oneOffSearchButtons?.container.toggleAttribute("wrap", wrap);
|
||||
}
|
||||
@@ -4144,6 +4142,12 @@ export class UrlbarView {
|
||||
}
|
||||
|
||||
on_blur() {
|
||||
+ if (
|
||||
+ this.document.commandDispatcher.focusedElement == this.input.inputField &&
|
||||
+ !lazy.UrlbarPrefs.get("closeOnWindowBlur")
|
||||
+ ) {
|
||||
+ return;
|
||||
+ }
|
||||
// If the view is open without the input being focused, it will not close
|
||||
// automatically when the window loses focus. We might be in this state
|
||||
// after a Search Tip is shown on an engine homepage.
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
|
||||
--- a/browser/app/profile/firefox.js
|
||||
+++ b/browser/app/profile/firefox.js
|
||||
@@ -411,10 +411,13 @@
|
||||
pref("browser.urlbar.maxRichResults", 10);
|
||||
|
||||
// The maximum number of historical search results to show.
|
||||
pref("browser.urlbar.maxHistoricalSearchSuggestions", 2);
|
||||
|
||||
+// Whether to close the urlbar when blurring the window while the urlbar is focused.
|
||||
+pref("browser.urlbar.closeOnWindowBlur", true);
|
||||
+
|
||||
// The default behavior for the urlbar can be configured to use any combination
|
||||
// of the match filters with each additional filter adding more results (union).
|
||||
pref("browser.urlbar.suggest.bookmark", true);
|
||||
pref("browser.urlbar.suggest.clipboard", true);
|
||||
pref("browser.urlbar.suggest.history", true);
|
||||
diff --git a/browser/components/urlbar/UrlbarPrefs.sys.mjs b/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||
--- a/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||
+++ b/browser/components/urlbar/UrlbarPrefs.sys.mjs
|
||||
@@ -152,10 +152,13 @@
|
||||
["filter.javascript", true],
|
||||
|
||||
// Feature gate pref for flight status suggestions in the urlbar.
|
||||
["flightStatus.featureGate", false],
|
||||
|
||||
+ // Whether to close the urlbar when blurring the window while the urlbar is focused.
|
||||
+ ["closeOnWindowBlur", true],
|
||||
+
|
||||
// The minimum prefix length of a flight status keyword the user must type to
|
||||
// trigger the suggestion. 0 means the min length should be taken from Nimbus
|
||||
// or remote settings.
|
||||
["flightStatus.minKeywordLength", 0],
|
||||
|
||||
diff --git a/browser/components/urlbar/content/UrlbarView.mjs b/browser/components/urlbar/content/UrlbarView.mjs
|
||||
--- a/browser/components/urlbar/content/UrlbarView.mjs
|
||||
+++ b/browser/components/urlbar/content/UrlbarView.mjs
|
||||
@@ -3909,10 +3909,16 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
on_blur() {
|
||||
+ if (
|
||||
+ this.document.commandDispatcher.focusedElement == this.input.inputField &&
|
||||
+ !lazy.UrlbarPrefs.get("closeOnWindowBlur")
|
||||
+ ) {
|
||||
+ return;
|
||||
+ }
|
||||
// If the view is open without the input being focused, it will not close
|
||||
// automatically when the window loses focus. We might be in this state
|
||||
// after a Search Tip is shown on an engine homepage.
|
||||
if (!lazy.UrlbarPrefs.get("ui.popup.disable_autohide")) {
|
||||
this.close();
|
||||
diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
--- a/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
+++ b/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
@@ -5460,11 +5460,17 @@
|
||||
_on_blur(event) {
|
||||
if (this.view.resultMenu.hasAttribute("open")) {
|
||||
return;
|
||||
}
|
||||
|
||||
lazy.logger.debug("Blur Event");
|
||||
+ if (
|
||||
+ this.document.commandDispatcher.focusedElement == this.inputField &&
|
||||
+ !lazy.UrlbarPrefs.get("closeOnWindowBlur")
|
||||
+ ) {
|
||||
+ return;
|
||||
+ }
|
||||
// We cannot count every blur events after a missed engagement as abandoment
|
||||
// because the user may have clicked on some view element that executes
|
||||
// a command causing a focus change. For example opening preferences from
|
||||
// the oneoff settings button.
|
||||
// For now we detect that case by discarding the event on command, but we
|
||||
// may want to figure out a more robust way to detect abandonment.
|
||||
166
src/external-patches/firefox/bug_2011236.patch
Normal file
166
src/external-patches/firefox/bug_2011236.patch
Normal file
@@ -0,0 +1,166 @@
|
||||
diff --git a/browser/components/sessionstore/test/browser.toml b/browser/components/sessionstore/test/browser.toml
|
||||
--- a/browser/components/sessionstore/test/browser.toml
|
||||
+++ b/browser/components/sessionstore/test/browser.toml
|
||||
@@ -14,10 +14,12 @@
|
||||
"browser_frame_history_c.html",
|
||||
"browser_frame_history_c1.html",
|
||||
"browser_frame_history_c2.html",
|
||||
"browser_formdata_format_sample.html",
|
||||
"browser_sessionHistory_slow.sjs",
|
||||
+ "browser_policy_container_sample.html",
|
||||
+ "browser_policy_container_sample_frame.html",
|
||||
"browser_scrollPositions_sample.html",
|
||||
"browser_scrollPositions_sample2.html",
|
||||
"browser_scrollPositions_sample_frameset.html",
|
||||
"browser_scrollPositions_readerModeArticle.html",
|
||||
"browser_sessionStorage.html",
|
||||
@@ -226,10 +228,12 @@
|
||||
["browser_pinned_tabs.js"]
|
||||
skip-if = [
|
||||
"ccov", # Bug 1625525
|
||||
]
|
||||
|
||||
+["browser_policy_container_not_stored.js"]
|
||||
+
|
||||
["browser_privatetabs.js"]
|
||||
|
||||
["browser_purge_domaindata.js"]
|
||||
|
||||
["browser_purge_shistory.js"]
|
||||
diff --git a/browser/components/sessionstore/test/browser_policy_container_not_stored.js b/browser/components/sessionstore/test/browser_policy_container_not_stored.js
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/browser/components/sessionstore/test/browser_policy_container_not_stored.js
|
||||
@@ -0,0 +1,51 @@
|
||||
+/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
+
|
||||
+"use strict";
|
||||
+
|
||||
+/**
|
||||
+ * A session history entry only needs to retain the policy container for loads
|
||||
+ * that inherit their policies (about:blank, about:srcdoc, blob:, data:, ...).
|
||||
+ * Anything fetched over the network gets its policies from the response again,
|
||||
+ * so storing them would only bloat the session store (bug 2011236).
|
||||
+ */
|
||||
+
|
||||
+const TEST_ROOT = getRootDirectory(gTestPath).replace(
|
||||
+ "chrome://mochitests/content",
|
||||
+ "https://example.com"
|
||||
+);
|
||||
+const PARENT_URL = TEST_ROOT + "browser_policy_container_sample.html";
|
||||
+const FRAME_URL = TEST_ROOT + "browser_policy_container_sample_frame.html";
|
||||
+
|
||||
+add_task(async function test_policy_container_only_for_inheriting_loads() {
|
||||
+ const tab = BrowserTestUtils.addTab(gBrowser, PARENT_URL);
|
||||
+ gBrowser.selectedTab = tab;
|
||||
+ await promiseBrowserLoaded(tab.linkedBrowser, true, PARENT_URL);
|
||||
+ await TabStateFlusher.flush(tab.linkedBrowser);
|
||||
+
|
||||
+ const state = JSON.parse(ss.getTabState(tab));
|
||||
+ const topEntry = state.entries.at(-1);
|
||||
+ is(topEntry.url, PARENT_URL, "collected the parent entry");
|
||||
+
|
||||
+ const children = topEntry.children ?? [];
|
||||
+ const networkFrame = children.find(child => child.url === FRAME_URL);
|
||||
+ const blankFrame = children.find(child => child.url === "about:blank");
|
||||
+
|
||||
+ ok(networkFrame, "collected the network-scheme subframe entry");
|
||||
+ ok(blankFrame, "collected the about:blank subframe entry");
|
||||
+
|
||||
+ // The parent has a CSP, so both subframes inherit a policy container onto
|
||||
+ // their load state. Only the one that cannot recover it from a response
|
||||
+ // should keep it in session history.
|
||||
+ ok(
|
||||
+ !("policyContainer" in networkFrame),
|
||||
+ "https subframe entry does not store a policyContainer"
|
||||
+ );
|
||||
+ ok(
|
||||
+ "policyContainer" in blankFrame,
|
||||
+ "about:blank subframe entry still stores its inherited policyContainer"
|
||||
+ );
|
||||
+
|
||||
+ BrowserTestUtils.removeTab(tab);
|
||||
+});
|
||||
diff --git a/browser/components/sessionstore/test/browser_policy_container_sample.html b/browser/components/sessionstore/test/browser_policy_container_sample.html
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/browser/components/sessionstore/test/browser_policy_container_sample.html
|
||||
@@ -0,0 +1,12 @@
|
||||
+<!DOCTYPE html>
|
||||
+<html>
|
||||
+<head>
|
||||
+ <meta charset="utf-8">
|
||||
+ <meta http-equiv="Content-Security-Policy" content="default-src * data: blob: 'unsafe-inline'">
|
||||
+ <title>policyContainer session store sample</title>
|
||||
+</head>
|
||||
+<body>
|
||||
+ <iframe id="network" src="browser_policy_container_sample_frame.html"></iframe>
|
||||
+ <iframe id="blank" src="about:blank"></iframe>
|
||||
+</body>
|
||||
+</html>
|
||||
diff --git a/browser/components/sessionstore/test/browser_policy_container_sample_frame.html b/browser/components/sessionstore/test/browser_policy_container_sample_frame.html
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/browser/components/sessionstore/test/browser_policy_container_sample_frame.html
|
||||
@@ -0,0 +1,10 @@
|
||||
+<!DOCTYPE html>
|
||||
+<html>
|
||||
+<head>
|
||||
+ <meta charset="utf-8">
|
||||
+ <title>policyContainer session store sample frame</title>
|
||||
+</head>
|
||||
+<body>
|
||||
+ frame
|
||||
+</body>
|
||||
+</html>
|
||||
diff --git a/docshell/shistory/SessionHistoryEntry.cpp b/docshell/shistory/SessionHistoryEntry.cpp
|
||||
--- a/docshell/shistory/SessionHistoryEntry.cpp
|
||||
+++ b/docshell/shistory/SessionHistoryEntry.cpp
|
||||
@@ -41,10 +41,18 @@
|
||||
extern mozilla::LazyLogModule gSHLog;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
+// Only store policy container for loads that can't carry it themselves
|
||||
+// (about:blank, about:srcdoc, blob:, data:, ...)
|
||||
+// bug 1867137, bug 2011236
|
||||
+static nsIPolicyContainer* PolicyContainerToStore(
|
||||
+ nsIURI* aURI, nsIPolicyContainer* aPolicyContainer) {
|
||||
+ return CSP_ShouldURIInheritCSP(aURI) ? aPolicyContainer : nullptr;
|
||||
+}
|
||||
+
|
||||
SessionHistoryInfo::SessionHistoryInfo(nsDocShellLoadState* aLoadState,
|
||||
nsIChannel* aChannel)
|
||||
: mURI(aLoadState->URI()),
|
||||
mOriginalURI(aLoadState->OriginalURI()),
|
||||
mResultPrincipalURI(aLoadState->ResultPrincipalURI()),
|
||||
@@ -59,9 +67,10 @@
|
||||
mLoadReplace(aLoadState->LoadReplace()),
|
||||
mHasUserActivation(aLoadState->HasValidUserGestureActivation()),
|
||||
mSharedState(SharedState::Create(
|
||||
aLoadState->TriggeringPrincipal(), aLoadState->PrincipalToInherit(),
|
||||
aLoadState->PartitionedPrincipalToInherit(),
|
||||
- aLoadState->PolicyContainer(),
|
||||
+ PolicyContainerToStore(aLoadState->URI(),
|
||||
+ aLoadState->PolicyContainer()),
|
||||
/* FIXME Is this correct? */
|
||||
aLoadState->TypeHint())) {
|
||||
// Pull the upload stream off of the channel instead of the load state, as
|
||||
@@ -124,11 +133,12 @@
|
||||
loadInfo->GetPrincipalToInherit(
|
||||
getter_AddRefs(mSharedState.Get()->mPrincipalToInherit));
|
||||
|
||||
mSharedState.Get()->mPartitionedPrincipalToInherit =
|
||||
aPartitionedPrincipalToInherit;
|
||||
- mSharedState.Get()->mPolicyContainer = aPolicyContainer;
|
||||
+ mSharedState.Get()->mPolicyContainer =
|
||||
+ PolicyContainerToStore(mURI, aPolicyContainer);
|
||||
aChannel->GetContentType(mSharedState.Get()->mContentType);
|
||||
aChannel->GetOriginalURI(getter_AddRefs(mOriginalURI));
|
||||
|
||||
uint32_t loadFlags;
|
||||
aChannel->GetLoadFlags(&loadFlags);
|
||||
|
||||
@@ -7,14 +7,6 @@
|
||||
"id": "D299584",
|
||||
"name": "Native MacOS popovers fix"
|
||||
},
|
||||
{
|
||||
"type": "phabricator",
|
||||
"id": "D284404",
|
||||
"name": "Add urlbar closeOnWindowBlur preference",
|
||||
"replaces": {
|
||||
"\n\n": "\n // may want to figure out a more robust way to detect abandonment."
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "local",
|
||||
// TODO: Convert into https://phabricator.services.mozilla.com/D298079
|
||||
@@ -48,5 +40,16 @@
|
||||
"this._lastJsonLength = uncompressedBytes;": "this._lastJsonLength = uncompressedBytes.jsonLength;",
|
||||
" jsonLengthHint,": " lengthHint: jsonLengthHint,"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "phabricator",
|
||||
"id": "D320897",
|
||||
"name": "Bug 2011236",
|
||||
"replaces": {
|
||||
// The upstream patch context includes a MOZ_DIAGNOSTIC_ASSERT that
|
||||
// doesn't exist yet in our Firefox version.
|
||||
"@@ -59,11 +67,12 @@": "@@ -59,9 +67,10 @@",
|
||||
"aLoadState->TypeHint())) {\n MOZ_DIAGNOSTIC_ASSERT(!mURI->SchemeIs(\"javascript\"));\n \n // Pull": "aLoadState->TypeHint())) {\n // Pull"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -832,8 +832,9 @@ window.gZenCompactModeManager = {
|
||||
|
||||
const onLeave = event => {
|
||||
if (AppConstants.platform == "macosx") {
|
||||
const buttonRect =
|
||||
gZenVerticalTabsManager.actualWindowButtons.getBoundingClientRect();
|
||||
const buttonRect = window.windowUtils.getBoundsWithoutFlushing(
|
||||
gZenVerticalTabsManager.actualWindowButtons
|
||||
);
|
||||
const MAC_WINDOW_BUTTONS_X_BORDER = buttonRect.width + buttonRect.x;
|
||||
const MAC_WINDOW_BUTTONS_Y_BORDER = buttonRect.height + buttonRect.y;
|
||||
if (
|
||||
|
||||
@@ -1700,6 +1700,15 @@ class nsZenWorkspaces {
|
||||
}
|
||||
|
||||
makeSureEmptyTabIsFirst() {
|
||||
if (
|
||||
gZenUIManager.testingEnabled &&
|
||||
this._emptyTab &&
|
||||
(this._emptyTab.closing || !this._emptyTab.isConnected)
|
||||
) {
|
||||
this._emptyTab = gBrowser.tabs.find(
|
||||
tab => tab.hasAttribute("zen-empty-tab") && !tab.closing
|
||||
);
|
||||
}
|
||||
const emptyTab = this._emptyTab;
|
||||
if (emptyTab) {
|
||||
emptyTab.setAttribute("zen-workspace-id", this.activeWorkspace);
|
||||
@@ -3230,8 +3239,10 @@ class nsZenWorkspaces {
|
||||
return width;
|
||||
}, 0);
|
||||
|
||||
// Check if the total width exceeds the parent's width
|
||||
if (totalWidth > parent.clientWidth) {
|
||||
// Check if the total width exceeds the parent's width.
|
||||
const parentWidth =
|
||||
window.windowUtils.getBoundsWithoutFlushing(parent).width;
|
||||
if (totalWidth > parentWidth) {
|
||||
parent.setAttribute("icons-overflow", "true");
|
||||
} else {
|
||||
parent.removeAttribute("icons-overflow");
|
||||
@@ -3239,7 +3250,7 @@ class nsZenWorkspaces {
|
||||
|
||||
// Set the width of each icon to the maximum size they can fit on
|
||||
const widthPerButton = Math.max(
|
||||
(parent.clientWidth - separation * (parent.children.length - 1)) /
|
||||
(parentWidth - separation * (parent.children.length - 1)) /
|
||||
parent.children.length,
|
||||
minButtonSize
|
||||
);
|
||||
|
||||
@@ -3,6 +3,36 @@
|
||||
# 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/.
|
||||
|
||||
[alerts]
|
||||
source = "browser/base/content/test/alerts"
|
||||
is_direct_path = true
|
||||
|
||||
[backforward]
|
||||
source = "browser/base/content/test/backforward"
|
||||
is_direct_path = true
|
||||
|
||||
[caps]
|
||||
source = "browser/base/content/test/caps"
|
||||
is_direct_path = true
|
||||
|
||||
[gesture]
|
||||
source = "browser/base/content/test/gesture"
|
||||
is_direct_path = true
|
||||
|
||||
[gesture.replace-manifest]
|
||||
"[DEFAULT]" = '''[DEFAULT]
|
||||
prefs = [
|
||||
"zen.window-sync.enabled=false",
|
||||
]'''
|
||||
|
||||
[linkHandling]
|
||||
source = "browser/base/content/test/linkHandling"
|
||||
is_direct_path = true
|
||||
disable = [
|
||||
# Glance opens with alt+click, firefox doesnt know that.
|
||||
"browser_javascript_links.js",
|
||||
]
|
||||
|
||||
[readermode]
|
||||
source = "toolkit/components/reader/tests/browser"
|
||||
is_direct_path = true
|
||||
@@ -33,6 +63,68 @@ xpcshell = true
|
||||
[services-crypto.replace-manifest]
|
||||
"../../../" = "../../../../services/"
|
||||
|
||||
[sessionstore]
|
||||
source = "browser/components/sessionstore/test"
|
||||
is_direct_path = true
|
||||
disable = [
|
||||
"browser_1933485_tab_groups_history.js",
|
||||
"browser_1953801_tab_groups_history_close_other.js",
|
||||
"browser_aboutSessionRestore.js",
|
||||
"browser_bfcache_telemetry.js",
|
||||
"browser_closedId.js",
|
||||
"browser_closed_objects_changed_notifications_tabs.js",
|
||||
"browser_closed_objects_changed_notifications_windows.js",
|
||||
"browser_closed_tabs_closed_windows.js",
|
||||
"browser_closed_tabs_windows.js",
|
||||
"browser_cookies_partitioned.js",
|
||||
"browser_crashedTabs.js",
|
||||
"browser_dying_cache.js",
|
||||
"browser_firefoxView_restore.js",
|
||||
"browser_firefoxView_selected_restore.js",
|
||||
"browser_forget_closed_tab_window_byId.js",
|
||||
"browser_movePendingTabToNewWindow.js",
|
||||
"browser_newtab_userTypedValue.js",
|
||||
"browser_pinned_tabs.js",
|
||||
"browser_purge_domaindata.js",
|
||||
"browser_reopen_all_windows.js",
|
||||
"browser_restoreLastActionCorrectOrder.js",
|
||||
"browser_restoreLastClosedTabOrWindowOrSession.js",
|
||||
"browser_restore_container_tabs_oa.js",
|
||||
"browser_restore_tabless_window.js",
|
||||
"browser_restore_verticalPinnedTabs.js",
|
||||
"browser_restored_window_features.js",
|
||||
"browser_scrollPositions.js",
|
||||
"browser_scrollPositionsReaderMode.js",
|
||||
"browser_searchModeSwitcher_restore.js",
|
||||
"browser_speculative_connect.js",
|
||||
"browser_splitview_integer_ids.js",
|
||||
"browser_splitview_restore_in_closed_window.js",
|
||||
"browser_splitview_string_migration.js",
|
||||
"browser_swapDocShells.js",
|
||||
"browser_tab_groups_restore_closed_in_closed_window.js",
|
||||
"browser_tab_groups_restore_closed_in_open_window.js",
|
||||
"browser_tab_groups_restore_closed_many_tabs.js",
|
||||
"browser_tab_groups_closed.js",
|
||||
"browser_tab_groups_restore_multiple.js",
|
||||
"browser_tab_groups_restore_saved.js",
|
||||
"browser_tab_groups_restore_simple.js",
|
||||
"browser_tab_groups_save_on_removeAllTabsBut.js",
|
||||
"browser_tab_groups_save_on_removeTabsToTheEnd.js",
|
||||
"browser_tab_groups_save_on_removeTabsToTheStart.js",
|
||||
"browser_tab_groups_save_on_window_close.js",
|
||||
"browser_tab_groups_state.js",
|
||||
"browser_tab_groups_undo.js",
|
||||
"browser_tab_label_during_restore.js",
|
||||
"browser_undoCloseById.js",
|
||||
"browser_urlbarSearchMode.js",
|
||||
"browser_windowStateContainer.js",
|
||||
"browser_wireframe_basic.js",
|
||||
]
|
||||
|
||||
[sessionstore.replace-manifest]
|
||||
'prefs = [' = '''prefs = [
|
||||
"zen.window-sync.enabled=false",'''
|
||||
|
||||
[shell]
|
||||
source = "browser/components/shell/test"
|
||||
is_direct_path = true
|
||||
@@ -59,3 +151,10 @@ source = "toolkit/components/tooltiptext"
|
||||
disable = [
|
||||
"browser_input_file_tooltips.js",
|
||||
]
|
||||
|
||||
[zoom]
|
||||
source = "browser/base/content/test/zoom"
|
||||
is_direct_path = true
|
||||
|
||||
[zoom.replace-manifest]
|
||||
"../general/" = "../../../../browser/base/content/test/general/"
|
||||
|
||||
32
src/zen/tests/mochitests/alerts/browser.toml
Normal file
32
src/zen/tests/mochitests/alerts/browser.toml
Normal file
@@ -0,0 +1,32 @@
|
||||
[DEFAULT]
|
||||
support-files = [
|
||||
"head.js",
|
||||
"file_dom_notifications.html",
|
||||
]
|
||||
|
||||
["browser_notification_close.js"]
|
||||
https_first_disabled = true
|
||||
skip-if = [
|
||||
"os == 'win'", # Bug 1227785
|
||||
]
|
||||
|
||||
["browser_notification_do_not_disturb.js"]
|
||||
https_first_disabled = true
|
||||
|
||||
["browser_notification_open_settings.js"]
|
||||
https_first_disabled = true
|
||||
skip-if = [
|
||||
"os == 'win'", # Bug 1411118
|
||||
]
|
||||
|
||||
["browser_notification_remove_permission.js"]
|
||||
https_first_disabled = true
|
||||
skip-if = [
|
||||
"os == 'win'", # Bug 1411118
|
||||
]
|
||||
|
||||
["browser_notification_tab_switching.js"]
|
||||
https_first_disabled = true
|
||||
skip-if = [
|
||||
"os == 'win'", # Bug 1243263
|
||||
]
|
||||
@@ -0,0 +1,78 @@
|
||||
"use strict";
|
||||
|
||||
const { PlacesTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/PlacesTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
const { PermissionTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/PermissionTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
let notificationURL =
|
||||
"https://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
|
||||
|
||||
add_task(async function test_notificationClose() {
|
||||
await addNotificationPermission(notificationURL);
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: notificationURL,
|
||||
},
|
||||
async function dummyTabTask(aBrowser) {
|
||||
await openNotification(aBrowser, "showNotification2");
|
||||
|
||||
info("Notification alert showing");
|
||||
|
||||
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
|
||||
if (!alertWindow) {
|
||||
ok(true, "Notifications don't use XUL windows on all platforms.");
|
||||
await closeNotification(aBrowser);
|
||||
return;
|
||||
}
|
||||
|
||||
let alertTitleLabel =
|
||||
alertWindow.document.getElementById("alertTitleLabel");
|
||||
is(
|
||||
alertTitleLabel.value,
|
||||
"Test title",
|
||||
"Title text of notification should be present"
|
||||
);
|
||||
let alertTextLabel =
|
||||
alertWindow.document.getElementById("alertTextLabel");
|
||||
is(
|
||||
alertTextLabel.textContent,
|
||||
"Test body 2",
|
||||
"Body text of notification should be present"
|
||||
);
|
||||
|
||||
let alertCloseButton = alertWindow.document.querySelector(".close-icon");
|
||||
is(alertCloseButton.localName, "toolbarbutton", "close button found");
|
||||
let promiseBeforeUnloadEvent = BrowserTestUtils.waitForEvent(
|
||||
alertWindow,
|
||||
"beforeunload"
|
||||
);
|
||||
let closedTime = alertWindow.Date.now();
|
||||
alertCloseButton.click();
|
||||
info("Clicked on close button");
|
||||
await promiseBeforeUnloadEvent;
|
||||
|
||||
ok(true, "Alert should close when the close button is clicked");
|
||||
let currentTime = alertWindow.Date.now();
|
||||
// The notification will self-close at 12 seconds, so this checks
|
||||
// that the notification closed before the timeout.
|
||||
Assert.less(
|
||||
currentTime - closedTime,
|
||||
5000,
|
||||
"Close requested at " +
|
||||
closedTime +
|
||||
", actually closed at " +
|
||||
currentTime
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function cleanup() {
|
||||
PermissionTestUtils.remove(notificationURL, "desktop-notification");
|
||||
});
|
||||
@@ -0,0 +1,159 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests that notifications can be silenced using nsIAlertsDoNotDisturb
|
||||
* on systems where that interface and its methods are implemented for
|
||||
* the nsIAlertService.
|
||||
*/
|
||||
|
||||
const ALERT_SERVICE = Cc["@mozilla.org/alerts-service;1"]
|
||||
.getService(Ci.nsIAlertsService)
|
||||
.QueryInterface(Ci.nsIAlertsDoNotDisturb);
|
||||
|
||||
const PAGE =
|
||||
"https://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
|
||||
|
||||
// The amount of time in seconds that we will wait for a notification
|
||||
// to show up before we decide that it's not coming.
|
||||
const NOTIFICATION_TIMEOUT_SECS = 2000;
|
||||
|
||||
add_setup(async function () {
|
||||
await addNotificationPermission(PAGE);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that the manualDoNotDisturb attribute can prevent
|
||||
* notifications from appearing.
|
||||
*/
|
||||
add_task(async function test_manualDoNotDisturb() {
|
||||
try {
|
||||
// Only run the test if the do-not-disturb
|
||||
// interface has been implemented.
|
||||
ALERT_SERVICE.manualDoNotDisturb;
|
||||
ok(true, "Alert service implements do-not-disturb interface");
|
||||
} catch (e) {
|
||||
ok(
|
||||
true,
|
||||
"Alert service doesn't implement do-not-disturb interface, exiting test"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// In the event that something goes wrong during this test, make sure
|
||||
// we put the attribute back to the default setting when this test file
|
||||
// exits.
|
||||
registerCleanupFunction(() => {
|
||||
ALERT_SERVICE.manualDoNotDisturb = false;
|
||||
});
|
||||
|
||||
// Make sure that do-not-disturb is not enabled before we start.
|
||||
ok(
|
||||
!ALERT_SERVICE.manualDoNotDisturb,
|
||||
"Alert service should not be disabled when test starts"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.withNewTab(PAGE, async browser => {
|
||||
await openNotification(browser, "showNotification2");
|
||||
|
||||
info("Notification alert showing");
|
||||
|
||||
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
|
||||
|
||||
// For now, only the XUL alert backend implements the manualDoNotDisturb
|
||||
// method for nsIAlertsDoNotDisturb, so we expect there to be a XUL alert
|
||||
// window. If the method gets implemented by native backends in the future,
|
||||
// we'll probably want to branch here and set the manualDoNotDisturb
|
||||
// attribute manually.
|
||||
ok(alertWindow, "Expected a XUL alert window.");
|
||||
|
||||
// We're using the XUL notification backend. This means that there's
|
||||
// a menuitem for enabling manualDoNotDisturb. We exercise that
|
||||
// menuitem here.
|
||||
let doNotDisturbMenuItem = alertWindow.document.getElementById(
|
||||
"doNotDisturbMenuItem"
|
||||
);
|
||||
is(doNotDisturbMenuItem.localName, "menuitem", "menuitem found");
|
||||
|
||||
let unloadPromise = BrowserTestUtils.waitForEvent(
|
||||
alertWindow,
|
||||
"beforeunload"
|
||||
);
|
||||
|
||||
doNotDisturbMenuItem.click();
|
||||
info("Clicked on do-not-disturb menuitem");
|
||||
await unloadPromise;
|
||||
|
||||
// At this point, we should be configured to not display notifications
|
||||
// to the user.
|
||||
ok(
|
||||
ALERT_SERVICE.manualDoNotDisturb,
|
||||
"Alert service should be disabled after clicking menuitem"
|
||||
);
|
||||
|
||||
// The notification should not appear, but there is no way from the
|
||||
// client-side to know that it was blocked, except for waiting some time
|
||||
// and realizing that the "onshow" event never fired.
|
||||
await Assert.rejects(
|
||||
openNotification(browser, "showNotification2", NOTIFICATION_TIMEOUT_SECS),
|
||||
/timed out/,
|
||||
"The notification should never display."
|
||||
);
|
||||
|
||||
ALERT_SERVICE.manualDoNotDisturb = false;
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that the suppressForScreenSharing attribute can prevent
|
||||
* notifications from appearing.
|
||||
*/
|
||||
add_task(async function test_suppressForScreenSharing() {
|
||||
try {
|
||||
// Only run the test if the do-not-disturb
|
||||
// interface has been implemented.
|
||||
ALERT_SERVICE.suppressForScreenSharing;
|
||||
ok(true, "Alert service implements do-not-disturb interface");
|
||||
} catch (e) {
|
||||
ok(
|
||||
true,
|
||||
"Alert service doesn't implement do-not-disturb interface, exiting test"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// In the event that something goes wrong during this test, make sure
|
||||
// we put the attribute back to the default setting when this test file
|
||||
// exits.
|
||||
registerCleanupFunction(() => {
|
||||
ALERT_SERVICE.suppressForScreenSharing = false;
|
||||
});
|
||||
|
||||
// Make sure that do-not-disturb is not enabled before we start.
|
||||
ok(
|
||||
!ALERT_SERVICE.suppressForScreenSharing,
|
||||
"Alert service should not be suppressing for screen sharing when test " +
|
||||
"starts"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.withNewTab(PAGE, async browser => {
|
||||
await openNotification(browser, "showNotification2");
|
||||
|
||||
info("Notification alert showing");
|
||||
await closeNotification(browser);
|
||||
ALERT_SERVICE.suppressForScreenSharing = true;
|
||||
|
||||
// The notification should not appear, but there is no way from the
|
||||
// client-side to know that it was blocked, except for waiting some time
|
||||
// and realizing that the "onshow" event never fired.
|
||||
await Assert.rejects(
|
||||
openNotification(browser, "showNotification2", NOTIFICATION_TIMEOUT_SECS),
|
||||
/timed out/,
|
||||
"The notification should never display."
|
||||
);
|
||||
});
|
||||
|
||||
ALERT_SERVICE.suppressForScreenSharing = false;
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
"use strict";
|
||||
|
||||
var notificationURL =
|
||||
"https://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
|
||||
// BrowserGlue passes "privacy-permissions" to openPreferences when the
|
||||
// notifications-open-settings observer fires; the Settings Redesign
|
||||
// LegacyPaneMappings shim routes that to the permissionsData pane.
|
||||
var expectedURL = Services.prefs.getBoolPref(
|
||||
"browser.settings-redesign.enabled",
|
||||
false
|
||||
)
|
||||
? "about:preferences#permissionsData"
|
||||
: "about:preferences#privacy";
|
||||
|
||||
add_task(async function test_settingsOpen_observer() {
|
||||
info(
|
||||
"Opening a dummy tab so openPreferences=>switchToTabHavingURI doesn't use the blank tab."
|
||||
);
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: "about:robots",
|
||||
},
|
||||
async function dummyTabTask() {
|
||||
// Ensure preferences is loaded before removing the tab.
|
||||
let syncPaneLoadedPromise = TestUtils.topicObserved(
|
||||
"sync-pane-loaded",
|
||||
() => true
|
||||
);
|
||||
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, expectedURL);
|
||||
info("simulate a notifications-open-settings notification");
|
||||
let uri = NetUtil.newURI("https://example.com");
|
||||
let principal = Services.scriptSecurityManager.createContentPrincipal(
|
||||
uri,
|
||||
{}
|
||||
);
|
||||
Services.obs.notifyObservers(principal, "notifications-open-settings");
|
||||
let tab = await tabPromise;
|
||||
ok(tab, "The notification settings tab opened");
|
||||
await syncPaneLoadedPromise;
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_settingsOpen_button() {
|
||||
info("Adding notification permission");
|
||||
await addNotificationPermission(notificationURL);
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: notificationURL,
|
||||
},
|
||||
async function tabTask(aBrowser) {
|
||||
info("Waiting for notification");
|
||||
await openNotification(aBrowser, "showNotification2");
|
||||
|
||||
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
|
||||
if (!alertWindow) {
|
||||
ok(true, "Notifications don't use XUL windows on all platforms.");
|
||||
await closeNotification(aBrowser);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure preferences is loaded before removing the tab.
|
||||
let syncPaneLoadedPromise = TestUtils.topicObserved(
|
||||
"sync-pane-loaded",
|
||||
() => true
|
||||
);
|
||||
let closePromise = promiseWindowClosed(alertWindow);
|
||||
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, expectedURL);
|
||||
let openSettingsMenuItem = alertWindow.document.getElementById(
|
||||
"openSettingsMenuItem"
|
||||
);
|
||||
openSettingsMenuItem.click();
|
||||
|
||||
info("Waiting for notification settings tab");
|
||||
let tab = await tabPromise;
|
||||
ok(tab, "The notification settings tab opened");
|
||||
|
||||
await syncPaneLoadedPromise;
|
||||
await closePromise;
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
"use strict";
|
||||
|
||||
const { PermissionTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/PermissionTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
var tab;
|
||||
var notificationURL =
|
||||
"https://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
|
||||
var alertWindowClosed = false;
|
||||
var permRemoved = false;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
gBrowser.removeTab(tab);
|
||||
window.restore();
|
||||
});
|
||||
|
||||
addNotificationPermission(notificationURL).then(function openTab() {
|
||||
tab = BrowserTestUtils.addTab(gBrowser, notificationURL);
|
||||
gBrowser.selectedTab = tab;
|
||||
BrowserTestUtils.browserLoaded(tab.linkedBrowser).then(() => onLoad());
|
||||
});
|
||||
}
|
||||
|
||||
function onLoad() {
|
||||
openNotification(tab.linkedBrowser, "showNotification2").then(onAlertShowing);
|
||||
}
|
||||
|
||||
function onAlertShowing() {
|
||||
info("Notification alert showing");
|
||||
|
||||
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
|
||||
if (!alertWindow) {
|
||||
ok(true, "Notifications don't use XUL windows on all platforms.");
|
||||
closeNotification(tab.linkedBrowser).then(finish);
|
||||
return;
|
||||
}
|
||||
ok(
|
||||
PermissionTestUtils.testExactPermission(
|
||||
notificationURL,
|
||||
"desktop-notification"
|
||||
),
|
||||
"Permission should exist prior to removal"
|
||||
);
|
||||
let disableForOriginMenuItem = alertWindow.document.getElementById(
|
||||
"disableForOriginMenuItem"
|
||||
);
|
||||
is(disableForOriginMenuItem.localName, "menuitem", "menuitem found");
|
||||
Services.obs.addObserver(permObserver, "perm-changed");
|
||||
alertWindow.addEventListener("beforeunload", onAlertClosing);
|
||||
disableForOriginMenuItem.click();
|
||||
info("Clicked on disable-for-origin menuitem");
|
||||
}
|
||||
|
||||
function permObserver(subject, topic, data) {
|
||||
if (topic != "perm-changed") {
|
||||
return;
|
||||
}
|
||||
|
||||
let permission = subject.QueryInterface(Ci.nsIPermission);
|
||||
is(
|
||||
permission.type,
|
||||
"desktop-notification",
|
||||
"desktop-notification permission changed"
|
||||
);
|
||||
is(data, "deleted", "desktop-notification permission deleted");
|
||||
|
||||
Services.obs.removeObserver(permObserver, "perm-changed");
|
||||
permRemoved = true;
|
||||
if (alertWindowClosed) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
function onAlertClosing(event) {
|
||||
event.target.removeEventListener("beforeunload", onAlertClosing);
|
||||
|
||||
alertWindowClosed = true;
|
||||
if (permRemoved) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { PermissionTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/PermissionTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
var tab;
|
||||
var notification;
|
||||
var notificationURL =
|
||||
"https://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
|
||||
var newWindowOpenedFromTab;
|
||||
|
||||
add_task(async function test_notificationPreventDefaultAndSwitchTabs() {
|
||||
await addNotificationPermission(notificationURL);
|
||||
|
||||
let originalTab = gBrowser.selectedTab;
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: notificationURL,
|
||||
},
|
||||
async function dummyTabTask(aBrowser) {
|
||||
// Put new tab in background so it is obvious when it is re-focused.
|
||||
await BrowserTestUtils.switchTab(gBrowser, originalTab);
|
||||
isnot(
|
||||
gBrowser.selectedBrowser,
|
||||
aBrowser,
|
||||
"Notification page loaded as a background tab"
|
||||
);
|
||||
|
||||
// First, show a notification that will be have the tab-switching prevented.
|
||||
function promiseNotificationEvent(evt) {
|
||||
return SpecialPowers.spawn(
|
||||
aBrowser,
|
||||
[evt],
|
||||
async function (contentEvt) {
|
||||
return new Promise(resolve => {
|
||||
let contentNotification = content.wrappedJSObject._notification;
|
||||
contentNotification.addEventListener(
|
||||
contentEvt,
|
||||
function (event) {
|
||||
resolve({ defaultPrevented: event.defaultPrevented });
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
await openNotification(aBrowser, "showNotification1");
|
||||
info("Notification alert showing");
|
||||
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
|
||||
if (!alertWindow) {
|
||||
ok(true, "Notifications don't use XUL windows on all platforms.");
|
||||
await closeNotification(aBrowser);
|
||||
return;
|
||||
}
|
||||
info("Clicking on notification");
|
||||
let promiseClickEvent = promiseNotificationEvent("click");
|
||||
|
||||
// NB: This executeSoon is needed to allow the non-e10s runs of this test
|
||||
// a chance to set the event listener on the page. Otherwise, we
|
||||
// synchronously fire the click event before we listen for the event.
|
||||
executeSoon(() => {
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
alertWindow.document.getElementById("alertTitleLabel"),
|
||||
{},
|
||||
alertWindow
|
||||
);
|
||||
});
|
||||
let clickEvent = await promiseClickEvent;
|
||||
ok(
|
||||
clickEvent.defaultPrevented,
|
||||
"The event handler for the first notification cancels the event"
|
||||
);
|
||||
isnot(
|
||||
gBrowser.selectedBrowser,
|
||||
aBrowser,
|
||||
"Notification page still a background tab"
|
||||
);
|
||||
let notificationClosed = promiseNotificationEvent("close");
|
||||
await closeNotification(aBrowser);
|
||||
await notificationClosed;
|
||||
|
||||
// Second, show a notification that will cause the tab to get switched.
|
||||
await openNotification(aBrowser, "showNotification2");
|
||||
alertWindow = Services.wm.getMostRecentWindow("alert:alert");
|
||||
let promiseTabSelect = BrowserTestUtils.waitForEvent(
|
||||
gBrowser.tabContainer,
|
||||
"TabSelect"
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
alertWindow.document.getElementById("alertTitleLabel"),
|
||||
{},
|
||||
alertWindow
|
||||
);
|
||||
await promiseTabSelect;
|
||||
is(
|
||||
gBrowser.selectedBrowser.currentURI.spec,
|
||||
notificationURL,
|
||||
"Clicking on the second notification should select its originating tab"
|
||||
);
|
||||
notificationClosed = promiseNotificationEvent("close");
|
||||
await closeNotification(aBrowser);
|
||||
await notificationClosed;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function cleanup() {
|
||||
PermissionTestUtils.remove(notificationURL, "desktop-notification");
|
||||
});
|
||||
39
src/zen/tests/mochitests/alerts/file_dom_notifications.html
Normal file
39
src/zen/tests/mochitests/alerts/file_dom_notifications.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
function showNotification1() {
|
||||
var options = {
|
||||
dir: undefined,
|
||||
lang: undefined,
|
||||
body: "Test body 1",
|
||||
tag: "Test tag",
|
||||
icon: undefined,
|
||||
};
|
||||
var n = new Notification("Test title", options);
|
||||
n.addEventListener("click", function(event) {
|
||||
event.preventDefault();
|
||||
});
|
||||
return n;
|
||||
}
|
||||
|
||||
function showNotification2() {
|
||||
var options = {
|
||||
dir: undefined,
|
||||
lang: undefined,
|
||||
body: "Test body 2",
|
||||
tag: "Test tag",
|
||||
icon: undefined,
|
||||
};
|
||||
return new Notification("Test title", options);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<form id="notificationForm" onsubmit="showNotification();">
|
||||
<input type="submit" value="Show notification" id="submit"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
73
src/zen/tests/mochitests/alerts/head.js
Normal file
73
src/zen/tests/mochitests/alerts/head.js
Normal file
@@ -0,0 +1,73 @@
|
||||
// Platforms may default to reducing motion. We override this to ensure the
|
||||
// alert slide animation is enabled in tests.
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [["ui.prefersReducedMotion", 0]],
|
||||
});
|
||||
|
||||
async function addNotificationPermission(originString) {
|
||||
return SpecialPowers.pushPermissions([
|
||||
{
|
||||
type: "desktop-notification",
|
||||
allow: true,
|
||||
context: originString,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to `BrowserTestUtils.closeWindow`, but
|
||||
* doesn't call `window.close()`.
|
||||
*/
|
||||
function promiseWindowClosed(window) {
|
||||
return new Promise(function (resolve) {
|
||||
Services.ww.registerNotification(function observer(subject, topic) {
|
||||
if (topic == "domwindowclosed" && subject == window) {
|
||||
Services.ww.unregisterNotification(observer);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* These two functions work with file_dom_notifications.html to open the
|
||||
* notification and close it.
|
||||
*
|
||||
* |fn| can be showNotification1 or showNotification2.
|
||||
* if |timeout| is passed, then the promise returned from this function is
|
||||
* rejected after the requested number of miliseconds.
|
||||
*/
|
||||
function openNotification(aBrowser, fn, timeout) {
|
||||
info(`openNotification: ${fn}`);
|
||||
return SpecialPowers.spawn(
|
||||
aBrowser,
|
||||
[fn, timeout],
|
||||
async function (contentFn, contentTimeout) {
|
||||
await new Promise((resolve, reject) => {
|
||||
let win = content.wrappedJSObject;
|
||||
let notification = win[contentFn]();
|
||||
win._notification = notification;
|
||||
|
||||
function listener() {
|
||||
notification.removeEventListener("show", listener);
|
||||
resolve();
|
||||
}
|
||||
|
||||
notification.addEventListener("show", listener);
|
||||
|
||||
if (contentTimeout) {
|
||||
content.setTimeout(() => {
|
||||
notification.removeEventListener("show", listener);
|
||||
reject("timed out");
|
||||
}, contentTimeout);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function closeNotification(aBrowser) {
|
||||
return SpecialPowers.spawn(aBrowser, [], function () {
|
||||
content.wrappedJSObject._notification.close();
|
||||
});
|
||||
}
|
||||
7
src/zen/tests/mochitests/backforward/browser.toml
Normal file
7
src/zen/tests/mochitests/backforward/browser.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[DEFAULT]
|
||||
|
||||
["browser_history_menu.js"]
|
||||
fail-if = [
|
||||
"a11y_checks", # Bug 1854233 navigator-toolbox may not be focusable
|
||||
]
|
||||
https_first_disabled = true
|
||||
179
src/zen/tests/mochitests/backforward/browser_history_menu.js
Normal file
179
src/zen/tests/mochitests/backforward/browser_history_menu.js
Normal file
@@ -0,0 +1,179 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// This test verifies that the back forward button long-press menu and context menu
|
||||
// shows the correct history items.
|
||||
|
||||
add_task(async function mousedown_back() {
|
||||
await testBackForwardMenu(false);
|
||||
});
|
||||
|
||||
add_task(async function contextmenu_back() {
|
||||
await testBackForwardMenu(true);
|
||||
});
|
||||
|
||||
async function openHistoryMenu(useContextMenu) {
|
||||
let backButton = document.getElementById("back-button");
|
||||
let rect = backButton.getBoundingClientRect();
|
||||
|
||||
info("waiting for the history menu to open");
|
||||
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(
|
||||
useContextMenu ? document.getElementById("backForwardMenu") : backButton,
|
||||
"popupshown"
|
||||
);
|
||||
if (useContextMenu) {
|
||||
EventUtils.synthesizeMouseAtCenter(backButton, {
|
||||
type: "contextmenu",
|
||||
button: 2,
|
||||
});
|
||||
} else {
|
||||
EventUtils.synthesizeMouseAtCenter(backButton, { type: "mousedown" });
|
||||
}
|
||||
|
||||
EventUtils.synthesizeMouse(backButton, rect.width / 2, rect.height, {
|
||||
type: "mouseup",
|
||||
});
|
||||
let popupEvent = await popupShownPromise;
|
||||
|
||||
ok(true, "history menu opened");
|
||||
|
||||
return popupEvent;
|
||||
}
|
||||
|
||||
async function testBackForwardMenu(useContextMenu) {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
"http://example.com"
|
||||
);
|
||||
|
||||
for (let iter = 2; iter <= 4; iter++) {
|
||||
// Iterate three times. For the first two times through the loop, add a new history item.
|
||||
// But for the last iteration, go back in the history instead.
|
||||
await SpecialPowers.spawn(
|
||||
gBrowser.selectedBrowser,
|
||||
[iter],
|
||||
async function (iterChild) {
|
||||
if (iterChild == 4) {
|
||||
let popStatePromise = new Promise(function (resolve) {
|
||||
content.onpopstate = resolve;
|
||||
});
|
||||
content.history.back();
|
||||
await popStatePromise;
|
||||
} else {
|
||||
// With the back-button intervention enabled, we need to make sure to
|
||||
// trigger a user activation on each history entry, or they won't
|
||||
// show in the menu.
|
||||
content.document.notifyUserGestureActivation();
|
||||
content.history.pushState({}, "" + iterChild, iterChild + ".html");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Wait for the session data to be flushed before continuing the test
|
||||
await new Promise(resolve =>
|
||||
SessionStore.getSessionHistory(gBrowser.selectedTab, resolve)
|
||||
);
|
||||
|
||||
let popupEvent = await openHistoryMenu(useContextMenu);
|
||||
|
||||
// Wait for the session data to be flushed before continuing the test
|
||||
await new Promise(resolve =>
|
||||
SessionStore.getSessionHistory(gBrowser.selectedTab, resolve)
|
||||
);
|
||||
|
||||
is(
|
||||
popupEvent.target.children.length,
|
||||
iter > 3 ? 3 : iter,
|
||||
"Correct number of history items"
|
||||
);
|
||||
|
||||
let node = popupEvent.target.lastElementChild;
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
is(node.getAttribute("uri"), "http://example.com/", "'1' item uri");
|
||||
is(node.getAttribute("index"), "0", "'1' item index");
|
||||
is(
|
||||
node.getAttribute("historyindex"),
|
||||
iter == 3 ? "-2" : "-1",
|
||||
"'1' item historyindex"
|
||||
);
|
||||
|
||||
node = node.previousElementSibling;
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
is(node.getAttribute("uri"), "http://example.com/2.html", "'2' item uri");
|
||||
is(node.getAttribute("index"), "1", "'2' item index");
|
||||
is(
|
||||
node.getAttribute("historyindex"),
|
||||
iter == 3 ? "-1" : "0",
|
||||
"'2' item historyindex"
|
||||
);
|
||||
|
||||
if (iter >= 3) {
|
||||
node = node.previousElementSibling;
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
is(node.getAttribute("uri"), "http://example.com/3.html", "'3' item uri");
|
||||
is(node.getAttribute("index"), "2", "'3' item index");
|
||||
is(
|
||||
node.getAttribute("historyindex"),
|
||||
iter == 4 ? "1" : "0",
|
||||
"'3' item historyindex"
|
||||
);
|
||||
}
|
||||
|
||||
// Close the popup, but on the last iteration, click on one of the history items
|
||||
// to ensure it opens in a new tab.
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(
|
||||
popupEvent.target,
|
||||
"popuphidden"
|
||||
);
|
||||
|
||||
if (iter < 4) {
|
||||
popupEvent.target.hidePopup();
|
||||
} else {
|
||||
let newTabPromise = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
url => url == "http://example.com/"
|
||||
);
|
||||
|
||||
popupEvent.target.activateItem(popupEvent.target.children[2], {
|
||||
button: 1,
|
||||
});
|
||||
|
||||
let newtab = await newTabPromise;
|
||||
gBrowser.removeTab(newtab);
|
||||
}
|
||||
|
||||
await popupHiddenPromise;
|
||||
}
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
|
||||
// Make sure that the history popup appears after navigating around in a preferences page.
|
||||
add_task(async function test_preferences_page() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
"about:preferences"
|
||||
);
|
||||
|
||||
openPreferences("search");
|
||||
let popupEvent = await openHistoryMenu(true);
|
||||
|
||||
// Wait for the session data to be flushed before continuing the test
|
||||
await new Promise(resolve =>
|
||||
SessionStore.getSessionHistory(gBrowser.selectedTab, resolve)
|
||||
);
|
||||
|
||||
is(popupEvent.target.children.length, 2, "Correct number of history items");
|
||||
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(
|
||||
popupEvent.target,
|
||||
"popuphidden"
|
||||
);
|
||||
popupEvent.target.hidePopup();
|
||||
await popupHiddenPromise;
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
10
src/zen/tests/mochitests/caps/browser.toml
Normal file
10
src/zen/tests/mochitests/caps/browser.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[DEFAULT]
|
||||
|
||||
["browser_principalSerialization_csp.js"]
|
||||
|
||||
["browser_principalSerialization_json.js"]
|
||||
skip-if = [
|
||||
"debug", # deliberately bypass assertions when deserializing. Bug 965637 removed the CSP from Principals, but the remaining bits in such Principals should deserialize correctly.
|
||||
]
|
||||
|
||||
["browser_principalSerialization_version1.js"]
|
||||
@@ -0,0 +1,106 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Within Bug 965637 we move the CSP away from the Principal. Serialized Principals however
|
||||
* might still have CSPs serialized within them. This tests ensures that we do not
|
||||
* encounter a memory corruption when deserializing. It's fine that the deserialized
|
||||
* CSP is null, but the Principal itself should deserialize correctly.
|
||||
*/
|
||||
|
||||
add_task(async function test_deserialize_principal_with_csp() {
|
||||
/*
|
||||
This test should be resilient to changes in principal serialization, if these are failing then it's likely the code will break session storage.
|
||||
To recreate this for another version, copy the function into the browser console, browse some pages and printHistory.
|
||||
|
||||
Generated with:
|
||||
function printHistory() {
|
||||
let tests = [];
|
||||
let entries = SessionStore.getSessionHistory(gBrowser.selectedTab).entries.map((entry) => { return entry.triggeringPrincipal_base64 });
|
||||
entries.push(E10SUtils.serializePrincipal(gBrowser.selectedTab.linkedBrowser._contentPrincipal));
|
||||
for (let entry of entries) {
|
||||
console.log(entry);
|
||||
let testData = {};
|
||||
testData.input = entry;
|
||||
let principal = E10SUtils.deserializePrincipal(testData.input);
|
||||
testData.output = {};
|
||||
if (principal.URI === null) {
|
||||
testData.output.URI = false;
|
||||
} else {
|
||||
testData.output.URISpec = principal.URI.spec;
|
||||
}
|
||||
testData.output.originAttributes = principal.originAttributes;
|
||||
testData.output.cspJSON = principal.cspJSON;
|
||||
|
||||
tests.push(testData);
|
||||
}
|
||||
return tests;
|
||||
}
|
||||
printHistory(); // Copy this into: serializedPrincipalsFromFirefox
|
||||
*/
|
||||
|
||||
let serializedPrincipalsFromFirefox = [
|
||||
{
|
||||
input:
|
||||
"ZT4OTT7kRfqycpfCC8AeuAAAAAAAAAAAwAAAAAAAAEYB3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAHmh0dHBzOi8vd3d3Lm1vemlsbGEub3JnL2VuLVVTLwAAAAAAAAAFAAAACAAAAA8AAAAA/////wAAAAD/////AAAACAAAAA8AAAAXAAAABwAAABcAAAAHAAAAFwAAAAcAAAAeAAAAAAAAAAD/////AAAAAP////8AAAAA/////wAAAAD/////AQAAAAAAAAAAAAAAAQnZ7Rrl1EAEv+Anzrkj2ayzxMCuvV5MrYfgjSENuz+fAd6UctCANBHTk5kAEEug/UCSBzpUbXhPMJE6uHGBMgjGAAAAAv////8AAAG7AQAAAB5odHRwczovL3d3dy5tb3ppbGxhLm9yZy9lbi1VUy8AAAAAAAAABQAAAAgAAAAPAAAAAP////8AAAAA/////wAAAAgAAAAPAAAAFwAAAAcAAAAXAAAABwAAABcAAAAHAAAAHgAAAAAAAAAA/////wAAAAD/////AAAAAP////8AAAAA/////wEAAAAAAAAAAAABAAAFtgBzAGMAcgBpAHAAdAAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIAAnAHUAbgBzAGEAZgBlAC0AaQBuAGwAaQBuAGUAJwAgACcAdQBuAHMAYQBmAGUALQBlAHYAYQBsACcAIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQB0AGEAZwBtAGEAbgBhAGcAZQByAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQAtAGEAbgBhAGwAeQB0AGkAYwBzAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdABhAGcAbQBhAG4AYQBnAGUAcgAuAGcAbwBvAGcAbABlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgB5AG8AdQB0AHUAYgBlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AcwAuAHkAdABpAG0AZwAuAGMAbwBtADsAIABpAG0AZwAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIABkAGEAdABhADoAIABoAHQAdABwAHMAOgAvAC8AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAZABzAGUAcgB2AGkAYwBlAC4AZwBvAG8AZwBsAGUALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGQAcwBlAHIAdgBpAGMAZQAuAGcAbwBvAGcAbABlAC4AZABlACAAaAB0AHQAcABzADoALwAvAGEAZABzAGUAcgB2AGkAYwBlAC4AZwBvAG8AZwBsAGUALgBkAGsAIABoAHQAdABwAHMAOgAvAC8AYwByAGUAYQB0AGkAdgBlAGMAbwBtAG0AbwBuAHMALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwBhAGQALgBkAG8AdQBiAGwAZQBjAGwAaQBjAGsALgBuAGUAdAA7ACAAZABlAGYAYQB1AGwAdAAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AOwAgAGYAcgBhAG0AZQAtAHMAcgBjACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAtAG4AbwBjAG8AbwBrAGkAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHQAcgBhAGMAawBlAHIAdABlAHMAdAAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AcwB1AHIAdgBlAHkAZwBpAHoAbQBvAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAYwBjAG8AdQBuAHQAcwAuAGYAaQByAGUAZgBvAHgALgBjAG8AbQAuAGMAbgAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHkAbwB1AHQAdQBiAGUALgBjAG8AbQA7ACAAcwB0AHkAbABlAC0AcwByAGMAIAAnAHMAZQBsAGYAJwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG4AZQB0ACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBjAG8AbQAgACcAdQBuAHMAYQBmAGUALQBpAG4AbABpAG4AZQAnADsAIABjAG8AbgBuAGUAYwB0AC0AcwByAGMAIAAnAHMAZQBsAGYAJwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG4AZQB0ACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAC0AYQBuAGEAbAB5AHQAaQBjAHMALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0ALwAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0ALgBjAG4ALwA7ACAAYwBoAGkAbABkAC0AcwByAGMAIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQB0AGEAZwBtAGEAbgBhAGcAZQByAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQAtAGEAbgBhAGwAeQB0AGkAYwBzAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgB5AG8AdQB0AHUAYgBlAC0AbgBvAGMAbwBvAGsAaQBlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdAByAGEAYwBrAGUAcgB0AGUAcwB0AC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBzAHUAcgB2AGUAeQBnAGkAegBtAG8ALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtAC4AYwBuACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAuAGMAbwBtAAA=",
|
||||
output: {
|
||||
// Within Bug 965637 we removed CSP from Principals. Already serialized Principals however should still deserialize correctly (just without the CSP).
|
||||
// "cspJSON": "{\"csp-policies\":[{\"child-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"connect-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://accounts.firefox.com/\",\"https://accounts.firefox.com.cn/\"],\"default-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\"],\"frame-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"img-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"data:\",\"https://mozilla.org\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://adservice.google.com\",\"https://adservice.google.de\",\"https://adservice.google.dk\",\"https://creativecommons.org\",\"https://ad.doubleclick.net\"],\"report-only\":false,\"script-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\",\"'unsafe-eval'\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://tagmanager.google.com\",\"https://www.youtube.com\",\"https://s.ytimg.com\"],\"style-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\"]}]}",
|
||||
URISpec: "https://www.mozilla.org/en-US/",
|
||||
originAttributes: {
|
||||
firstPartyDomain: "",
|
||||
inIsolatedMozBrowser: false,
|
||||
privateBrowsingId: 0,
|
||||
userContextId: 0,
|
||||
geckoViewSessionContextId: "",
|
||||
partitionKey: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input:
|
||||
"ZT4OTT7kRfqycpfCC8AeuAAAAAAAAAAAwAAAAAAAAEYB3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAL2h0dHBzOi8vd3d3Lm1vemlsbGEub3JnL2VuLVVTL2ZpcmVmb3gvYWNjb3VudHMvAAAAAAAAAAUAAAAIAAAADwAAAAj/////AAAACP////8AAAAIAAAADwAAABcAAAAYAAAAFwAAABgAAAAXAAAAGAAAAC8AAAAAAAAAL/////8AAAAA/////wAAABf/////AAAAF/////8BAAAAAAAAAAAAAAABCdntGuXUQAS/4CfOuSPZrLPEwK69Xkyth+CNIQ27P58B3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAL2h0dHBzOi8vd3d3Lm1vemlsbGEub3JnL2VuLVVTL2ZpcmVmb3gvYWNjb3VudHMvAAAAAAAAAAUAAAAIAAAADwAAAAj/////AAAACP////8AAAAIAAAADwAAABcAAAAYAAAAFwAAABgAAAAXAAAAGAAAAC8AAAAAAAAAL/////8AAAAA/////wAAABf/////AAAAF/////8BAAAAAAAAAAAAAQAABbYAcwBjAHIAaQBwAHQALQBzAHIAYwAgACcAcwBlAGwAZgAnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbgBlAHQAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAGMAbwBtACAAJwB1AG4AcwBhAGYAZQAtAGkAbgBsAGkAbgBlACcAIAAnAHUAbgBzAGEAZgBlAC0AZQB2AGEAbAAnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBnAG8AbwBnAGwAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHMALgB5AHQAaQBtAGcALgBjAG8AbQA7ACAAaQBtAGcALQBzAHIAYwAgACcAcwBlAGwAZgAnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbgBlAHQAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAGMAbwBtACAAZABhAHQAYQA6ACAAaAB0AHQAcABzADoALwAvAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAC0AYQBuAGEAbAB5AHQAaQBjAHMALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGQAcwBlAHIAdgBpAGMAZQAuAGcAbwBvAGcAbABlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBkAHMAZQByAHYAaQBjAGUALgBnAG8AbwBnAGwAZQAuAGQAZQAgAGgAdAB0AHAAcwA6AC8ALwBhAGQAcwBlAHIAdgBpAGMAZQAuAGcAbwBvAGcAbABlAC4AZABrACAAaAB0AHQAcABzADoALwAvAGMAcgBlAGEAdABpAHYAZQBjAG8AbQBtAG8AbgBzAC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AYQBkAC4AZABvAHUAYgBsAGUAYwBsAGkAYwBrAC4AbgBlAHQAOwAgAGQAZQBmAGEAdQBsAHQALQBzAHIAYwAgACcAcwBlAGwAZgAnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbgBlAHQAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAGMAbwBtADsAIABmAHIAYQBtAGUALQBzAHIAYwAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAC0AYQBuAGEAbAB5AHQAaQBjAHMALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHkAbwB1AHQAdQBiAGUALQBuAG8AYwBvAG8AawBpAGUALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB0AHIAYQBjAGsAZQByAHQAZQBzAHQALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHMAdQByAHYAZQB5AGcAaQB6AG0AbwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAYwBjAG8AdQBuAHQAcwAuAGYAaQByAGUAZgBvAHgALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0ALgBjAG4AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgB5AG8AdQB0AHUAYgBlAC4AYwBvAG0AOwAgAHMAdAB5AGwAZQAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIAAnAHUAbgBzAGEAZgBlAC0AaQBuAGwAaQBuAGUAJwA7ACAAYwBvAG4AbgBlAGMAdAAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQB0AGEAZwBtAGEAbgBhAGcAZQByAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQAtAGEAbgBhAGwAeQB0AGkAYwBzAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtAC8AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtAC4AYwBuAC8AOwAgAGMAaABpAGwAZAAtAHMAcgBjACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAtAG4AbwBjAG8AbwBrAGkAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHQAcgBhAGMAawBlAHIAdABlAHMAdAAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AcwB1AHIAdgBlAHkAZwBpAHoAbQBvAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAYwBjAG8AdQBuAHQAcwAuAGYAaQByAGUAZgBvAHgALgBjAG8AbQAuAGMAbgAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHkAbwB1AHQAdQBiAGUALgBjAG8AbQAA",
|
||||
output: {
|
||||
URISpec: "https://www.mozilla.org/en-US/firefox/accounts/",
|
||||
originAttributes: {
|
||||
firstPartyDomain: "",
|
||||
inIsolatedMozBrowser: false,
|
||||
privateBrowsingId: 0,
|
||||
userContextId: 0,
|
||||
geckoViewSessionContextId: "",
|
||||
partitionKey: "",
|
||||
},
|
||||
// Within Bug 965637 we removed CSP from Principals. Already serialized Principals however should still deserialize correctly (just without the CSP).
|
||||
// "cspJSON": "{\"csp-policies\":[{\"child-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"connect-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://accounts.firefox.com/\",\"https://accounts.firefox.com.cn/\"],\"default-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\"],\"frame-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"img-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"data:\",\"https://mozilla.org\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://adservice.google.com\",\"https://adservice.google.de\",\"https://adservice.google.dk\",\"https://creativecommons.org\",\"https://ad.doubleclick.net\"],\"report-only\":false,\"script-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\",\"'unsafe-eval'\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://tagmanager.google.com\",\"https://www.youtube.com\",\"https://s.ytimg.com\"],\"style-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\"]}]}",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (let test of serializedPrincipalsFromFirefox) {
|
||||
let principal = E10SUtils.deserializePrincipal(test.input);
|
||||
|
||||
for (let key in principal.originAttributes) {
|
||||
is(
|
||||
principal.originAttributes[key],
|
||||
test.output.originAttributes[key],
|
||||
`Ensure value of ${key} is ${test.output.originAttributes[key]}`
|
||||
);
|
||||
}
|
||||
|
||||
if ("URI" in test.output && test.output.URI === false) {
|
||||
is(
|
||||
principal.isContentPrincipal,
|
||||
false,
|
||||
"Should have not have a URI for system"
|
||||
);
|
||||
} else {
|
||||
is(
|
||||
principal.spec,
|
||||
test.output.URISpec,
|
||||
`Should have spec ${test.output.URISpec}`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,161 @@
|
||||
"use strict";
|
||||
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
This test file exists to ensure whenever changes to principal serialization happens,
|
||||
we guarantee that the data can be restored and generated into a new principal.
|
||||
|
||||
The tests are written to be brittle so we encode all versions of the changes into the tests.
|
||||
*/
|
||||
|
||||
add_task(async function test_nullPrincipal() {
|
||||
const nullId = "0";
|
||||
// fields
|
||||
const uri = 0;
|
||||
const suffix = 1;
|
||||
|
||||
const nullReplaceRegex =
|
||||
/moz-nullprincipal:{[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}}/;
|
||||
const NULL_REPLACE = "NULL_PRINCIPAL_URL";
|
||||
|
||||
/*
|
||||
This test should NOT be resilient to changes in versioning,
|
||||
however it exists purely to verify the code doesn't unintentionally change without updating versioning and migration code.
|
||||
*/
|
||||
let tests = [
|
||||
{
|
||||
input: { OA: {} },
|
||||
expected: `{"${nullId}":{"${uri}":"${NULL_REPLACE}"}}`,
|
||||
},
|
||||
{
|
||||
input: { OA: {} },
|
||||
expected: `{"${nullId}":{"${uri}":"${NULL_REPLACE}"}}`,
|
||||
},
|
||||
{
|
||||
input: { OA: { userContextId: 0 } },
|
||||
expected: `{"${nullId}":{"${uri}":"${NULL_REPLACE}"}}`,
|
||||
},
|
||||
{
|
||||
input: { OA: { userContextId: 2 } },
|
||||
expected: `{"${nullId}":{"${uri}":"${NULL_REPLACE}","${suffix}":"^userContextId=2"}}`,
|
||||
},
|
||||
{
|
||||
input: { OA: { privateBrowsingId: 1 } },
|
||||
expected: `{"${nullId}":{"${uri}":"${NULL_REPLACE}","${suffix}":"^privateBrowsingId=1"}}`,
|
||||
},
|
||||
{
|
||||
input: { OA: { privateBrowsingId: 0 } },
|
||||
expected: `{"${nullId}":{"${uri}":"${NULL_REPLACE}"}}`,
|
||||
},
|
||||
];
|
||||
|
||||
for (let test of tests) {
|
||||
let p = Services.scriptSecurityManager.createNullPrincipal(test.input.OA);
|
||||
let sp = E10SUtils.serializePrincipal(p);
|
||||
// Not sure why cppjson is adding a \n here
|
||||
let spr = sp.replace(nullReplaceRegex, NULL_REPLACE);
|
||||
is(
|
||||
test.expected,
|
||||
spr,
|
||||
"Expected serialized object for " + JSON.stringify(test.input)
|
||||
);
|
||||
let dp = E10SUtils.deserializePrincipal(sp);
|
||||
|
||||
// Check all the origin attributes
|
||||
for (let key in test.input.OA) {
|
||||
is(
|
||||
dp.originAttributes[key],
|
||||
test.input.OA[key],
|
||||
"Ensure value of " + key + " is " + test.input.OA[key]
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_contentPrincipal() {
|
||||
const contentId = "1";
|
||||
// fields
|
||||
const content = 0;
|
||||
// const domain = 1;
|
||||
const suffix = 2;
|
||||
// const csp = 3;
|
||||
|
||||
/*
|
||||
This test should NOT be resilient to changes in versioning,
|
||||
however it exists purely to verify the code doesn't unintentionally change without updating versioning and migration code.
|
||||
*/
|
||||
let tests = [
|
||||
{
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
input: { uri: "http://example.com/", OA: {} },
|
||||
expected: `{"${contentId}":{"${content}":"http://example.com/"}}`,
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
input: { uri: "http://mozilla1.com/", OA: {} },
|
||||
expected: `{"${contentId}":{"${content}":"http://mozilla1.com/"}}`,
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
input: { uri: "http://mozilla2.com/", OA: { userContextId: 0 } },
|
||||
expected: `{"${contentId}":{"${content}":"http://mozilla2.com/"}}`,
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
input: { uri: "http://mozilla3.com/", OA: { userContextId: 2 } },
|
||||
expected: `{"${contentId}":{"${content}":"http://mozilla3.com/","${suffix}":"^userContextId=2"}}`,
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
input: { uri: "http://mozilla4.com/", OA: { privateBrowsingId: 1 } },
|
||||
expected: `{"${contentId}":{"${content}":"http://mozilla4.com/","${suffix}":"^privateBrowsingId=1"}}`,
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
input: { uri: "http://mozilla5.com/", OA: { privateBrowsingId: 0 } },
|
||||
expected: `{"${contentId}":{"${content}":"http://mozilla5.com/"}}`,
|
||||
},
|
||||
];
|
||||
|
||||
for (let test of tests) {
|
||||
let uri = Services.io.newURI(test.input.uri);
|
||||
let p = Services.scriptSecurityManager.createContentPrincipal(
|
||||
uri,
|
||||
test.input.OA
|
||||
);
|
||||
let sp = E10SUtils.serializePrincipal(p);
|
||||
is(test.expected, sp, "Expected serialized object for " + test.input.uri);
|
||||
let dp = E10SUtils.deserializePrincipal(sp);
|
||||
is(dp.URI.spec, test.input.uri, "Ensure spec is the same");
|
||||
|
||||
// Check all the origin attributes
|
||||
for (let key in test.input.OA) {
|
||||
is(
|
||||
dp.originAttributes[key],
|
||||
test.input.OA[key],
|
||||
"Ensure value of " + key + " is " + test.input.OA[key]
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_systemPrincipal() {
|
||||
const systemId = "3";
|
||||
/*
|
||||
This test should NOT be resilient to changes in versioning,
|
||||
however it exists purely to verify the code doesn't unintentionally change without updating versioning and migration code.
|
||||
*/
|
||||
const expected = `{"${systemId}":{}}`;
|
||||
|
||||
let p = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
let sp = E10SUtils.serializePrincipal(p);
|
||||
is(expected, sp, "Expected serialized object for system principal");
|
||||
let dp = E10SUtils.deserializePrincipal(sp);
|
||||
is(
|
||||
dp,
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
"Deserialized the system principal"
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,159 @@
|
||||
"use strict";
|
||||
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
This test file exists to ensure whenever changes to principal serialization happens,
|
||||
we guarantee that the data can be restored and generated into a new principal.
|
||||
|
||||
The tests are written to be brittle so we encode all versions of the changes into the tests.
|
||||
*/
|
||||
|
||||
add_task(function test_nullPrincipal() {
|
||||
/*
|
||||
As Null principals are designed to be non deterministic we just need to ensure that
|
||||
a previous serialized version matches what it was generated as.
|
||||
|
||||
This test should be resilient to changes in versioning, however it should also be duplicated for a new serialization change.
|
||||
*/
|
||||
// Principal created with: E10SUtils.serializePrincipal(Services.scriptSecurityManager.createNullPrincipal({ }));
|
||||
let p = E10SUtils.deserializePrincipal(
|
||||
"vQZuXxRvRHKDMXv9BbHtkAAAAAAAAAAAwAAAAAAAAEYAAAA4bW96LW51bGxwcmluY2lwYWw6ezU2Y2FjNTQwLTg2NGQtNDdlNy04ZTI1LTE2MTRlYWI1MTU1ZX0AAAAA"
|
||||
);
|
||||
is(
|
||||
"moz-nullprincipal:{56cac540-864d-47e7-8e25-1614eab5155e}",
|
||||
p.URI.spec,
|
||||
"Deserialized principal doesn't have the correct URI"
|
||||
);
|
||||
|
||||
// Principal created with: E10SUtils.serializePrincipal(Services.scriptSecurityManager.createNullPrincipal({ userContextId: 2 }));
|
||||
let p2 = E10SUtils.deserializePrincipal(
|
||||
"vQZuXxRvRHKDMXv9BbHtkAAAAAAAAAAAwAAAAAAAAEYAAAA4bW96LW51bGxwcmluY2lwYWw6ezA1ZjllN2JhLWIwODMtNDJhMi1iNDdkLTZiODRmNmYwYTM3OX0AAAAQXnVzZXJDb250ZXh0SWQ9Mg=="
|
||||
);
|
||||
is(
|
||||
"moz-nullprincipal:{05f9e7ba-b083-42a2-b47d-6b84f6f0a379}",
|
||||
p2.URI.spec,
|
||||
"Deserialized principal doesn't have the correct URI"
|
||||
);
|
||||
is(p2.originAttributes.userContextId, 2, "Expected a userContextId of 2");
|
||||
});
|
||||
|
||||
add_task(async function test_realHistoryCheck() {
|
||||
/*
|
||||
This test should be resilient to changes in principal serialization, if these are failing then it's likely the code will break session storage.
|
||||
To recreate this for another version, copy the function into the browser console, browse some pages and printHistory.
|
||||
|
||||
Generated with:
|
||||
function printHistory() {
|
||||
let tests = [];
|
||||
let entries = SessionStore.getSessionHistory(gBrowser.selectedTab).entries.map((entry) => { return entry.triggeringPrincipal_base64 });
|
||||
entries.push(E10SUtils.serializePrincipal(gBrowser.selectedTab.linkedBrowser._contentPrincipal));
|
||||
for (let entry of entries) {
|
||||
console.log(entry);
|
||||
let testData = {};
|
||||
testData.input = entry;
|
||||
let principal = E10SUtils.deserializePrincipal(testData.input);
|
||||
testData.output = {};
|
||||
if (principal.URI === null) {
|
||||
testData.output.URI = false;
|
||||
} else {
|
||||
testData.output.URISpec = principal.URI.spec;
|
||||
}
|
||||
testData.output.originAttributes = principal.originAttributes;
|
||||
|
||||
tests.push(testData);
|
||||
}
|
||||
return tests;
|
||||
}
|
||||
printHistory(); // Copy this into: serializedPrincipalsFromFirefox
|
||||
*/
|
||||
|
||||
let serializedPrincipalsFromFirefox = [
|
||||
{
|
||||
input: "SmIS26zLEdO3ZQBgsLbOywAAAAAAAAAAwAAAAAAAAEY=",
|
||||
output: {
|
||||
URI: false,
|
||||
originAttributes: {
|
||||
firstPartyDomain: "",
|
||||
inIsolatedMozBrowser: false,
|
||||
privateBrowsingId: 0,
|
||||
userContextId: 0,
|
||||
geckoViewSessionContextId: "",
|
||||
partitionKey: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input:
|
||||
"ZT4OTT7kRfqycpfCC8AeuAAAAAAAAAAAwAAAAAAAAEYB3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAe2h0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTLz91dG1fc291cmNlPXd3dy5tb3ppbGxhLm9yZyZ1dG1fbWVkaXVtPXJlZmVycmFsJnV0bV9jYW1wYWlnbj1uYXYmdXRtX2NvbnRlbnQ9ZGV2ZWxvcGVycwAAAAAAAAAFAAAACAAAABUAAAAA/////wAAAAD/////AAAACAAAABUAAAAdAAAAXgAAAB0AAAAHAAAAHQAAAAcAAAAkAAAAAAAAAAD/////AAAAAP////8AAAAlAAAAVgAAAAD/////AQAAAAAAAAAAAAAAAA==",
|
||||
output: {
|
||||
URISpec:
|
||||
"https://developer.mozilla.org/en-US/?utm_source=www.mozilla.org&utm_medium=referral&utm_campaign=nav&utm_content=developers",
|
||||
originAttributes: {
|
||||
firstPartyDomain: "",
|
||||
inIsolatedMozBrowser: false,
|
||||
privateBrowsingId: 0,
|
||||
userContextId: 0,
|
||||
geckoViewSessionContextId: "",
|
||||
partitionKey: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "SmIS26zLEdO3ZQBgsLbOywAAAAAAAAAAwAAAAAAAAEY=",
|
||||
output: {
|
||||
URI: false,
|
||||
originAttributes: {
|
||||
firstPartyDomain: "",
|
||||
inIsolatedMozBrowser: false,
|
||||
privateBrowsingId: 0,
|
||||
userContextId: 0,
|
||||
geckoViewSessionContextId: "",
|
||||
partitionKey: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input:
|
||||
"vQZuXxRvRHKDMXv9BbHtkAAAAAAAAAAAwAAAAAAAAEYAAAA4bW96LW51bGxwcmluY2lwYWw6ezA0NWNhMThkLTQzNmMtNDc0NC1iYmI2LWIxYTE1MzY2ZGY3OX0AAAAA",
|
||||
output: {
|
||||
URISpec: "moz-nullprincipal:{045ca18d-436c-4744-bbb6-b1a15366df79}",
|
||||
originAttributes: {
|
||||
firstPartyDomain: "",
|
||||
inIsolatedMozBrowser: false,
|
||||
privateBrowsingId: 0,
|
||||
userContextId: 0,
|
||||
geckoViewSessionContextId: "",
|
||||
partitionKey: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (let test of serializedPrincipalsFromFirefox) {
|
||||
let principal = E10SUtils.deserializePrincipal(test.input);
|
||||
|
||||
for (let key in principal.originAttributes) {
|
||||
is(
|
||||
principal.originAttributes[key],
|
||||
test.output.originAttributes[key],
|
||||
`Ensure value of ${key} is ${test.output.originAttributes[key]}`
|
||||
);
|
||||
}
|
||||
|
||||
if ("URI" in test.output && test.output.URI === false) {
|
||||
is(
|
||||
principal.isContentPrincipal,
|
||||
false,
|
||||
"Should have not have a URI for system"
|
||||
);
|
||||
} else {
|
||||
is(
|
||||
principal.spec,
|
||||
test.output.URISpec,
|
||||
`Should have spec ${test.output.URISpec}`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
11
src/zen/tests/mochitests/gesture/browser.toml
Normal file
11
src/zen/tests/mochitests/gesture/browser.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[DEFAULT]
|
||||
prefs = [
|
||||
"zen.window-sync.enabled=false",
|
||||
]
|
||||
|
||||
["browser_gesture_navigation.js"]
|
||||
|
||||
["browser_gesture_scroll.js"]
|
||||
skip-if = [
|
||||
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Bug 1988390
|
||||
]
|
||||
231
src/zen/tests/mochitests/gesture/browser_gesture_navigation.js
Normal file
231
src/zen/tests/mochitests/gesture/browser_gesture_navigation.js
Normal file
@@ -0,0 +1,231 @@
|
||||
"use strict";
|
||||
|
||||
add_setup(async () => {
|
||||
// Disable window occlusion. See bug 1733955 / bug 1779559.
|
||||
if (navigator.platform.indexOf("Win") == 0) {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["widget.windows.window_occlusion_tracking.enabled", false]],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async () => {
|
||||
// Open a new browser window to make sure there is no navigation history.
|
||||
const newBrowser = await BrowserTestUtils.openNewBrowserWindow({});
|
||||
|
||||
let event = {
|
||||
direction: SimpleGestureEvent.DIRECTION_LEFT,
|
||||
};
|
||||
ok(!newBrowser.gGestureSupport._shouldDoSwipeGesture(event));
|
||||
|
||||
event = {
|
||||
direction: SimpleGestureEvent.DIRECTION_RIGHT,
|
||||
};
|
||||
ok(!newBrowser.gGestureSupport._shouldDoSwipeGesture(event));
|
||||
|
||||
await BrowserTestUtils.closeWindow(newBrowser);
|
||||
});
|
||||
|
||||
function createSimpleGestureEvent(type, direction) {
|
||||
let event = document.createEvent("SimpleGestureEvent");
|
||||
event.initSimpleGestureEvent(
|
||||
type,
|
||||
false /* canBubble */,
|
||||
false /* cancelableArg */,
|
||||
window,
|
||||
0 /* detail */,
|
||||
0 /* screenX */,
|
||||
0 /* screenY */,
|
||||
0 /* clientX */,
|
||||
0 /* clientY */,
|
||||
false /* ctrlKey */,
|
||||
false /* altKey */,
|
||||
false /* shiftKey */,
|
||||
false /* metaKey */,
|
||||
0 /* button */,
|
||||
null /* relatedTarget */,
|
||||
0 /* allowedDirections */,
|
||||
direction,
|
||||
1 /* delta */
|
||||
);
|
||||
return event;
|
||||
}
|
||||
|
||||
add_task(async () => {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["ui.swipeAnimationEnabled", false]],
|
||||
});
|
||||
|
||||
// Open a new browser window and load two pages so that the browser can go
|
||||
// back but can't go forward.
|
||||
const newWindow = await BrowserTestUtils.openNewBrowserWindow({});
|
||||
|
||||
// gHistroySwipeAnimation gets initialized in a requestIdleCallback so we need
|
||||
// to wait for the initialization.
|
||||
await TestUtils.waitForCondition(() => {
|
||||
return (
|
||||
// There's no explicit notification for the initialization, so we wait
|
||||
// until `isLTR` matches the browser locale state.
|
||||
newWindow.gHistorySwipeAnimation.isLTR != Services.locale.isAppLocaleRTL
|
||||
);
|
||||
});
|
||||
|
||||
BrowserTestUtils.startLoadingURIString(
|
||||
newWindow.gBrowser.selectedBrowser,
|
||||
"about:mozilla"
|
||||
);
|
||||
await BrowserTestUtils.browserLoaded(
|
||||
newWindow.gBrowser.selectedBrowser,
|
||||
false,
|
||||
"about:mozilla"
|
||||
);
|
||||
BrowserTestUtils.startLoadingURIString(
|
||||
newWindow.gBrowser.selectedBrowser,
|
||||
"about:about"
|
||||
);
|
||||
await BrowserTestUtils.browserLoaded(
|
||||
newWindow.gBrowser.selectedBrowser,
|
||||
false,
|
||||
"about:about"
|
||||
);
|
||||
|
||||
let event = createSimpleGestureEvent(
|
||||
"MozSwipeGestureMayStart",
|
||||
SimpleGestureEvent.DIRECTION_LEFT
|
||||
);
|
||||
newWindow.gGestureSupport._shouldDoSwipeGesture(event);
|
||||
|
||||
// Assuming we are on LTR environment.
|
||||
is(
|
||||
event.allowedDirections,
|
||||
SimpleGestureEvent.DIRECTION_LEFT,
|
||||
"Allows only swiping to left, i.e. backward"
|
||||
);
|
||||
|
||||
event = createSimpleGestureEvent(
|
||||
"MozSwipeGestureMayStart",
|
||||
SimpleGestureEvent.DIRECTION_RIGHT
|
||||
);
|
||||
newWindow.gGestureSupport._shouldDoSwipeGesture(event);
|
||||
is(
|
||||
event.allowedDirections,
|
||||
SimpleGestureEvent.DIRECTION_LEFT,
|
||||
"Allows only swiping to left, i.e. backward"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(newWindow);
|
||||
});
|
||||
|
||||
add_task(async () => {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["ui.swipeAnimationEnabled", true]],
|
||||
});
|
||||
|
||||
// Open a new browser window and load two pages so that the browser can go
|
||||
// back but can't go forward.
|
||||
const newWindow = await BrowserTestUtils.openNewBrowserWindow({});
|
||||
|
||||
if (!newWindow.gHistorySwipeAnimation._isSupported()) {
|
||||
await BrowserTestUtils.closeWindow(newWindow);
|
||||
return;
|
||||
}
|
||||
|
||||
function sendSwipeSequence(sendEnd) {
|
||||
let event = createSimpleGestureEvent(
|
||||
"MozSwipeGestureMayStart",
|
||||
SimpleGestureEvent.DIRECTION_LEFT
|
||||
);
|
||||
newWindow.gGestureSupport.handleEvent(event);
|
||||
|
||||
event = createSimpleGestureEvent(
|
||||
"MozSwipeGestureStart",
|
||||
SimpleGestureEvent.DIRECTION_LEFT
|
||||
);
|
||||
newWindow.gGestureSupport.handleEvent(event);
|
||||
|
||||
event = createSimpleGestureEvent(
|
||||
"MozSwipeGestureUpdate",
|
||||
SimpleGestureEvent.DIRECTION_LEFT
|
||||
);
|
||||
newWindow.gGestureSupport.handleEvent(event);
|
||||
|
||||
event = createSimpleGestureEvent(
|
||||
"MozSwipeGestureUpdate",
|
||||
SimpleGestureEvent.DIRECTION_LEFT
|
||||
);
|
||||
newWindow.gGestureSupport.handleEvent(event);
|
||||
|
||||
if (sendEnd) {
|
||||
sendSwipeEnd();
|
||||
}
|
||||
}
|
||||
function sendSwipeEnd() {
|
||||
let event = createSimpleGestureEvent(
|
||||
"MozSwipeGestureEnd",
|
||||
SimpleGestureEvent.DIRECTION_LEFT
|
||||
);
|
||||
newWindow.gGestureSupport.handleEvent(event);
|
||||
}
|
||||
|
||||
// gHistroySwipeAnimation gets initialized in a requestIdleCallback so we need
|
||||
// to wait for the initialization.
|
||||
await TestUtils.waitForCondition(() => {
|
||||
return (
|
||||
// There's no explicit notification for the initialization, so we wait
|
||||
// until `isLTR` matches the browser locale state.
|
||||
newWindow.gHistorySwipeAnimation.isLTR != Services.locale.isAppLocaleRTL
|
||||
);
|
||||
});
|
||||
|
||||
BrowserTestUtils.startLoadingURIString(
|
||||
newWindow.gBrowser.selectedBrowser,
|
||||
"about:mozilla"
|
||||
);
|
||||
await BrowserTestUtils.browserLoaded(
|
||||
newWindow.gBrowser.selectedBrowser,
|
||||
false,
|
||||
"about:mozilla"
|
||||
);
|
||||
BrowserTestUtils.startLoadingURIString(
|
||||
newWindow.gBrowser.selectedBrowser,
|
||||
"about:about"
|
||||
);
|
||||
await BrowserTestUtils.browserLoaded(
|
||||
newWindow.gBrowser.selectedBrowser,
|
||||
false,
|
||||
"about:about"
|
||||
);
|
||||
|
||||
// Start a swipe that's not enough to navigate
|
||||
sendSwipeSequence(/* sendEnd = */ true);
|
||||
|
||||
// Wait two frames
|
||||
await new Promise(r =>
|
||||
window.requestAnimationFrame(() => window.requestAnimationFrame(r))
|
||||
);
|
||||
|
||||
// The transition to fully stopped shouldn't have had enough time yet to
|
||||
// become fully stopped.
|
||||
ok(
|
||||
newWindow.gHistorySwipeAnimation._isStoppingAnimation,
|
||||
"should be stopping anim"
|
||||
);
|
||||
|
||||
// Start another swipe.
|
||||
sendSwipeSequence(/* sendEnd = */ false);
|
||||
|
||||
// Wait two frames
|
||||
await new Promise(r =>
|
||||
window.requestAnimationFrame(() => window.requestAnimationFrame(r))
|
||||
);
|
||||
|
||||
// We should have started a new swipe, ie we shouldn't be stopping.
|
||||
ok(
|
||||
!newWindow.gHistorySwipeAnimation._isStoppingAnimation,
|
||||
"should not be stopping anim"
|
||||
);
|
||||
|
||||
sendSwipeEnd();
|
||||
|
||||
await BrowserTestUtils.closeWindow(newWindow);
|
||||
});
|
||||
43
src/zen/tests/mochitests/gesture/browser_gesture_scroll.js
Normal file
43
src/zen/tests/mochitests/gesture/browser_gesture_scroll.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const URL = `data:text/html,
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<div style="height: 200vh"></div>
|
||||
Some content
|
||||
<div style="height: 200vh"></div>
|
||||
`;
|
||||
|
||||
function getScrollPos(browser) {
|
||||
return SpecialPowers.spawn(browser, [], () => {
|
||||
return {
|
||||
scrollY: Math.round(content.scrollY),
|
||||
scrollMaxY: Math.round(content.scrollMaxY),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Bug 1964901
|
||||
add_task(async function test_scroll_command() {
|
||||
await BrowserTestUtils.withNewTab(URL, async function (browser) {
|
||||
{
|
||||
let { scrollY, scrollMaxY } = await getScrollPos(browser);
|
||||
is(scrollY, 0, "Should be scrolled to the top");
|
||||
isnot(scrollMaxY, 0, "Should be scrollable");
|
||||
}
|
||||
let scrollEvent = SpecialPowers.spawn(browser, [], async () => {
|
||||
await new Promise(r => {
|
||||
content.addEventListener("scrollend", r, { once: true });
|
||||
});
|
||||
});
|
||||
goDoCommand("cmd_scrollBottom");
|
||||
await scrollEvent;
|
||||
{
|
||||
let { scrollY, scrollMaxY } = await getScrollPos(browser);
|
||||
is(scrollY, scrollMaxY, "Should be scrolled to the bottom");
|
||||
}
|
||||
});
|
||||
});
|
||||
12
src/zen/tests/mochitests/linkHandling/browser.toml
Normal file
12
src/zen/tests/mochitests/linkHandling/browser.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[DEFAULT]
|
||||
|
||||
["browser_contentAreaClick_subframe_javascript.js"]
|
||||
support-files = [
|
||||
"file_contentAreaClick_subframe_javascript.html"
|
||||
]
|
||||
|
||||
["browser_javascript_links.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
support-files = [
|
||||
"file_javascript_links_subframe.html"
|
||||
]
|
||||
@@ -0,0 +1,49 @@
|
||||
const gExampleComRoot = getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content/",
|
||||
"https://example.com/"
|
||||
);
|
||||
const IFRAME_FILE = "file_contentAreaClick_subframe_javascript.html";
|
||||
|
||||
add_task(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.link.alternative_click.block_javascript", false]],
|
||||
});
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
`data:text/html,<iframe src="${gExampleComRoot + IFRAME_FILE}"></iframe>`,
|
||||
async browser => {
|
||||
let newTabPromise = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
"about:blank"
|
||||
);
|
||||
let javascriptRanPromise = TestUtils.topicObserved(
|
||||
"contentAreaClick-javascriptRan"
|
||||
);
|
||||
|
||||
// ctrl/cmd-click the link in the subframe. This should cause it to be
|
||||
// loaded in a new tab.
|
||||
info("Clicking link");
|
||||
let expectedRemoteType =
|
||||
browser.browsingContext.children[0].currentRemoteType;
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
"a",
|
||||
{ ctrlKey: true, metaKey: true },
|
||||
browser.browsingContext.children[0]
|
||||
);
|
||||
|
||||
info("Waiting for new tab");
|
||||
let newTab = await newTabPromise;
|
||||
|
||||
info("Waiting to be notified that the javascript ran");
|
||||
await javascriptRanPromise;
|
||||
is(
|
||||
newTab.linkedBrowser.remoteType,
|
||||
expectedRemoteType,
|
||||
"new tab was loaded in expected process"
|
||||
);
|
||||
|
||||
info("Removing the tab");
|
||||
BrowserTestUtils.removeTab(newTab);
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_PATH = getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content/",
|
||||
"https://example.com/"
|
||||
);
|
||||
const IFRAME_PATH = TEST_PATH + "file_javascript_links_subframe.html";
|
||||
|
||||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.link.alternative_click.block_javascript", true],
|
||||
["browser.tabs.opentabfor.middleclick", true],
|
||||
["middlemouse.paste", false],
|
||||
["middlemouse.contentLoadURL", false],
|
||||
["general.autoScroll", false],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function () {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
`data:text/html,<a href="javascript:alert(1);">click me`,
|
||||
async browser => {
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
"a",
|
||||
{ button: 0, ctrlKey: true, metaKey: true },
|
||||
browser
|
||||
);
|
||||
is(
|
||||
gBrowser.tabs.length,
|
||||
2,
|
||||
"Accel+click on javascript: link shouldn't open a new tab"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
"a",
|
||||
{ button: 1 },
|
||||
browser
|
||||
);
|
||||
is(
|
||||
gBrowser.tabs.length,
|
||||
2,
|
||||
"Middle click on javascript: link shouldn't open a new tab"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
"a",
|
||||
{ button: 0, shiftKey: true },
|
||||
browser
|
||||
);
|
||||
// This is fragile and might miss the new window, but the test will fail
|
||||
// anyway when finishing with an extra window left behind.
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
is(
|
||||
BrowserWindowTracker.windowCount,
|
||||
1,
|
||||
"Shift+click on javascript: link shouldn't open a new window"
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function iframe_link() {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
`data:text/html,<iframe src="${IFRAME_PATH}"></iframe>`,
|
||||
async browser => {
|
||||
// ctrl/cmd-click the link in the subframe.
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
"a",
|
||||
{ ctrlKey: true, metaKey: true },
|
||||
browser.browsingContext.children[0]
|
||||
);
|
||||
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
is(
|
||||
gBrowser.tabs.length,
|
||||
2,
|
||||
"Click on javascript: link in iframe shouldn't open a new tab"
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
<!DOCTYPE html>
|
||||
<a href="javascript:SpecialPowers.notifyObserversInParentProcess(null, 'contentAreaClick-javascriptRan');">link</a>
|
||||
@@ -0,0 +1,2 @@
|
||||
<!DOCTYPE html>
|
||||
<a href="javascript:alert(1)">click me
|
||||
@@ -8,11 +8,18 @@
|
||||
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
"alerts/browser.toml",
|
||||
"backforward/browser.toml",
|
||||
"caps/browser.toml",
|
||||
"gesture/browser.toml",
|
||||
"linkHandling/browser.toml",
|
||||
"readermode/browser.toml",
|
||||
"safebrowsing/browser.toml",
|
||||
"sessionstore/browser.toml",
|
||||
"shell/browser.toml",
|
||||
"tabMediaIndicator/browser.toml",
|
||||
"tooltiptext/browser.toml",
|
||||
"zoom/browser.toml",
|
||||
]
|
||||
XPCSHELL_TESTS_MANIFESTS += [
|
||||
"remote-settings/xpcshell.toml",
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
BrowserTestUtils: "resource://testing-common/BrowserTestUtils.sys.mjs",
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
||||
TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs",
|
||||
TestUtils: "resource://testing-common/TestUtils.sys.mjs",
|
||||
});
|
||||
|
||||
export var SessionStoreTestUtils = {
|
||||
/**
|
||||
* Running this init allows helpers to access test scope helpers, like Assert
|
||||
* and SimpleTest.
|
||||
* Tests should call this init() before using the helpers which rely on properties assign here.
|
||||
*
|
||||
* @param {object} scope The global scope where tests are being run.
|
||||
* @param {DOMWindow} windowGlobal The global window object, for acessing gBrowser etc.
|
||||
*/
|
||||
init(scope, windowGlobal) {
|
||||
if (!scope) {
|
||||
throw new Error(
|
||||
"Must initialize SessionStoreTestUtils with a test scope"
|
||||
);
|
||||
}
|
||||
if (!windowGlobal) {
|
||||
throw new Error("this.windowGlobal must be defined when we init");
|
||||
}
|
||||
this._scopeRef = new WeakRef(scope);
|
||||
this._windowGlobalRef = new WeakRef(windowGlobal);
|
||||
},
|
||||
|
||||
get info() {
|
||||
return this._scopeRef.deref()?.info;
|
||||
},
|
||||
|
||||
get registerCleanupFunction() {
|
||||
return this._scopeRef.deref()?.registerCleanupFunction;
|
||||
},
|
||||
|
||||
get windowGlobal() {
|
||||
return this._windowGlobalRef.deref();
|
||||
},
|
||||
|
||||
async closeTab(tab) {
|
||||
await lazy.TabStateFlusher.flush(tab.linkedBrowser);
|
||||
let sessionUpdatePromise =
|
||||
lazy.BrowserTestUtils.waitForSessionStoreUpdate(tab);
|
||||
lazy.BrowserTestUtils.removeTab(tab);
|
||||
await sessionUpdatePromise;
|
||||
},
|
||||
|
||||
async openAndCloseTab(window, url) {
|
||||
let { updatePromise } = await lazy.BrowserTestUtils.withNewTab(
|
||||
{ url, gBrowser: window.gBrowser },
|
||||
async browser => {
|
||||
return {
|
||||
updatePromise: lazy.BrowserTestUtils.waitForSessionStoreUpdate({
|
||||
linkedBrowser: browser,
|
||||
}),
|
||||
};
|
||||
}
|
||||
);
|
||||
await updatePromise;
|
||||
return lazy.TestUtils.topicObserved("sessionstore-closed-objects-changed");
|
||||
},
|
||||
|
||||
// This assumes that tests will at least have some state/entries
|
||||
waitForBrowserState(aState, aSetStateCallback) {
|
||||
if (typeof aState == "string") {
|
||||
aState = JSON.parse(aState);
|
||||
}
|
||||
if (typeof aState != "object") {
|
||||
throw new TypeError(
|
||||
"Argument must be an object or a JSON representation of an object"
|
||||
);
|
||||
}
|
||||
if (!this.windowGlobal) {
|
||||
throw new Error(
|
||||
"no windowGlobal defined, please call init() first with the scope and window object"
|
||||
);
|
||||
}
|
||||
let windows = [this.windowGlobal];
|
||||
let tabsRestored = 0;
|
||||
let expectedTabsRestored = 0;
|
||||
let expectedWindows = aState.windows.length;
|
||||
let windowsOpen = 1;
|
||||
let listening = false;
|
||||
let windowObserving = false;
|
||||
let restoreHiddenTabs = Services.prefs.getBoolPref(
|
||||
"browser.sessionstore.restore_hidden_tabs"
|
||||
);
|
||||
// This should match the |restoreTabsLazily| value that
|
||||
// SessionStore.restoreWindow() uses.
|
||||
let restoreTabsLazily =
|
||||
Services.prefs.getBoolPref("browser.sessionstore.restore_on_demand") &&
|
||||
Services.prefs.getBoolPref("browser.sessionstore.restore_tabs_lazily");
|
||||
|
||||
aState.windows.forEach(function (winState) {
|
||||
winState.tabs.forEach(function (tabState) {
|
||||
if (!restoreTabsLazily && (restoreHiddenTabs || !tabState.hidden)) {
|
||||
expectedTabsRestored++;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// If there are only hidden tabs and restoreHiddenTabs = false, we still
|
||||
// expect one of them to be restored because it gets shown automatically.
|
||||
// Otherwise if lazy tab restore there will only be one tab restored per window.
|
||||
if (!expectedTabsRestored) {
|
||||
expectedTabsRestored = 1;
|
||||
} else if (restoreTabsLazily) {
|
||||
expectedTabsRestored = aState.windows.length;
|
||||
}
|
||||
|
||||
function onSSTabRestored() {
|
||||
if (++tabsRestored == expectedTabsRestored) {
|
||||
// Remove the event listener from each window
|
||||
windows.forEach(function (win) {
|
||||
win.gBrowser.tabContainer.removeEventListener(
|
||||
"SSTabRestored",
|
||||
onSSTabRestored,
|
||||
true
|
||||
);
|
||||
});
|
||||
listening = false;
|
||||
SessionStoreTestUtils.info("running " + aSetStateCallback.name);
|
||||
lazy.TestUtils.executeSoon(aSetStateCallback);
|
||||
}
|
||||
}
|
||||
|
||||
// Used to add our listener to further windows so we can catch SSTabRestored
|
||||
// coming from them when creating a multi-window state.
|
||||
function windowObserver(aSubject, aTopic) {
|
||||
if (aTopic == "domwindowopened") {
|
||||
let newWindow = aSubject;
|
||||
newWindow.addEventListener(
|
||||
"load",
|
||||
function () {
|
||||
if (++windowsOpen == expectedWindows) {
|
||||
Services.ww.unregisterNotification(windowObserver);
|
||||
windowObserving = false;
|
||||
}
|
||||
|
||||
// Track this window so we can remove the progress listener later
|
||||
windows.push(newWindow);
|
||||
// Add the progress listener
|
||||
newWindow.gBrowser.tabContainer.addEventListener(
|
||||
"SSTabRestored",
|
||||
onSSTabRestored,
|
||||
true
|
||||
);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// We only want to register the notification if we expect more than 1 window
|
||||
if (expectedWindows > 1) {
|
||||
this.registerCleanupFunction(function () {
|
||||
if (windowObserving) {
|
||||
Services.ww.unregisterNotification(windowObserver);
|
||||
}
|
||||
});
|
||||
windowObserving = true;
|
||||
Services.ww.registerNotification(windowObserver);
|
||||
}
|
||||
|
||||
this.registerCleanupFunction(function () {
|
||||
if (listening) {
|
||||
windows.forEach(function (win) {
|
||||
win.gBrowser.tabContainer.removeEventListener(
|
||||
"SSTabRestored",
|
||||
onSSTabRestored,
|
||||
true
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
// Add the event listener for this window as well.
|
||||
listening = true;
|
||||
this.windowGlobal.gBrowser.tabContainer.addEventListener(
|
||||
"SSTabRestored",
|
||||
onSSTabRestored,
|
||||
true
|
||||
);
|
||||
|
||||
// Ensure setBrowserState() doesn't remove the initial tab.
|
||||
this.windowGlobal.gBrowser.selectedTab = this.windowGlobal.gBrowser.tabs[0];
|
||||
|
||||
// Finally, call setBrowserState
|
||||
lazy.SessionStore.setBrowserState(JSON.stringify(aState));
|
||||
},
|
||||
|
||||
promiseBrowserState(aState) {
|
||||
return new Promise(resolve => this.waitForBrowserState(aState, resolve));
|
||||
},
|
||||
};
|
||||
483
src/zen/tests/mochitests/sessionstore/browser.toml
Normal file
483
src/zen/tests/mochitests/sessionstore/browser.toml
Normal file
@@ -0,0 +1,483 @@
|
||||
[DEFAULT]
|
||||
support-files = [
|
||||
"head.js",
|
||||
"browser_formdata_sample.html",
|
||||
"browser_formdata_xpath_sample.html",
|
||||
"browser_frametree_sample.html",
|
||||
"browser_frametree_sample_frameset.html",
|
||||
"browser_frametree_sample_iframes.html",
|
||||
"browser_frame_history_index.html",
|
||||
"browser_frame_history_index2.html",
|
||||
"browser_frame_history_index_blank.html",
|
||||
"browser_frame_history_a.html",
|
||||
"browser_frame_history_b.html",
|
||||
"browser_frame_history_c.html",
|
||||
"browser_frame_history_c1.html",
|
||||
"browser_frame_history_c2.html",
|
||||
"browser_formdata_format_sample.html",
|
||||
"browser_sessionHistory_slow.sjs",
|
||||
"browser_policy_container_sample.html",
|
||||
"browser_policy_container_sample_frame.html",
|
||||
"browser_scrollPositions_sample.html",
|
||||
"browser_scrollPositions_sample2.html",
|
||||
"browser_scrollPositions_sample_frameset.html",
|
||||
"browser_scrollPositions_readerModeArticle.html",
|
||||
"browser_sessionStorage.html",
|
||||
"browser_speculative_connect.html",
|
||||
"coopHeaderCommon.sjs",
|
||||
"restore_redirect_http.html",
|
||||
"restore_redirect_http.html^headers^",
|
||||
"restore_redirect_js.html",
|
||||
"restore_redirect_target.html",
|
||||
"empty.html",
|
||||
"coop_coep.html",
|
||||
"coop_coep.html^headers^",
|
||||
]
|
||||
# remove this after bug 1628486 is landed
|
||||
prefs = [
|
||||
"zen.window-sync.enabled=false",
|
||||
"network.cookie.cookieBehavior=5",
|
||||
"gfx.font_rendering.fallback.async=false",
|
||||
"browser.sessionstore.closedTabsFromAllWindows=true",
|
||||
"browser.sessionstore.closedTabsFromClosedWindows=true",
|
||||
# Override the test default, allowing the session restore infobar to be shown if necessary
|
||||
"browser.startup.couldRestoreSession.count=0",
|
||||
]
|
||||
|
||||
["browser_1933485_tab_groups_history.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_1953801_tab_groups_history_close_other.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_aboutPrivateBrowsing.js"]
|
||||
|
||||
["browser_aboutRestartrequired_noRestore.js"]
|
||||
|
||||
["browser_aboutSessionRestore.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_async_duplicate_tab.js"]
|
||||
support-files = ["file_async_duplicate_tab.html"]
|
||||
|
||||
["browser_async_flushes.js"]
|
||||
support-files = ["file_async_flushes.html"]
|
||||
run-if = [
|
||||
"crashreporter",
|
||||
]
|
||||
|
||||
["browser_async_remove_tab.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && opt", # Bug 1787024
|
||||
"os == 'win' && os_version == '11.26100' && arch == 'x86_64' && asan", # Bug 1787024
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86_64' && asan", # Bug 1787024
|
||||
]
|
||||
|
||||
["browser_async_window_flushing.js"]
|
||||
https_first_disabled = true
|
||||
skip-if = [
|
||||
"os == 'mac' && os_version == '10.15' && arch == 'x86_64' && opt", # Bug 1775616
|
||||
"os == 'win' && os_version == '11.26100' && arch == 'x86_64' && asan", # Bug 1775616
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86_64' && asan", # Bug 1775616
|
||||
"os == 'win' && os_version == '11.26100' && arch == 'x86_64' && opt", # Bug 1775616
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86_64' && opt", # Bug 1775616
|
||||
]
|
||||
|
||||
["browser_attributes.js"]
|
||||
|
||||
["browser_background_tab_crash.js"]
|
||||
https_first_disabled = true
|
||||
run-if = [
|
||||
"crashreporter",
|
||||
]
|
||||
tags = "os_integration"
|
||||
|
||||
["browser_backup_recovery.js"]
|
||||
https_first_disabled = true
|
||||
tags = "os_integration"
|
||||
|
||||
["browser_bfcache_telemetry.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_broadcast.js"]
|
||||
https_first_disabled = true
|
||||
|
||||
["browser_capabilities.js"]
|
||||
|
||||
["browser_cleaner.js"]
|
||||
|
||||
["browser_closedId.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_closed_objects_changed_notifications_tabs.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_closed_objects_changed_notifications_windows.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_closed_tabs_closed_windows.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_closed_tabs_windows.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_cookies.js"]
|
||||
|
||||
["browser_cookies_legacy.js"]
|
||||
|
||||
["browser_cookies_partitioned.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_cookies_privacy.js"]
|
||||
|
||||
["browser_cookies_sameSite.js"]
|
||||
|
||||
["browser_crashedTabs.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
https_first_disabled = true
|
||||
run-if = [
|
||||
"crashreporter",
|
||||
]
|
||||
|
||||
["browser_csp_policy_container_migration.js"]
|
||||
|
||||
["browser_docshell_uuid_consistency.js"]
|
||||
|
||||
["browser_duplicate_history.js"]
|
||||
|
||||
["browser_duplicate_tab_in_new_window.js"]
|
||||
|
||||
["browser_dying_cache.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_dynamic_frames.js"]
|
||||
|
||||
["browser_firefoxView_restore.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_firefoxView_selected_restore.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_focus_after_restore.js"]
|
||||
tags = "os_integration"
|
||||
|
||||
["browser_forget_async_closings.js"]
|
||||
|
||||
["browser_forget_closed_tab_window_byId.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
https_first_disabled = true
|
||||
|
||||
["browser_formdata.js"]
|
||||
|
||||
["browser_formdata_cc.js"]
|
||||
skip-if = [
|
||||
"asan", # test runs too long
|
||||
]
|
||||
|
||||
["browser_formdata_face.js"]
|
||||
|
||||
["browser_formdata_format.js"]
|
||||
|
||||
["browser_formdata_max_size.js"]
|
||||
|
||||
["browser_formdata_password.js"]
|
||||
support-files = ["file_formdata_password.html"]
|
||||
|
||||
["browser_formdata_xpath.js"]
|
||||
|
||||
["browser_frame_history.js"]
|
||||
|
||||
["browser_frametree.js"]
|
||||
https_first_disabled = true
|
||||
|
||||
["browser_global_store.js"]
|
||||
|
||||
["browser_history_persist.js"]
|
||||
|
||||
["browser_ignore_updates_crashed_tabs.js"]
|
||||
https_first_disabled = true
|
||||
run-if = [
|
||||
"crashreporter",
|
||||
]
|
||||
skip-if = [
|
||||
"asan",
|
||||
]
|
||||
|
||||
["browser_label_and_icon.js"]
|
||||
https_first_disabled = true
|
||||
skip-if = [
|
||||
"os == 'mac' && os_version == '10.15' && arch == 'x86_64' && opt", # Bug 1638958
|
||||
"os == 'mac' && os_version == '14.70' && arch == 'x86_64' && opt && socketprocess_networking", # Bug 1868915
|
||||
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
|
||||
"os == 'win' && os_version == '11.26100' && arch == 'x86_64' && opt", # Bug 1775605
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86_64' && opt", # Bug 1775605
|
||||
]
|
||||
|
||||
["browser_movePendingTabToNewWindow.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
https_first_disabled = true
|
||||
tags = "os_integration"
|
||||
|
||||
["browser_multiple_navigateAndRestore.js"]
|
||||
|
||||
["browser_multiple_select_after_load.js"]
|
||||
|
||||
["browser_navigation_api_restore.js"]
|
||||
support-files = [
|
||||
"empty_frame.html",
|
||||
"entry1.html",
|
||||
"entry2.html",
|
||||
"entry3.html",
|
||||
]
|
||||
|
||||
["browser_newtab_userTypedValue.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_not_collect_when_idle.js"]
|
||||
|
||||
["browser_page_title.js"]
|
||||
|
||||
["browser_parentProcessRestoreHash.js"]
|
||||
https_first_disabled = true
|
||||
tags = "openUILinkIn"
|
||||
|
||||
["browser_pending_tabs.js"]
|
||||
|
||||
["browser_pinned_tabs.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
skip-if = [
|
||||
"ccov", # Bug 1625525
|
||||
]
|
||||
|
||||
["browser_policy_container_not_stored.js"]
|
||||
|
||||
["browser_privatetabs.js"]
|
||||
|
||||
["browser_purge_domaindata.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_purge_shistory.js"]
|
||||
|
||||
["browser_remoteness_flip_on_restore.js"]
|
||||
|
||||
["browser_reopen_all_windows.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
https_first_disabled = true
|
||||
skip-if = [
|
||||
"asan", # high memory
|
||||
]
|
||||
tags = "os_integration"
|
||||
|
||||
["browser_replace_load.js"]
|
||||
skip-if = [
|
||||
"true", # Bug 1646894
|
||||
]
|
||||
|
||||
["browser_restoreLastActionCorrectOrder.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_restoreLastClosedTabOrWindowOrSession.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_restoreTabContainer.js"]
|
||||
|
||||
["browser_restore_container_tabs_oa.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_restore_cookies_noOriginAttributes.js"]
|
||||
|
||||
["browser_restore_pageProxyState.js"]
|
||||
|
||||
["browser_restore_private_tab_os.js"]
|
||||
|
||||
["browser_restore_redirect.js"]
|
||||
https_first_disabled = true
|
||||
|
||||
["browser_restore_reversed_z_order.js"]
|
||||
skip-if = [
|
||||
"true", # Bug 1455602
|
||||
]
|
||||
|
||||
["browser_restore_srcdoc.js"]
|
||||
|
||||
["browser_restore_tabless_window.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_restore_verticalPinnedTabs.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_restored_window_features.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
skip-if = [
|
||||
"os == 'win' && os_version == '11.26200' && asan", # Bug 2019745
|
||||
]
|
||||
|
||||
["browser_revive_crashed_bg_tabs.js"]
|
||||
https_first_disabled = true
|
||||
run-if = [
|
||||
"crashreporter",
|
||||
]
|
||||
|
||||
["browser_scrollPositions.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
https_first_disabled = true
|
||||
run-if = [
|
||||
"fission",
|
||||
]
|
||||
|
||||
["browser_scrollPositionsReaderMode.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_searchModeSwitcher_restore.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_sessionHistory.js"]
|
||||
https_first_disabled = true
|
||||
support-files = ["file_sessionHistory_hashchange.html"]
|
||||
|
||||
["browser_sessionHistory_partitionedPrincipalToInherit.js"]
|
||||
|
||||
["browser_sessionStorage.js"]
|
||||
tags = "os_integration"
|
||||
|
||||
["browser_sessionStorage_size.js"]
|
||||
|
||||
["browser_sessionStoreContainer.js"]
|
||||
|
||||
["browser_should_restore_tab.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && debug && socketprocess_networking", # Bug 1848488
|
||||
"os == 'win' && os_version == '11.26100' && arch == 'x86' && debug && verify-standalone",
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86' && debug && verify-standalone",
|
||||
"os == 'win' && os_version == '11.26100' && arch == 'x86_64' && debug", # Bug 1848488
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86_64' && debug", # Bug 1848488
|
||||
]
|
||||
|
||||
["browser_sizemodeBeforeMinimized.js"]
|
||||
skip-if = [
|
||||
"os == 'win' && os_version == '11.26200' && asan", # Bug 2019745
|
||||
]
|
||||
|
||||
["browser_speculative_connect.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_splitview_integer_ids.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_splitview_restore_in_closed_window.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_splitview_string_migration.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_swapDocShells.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_switch_remoteness.js"]
|
||||
|
||||
["browser_tab_groups_closed.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && debug && socketprocess_networking", # Bug 1934803
|
||||
"os == 'win' && os_version == '11.26100' && arch == 'x86_64' && debug", # Bug 1934803
|
||||
"os == 'win' && os_version == '11.26200' && arch == 'x86_64' && debug", # Bug 1934803
|
||||
]
|
||||
|
||||
["browser_tab_groups_closed_groups_in_closed_windows.js"]
|
||||
|
||||
["browser_tab_groups_empty.js"]
|
||||
|
||||
["browser_tab_groups_restore_closed_in_closed_window.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_tab_groups_restore_closed_in_open_window.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_tab_groups_restore_closed_many_tabs.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
skip-if = [
|
||||
"os == 'mac' && os_version == '15.30' && arch == 'aarch64' && opt", # Bug 1954300
|
||||
]
|
||||
|
||||
["browser_tab_groups_restore_multiple.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_tab_groups_restore_saved.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_tab_groups_restore_simple.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_tab_groups_restore_to_group.js"]
|
||||
|
||||
["browser_tab_groups_save_on_removeAllTabsBut.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_tab_groups_save_on_removeTabsToTheEnd.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_tab_groups_save_on_removeTabsToTheStart.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_tab_groups_save_on_window_close.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_tab_groups_saved.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && opt", # Bug 1945957
|
||||
]
|
||||
|
||||
["browser_tab_groups_state.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_tab_groups_undo.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
skip-if = [
|
||||
"os == 'mac' && os_version == '15.30' && arch == 'aarch64'", # Bug 2023967
|
||||
]
|
||||
["browser_tab_label_during_restore.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
https_first_disabled = true
|
||||
|
||||
["browser_tab_notes_canonicalurl.js"]
|
||||
|
||||
["browser_tabicon_after_bg_tab_crash.js"]
|
||||
run-if = [
|
||||
"crashreporter",
|
||||
]
|
||||
|
||||
["browser_tabs_in_urlbar.js"]
|
||||
https_first_disabled = true
|
||||
|
||||
["browser_undoCloseById.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
skip-if = [
|
||||
"debug",
|
||||
]
|
||||
|
||||
["browser_undoCloseById_targetWindow.js"]
|
||||
|
||||
["browser_unrestored_crashedTabs.js"]
|
||||
run-if = [
|
||||
"crashreporter",
|
||||
]
|
||||
|
||||
["browser_upgrade_backup.js"]
|
||||
skip-if = [
|
||||
"asan",
|
||||
"tsan",
|
||||
]
|
||||
|
||||
["browser_urlbarSearchMode.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_userTyped_restored_after_discard.js"]
|
||||
|
||||
["browser_windowRestore_perwindowpb.js"]
|
||||
|
||||
["browser_windowStateContainer.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
|
||||
["browser_wireframe_basic.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
22
src/zen/tests/mochitests/sessionstore/browser_1234021.js
Normal file
22
src/zen/tests/mochitests/sessionstore/browser_1234021.js
Normal file
@@ -0,0 +1,22 @@
|
||||
"use strict";
|
||||
|
||||
const PREF = "network.cookie.cookieBehavior";
|
||||
const PAGE_URL =
|
||||
"http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_1234021_page.html";
|
||||
const BEHAVIOR_REJECT = 2;
|
||||
|
||||
add_task(async function test() {
|
||||
await pushPrefs([PREF, BEHAVIOR_REJECT]);
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: PAGE_URL,
|
||||
},
|
||||
async function handler(aBrowser) {
|
||||
await TabStateFlusher.flush(aBrowser);
|
||||
ok(true, "Flush didn't time out");
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<script>
|
||||
sessionStorage;
|
||||
</script>
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
window.onbeforeunload = function() {
|
||||
return true;
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
TEST PAGE
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,95 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function test() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.require_user_interaction_for_beforeunload", false]],
|
||||
});
|
||||
|
||||
let url = "about:robots";
|
||||
let tab0 = gBrowser.tabs[0];
|
||||
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
|
||||
const staleAttributes = [
|
||||
"activemedia-blocked",
|
||||
"busy",
|
||||
"pendingicon",
|
||||
"progress",
|
||||
"soundplaying",
|
||||
];
|
||||
for (let attr of staleAttributes) {
|
||||
tab0.toggleAttribute(attr, true);
|
||||
}
|
||||
gBrowser.discardBrowser(tab0);
|
||||
ok(!tab0.linkedPanel, "tab0 is suspended");
|
||||
for (let attr of staleAttributes) {
|
||||
ok(
|
||||
!tab0.hasAttribute(attr),
|
||||
`discarding browser removes "${attr}" tab attribute`
|
||||
);
|
||||
}
|
||||
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab0);
|
||||
ok(tab0.linkedPanel, "selecting tab unsuspends it");
|
||||
|
||||
// Test that active tab is not able to be suspended.
|
||||
gBrowser.discardBrowser(tab0);
|
||||
ok(tab0.linkedPanel, "active tab is not able to be suspended");
|
||||
|
||||
// Test that tab that is closing is not able to be suspended.
|
||||
gBrowser._beginRemoveTab(tab1);
|
||||
gBrowser.discardBrowser(tab1);
|
||||
|
||||
ok(tab1.linkedPanel, "cannot suspend a tab that is closing");
|
||||
|
||||
gBrowser._endRemoveTab(tab1);
|
||||
|
||||
// Open tab containing a page which has a beforeunload handler which shows a prompt.
|
||||
url =
|
||||
"http://example.com/browser/browser/components/sessionstore/test/browser_1284886_suspend_tab.html";
|
||||
tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab0);
|
||||
|
||||
// Test that tab with beforeunload handler which would show a prompt cannot be suspended.
|
||||
gBrowser.discardBrowser(tab1);
|
||||
ok(
|
||||
tab1.linkedPanel,
|
||||
"cannot suspend a tab with beforeunload handler which would show a prompt"
|
||||
);
|
||||
|
||||
// Test that tab with beforeunload handler which would show a prompt will be suspended if forced.
|
||||
gBrowser.discardBrowser(tab1, true);
|
||||
ok(
|
||||
!tab1.linkedPanel,
|
||||
"force suspending a tab with beforeunload handler which would show a prompt"
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(tab1);
|
||||
|
||||
// Open tab containing a page which has a beforeunload handler which does not show a prompt.
|
||||
url =
|
||||
"http://example.com/browser/browser/components/sessionstore/test/browser_1284886_suspend_tab_2.html";
|
||||
tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab0);
|
||||
|
||||
// Test that tab with beforeunload handler which would not show a prompt can be suspended.
|
||||
gBrowser.discardBrowser(tab1);
|
||||
ok(
|
||||
!tab1.linkedPanel,
|
||||
"can suspend a tab with beforeunload handler which would not show a prompt"
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(tab1);
|
||||
|
||||
// Test that non-remote tab is not able to be suspended.
|
||||
url = "about:robots";
|
||||
tab1 = BrowserTestUtils.addTab(gBrowser, url, { forceNotRemote: true });
|
||||
await promiseBrowserLoaded(tab1.linkedBrowser, true, url);
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab1);
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab0);
|
||||
|
||||
gBrowser.discardBrowser(tab1);
|
||||
ok(tab1.linkedPanel, "cannot suspend a remote tab");
|
||||
|
||||
BrowserTestUtils.removeTab(tab1);
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
window.onbeforeunload = function() {
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
TEST PAGE
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,39 @@
|
||||
add_task(async function test() {
|
||||
const win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
async function changeSizeMode(mode) {
|
||||
let promise = BrowserTestUtils.waitForEvent(win, "sizemodechange");
|
||||
win[mode]();
|
||||
await promise;
|
||||
}
|
||||
if (win.windowState != win.STATE_NORMAL) {
|
||||
await changeSizeMode("restore");
|
||||
}
|
||||
|
||||
const { outerWidth, outerHeight, screenX, screenY } = win;
|
||||
function checkCurrentState(sizemode) {
|
||||
let state = ss.getWindowState(win);
|
||||
let winState = state.windows[0];
|
||||
let msgSuffix = ` should match on ${sizemode} mode`;
|
||||
is(winState.width, outerWidth, "width" + msgSuffix);
|
||||
is(winState.height, outerHeight, "height" + msgSuffix);
|
||||
// The position attributes seem to be affected on macOS when the
|
||||
// window gets maximized, so skip checking them for now.
|
||||
if (AppConstants.platform != "macosx" || sizemode == "normal") {
|
||||
is(winState.screenX, screenX, "screenX" + msgSuffix);
|
||||
is(winState.screenY, screenY, "screenY" + msgSuffix);
|
||||
}
|
||||
is(winState.sizemode, sizemode, "sizemode should match");
|
||||
}
|
||||
|
||||
checkCurrentState("normal");
|
||||
|
||||
await changeSizeMode("maximize");
|
||||
checkCurrentState("maximized");
|
||||
|
||||
await changeSizeMode("minimize");
|
||||
checkCurrentState("minimized");
|
||||
|
||||
// Clean up.
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
"use strict";
|
||||
|
||||
const ORIG_STATE = SessionStore.getBrowserState();
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
await SessionStoreTestUtils.promiseBrowserState(ORIG_STATE);
|
||||
});
|
||||
|
||||
// This test ensures that closed tab groups are immediately stored in the
|
||||
// closedGroups array, even if their history was not stored in the tab state at
|
||||
// the time the tab group was closed.
|
||||
add_task(
|
||||
async function test_browser_1933485_tabGroupImmediatelyStoredInClosedGroups() {
|
||||
let win = await promiseNewWindowLoaded();
|
||||
|
||||
const urls = ["about:blank", "about:robots", "https://www.example.com/"];
|
||||
const tabs = urls.map(url => BrowserTestUtils.addTab(win.gBrowser, url));
|
||||
await Promise.all(
|
||||
tabs.map((t, i) =>
|
||||
BrowserTestUtils.browserLoaded(t.linkedBrowser, { wantLoad: urls[i] })
|
||||
)
|
||||
);
|
||||
|
||||
const tabGroup = win.gBrowser.addTabGroup(tabs);
|
||||
|
||||
let removePromise = BrowserTestUtils.waitForEvent(
|
||||
tabGroup,
|
||||
"TabGroupRemoved"
|
||||
);
|
||||
win.gBrowser.removeTabGroup(tabGroup);
|
||||
await removePromise;
|
||||
|
||||
const closedGroupState = SessionStore.getClosedTabGroups(win);
|
||||
|
||||
Assert.equal(
|
||||
closedGroupState.length,
|
||||
1,
|
||||
"Tab group is stored in closedGroups"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,55 @@
|
||||
"use strict";
|
||||
|
||||
const ORIG_STATE = SessionStore.getBrowserState();
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
await SessionStoreTestUtils.promiseBrowserState(ORIG_STATE);
|
||||
});
|
||||
|
||||
add_task(
|
||||
async function test_browser_1953801_tabGroupImmediatelyStoredInSavedGroupsOnCloseOtherTabs() {
|
||||
let savedGroupState;
|
||||
let win = await promiseNewWindowLoaded();
|
||||
|
||||
savedGroupState = SessionStore.getSavedTabGroups(win);
|
||||
Assert.equal(
|
||||
savedGroupState.length,
|
||||
0,
|
||||
"Should start with no saved groups"
|
||||
);
|
||||
|
||||
const tabs = [
|
||||
BrowserTestUtils.addTab(win.gBrowser, "about:robots"),
|
||||
BrowserTestUtils.addTab(win.gBrowser, "about:robots"),
|
||||
BrowserTestUtils.addTab(win.gBrowser, "https://www.example.com"),
|
||||
];
|
||||
await Promise.all(tabs.map(t => promiseBrowserLoaded(t.linkedBrowser)));
|
||||
|
||||
const tabGroup = win.gBrowser.addTabGroup([tabs[1], tabs[2]], {
|
||||
label: "group-to-save",
|
||||
});
|
||||
|
||||
await TestUtils.waitForCondition(
|
||||
() => SessionStore.getWindowState(win).windows[0].groups.length == 1,
|
||||
"Waiting for group to appear in session store"
|
||||
);
|
||||
|
||||
let removePromise = BrowserTestUtils.waitForEvent(
|
||||
tabGroup,
|
||||
"TabGroupRemoved"
|
||||
);
|
||||
win.gBrowser.removeAllTabsBut(win.gBrowser.tabs[0]);
|
||||
await removePromise;
|
||||
|
||||
savedGroupState = SessionStore.getSavedTabGroups(win);
|
||||
Assert.equal(
|
||||
savedGroupState.length,
|
||||
1,
|
||||
"Tab group is stored in saved groups"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
forgetClosedWindows();
|
||||
SessionStore.forgetSavedTabGroup(tabGroup.id);
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,199 @@
|
||||
/* 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() {
|
||||
/** Test (B) for Bug 248970 */
|
||||
waitForExplicitFinish();
|
||||
|
||||
let windowsToClose = [];
|
||||
let file = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
let filePath = file.path;
|
||||
let fieldList = {
|
||||
"//input[@name='input']": Date.now().toString(16),
|
||||
"//input[@name='spaced 1']": Math.random().toString(),
|
||||
"//input[3]": "three",
|
||||
"//input[@type='checkbox']": true,
|
||||
"//input[@name='uncheck']": false,
|
||||
"//input[@type='radio'][1]": false,
|
||||
"//input[@type='radio'][2]": true,
|
||||
"//input[@type='radio'][3]": false,
|
||||
"//select": 2,
|
||||
"//select[@multiple]": [1, 3],
|
||||
"//textarea[1]": "",
|
||||
"//textarea[2]": "Some text... " + Math.random(),
|
||||
"//textarea[3]": "Some more text\n" + new Date(),
|
||||
"//input[@type='file']": filePath,
|
||||
};
|
||||
|
||||
registerCleanupFunction(async function () {
|
||||
for (let win of windowsToClose) {
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
}
|
||||
});
|
||||
|
||||
function checkNoThrow(aLambda) {
|
||||
try {
|
||||
return aLambda() || true;
|
||||
} catch (ex) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getElementByXPath(aTab, aQuery) {
|
||||
let doc = aTab.linkedBrowser.contentDocument;
|
||||
let xptype = doc.defaultView.XPathResult.FIRST_ORDERED_NODE_TYPE;
|
||||
return doc.evaluate(aQuery, doc, null, xptype, null).singleNodeValue;
|
||||
}
|
||||
|
||||
function setFormValue(aTab, aQuery, aValue) {
|
||||
let node = getElementByXPath(aTab, aQuery);
|
||||
if (typeof aValue == "string") {
|
||||
node.value = aValue;
|
||||
} else if (typeof aValue == "boolean") {
|
||||
node.checked = aValue;
|
||||
} else if (typeof aValue == "number") {
|
||||
node.selectedIndex = aValue;
|
||||
} else {
|
||||
Array.prototype.forEach.call(
|
||||
node.options,
|
||||
(aOpt, aIx) => (aOpt.selected = aValue.indexOf(aIx) > -1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function compareFormValue(aTab, aQuery, aValue) {
|
||||
let node = getElementByXPath(aTab, aQuery);
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
if (ChromeUtils.getClassName(node) === "HTMLInputElement") {
|
||||
return (
|
||||
aValue ==
|
||||
(node.type == "checkbox" || node.type == "radio"
|
||||
? node.checked
|
||||
: node.value)
|
||||
);
|
||||
}
|
||||
if (ChromeUtils.getClassName(node) === "HTMLTextAreaElement") {
|
||||
return aValue == node.value;
|
||||
}
|
||||
if (!node.multiple) {
|
||||
return aValue == node.selectedIndex;
|
||||
}
|
||||
return Array.prototype.every.call(
|
||||
node.options,
|
||||
(aOpt, aIx) => aValue.indexOf(aIx) > -1 == aOpt.selected
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test (B) : Session data restoration between windows
|
||||
*/
|
||||
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
const testURL = rootDir + "browser_248970_b_sample.html";
|
||||
const testURL2 =
|
||||
"http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_248970_b_sample.html";
|
||||
|
||||
whenNewWindowLoaded({ private: false }, function (aWin) {
|
||||
windowsToClose.push(aWin);
|
||||
|
||||
// get closed tab count
|
||||
let count = ss.getClosedTabCountForWindow(aWin);
|
||||
let max_tabs_undo = Services.prefs.getIntPref(
|
||||
"browser.sessionstore.max_tabs_undo"
|
||||
);
|
||||
ok(
|
||||
0 <= count && count <= max_tabs_undo,
|
||||
"getClosedTabCountForWindow should return zero or at most max_tabs_undo"
|
||||
);
|
||||
|
||||
// setup a state for tab (A) so we can check later that is restored
|
||||
let value = "Value " + Math.random();
|
||||
let state = { entries: [{ url: testURL }], extData: { key: value } };
|
||||
|
||||
// public session, add new tab: (A)
|
||||
let tab_A = BrowserTestUtils.addTab(aWin.gBrowser, testURL);
|
||||
ss.setTabState(tab_A, JSON.stringify(state));
|
||||
promiseBrowserLoaded(tab_A.linkedBrowser).then(() => {
|
||||
// make sure that the next closed tab will increase getClosedTabCountForWindow
|
||||
Services.prefs.setIntPref(
|
||||
"browser.sessionstore.max_tabs_undo",
|
||||
max_tabs_undo + 1
|
||||
);
|
||||
|
||||
// populate tab_A with form data
|
||||
for (let i in fieldList) {
|
||||
setFormValue(tab_A, i, fieldList[i]);
|
||||
}
|
||||
|
||||
// public session, close tab: (A)
|
||||
aWin.gBrowser.removeTab(tab_A);
|
||||
|
||||
// verify that closedTabCount increased
|
||||
Assert.greater(
|
||||
ss.getClosedTabCountForWindow(aWin),
|
||||
count,
|
||||
"getClosedTabCountForWindow has increased after closing a tab"
|
||||
);
|
||||
|
||||
// verify tab: (A), in undo list
|
||||
let tab_A_restored = checkNoThrow(() => ss.undoCloseTab(aWin, 0));
|
||||
ok(tab_A_restored, "a tab is in undo list");
|
||||
promiseTabRestored(tab_A_restored).then(() => {
|
||||
is(
|
||||
testURL,
|
||||
tab_A_restored.linkedBrowser.currentURI.spec,
|
||||
"it's the same tab that we expect"
|
||||
);
|
||||
aWin.gBrowser.removeTab(tab_A_restored);
|
||||
|
||||
whenNewWindowLoaded({ private: true }, function (win) {
|
||||
windowsToClose.push(win);
|
||||
|
||||
// setup a state for tab (B) so we can check that its duplicated
|
||||
// properly
|
||||
let key1 = "key1";
|
||||
let value1 = "Value " + Math.random();
|
||||
let state1 = {
|
||||
entries: [{ url: testURL2 }],
|
||||
extData: { key1: value1 },
|
||||
};
|
||||
|
||||
let tab_B = BrowserTestUtils.addTab(win.gBrowser, testURL2);
|
||||
promiseTabState(tab_B, state1).then(() => {
|
||||
// populate tab: (B) with different form data
|
||||
for (let item in fieldList) {
|
||||
setFormValue(tab_B, item, fieldList[item]);
|
||||
}
|
||||
|
||||
// duplicate tab: (B)
|
||||
let tab_C = win.gBrowser.duplicateTab(tab_B);
|
||||
promiseTabRestored(tab_C).then(() => {
|
||||
// verify the correctness of the duplicated tab
|
||||
is(
|
||||
ss.getCustomTabValue(tab_C, key1),
|
||||
value1,
|
||||
"tab successfully duplicated - correct state"
|
||||
);
|
||||
|
||||
for (let item in fieldList) {
|
||||
ok(
|
||||
compareFormValue(tab_C, item, fieldList[item]),
|
||||
'The value for "' + item + '" was correctly duplicated'
|
||||
);
|
||||
}
|
||||
|
||||
// private browsing session, close tab: (C) and (B)
|
||||
win.gBrowser.removeTab(tab_C);
|
||||
win.gBrowser.removeTab(tab_B);
|
||||
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
<meta charset="utf-8">
|
||||
<title>Test for bug 248970</title>
|
||||
|
||||
<h3>Text Fields</h3>
|
||||
<input type="text" name="input">
|
||||
<input type="text" name="spaced 1">
|
||||
<input>
|
||||
|
||||
<h3>Checkboxes and Radio buttons</h3>
|
||||
<input type="checkbox" name="check"> Check 1
|
||||
<input type="checkbox" name="uncheck" checked> Check 2
|
||||
<p>
|
||||
<input type="radio" name="group" value="1"> Radio 1
|
||||
<input type="radio" name="group" value="some"> Radio 2
|
||||
<input type="radio" name="group" checked> Radio 3
|
||||
|
||||
<h3>Selects</h3>
|
||||
<select name="any">
|
||||
<option value="1"> Select 1
|
||||
<option value="some"> Select 2
|
||||
<option>Select 3
|
||||
</select>
|
||||
<select multiple="multiple">
|
||||
<option value=1> Multi-select 1
|
||||
<option value=2> Multi-select 2
|
||||
<option value=3> Multi-select 3
|
||||
<option value=4> Multi-select 4
|
||||
</select>
|
||||
|
||||
<h3>Text Areas</h3>
|
||||
<textarea name="testarea"></textarea>
|
||||
<textarea name="sized one" rows="5" cols="25"></textarea>
|
||||
<textarea></textarea>
|
||||
|
||||
<h3>File Selector</h3>
|
||||
<input type="file">
|
||||
39
src/zen/tests/mochitests/sessionstore/browser_339445.js
Normal file
39
src/zen/tests/mochitests/sessionstore/browser_339445.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
add_task(async function test() {
|
||||
/** Test for Bug 339445 */
|
||||
|
||||
let testURL =
|
||||
"http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_339445_sample.html";
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, testURL);
|
||||
await promiseBrowserLoaded(tab.linkedBrowser, true, testURL);
|
||||
|
||||
await SpecialPowers.spawn(tab.linkedBrowser, [], function () {
|
||||
let doc = content.document;
|
||||
is(
|
||||
doc.getElementById("storageTestItem").textContent,
|
||||
"PENDING",
|
||||
"sessionStorage value has been set"
|
||||
);
|
||||
});
|
||||
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
await promiseTabRestored(tab2);
|
||||
|
||||
await SpecialPowers.spawn(tab2.linkedBrowser, [], function () {
|
||||
let doc2 = content.document;
|
||||
is(
|
||||
doc2.getElementById("storageTestItem").textContent,
|
||||
"SUCCESS",
|
||||
"sessionStorage value has been duplicated"
|
||||
);
|
||||
});
|
||||
|
||||
// clean up
|
||||
BrowserTestUtils.removeTab(tab2);
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
<meta charset="utf-8">
|
||||
<title>Test for bug 339445</title>
|
||||
|
||||
storageTestItem = <span id="storageTestItem">FAIL</span>
|
||||
|
||||
<!--
|
||||
storageTestItem's textContent will be one of the following:
|
||||
* FAIL : sessionStorage wasn't available
|
||||
* PENDING : the test value has been initialized on first load
|
||||
* SUCCESS : the test value was correctly retrieved
|
||||
-->
|
||||
|
||||
<script type="application/javascript">
|
||||
document.getElementById("storageTestItem").textContent =
|
||||
sessionStorage.storageTestItem || "PENDING";
|
||||
sessionStorage.storageTestItem = "SUCCESS";
|
||||
</script>
|
||||
69
src/zen/tests/mochitests/sessionstore/browser_345898.js
Normal file
69
src/zen/tests/mochitests/sessionstore/browser_345898.js
Normal file
@@ -0,0 +1,69 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 345898 */
|
||||
|
||||
// all of the following calls with illegal arguments should throw NS_ERROR_ILLEGAL_VALUE
|
||||
Assert.throws(
|
||||
() => ss.getWindowState({}),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid window for getWindowState throws"
|
||||
);
|
||||
Assert.throws(
|
||||
() => ss.setWindowState({}, "", false),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid window for setWindowState throws"
|
||||
);
|
||||
Assert.throws(
|
||||
() => ss.getTabState({}),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid tab for getTabState throws"
|
||||
);
|
||||
Assert.throws(
|
||||
() => ss.setTabState({}, "{}"),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid tab state for setTabState throws"
|
||||
);
|
||||
Assert.throws(
|
||||
() => ss.setTabState({}, JSON.stringify({ entries: [] })),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid tab for setTabState throws"
|
||||
);
|
||||
Assert.throws(
|
||||
() => ss.duplicateTab({}, {}),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid tab for duplicateTab throws"
|
||||
);
|
||||
Assert.throws(
|
||||
() => ss.duplicateTab({}, gBrowser.selectedTab),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid window for duplicateTab throws"
|
||||
);
|
||||
Assert.throws(
|
||||
() => ss.getClosedTabDataForWindow({}),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid window for getClosedTabData throws"
|
||||
);
|
||||
Assert.throws(
|
||||
() => ss.undoCloseTab({}, 0),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid window for undoCloseTab throws"
|
||||
);
|
||||
Assert.throws(
|
||||
() => ss.undoCloseTab(window, -1),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid index for undoCloseTab throws"
|
||||
);
|
||||
Assert.throws(
|
||||
() => ss.getCustomWindowValue({}, ""),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid window for getCustomWindowValue throws"
|
||||
);
|
||||
Assert.throws(
|
||||
() => ss.setCustomWindowValue({}, "", ""),
|
||||
/NS_ERROR_ILLEGAL_VALUE/,
|
||||
"Invalid window for setCustomWindowValue throws"
|
||||
);
|
||||
}
|
||||
136
src/zen/tests/mochitests/sessionstore/browser_350525.js
Normal file
136
src/zen/tests/mochitests/sessionstore/browser_350525.js
Normal file
@@ -0,0 +1,136 @@
|
||||
"use strict";
|
||||
|
||||
add_setup(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.ipc.processCount", 1]],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function () {
|
||||
/** Test for Bug 350525 */
|
||||
|
||||
function test(aLambda) {
|
||||
try {
|
||||
return aLambda() || true;
|
||||
} catch (ex) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* setCustomWindowValue, et al.
|
||||
*/
|
||||
let key = "Unique name: " + Date.now();
|
||||
let value = "Unique value: " + Math.random();
|
||||
|
||||
// test adding
|
||||
ok(
|
||||
test(() => ss.setCustomWindowValue(window, key, value)),
|
||||
"set a window value"
|
||||
);
|
||||
|
||||
// test retrieving
|
||||
is(
|
||||
ss.getCustomWindowValue(window, key),
|
||||
value,
|
||||
"stored window value matches original"
|
||||
);
|
||||
|
||||
// test deleting
|
||||
ok(
|
||||
test(() => ss.deleteCustomWindowValue(window, key)),
|
||||
"delete the window value"
|
||||
);
|
||||
|
||||
// value should not exist post-delete
|
||||
is(ss.getCustomWindowValue(window, key), "", "window value was deleted");
|
||||
|
||||
// test deleting a non-existent value
|
||||
ok(
|
||||
test(() => ss.deleteCustomWindowValue(window, key)),
|
||||
"delete non-existent window value"
|
||||
);
|
||||
|
||||
/**
|
||||
* setCustomTabValue, et al.
|
||||
*/
|
||||
key = "Unique name: " + Math.random();
|
||||
value = "Unique value: " + Date.now();
|
||||
let tab = BrowserTestUtils.addTab(gBrowser);
|
||||
tab.linkedBrowser.stop();
|
||||
|
||||
// test adding
|
||||
ok(
|
||||
test(() => ss.setCustomTabValue(tab, key, value)),
|
||||
"store a tab value"
|
||||
);
|
||||
|
||||
// test retrieving
|
||||
is(ss.getCustomTabValue(tab, key), value, "stored tab value match original");
|
||||
|
||||
// test deleting
|
||||
ok(
|
||||
test(() => ss.deleteCustomTabValue(tab, key)),
|
||||
"delete the tab value"
|
||||
);
|
||||
|
||||
// value should not exist post-delete
|
||||
is(ss.getCustomTabValue(tab, key), "", "tab value was deleted");
|
||||
|
||||
// test deleting a non-existent value
|
||||
ok(
|
||||
test(() => ss.deleteCustomTabValue(tab, key)),
|
||||
"delete non-existent tab value"
|
||||
);
|
||||
|
||||
// clean up
|
||||
await promiseRemoveTabAndSessionState(tab);
|
||||
|
||||
/**
|
||||
* getClosedTabCountForWindow, undoCloseTab
|
||||
*/
|
||||
|
||||
// get closed tab count
|
||||
let count = ss.getClosedTabCountForWindow(window);
|
||||
let max_tabs_undo = Services.prefs.getIntPref(
|
||||
"browser.sessionstore.max_tabs_undo"
|
||||
);
|
||||
ok(
|
||||
0 <= count && count <= max_tabs_undo,
|
||||
"getClosedTabCountForWindow returns zero or at most max_tabs_undo"
|
||||
);
|
||||
|
||||
// create a new tab
|
||||
let testURL = "about:mozilla";
|
||||
tab = BrowserTestUtils.addTab(gBrowser, testURL);
|
||||
await promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
// make sure that the next closed tab will increase getClosedTabCountForWindow
|
||||
Services.prefs.setIntPref(
|
||||
"browser.sessionstore.max_tabs_undo",
|
||||
max_tabs_undo + 1
|
||||
);
|
||||
registerCleanupFunction(() =>
|
||||
Services.prefs.clearUserPref("browser.sessionstore.max_tabs_undo")
|
||||
);
|
||||
|
||||
// remove tab
|
||||
await promiseRemoveTabAndSessionState(tab);
|
||||
|
||||
// getClosedTabCountForWindow
|
||||
let newcount = ss.getClosedTabCountForWindow(window);
|
||||
Assert.greater(
|
||||
newcount,
|
||||
count,
|
||||
"after closing a tab, getClosedTabCountForWindow has been incremented"
|
||||
);
|
||||
|
||||
// undoCloseTab
|
||||
tab = test(() => ss.undoCloseTab(window, 0));
|
||||
ok(tab, "undoCloseTab doesn't throw");
|
||||
|
||||
await promiseTabRestored(tab);
|
||||
is(tab.linkedBrowser.currentURI.spec, testURL, "correct tab was reopened");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
@@ -0,0 +1,490 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Checks that restoring the last browser window in session is actually
|
||||
* working.
|
||||
*
|
||||
* @see https://bugzilla.mozilla.org/show_bug.cgi?id=354894
|
||||
* Note: It is implicitly tested that restoring the last window works when
|
||||
* non-browser windows are around. The "Run Tests" window as well as the main
|
||||
* browser window (wherein the test code gets executed) won't be considered
|
||||
* browser windows. To achiveve this said main browser window has its windowtype
|
||||
* attribute modified so that it's not considered a browser window any longer.
|
||||
* This is crucial, because otherwise there would be two browser windows around,
|
||||
* said main test window and the one opened by the tests, and hence the new
|
||||
* logic wouldn't be executed at all.
|
||||
* Note: Mac only tests the new notifications, as restoring the last window is
|
||||
* not enabled on that platform (platform shim; the application is kept running
|
||||
* although there are no windows left)
|
||||
* Note: There is a difference when closing a browser window with
|
||||
* BrowserCommands.tryToCloseWindow() as opposed to close(). The former will make
|
||||
* nsSessionStore restore a window next time it gets a chance and will post
|
||||
* notifications. The latter won't.
|
||||
*/
|
||||
|
||||
// The rejection "BrowserWindowTracker.getTopWindow(...) is null" is left
|
||||
// unhandled in some cases. This bug should be fixed, but for the moment this
|
||||
// file allows a class of rejections.
|
||||
//
|
||||
// NOTE: Allowing a whole class of rejections should be avoided. Normally you
|
||||
// should use "expectUncaughtRejection" to flag individual failures.
|
||||
const { PromiseTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/PromiseTestUtils.sys.mjs"
|
||||
);
|
||||
PromiseTestUtils.allowMatchingRejectionsGlobally(/getTopWindow/);
|
||||
|
||||
// Some urls that might be opened in tabs and/or popups
|
||||
// Do not use about:blank:
|
||||
// That one is reserved for special purposes in the tests
|
||||
const TEST_URLS = ["about:mozilla", "about:buildconfig"];
|
||||
|
||||
// Number of -request notifications to except
|
||||
// remember to adjust when adding new tests
|
||||
const NOTIFICATIONS_EXPECTED = 6;
|
||||
|
||||
// Window features of popup windows
|
||||
const POPUP_FEATURES = "toolbar=no,resizable=no,status=no";
|
||||
|
||||
// Window features of browser windows
|
||||
const CHROME_FEATURES = "chrome,all,dialog=no";
|
||||
|
||||
const IS_MAC = navigator.platform.match(/Mac/);
|
||||
|
||||
/**
|
||||
* Returns an Object with two properties:
|
||||
* open (int):
|
||||
* A count of how many non-closed navigator:browser windows there are.
|
||||
* winstates (int):
|
||||
* A count of how many windows there are in the SessionStore state.
|
||||
*/
|
||||
function getBrowserWindowsCount() {
|
||||
let open = 0;
|
||||
for (let win of Services.wm.getEnumerator("navigator:browser")) {
|
||||
if (!win.closed) {
|
||||
++open;
|
||||
}
|
||||
}
|
||||
|
||||
let winstates = JSON.parse(ss.getBrowserState()).windows.length;
|
||||
|
||||
return { open, winstates };
|
||||
}
|
||||
|
||||
add_setup(async function () {
|
||||
// Make sure we've only got one browser window to start with
|
||||
let { open, winstates } = getBrowserWindowsCount();
|
||||
is(open, 1, "Should only be one open window");
|
||||
is(winstates, 1, "Should only be one window state in SessionStore");
|
||||
|
||||
// This test takes some time to run, and it could timeout randomly.
|
||||
// So we require a longer timeout. See bug 528219.
|
||||
requestLongerTimeout(3);
|
||||
|
||||
// Make the main test window not count as a browser window any longer
|
||||
let oldWinType = document.documentElement.getAttribute("windowtype");
|
||||
document.documentElement.setAttribute("windowtype", "navigator:testrunner");
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
document.documentElement.setAttribute("windowtype", oldWinType);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Sets up one of our tests by setting the right preferences, and
|
||||
* then opening up a browser window preloaded with some tabs.
|
||||
*
|
||||
* @param options (Object)
|
||||
* An object that can contain the following properties:
|
||||
*
|
||||
* private:
|
||||
* Whether or not the opened window should be private.
|
||||
*
|
||||
* denyFirst:
|
||||
* Whether or not the first window that attempts to close
|
||||
* via closeWindowForRestoration should be denied.
|
||||
*
|
||||
* @param testFunction (Function*)
|
||||
* A generator function that yields Promises to be run
|
||||
* once the test has been set up.
|
||||
*
|
||||
* @returns Promise
|
||||
* Resolves once the test has been cleaned up.
|
||||
*/
|
||||
let setupTest = async function (options, testFunction) {
|
||||
await pushPrefs(
|
||||
["browser.startup.page", 3],
|
||||
["browser.tabs.warnOnClose", false]
|
||||
);
|
||||
// SessionStartup caches pref values, but as this test tries to simulate a
|
||||
// startup scenario, we'll reset them here.
|
||||
SessionStartup.resetForTest();
|
||||
|
||||
// Observe these, and also use to count the number of hits
|
||||
let observing = {
|
||||
"browser-lastwindow-close-requested": 0,
|
||||
"browser-lastwindow-close-granted": 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper: Will observe and handle the notifications for us
|
||||
*/
|
||||
let hitCount = 0;
|
||||
function observer(aCancel, aTopic) {
|
||||
// count so that we later may compare
|
||||
observing[aTopic]++;
|
||||
|
||||
// handle some tests
|
||||
if (options.denyFirst && ++hitCount == 1) {
|
||||
aCancel.QueryInterface(Ci.nsISupportsPRBool).data = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (let o in observing) {
|
||||
Services.obs.addObserver(observer, o);
|
||||
}
|
||||
|
||||
let newWin = await promiseNewWindowLoaded({
|
||||
private: options.private || false,
|
||||
});
|
||||
|
||||
await injectTestTabs(newWin);
|
||||
|
||||
await testFunction(newWin, observing);
|
||||
|
||||
let count = getBrowserWindowsCount();
|
||||
is(count.open, 0, "Got right number of open windows");
|
||||
is(count.winstates, 1, "Got right number of stored window states");
|
||||
|
||||
for (let o in observing) {
|
||||
Services.obs.removeObserver(observer, o);
|
||||
}
|
||||
|
||||
await popPrefs();
|
||||
// Act like nothing ever happened.
|
||||
SessionStartup.resetForTest();
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads a TEST_URLS into a browser window.
|
||||
*
|
||||
* @param win (Window)
|
||||
* The browser window to load the tabs in
|
||||
*/
|
||||
function injectTestTabs(win) {
|
||||
let promises = TEST_URLS.map(url =>
|
||||
BrowserTestUtils.addTab(win.gBrowser, url)
|
||||
).map(tab => BrowserTestUtils.browserLoaded(tab.linkedBrowser));
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to close a window via BrowserCommands.tryToCloseWindow so that
|
||||
* we get the browser-lastwindow-close-requested and
|
||||
* browser-lastwindow-close-granted observer notifications.
|
||||
*
|
||||
* @param win (Window)
|
||||
* The window to try to close
|
||||
* @returns Promise
|
||||
* Resolves to true if the window closed, or false if the window
|
||||
* was denied the ability to close.
|
||||
*/
|
||||
function closeWindowForRestoration(win) {
|
||||
return new Promise(resolve => {
|
||||
let closePromise = BrowserTestUtils.windowClosed(win);
|
||||
win.BrowserCommands.tryToCloseWindow();
|
||||
if (!win.closed) {
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
closePromise.then(() => {
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Normal in-session restore
|
||||
*
|
||||
* Note: Non-Mac only
|
||||
*
|
||||
* Should do the following:
|
||||
* 1. Open a new browser window
|
||||
* 2. Add some tabs
|
||||
* 3. Close that window
|
||||
* 4. Opening another window
|
||||
* 5. Checks that state is restored
|
||||
*/
|
||||
add_task(async function test_open_close_normal() {
|
||||
if (IS_MAC) {
|
||||
return;
|
||||
}
|
||||
|
||||
await setupTest({ denyFirst: true }, async function (newWin, obs) {
|
||||
let closed = await closeWindowForRestoration(newWin);
|
||||
ok(!closed, "First close request should have been denied");
|
||||
|
||||
closed = await closeWindowForRestoration(newWin);
|
||||
ok(closed, "Second close request should be accepted");
|
||||
|
||||
newWin = await promiseNewWindowLoaded();
|
||||
is(
|
||||
newWin.gBrowser.browsers.length,
|
||||
TEST_URLS.length + 2,
|
||||
"Restored window in-session with otherpopup windows around"
|
||||
);
|
||||
|
||||
// Note that this will not result in the the browser-lastwindow-close
|
||||
// notifications firing for this other newWin.
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
|
||||
// setupTest gave us a window which was denied for closing once, and then
|
||||
// closed.
|
||||
is(
|
||||
obs["browser-lastwindow-close-requested"],
|
||||
2,
|
||||
"Got expected browser-lastwindow-close-requested notifications"
|
||||
);
|
||||
is(
|
||||
obs["browser-lastwindow-close-granted"],
|
||||
1,
|
||||
"Got expected browser-lastwindow-close-granted notifications"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* PrivateBrowsing in-session restore
|
||||
*
|
||||
* Note: Non-Mac only
|
||||
*
|
||||
* Should do the following:
|
||||
* 1. Open a new browser window A
|
||||
* 2. Add some tabs
|
||||
* 3. Close the window A as the last window
|
||||
* 4. Open a private browsing window B
|
||||
* 5. Make sure that B didn't restore the tabs from A
|
||||
* 6. Close private browsing window B
|
||||
* 7. Open a new window C
|
||||
* 8. Make sure that new window C has restored tabs from A
|
||||
*/
|
||||
add_task(async function test_open_close_private_browsing() {
|
||||
if (IS_MAC) {
|
||||
return;
|
||||
}
|
||||
|
||||
await setupTest({}, async function (newWin, obs) {
|
||||
let closed = await closeWindowForRestoration(newWin);
|
||||
ok(closed, "Should be able to close the window");
|
||||
|
||||
newWin = await promiseNewWindowLoaded({ private: true });
|
||||
is(
|
||||
newWin.gBrowser.browsers.length,
|
||||
1,
|
||||
"Did not restore in private browsing mode"
|
||||
);
|
||||
|
||||
closed = await closeWindowForRestoration(newWin);
|
||||
ok(closed, "Should be able to close the window");
|
||||
|
||||
newWin = await promiseNewWindowLoaded();
|
||||
is(
|
||||
newWin.gBrowser.browsers.length,
|
||||
TEST_URLS.length + 2,
|
||||
"Restored tabs in a new non-private window"
|
||||
);
|
||||
|
||||
// Note that this will not result in the the browser-lastwindow-close
|
||||
// notifications firing for this other newWin.
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
|
||||
// We closed two windows with closeWindowForRestoration, and both
|
||||
// should have been successful.
|
||||
is(
|
||||
obs["browser-lastwindow-close-requested"],
|
||||
2,
|
||||
"Got expected browser-lastwindow-close-requested notifications"
|
||||
);
|
||||
is(
|
||||
obs["browser-lastwindow-close-granted"],
|
||||
2,
|
||||
"Got expected browser-lastwindow-close-granted notifications"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Open some popup window to check it isn't restored. Instead nothing at all
|
||||
* should be restored
|
||||
*
|
||||
* Note: Non-Mac only
|
||||
*
|
||||
* Should do the following:
|
||||
* 1. Open a popup
|
||||
* 2. Add another tab to the popup (so that it gets stored) and close it again
|
||||
* 3. Open a window
|
||||
* 4. Check that nothing at all is restored
|
||||
* 5. Open two browser windows and close them again
|
||||
* 6. undoCloseWindow() one
|
||||
* 7. Open another browser window
|
||||
* 8. Check that nothing at all is restored
|
||||
*/
|
||||
add_task(async function test_open_close_only_popup() {
|
||||
if (IS_MAC) {
|
||||
return;
|
||||
}
|
||||
|
||||
await setupTest({}, async function (newWin, obs) {
|
||||
// We actually don't care about the initial window in this test.
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
|
||||
// This will cause nsSessionStore to restore a window the next time it
|
||||
// gets a chance.
|
||||
let popupPromise = BrowserTestUtils.waitForNewWindow();
|
||||
openDialog(location, "popup", POPUP_FEATURES, TEST_URLS[1]);
|
||||
let popup = await popupPromise;
|
||||
|
||||
is(
|
||||
popup.gBrowser.browsers.length,
|
||||
1,
|
||||
"Did not restore the popup window (1)"
|
||||
);
|
||||
|
||||
let closed = await closeWindowForRestoration(popup);
|
||||
ok(closed, "Should be able to close the window");
|
||||
|
||||
popupPromise = BrowserTestUtils.waitForNewWindow();
|
||||
openDialog(location, "popup", POPUP_FEATURES, TEST_URLS[1]);
|
||||
popup = await popupPromise;
|
||||
|
||||
BrowserTestUtils.addTab(popup.gBrowser, TEST_URLS[0]);
|
||||
is(
|
||||
popup.gBrowser.browsers.length,
|
||||
2,
|
||||
"Did not restore to the popup window (2)"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(popup);
|
||||
|
||||
newWin = await promiseNewWindowLoaded();
|
||||
isnot(
|
||||
newWin.gBrowser.browsers.length,
|
||||
2,
|
||||
"Did not restore the popup window"
|
||||
);
|
||||
is(
|
||||
TEST_URLS.indexOf(newWin.gBrowser.browsers[0].currentURI.spec),
|
||||
-1,
|
||||
"Did not restore the popup window (2)"
|
||||
);
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
|
||||
// We closed one popup window with closeWindowForRestoration, and popup
|
||||
// windows should never fire the browser-lastwindow notifications.
|
||||
is(
|
||||
obs["browser-lastwindow-close-requested"],
|
||||
0,
|
||||
"Got expected browser-lastwindow-close-requested notifications"
|
||||
);
|
||||
is(
|
||||
obs["browser-lastwindow-close-granted"],
|
||||
0,
|
||||
"Got expected browser-lastwindow-close-granted notifications"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Open some windows and do undoCloseWindow. This should prevent any
|
||||
* restoring later in the test
|
||||
*
|
||||
* Note: Non-Mac only
|
||||
*
|
||||
* Should do the following:
|
||||
* 1. Open two browser windows and close them again
|
||||
* 2. undoCloseWindow() one
|
||||
* 3. Open another browser window
|
||||
* 4. Make sure nothing at all is restored
|
||||
*/
|
||||
add_task(async function test_open_close_restore_from_popup() {
|
||||
if (IS_MAC) {
|
||||
return;
|
||||
}
|
||||
|
||||
await setupTest({}, async function (newWin) {
|
||||
let newWin2 = await promiseNewWindowLoaded();
|
||||
await injectTestTabs(newWin2);
|
||||
|
||||
let closed = await closeWindowForRestoration(newWin);
|
||||
ok(closed, "Should be able to close the window");
|
||||
closed = await closeWindowForRestoration(newWin2);
|
||||
ok(closed, "Should be able to close the window");
|
||||
|
||||
let counts = getBrowserWindowsCount();
|
||||
is(counts.open, 0, "Got right number of open windows");
|
||||
is(counts.winstates, 1, "Got right number of window states");
|
||||
|
||||
newWin = SessionWindowUI.undoCloseWindow(0);
|
||||
await BrowserTestUtils.waitForEvent(newWin, "load");
|
||||
|
||||
// Make sure we wait until this window is restored.
|
||||
await BrowserTestUtils.waitForEvent(
|
||||
newWin.gBrowser.tabContainer,
|
||||
"SSTabRestored"
|
||||
);
|
||||
|
||||
newWin2 = await promiseNewWindowLoaded();
|
||||
|
||||
is(
|
||||
TEST_URLS.indexOf(newWin2.gBrowser.browsers[0].currentURI.spec),
|
||||
-1,
|
||||
"Did not restore, as undoCloseWindow() was last called (2)"
|
||||
);
|
||||
|
||||
counts = getBrowserWindowsCount();
|
||||
is(counts.open, 2, "Got right number of open windows");
|
||||
is(counts.winstates, 3, "Got right number of window states");
|
||||
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
await BrowserTestUtils.closeWindow(newWin2);
|
||||
|
||||
counts = getBrowserWindowsCount();
|
||||
is(counts.open, 0, "Got right number of open windows");
|
||||
is(counts.winstates, 1, "Got right number of window states");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test if closing can be denied on Mac.
|
||||
*
|
||||
* Note: Mac only
|
||||
*/
|
||||
add_task(async function test_mac_notifications() {
|
||||
if (!IS_MAC) {
|
||||
return;
|
||||
}
|
||||
|
||||
await setupTest({ denyFirst: true }, async function (newWin, obs) {
|
||||
let closed = await closeWindowForRestoration(newWin);
|
||||
ok(!closed, "First close attempt should be denied");
|
||||
closed = await closeWindowForRestoration(newWin);
|
||||
ok(closed, "Second close attempt should be granted");
|
||||
|
||||
// We tried closing once, and got denied. Then we tried again and
|
||||
// succeeded. That means 2 close requests, and 1 close granted.
|
||||
is(
|
||||
obs["browser-lastwindow-close-requested"],
|
||||
2,
|
||||
"Got expected browser-lastwindow-close-requested notifications"
|
||||
);
|
||||
is(
|
||||
obs["browser-lastwindow-close-granted"],
|
||||
1,
|
||||
"Got expected browser-lastwindow-close-granted notifications"
|
||||
);
|
||||
});
|
||||
});
|
||||
52
src/zen/tests/mochitests/sessionstore/browser_367052.js
Normal file
52
src/zen/tests/mochitests/sessionstore/browser_367052.js
Normal file
@@ -0,0 +1,52 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(async function () {
|
||||
// make sure that the next closed tab will increase getClosedTabCountForWindow
|
||||
let max_tabs_undo = Services.prefs.getIntPref(
|
||||
"browser.sessionstore.max_tabs_undo"
|
||||
);
|
||||
Services.prefs.setIntPref(
|
||||
"browser.sessionstore.max_tabs_undo",
|
||||
max_tabs_undo + 1
|
||||
);
|
||||
registerCleanupFunction(() =>
|
||||
Services.prefs.clearUserPref("browser.sessionstore.max_tabs_undo")
|
||||
);
|
||||
|
||||
forgetClosedTabs(window);
|
||||
|
||||
// restore a blank tab
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:mozilla");
|
||||
await promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
let count = await promiseSHistoryCount(tab.linkedBrowser);
|
||||
Assert.greaterOrEqual(
|
||||
count,
|
||||
1,
|
||||
"the new tab does have at least one history entry"
|
||||
);
|
||||
|
||||
await promiseTabState(tab, { entries: [] });
|
||||
|
||||
// We may have a different sessionHistory object if the tab
|
||||
// switched from non-remote to remote.
|
||||
count = await promiseSHistoryCount(tab.linkedBrowser);
|
||||
is(count, 0, "the tab was restored without any history whatsoever");
|
||||
|
||||
await promiseRemoveTabAndSessionState(tab);
|
||||
is(
|
||||
ss.getClosedTabCountForWindow(window),
|
||||
0,
|
||||
"The closed blank tab wasn't added to Recently Closed Tabs"
|
||||
);
|
||||
});
|
||||
|
||||
function promiseSHistoryCount(browser) {
|
||||
return SpecialPowers.spawn(browser, [], async function () {
|
||||
return docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory.count;
|
||||
});
|
||||
}
|
||||
103
src/zen/tests/mochitests/sessionstore/browser_393716.js
Normal file
103
src/zen/tests/mochitests/sessionstore/browser_393716.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const URL = "about:config";
|
||||
|
||||
add_setup(async function () {
|
||||
// Make sure that the field of which we restore the state is visible on load.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.aboutConfig.showWarning", false]],
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Bug 393716 - Basic tests for getTabState(), setTabState(), and duplicateTab().
|
||||
*/
|
||||
add_task(async function test_set_tabstate() {
|
||||
let key = "Unique key: " + Date.now();
|
||||
let value = "Unique value: " + Math.random();
|
||||
|
||||
// create a new tab
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, URL);
|
||||
ss.setCustomTabValue(tab, key, value);
|
||||
await promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
// get the tab's state
|
||||
await TabStateFlusher.flush(tab.linkedBrowser);
|
||||
let state = ss.getTabState(tab);
|
||||
ok(state, "get the tab's state");
|
||||
|
||||
// verify the tab state's integrity
|
||||
state = JSON.parse(state);
|
||||
ok(
|
||||
state instanceof Object &&
|
||||
state.entries instanceof Array &&
|
||||
!!state.entries.length,
|
||||
"state object seems valid"
|
||||
);
|
||||
ok(
|
||||
state.entries.length == 1 && state.entries[0].url == URL,
|
||||
"Got the expected state object (test URL)"
|
||||
);
|
||||
ok(
|
||||
state.extData && state.extData[key] == value,
|
||||
"Got the expected state object (test manually set tab value)"
|
||||
);
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(async function test_set_tabstate_and_duplicate() {
|
||||
let key2 = "key2";
|
||||
let value2 = "Value " + Math.random();
|
||||
let value3 = "Another value: " + Date.now();
|
||||
let state = {
|
||||
entries: [{ url: URL, triggeringPrincipal_base64 }],
|
||||
extData: { key2: value2 },
|
||||
};
|
||||
|
||||
// create a new tab
|
||||
let tab = BrowserTestUtils.addTab(gBrowser);
|
||||
// set the tab's state
|
||||
ss.setTabState(tab, JSON.stringify(state));
|
||||
await promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
// verify the correctness of the restored tab
|
||||
ok(
|
||||
ss.getCustomTabValue(tab, key2) == value2 &&
|
||||
tab.linkedBrowser.currentURI.spec == URL,
|
||||
"the tab's state was correctly restored"
|
||||
);
|
||||
|
||||
// add text data
|
||||
await setPropertyOfFormField(
|
||||
tab.linkedBrowser,
|
||||
"#about-config-search",
|
||||
"value",
|
||||
value3
|
||||
);
|
||||
|
||||
// duplicate the tab
|
||||
let tab2 = ss.duplicateTab(window, tab);
|
||||
await promiseTabRestored(tab2);
|
||||
|
||||
// verify the correctness of the duplicated tab
|
||||
ok(
|
||||
ss.getCustomTabValue(tab2, key2) == value2 &&
|
||||
tab2.linkedBrowser.currentURI.spec == URL,
|
||||
"correctly duplicated the tab's state"
|
||||
);
|
||||
let textbox = await getPropertyOfFormField(
|
||||
tab2.linkedBrowser,
|
||||
"#about-config-search",
|
||||
"value"
|
||||
);
|
||||
is(textbox, value3, "also duplicated text data");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
123
src/zen/tests/mochitests/sessionstore/browser_394759_basic.js
Normal file
123
src/zen/tests/mochitests/sessionstore/browser_394759_basic.js
Normal file
@@ -0,0 +1,123 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URL =
|
||||
"data:text/html;charset=utf-8,<input%20id=txt>" +
|
||||
"<input%20type=checkbox%20id=chk>";
|
||||
|
||||
/**
|
||||
* This test ensures that closing a window is a reversible action. We will
|
||||
* close the the window, restore it and check that all data has been restored.
|
||||
* This includes window-specific data as well as form data for tabs.
|
||||
*/
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let uniqueKey = "bug 394759";
|
||||
let uniqueValue = "unik" + Date.now();
|
||||
let uniqueText = "pi != " + Math.random();
|
||||
|
||||
// Clear the list of closed windows.
|
||||
forgetClosedWindows();
|
||||
|
||||
provideWindow(function onTestURLLoaded(newWin) {
|
||||
BrowserTestUtils.addTab(newWin.gBrowser).linkedBrowser.stop();
|
||||
|
||||
// Mark the window with some unique data to be restored later on.
|
||||
ss.setCustomWindowValue(newWin, uniqueKey, uniqueValue);
|
||||
let [txt] = newWin.content.document.querySelectorAll("#txt");
|
||||
txt.value = uniqueText;
|
||||
|
||||
let browser = newWin.gBrowser.selectedBrowser;
|
||||
|
||||
setPropertyOfFormField(browser, "#chk", "checked", true).then(() => {
|
||||
BrowserTestUtils.closeWindow(newWin).then(() => {
|
||||
is(
|
||||
ss.getClosedWindowCount(),
|
||||
1,
|
||||
"The closed window was added to Recently Closed Windows"
|
||||
);
|
||||
|
||||
let data = SessionStore.getClosedWindowData();
|
||||
|
||||
// Verify that non JSON serialized data is the same as JSON serialized data.
|
||||
is(
|
||||
JSON.stringify(data),
|
||||
ss.getClosedWindowData(),
|
||||
"Non-serialized data is the same as serialized data"
|
||||
);
|
||||
|
||||
ok(
|
||||
data[0].title == TEST_URL &&
|
||||
JSON.stringify(data[0]).indexOf(uniqueText) > -1,
|
||||
"The closed window data was stored correctly"
|
||||
);
|
||||
|
||||
// Reopen the closed window and ensure its integrity.
|
||||
let newWin2 = ss.undoCloseWindow(0);
|
||||
|
||||
ok(
|
||||
newWin2.isChromeWindow,
|
||||
"undoCloseWindow actually returned a window"
|
||||
);
|
||||
is(
|
||||
ss.getClosedWindowCount(),
|
||||
0,
|
||||
"The reopened window was removed from Recently Closed Windows"
|
||||
);
|
||||
|
||||
// SSTabRestored will fire more than once, so we need to make sure we count them.
|
||||
let restoredTabs = 0;
|
||||
let expectedTabs = data[0].tabs.length;
|
||||
newWin2.addEventListener(
|
||||
"SSTabRestored",
|
||||
function sstabrestoredListener() {
|
||||
++restoredTabs;
|
||||
info("Restored tab " + restoredTabs + "/" + expectedTabs);
|
||||
if (restoredTabs < expectedTabs) {
|
||||
return;
|
||||
}
|
||||
|
||||
is(restoredTabs, expectedTabs, "Correct number of tabs restored");
|
||||
newWin2.removeEventListener(
|
||||
"SSTabRestored",
|
||||
sstabrestoredListener,
|
||||
true
|
||||
);
|
||||
|
||||
is(
|
||||
newWin2.gBrowser.tabs.length,
|
||||
2,
|
||||
"The window correctly restored 2 tabs"
|
||||
);
|
||||
is(
|
||||
newWin2.gBrowser.currentURI.spec,
|
||||
TEST_URL,
|
||||
"The window correctly restored the URL"
|
||||
);
|
||||
|
||||
let chk;
|
||||
[txt, chk] =
|
||||
newWin2.content.document.querySelectorAll("#txt, #chk");
|
||||
ok(
|
||||
txt.value == uniqueText && chk.checked,
|
||||
"The window correctly restored the form"
|
||||
);
|
||||
is(
|
||||
ss.getCustomWindowValue(newWin2, uniqueKey),
|
||||
uniqueValue,
|
||||
"The window correctly restored the data associated with it"
|
||||
);
|
||||
|
||||
// Clean up.
|
||||
BrowserTestUtils.closeWindow(newWin2).then(finish);
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
}, TEST_URL);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Test helper function that opens a series of windows, closes them
|
||||
* and then checks the closed window data from SessionStore against
|
||||
* expected results.
|
||||
*
|
||||
* @param windowsToOpen (Array)
|
||||
* An array of Objects, where each object must define a single
|
||||
* property "isPopup" for whether or not the opened window should
|
||||
* be a popup.
|
||||
* @param expectedResults (Array)
|
||||
* An Object with two properies: mac and other, where each points
|
||||
* at yet another Object, with the following properties:
|
||||
*
|
||||
* popup (int):
|
||||
* The number of popup windows we expect to be in the closed window
|
||||
* data.
|
||||
* normal (int):
|
||||
* The number of normal windows we expect to be in the closed window
|
||||
* data.
|
||||
* @returns Promise
|
||||
*/
|
||||
function testWindows(windowsToOpen, expectedResults) {
|
||||
return (async function () {
|
||||
let num = 0;
|
||||
for (let winData of windowsToOpen) {
|
||||
let features = "chrome,dialog=no," + (winData.isPopup ? "all=no" : "all");
|
||||
let url = "http://example.com/?window=" + num;
|
||||
num = num + 1;
|
||||
|
||||
let openWindowPromise = BrowserTestUtils.waitForNewWindow({ url });
|
||||
openDialog(AppConstants.BROWSER_CHROME_URL, "", features, url);
|
||||
let win = await openWindowPromise;
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
}
|
||||
|
||||
let closedWindowData = ss.getClosedWindowData();
|
||||
let numPopups = closedWindowData.filter(function (el) {
|
||||
return el.isPopup;
|
||||
}).length;
|
||||
let numNormal = ss.getClosedWindowCount() - numPopups;
|
||||
// #ifdef doesn't work in browser-chrome tests, so do a simple regex on platform
|
||||
let oResults = navigator.platform.match(/Mac/)
|
||||
? expectedResults.mac
|
||||
: expectedResults.other;
|
||||
is(
|
||||
numPopups,
|
||||
oResults.popup,
|
||||
"There were " + oResults.popup + " popup windows to reopen"
|
||||
);
|
||||
is(
|
||||
numNormal,
|
||||
oResults.normal,
|
||||
"There were " + oResults.normal + " normal windows to reopen"
|
||||
);
|
||||
})();
|
||||
}
|
||||
|
||||
add_task(async function test_closed_window_states() {
|
||||
// This test takes quite some time, and timeouts frequently, so we require
|
||||
// more time to run.
|
||||
// See Bug 518970.
|
||||
requestLongerTimeout(2);
|
||||
|
||||
let windowsToOpen = [
|
||||
{ isPopup: false },
|
||||
{ isPopup: true },
|
||||
{ isPopup: true },
|
||||
{ isPopup: true },
|
||||
{ isPopup: true },
|
||||
{ isPopup: true },
|
||||
];
|
||||
let expectedResults = {
|
||||
mac: { popup: 5, normal: 0 },
|
||||
other: { popup: 5, normal: 1 },
|
||||
};
|
||||
|
||||
await testWindows(windowsToOpen, expectedResults);
|
||||
|
||||
let windowsToOpen2 = [
|
||||
{ isPopup: false },
|
||||
{ isPopup: false },
|
||||
{ isPopup: false },
|
||||
{ isPopup: false },
|
||||
{ isPopup: false },
|
||||
{ isPopup: false },
|
||||
];
|
||||
let expectedResults2 = {
|
||||
mac: { popup: 0, normal: 5 },
|
||||
other: { popup: 0, normal: 5 },
|
||||
};
|
||||
|
||||
await testWindows(windowsToOpen2, expectedResults2);
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TESTS = [
|
||||
{ url: "about:config", key: "bug 394759 Non-PB", value: "uniq" + r() },
|
||||
{ url: "about:mozilla", key: "bug 394759 PB", value: "uniq" + r() },
|
||||
];
|
||||
|
||||
function promiseTestOpenCloseWindow(aIsPrivate, aTest) {
|
||||
return (async function () {
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow({
|
||||
private: aIsPrivate,
|
||||
});
|
||||
BrowserTestUtils.startLoadingURIString(
|
||||
win.gBrowser.selectedBrowser,
|
||||
aTest.url
|
||||
);
|
||||
await promiseBrowserLoaded(win.gBrowser.selectedBrowser, true, aTest.url);
|
||||
// Mark the window with some unique data to be restored later on.
|
||||
ss.setCustomWindowValue(win, aTest.key, aTest.value);
|
||||
await TabStateFlusher.flushWindow(win);
|
||||
// Close.
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
})();
|
||||
}
|
||||
|
||||
function promiseTestOnWindow(aIsPrivate, aValue) {
|
||||
return (async function () {
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow({
|
||||
private: aIsPrivate,
|
||||
});
|
||||
await TabStateFlusher.flushWindow(win);
|
||||
let data = ss.getClosedWindowData()[0];
|
||||
is(
|
||||
ss.getClosedWindowCount(),
|
||||
1,
|
||||
"Check that the closed window count hasn't changed"
|
||||
);
|
||||
Assert.greater(
|
||||
JSON.stringify(data).indexOf(aValue),
|
||||
-1,
|
||||
"Check the closed window data was stored correctly"
|
||||
);
|
||||
registerCleanupFunction(() => BrowserTestUtils.closeWindow(win));
|
||||
})();
|
||||
}
|
||||
|
||||
add_setup(async function () {
|
||||
forgetClosedWindows();
|
||||
forgetClosedTabs(window);
|
||||
});
|
||||
|
||||
add_task(async function main() {
|
||||
await promiseTestOpenCloseWindow(false, TESTS[0]);
|
||||
await promiseTestOpenCloseWindow(true, TESTS[1]);
|
||||
await promiseTestOnWindow(false, TESTS[0].value);
|
||||
await promiseTestOnWindow(true, TESTS[0].value);
|
||||
});
|
||||
250
src/zen/tests/mochitests/sessionstore/browser_394759_purge.js
Normal file
250
src/zen/tests/mochitests/sessionstore/browser_394759_purge.js
Normal file
@@ -0,0 +1,250 @@
|
||||
/* 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/. */
|
||||
|
||||
let { ForgetAboutSite } = ChromeUtils.importESModule(
|
||||
"moz-src:///toolkit/components/forgetaboutsite/ForgetAboutSite.sys.mjs"
|
||||
);
|
||||
|
||||
function promiseClearHistory() {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe() {
|
||||
Services.obs.removeObserver(
|
||||
this,
|
||||
"browser:purge-session-history-for-domain"
|
||||
);
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
Services.obs.addObserver(
|
||||
observer,
|
||||
"browser:purge-session-history-for-domain"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function () {
|
||||
// utility functions
|
||||
function countClosedTabsByTitle(aClosedTabList, aTitle) {
|
||||
return aClosedTabList.filter(aData => aData.title == aTitle).length;
|
||||
}
|
||||
|
||||
function countOpenTabsByTitle(aOpenTabList, aTitle) {
|
||||
return aOpenTabList.filter(aData =>
|
||||
aData.entries.some(aEntry => aEntry.title == aTitle)
|
||||
).length;
|
||||
}
|
||||
|
||||
// backup old state
|
||||
let oldState = ss.getBrowserState();
|
||||
let oldState_wins = JSON.parse(oldState).windows.length;
|
||||
if (oldState_wins != 1) {
|
||||
ok(
|
||||
false,
|
||||
"oldState in test_purge has " + oldState_wins + " windows instead of 1"
|
||||
);
|
||||
}
|
||||
|
||||
// create a new state for testing
|
||||
const REMEMBER = Date.now(),
|
||||
FORGET = Math.random();
|
||||
let testState = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{ url: "http://example.com/", triggeringPrincipal_base64 },
|
||||
],
|
||||
},
|
||||
],
|
||||
selected: 1,
|
||||
},
|
||||
],
|
||||
_closedWindows: [
|
||||
// _closedWindows[0]
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com/",
|
||||
triggeringPrincipal_base64,
|
||||
title: REMEMBER,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://mozilla.org/",
|
||||
triggeringPrincipal_base64,
|
||||
title: FORGET,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
selected: 2,
|
||||
title: "mozilla.org",
|
||||
_closedTabs: [],
|
||||
closedGroups: [],
|
||||
},
|
||||
// _closedWindows[1]
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://mozilla.org/",
|
||||
triggeringPrincipal_base64,
|
||||
title: FORGET,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com/",
|
||||
triggeringPrincipal_base64,
|
||||
title: REMEMBER,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com/",
|
||||
triggeringPrincipal_base64,
|
||||
title: REMEMBER,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://mozilla.org/",
|
||||
triggeringPrincipal_base64,
|
||||
title: FORGET,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com/",
|
||||
triggeringPrincipal_base64,
|
||||
title: REMEMBER,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
selected: 5,
|
||||
_closedTabs: [],
|
||||
closedGroups: [],
|
||||
},
|
||||
// _closedWindows[2]
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com/",
|
||||
triggeringPrincipal_base64,
|
||||
title: REMEMBER,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
selected: 1,
|
||||
_closedTabs: [
|
||||
{
|
||||
state: {
|
||||
entries: [
|
||||
{
|
||||
url: "http://mozilla.org/",
|
||||
triggeringPrincipal_base64,
|
||||
title: FORGET,
|
||||
},
|
||||
{
|
||||
url: "http://mozilla.org/again",
|
||||
triggeringPrincipal_base64,
|
||||
title: "doesn't matter",
|
||||
},
|
||||
],
|
||||
},
|
||||
pos: 1,
|
||||
title: FORGET,
|
||||
},
|
||||
{
|
||||
state: {
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com",
|
||||
triggeringPrincipal_base64,
|
||||
title: REMEMBER,
|
||||
},
|
||||
],
|
||||
},
|
||||
title: REMEMBER,
|
||||
},
|
||||
],
|
||||
closedGroups: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// set browser to test state
|
||||
ss.setBrowserState(JSON.stringify(testState));
|
||||
|
||||
// purge domain & check that we purged correctly for closed windows
|
||||
let clearHistoryPromise = promiseClearHistory();
|
||||
await ForgetAboutSite.removeDataFromBaseDomain("mozilla.org");
|
||||
await clearHistoryPromise;
|
||||
|
||||
let closedWindowData = ss.getClosedWindowData();
|
||||
|
||||
// First set of tests for _closedWindows[0] - tests basics
|
||||
let win = closedWindowData[0];
|
||||
is(win.tabs.length, 1, "1 tab was removed");
|
||||
is(countOpenTabsByTitle(win.tabs, FORGET), 0, "The correct tab was removed");
|
||||
is(
|
||||
countOpenTabsByTitle(win.tabs, REMEMBER),
|
||||
1,
|
||||
"The correct tab was remembered"
|
||||
);
|
||||
is(win.selected, 1, "Selected tab has changed");
|
||||
is(win.title, REMEMBER, "The window title was correctly updated");
|
||||
|
||||
// Test more complicated case
|
||||
win = closedWindowData[1];
|
||||
is(win.tabs.length, 3, "2 tabs were removed");
|
||||
is(
|
||||
countOpenTabsByTitle(win.tabs, FORGET),
|
||||
0,
|
||||
"The correct tabs were removed"
|
||||
);
|
||||
is(
|
||||
countOpenTabsByTitle(win.tabs, REMEMBER),
|
||||
3,
|
||||
"The correct tabs were remembered"
|
||||
);
|
||||
is(win.selected, 3, "Selected tab has changed");
|
||||
is(win.title, REMEMBER, "The window title was correctly updated");
|
||||
|
||||
// Tests handling of _closedTabs
|
||||
win = closedWindowData[2];
|
||||
is(
|
||||
countClosedTabsByTitle(win._closedTabs, REMEMBER),
|
||||
1,
|
||||
"The correct number of tabs were removed, and the correct ones"
|
||||
);
|
||||
is(
|
||||
countClosedTabsByTitle(win._closedTabs, FORGET),
|
||||
0,
|
||||
"All tabs to be forgotten were indeed removed"
|
||||
);
|
||||
|
||||
// restore pre-test state
|
||||
ss.setBrowserState(oldState);
|
||||
});
|
||||
52
src/zen/tests/mochitests/sessionstore/browser_423132.js
Normal file
52
src/zen/tests/mochitests/sessionstore/browser_423132.js
Normal file
@@ -0,0 +1,52 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests that cookies are stored and restored correctly
|
||||
* by sessionstore (bug 423132).
|
||||
*/
|
||||
add_task(async function () {
|
||||
const testURL =
|
||||
"http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_423132_sample.html";
|
||||
|
||||
Services.cookies.removeAll();
|
||||
// make sure that sessionstore.js can be forced to be created by setting
|
||||
// the interval pref to 0
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.sessionstore.interval", 0]],
|
||||
});
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, testURL);
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
await TabStateFlusher.flush(tab.linkedBrowser);
|
||||
|
||||
// get the sessionstore state for the window
|
||||
let state = ss.getBrowserState();
|
||||
|
||||
// verify our cookie got set during pageload
|
||||
let i = 0;
|
||||
for (var cookie of Services.cookies.cookies) {
|
||||
i++;
|
||||
}
|
||||
Assert.equal(i, 1, "expected one cookie");
|
||||
|
||||
// remove the cookie
|
||||
Services.cookies.removeAll();
|
||||
|
||||
// restore the window state
|
||||
await setBrowserState(state);
|
||||
|
||||
// at this point, the cookie should be restored...
|
||||
for (var cookie2 of Services.cookies.cookies) {
|
||||
if (cookie.name == cookie2.name) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
is(cookie.name, cookie2.name, "cookie name successfully restored");
|
||||
is(cookie.value, cookie2.value, "cookie value successfully restored");
|
||||
is(cookie.path, cookie2.path, "cookie path successfully restored");
|
||||
|
||||
// clean up
|
||||
Services.cookies.removeAll();
|
||||
BrowserTestUtils.removeTab(gBrowser.tabs[1]);
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript">
|
||||
// generate an enormous random number...
|
||||
var r = Math.floor(Math.random() * Math.pow(2, 62)).toString();
|
||||
|
||||
// ... and use it to set a randomly named cookie
|
||||
document.cookie = r + "=value; path=/ohai";
|
||||
</script>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
86
src/zen/tests/mochitests/sessionstore/browser_447951.js
Normal file
86
src/zen/tests/mochitests/sessionstore/browser_447951.js
Normal file
@@ -0,0 +1,86 @@
|
||||
/* 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() {
|
||||
/** Test for Bug 447951 */
|
||||
|
||||
waitForExplicitFinish();
|
||||
const baseURL =
|
||||
"http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_447951_sample.html#";
|
||||
|
||||
// Make sure the functionality added in bug 943339 doesn't affect the results
|
||||
Services.prefs.setIntPref("browser.sessionstore.max_serialize_back", -1);
|
||||
Services.prefs.setIntPref("browser.sessionstore.max_serialize_forward", -1);
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.max_serialize_back");
|
||||
Services.prefs.clearUserPref("browser.sessionstore.max_serialize_forward");
|
||||
});
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser);
|
||||
BrowserTestUtils.browserLoaded(tab.linkedBrowser, {
|
||||
wantLoad: "about:blank",
|
||||
}).then(() => {
|
||||
let tabState = { entries: [] };
|
||||
let max_entries = Services.prefs.getIntPref(
|
||||
"browser.sessionhistory.max_entries"
|
||||
);
|
||||
for (let i = 0; i < max_entries; i++) {
|
||||
tabState.entries.push({ url: baseURL + i, triggeringPrincipal_base64 });
|
||||
}
|
||||
|
||||
promiseTabState(tab, tabState)
|
||||
.then(() => {
|
||||
return TabStateFlusher.flush(tab.linkedBrowser);
|
||||
})
|
||||
.then(() => {
|
||||
tabState = JSON.parse(ss.getTabState(tab));
|
||||
is(
|
||||
tabState.entries.length,
|
||||
max_entries,
|
||||
"session history filled to the limit"
|
||||
);
|
||||
is(tabState.entries[0].url, baseURL + 0, "... but not more");
|
||||
|
||||
// visit yet another anchor (appending it to session history)
|
||||
SpecialPowers.spawn(tab.linkedBrowser, [], function () {
|
||||
content.window.document.querySelector("a").click();
|
||||
}).then(flushAndCheck);
|
||||
|
||||
function flushAndCheck() {
|
||||
TabStateFlusher.flush(tab.linkedBrowser).then(check);
|
||||
}
|
||||
|
||||
function check() {
|
||||
tabState = JSON.parse(ss.getTabState(tab));
|
||||
if (tab.linkedBrowser.currentURI.spec != baseURL + "end") {
|
||||
// It may take a few passes through the event loop before we
|
||||
// get the right URL.
|
||||
executeSoon(flushAndCheck);
|
||||
return;
|
||||
}
|
||||
|
||||
is(
|
||||
tab.linkedBrowser.currentURI.spec,
|
||||
baseURL + "end",
|
||||
"the new anchor was loaded"
|
||||
);
|
||||
is(
|
||||
tabState.entries[tabState.entries.length - 1].url,
|
||||
baseURL + "end",
|
||||
"... and ignored"
|
||||
);
|
||||
is(
|
||||
tabState.entries[0].url,
|
||||
baseURL + 1,
|
||||
"... and the first item was removed"
|
||||
);
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Testcase for bug 447951</title>
|
||||
|
||||
<a href="#end">click me</a>
|
||||
65
src/zen/tests/mochitests/sessionstore/browser_454908.js
Normal file
65
src/zen/tests/mochitests/sessionstore/browser_454908.js
Normal file
@@ -0,0 +1,65 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
if (gFissionBrowser) {
|
||||
addCoopTask(
|
||||
"browser_454908_sample.html",
|
||||
test_dont_save_passwords,
|
||||
HTTPSROOT
|
||||
);
|
||||
}
|
||||
addNonCoopTask("browser_454908_sample.html", test_dont_save_passwords, ROOT);
|
||||
addNonCoopTask(
|
||||
"browser_454908_sample.html",
|
||||
test_dont_save_passwords,
|
||||
HTTPROOT
|
||||
);
|
||||
addNonCoopTask(
|
||||
"browser_454908_sample.html",
|
||||
test_dont_save_passwords,
|
||||
HTTPSROOT
|
||||
);
|
||||
|
||||
const PASS = "pwd-" + Math.random();
|
||||
|
||||
/**
|
||||
* Bug 454908 - Don't save/restore values of password fields.
|
||||
*/
|
||||
async function test_dont_save_passwords(aURL) {
|
||||
// Make sure we do save form data.
|
||||
Services.prefs.clearUserPref("browser.sessionstore.privacy_level");
|
||||
|
||||
// Add a tab with a password field.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, aURL);
|
||||
let browser = tab.linkedBrowser;
|
||||
await promiseBrowserLoaded(browser);
|
||||
|
||||
// Fill in some values.
|
||||
let usernameValue = "User " + Math.random();
|
||||
await setPropertyOfFormField(browser, "#username", "value", usernameValue);
|
||||
await setPropertyOfFormField(browser, "#passwd", "value", PASS);
|
||||
|
||||
// Close and restore the tab.
|
||||
await promiseRemoveTabAndSessionState(tab);
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
browser = tab.linkedBrowser;
|
||||
await promiseTabRestored(tab);
|
||||
|
||||
// Check that password fields aren't saved/restored.
|
||||
let username = await getPropertyOfFormField(browser, "#username", "value");
|
||||
is(username, usernameValue, "username was saved/restored");
|
||||
let passwd = await getPropertyOfFormField(browser, "#passwd", "value");
|
||||
is(passwd, "", "password wasn't saved/restored");
|
||||
|
||||
// Write to disk and read our file.
|
||||
await forceSaveState();
|
||||
await promiseForEachSessionRestoreFile((state, key) =>
|
||||
// Ensure that we have not saved our password.
|
||||
ok(!state.includes(PASS), "password has not been written to file " + key)
|
||||
);
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
<title>Test for bug 454908</title>
|
||||
|
||||
<h3>Dummy Login</h3>
|
||||
<form>
|
||||
<p>Username: <input type="text" id="username">
|
||||
<p>Password: <input type="password" id="passwd">
|
||||
</form>
|
||||
90
src/zen/tests/mochitests/sessionstore/browser_456342.js
Normal file
90
src/zen/tests/mochitests/sessionstore/browser_456342.js
Normal file
@@ -0,0 +1,90 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
addCoopTask(
|
||||
"browser_456342_sample.xhtml",
|
||||
test_restore_nonstandard_input_values,
|
||||
HTTPSROOT
|
||||
);
|
||||
addNonCoopTask(
|
||||
"browser_456342_sample.xhtml",
|
||||
test_restore_nonstandard_input_values,
|
||||
ROOT
|
||||
);
|
||||
addNonCoopTask(
|
||||
"browser_456342_sample.xhtml",
|
||||
test_restore_nonstandard_input_values,
|
||||
HTTPROOT
|
||||
);
|
||||
addNonCoopTask(
|
||||
"browser_456342_sample.xhtml",
|
||||
test_restore_nonstandard_input_values,
|
||||
HTTPSROOT
|
||||
);
|
||||
|
||||
const EXPECTED_IDS = new Set(["searchTerm"]);
|
||||
|
||||
const EXPECTED_XPATHS = new Set([
|
||||
"/xhtml:html/xhtml:body/xhtml:form/xhtml:p[2]/xhtml:input",
|
||||
"/xhtml:html/xhtml:body/xhtml:form/xhtml:p[3]/xhtml:input[@name='fill-in']",
|
||||
"/xhtml:html/xhtml:body/xhtml:form/xhtml:p[4]/xhtml:input[@name='mistyped']",
|
||||
"/xhtml:html/xhtml:body/xhtml:form/xhtml:p[5]/xhtml:textarea[@name='textarea_pass']",
|
||||
]);
|
||||
|
||||
/**
|
||||
* Bug 456342 - Restore values from non-standard input field types.
|
||||
*/
|
||||
async function test_restore_nonstandard_input_values(aURL) {
|
||||
// Add tab with various non-standard input field types.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, aURL);
|
||||
let browser = tab.linkedBrowser;
|
||||
await promiseBrowserLoaded(browser);
|
||||
|
||||
// Fill in form values.
|
||||
let expectedValue = Math.random();
|
||||
|
||||
await SpecialPowers.spawn(browser, [expectedValue], valueChild => {
|
||||
for (let elem of content.document.forms[0].elements) {
|
||||
elem.value = valueChild;
|
||||
let event = elem.ownerDocument.createEvent("UIEvents");
|
||||
event.initUIEvent("input", true, true, elem.documentGlobal, 0);
|
||||
elem.dispatchEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
// Remove tab and check collected form data.
|
||||
await promiseRemoveTabAndSessionState(tab);
|
||||
let undoItems = ss.getClosedTabDataForWindow(window);
|
||||
let savedFormData = undoItems[0].state.formdata;
|
||||
|
||||
let foundIds = 0;
|
||||
for (let id of Object.keys(savedFormData.id)) {
|
||||
ok(EXPECTED_IDS.has(id), `Check saved ID "${id}" was expected`);
|
||||
is(
|
||||
savedFormData.id[id],
|
||||
"" + expectedValue,
|
||||
`Check saved value for #${id}`
|
||||
);
|
||||
foundIds++;
|
||||
}
|
||||
|
||||
let foundXpaths = 0;
|
||||
for (let exp of Object.keys(savedFormData.xpath)) {
|
||||
ok(EXPECTED_XPATHS.has(exp), `Check saved xpath "${exp}" was expected`);
|
||||
is(
|
||||
savedFormData.xpath[exp],
|
||||
"" + expectedValue,
|
||||
`Check saved value for ${exp}`
|
||||
);
|
||||
foundXpaths++;
|
||||
}
|
||||
|
||||
is(foundIds, EXPECTED_IDS.size, "Check number of fields saved by ID");
|
||||
is(
|
||||
foundXpaths,
|
||||
EXPECTED_XPATHS.size,
|
||||
"Check number of fields saved by xpath"
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head><title>Test for bug 456342</title></head>
|
||||
|
||||
<body>
|
||||
<form>
|
||||
<h3>Non-standard <input>s</h3>
|
||||
<p>Search <input type="search" id="searchTerm"/></p>
|
||||
<p>Image Search: <input type="image search" /></p>
|
||||
<p>Autocomplete: <input type="autocomplete" name="fill-in"/></p>
|
||||
<p>Mistyped: <input type="txet" name="mistyped"/></p>
|
||||
<p>Invalid attr: <textarea type="password" name="textarea_pass"/></p>
|
||||
|
||||
<h3>Ignored types</h3>
|
||||
<input type="hidden" name="hideme"/>
|
||||
<input type="HIDDEN" name="hideme2"/>
|
||||
<input type="submit" name="submit"/>
|
||||
<input type="reset" name="reset"/>
|
||||
<input type="image" name="image"/>
|
||||
<input type="button" name="button"/>
|
||||
<input type="password" name="password"/>
|
||||
<input type="PassWord" name="password2"/>
|
||||
<input type="PASSWORD" name="password3"/>
|
||||
<input autocomplete="off" name="auto1"/>
|
||||
<input type="text" autocomplete="OFF" name="auto2"/>
|
||||
<input type="text" autocomplete=" OFF " name="auto5"/>
|
||||
<input autocomplete=" off " name="auto6"/>
|
||||
<input autocomplete=" cc-CSC " name="auto7"/>
|
||||
<input autocomplete=" NEW-password " name="auto8"/>
|
||||
<textarea autocomplete="off" name="auto3"/>
|
||||
<select autocomplete="off" name="auto4">
|
||||
<option value="1" selected="true"/>
|
||||
<option value="2"/>
|
||||
<option value="3"/>
|
||||
</select>
|
||||
<select autocomplete="cc-CSC" name="CSC">
|
||||
<option value="123" selected="true"/>
|
||||
<option value="234"/>
|
||||
<option value="345"/>
|
||||
</select>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
78
src/zen/tests/mochitests/sessionstore/browser_459906.js
Normal file
78
src/zen/tests/mochitests/sessionstore/browser_459906.js
Normal file
@@ -0,0 +1,78 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 459906 */
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let testURL =
|
||||
"http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_459906_sample.html";
|
||||
let uniqueValue = "<b>Unique:</b> " + Date.now();
|
||||
|
||||
var frameCount = 0;
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, testURL);
|
||||
tab.linkedBrowser.addEventListener(
|
||||
"load",
|
||||
function listener() {
|
||||
// wait for all frames to load completely
|
||||
if (frameCount++ < 2) {
|
||||
return;
|
||||
}
|
||||
tab.linkedBrowser.removeEventListener("load", listener, true);
|
||||
|
||||
let iframes = tab.linkedBrowser.contentWindow.frames;
|
||||
iframes[1].document.body.innerHTML = uniqueValue;
|
||||
|
||||
frameCount = 0;
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener(
|
||||
"load",
|
||||
function loadListener() {
|
||||
// wait for all frames to load (and reload!) completely
|
||||
if (frameCount++ < 2) {
|
||||
return;
|
||||
}
|
||||
tab2.linkedBrowser.removeEventListener("load", loadListener, true);
|
||||
|
||||
executeSoon(function innerHTMLPoller() {
|
||||
let iframesTab2 = tab2.linkedBrowser.contentWindow.frames;
|
||||
if (iframesTab2[1].document.body.innerHTML !== uniqueValue) {
|
||||
// Poll again the value, since we can't ensure to run
|
||||
// after SessionStore has injected innerHTML value.
|
||||
// See bug 521802.
|
||||
info("Polling for innerHTML value");
|
||||
setTimeout(innerHTMLPoller, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
is(
|
||||
iframesTab2[1].document.body.innerHTML,
|
||||
uniqueValue,
|
||||
"rich textarea's content correctly duplicated"
|
||||
);
|
||||
|
||||
let innerDomain = null;
|
||||
try {
|
||||
innerDomain = iframesTab2[0].document.domain;
|
||||
} catch (ex) {
|
||||
/* throws for chrome: documents */
|
||||
}
|
||||
is(innerDomain, "mochi.test", "XSS exploit prevented!");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
finish();
|
||||
});
|
||||
},
|
||||
true
|
||||
);
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<title>Cross Domain File for bug 459906</title>
|
||||
|
||||
cheers from localhost
|
||||
@@ -0,0 +1,41 @@
|
||||
<!-- Testcase originally by David Bloom <bloom@google.com> -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<title>Test for bug 459906</title>
|
||||
|
||||
<body>
|
||||
<iframe src="data:text/html;charset=utf-8,not_on_localhost"></iframe>
|
||||
<iframe></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
var loadCount = 0;
|
||||
frames[0].addEventListener("DOMContentLoaded", handleLoad);
|
||||
frames[1].addEventListener("DOMContentLoaded", handleLoad);
|
||||
function handleLoad() {
|
||||
if (++loadCount < 2)
|
||||
return;
|
||||
frames[0].removeEventListener("DOMContentLoaded", handleLoad);
|
||||
frames[1].removeEventListener("DOMContentLoaded", handleLoad);
|
||||
frames[0].document.designMode = "on";
|
||||
frames[0].document.__defineGetter__("designMode", function() {
|
||||
// inject a cross domain file ...
|
||||
var documentInjected = false;
|
||||
document.getElementsByTagName("iframe")[0].onload =
|
||||
function() { documentInjected = true; };
|
||||
frames[0].location = "browser_459906_empty.html";
|
||||
|
||||
// ... and ensure that it has time to load
|
||||
for (var c = 0; !documentInjected && c < 20; c++) {
|
||||
var r = new XMLHttpRequest();
|
||||
r.open("GET", location.href, false);
|
||||
r.overrideMimeType("text/plain");
|
||||
r.send(null);
|
||||
}
|
||||
|
||||
return "on";
|
||||
});
|
||||
|
||||
frames[1].document.designMode = "on";
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
133
src/zen/tests/mochitests/sessionstore/browser_461634.js
Normal file
133
src/zen/tests/mochitests/sessionstore/browser_461634.js
Normal file
@@ -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/. */
|
||||
|
||||
add_task(async function testClosedTabData() {
|
||||
/** Test for Bug 461634 */
|
||||
|
||||
const REMEMBER = Date.now(),
|
||||
FORGET = Math.random();
|
||||
let test_state = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [{ entries: [] }],
|
||||
_closedTabs: [
|
||||
{
|
||||
state: { entries: [{ url: "http://www.example.net/" }] },
|
||||
title: FORGET,
|
||||
},
|
||||
{
|
||||
state: { entries: [{ url: "http://www.example.net/" }] },
|
||||
title: REMEMBER,
|
||||
},
|
||||
{
|
||||
state: { entries: [{ url: "http://www.example.net/" }] },
|
||||
title: FORGET,
|
||||
},
|
||||
{
|
||||
state: { entries: [{ url: "http://www.example.net/" }] },
|
||||
title: REMEMBER,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
let remember_count = 2;
|
||||
|
||||
function countByTitle(aClosedTabList, aTitle) {
|
||||
return aClosedTabList.filter(aData => aData.title == aTitle).length;
|
||||
}
|
||||
|
||||
function testForError(aFunction) {
|
||||
try {
|
||||
aFunction();
|
||||
return false;
|
||||
} catch (ex) {
|
||||
return ex.name == "NS_ERROR_ILLEGAL_VALUE";
|
||||
}
|
||||
}
|
||||
|
||||
// Open a window and add the above closed tab list.
|
||||
let newWin = openDialog(location, "", "chrome,all,dialog=no");
|
||||
await promiseWindowLoaded(newWin);
|
||||
|
||||
Services.prefs.setIntPref(
|
||||
"browser.sessionstore.max_tabs_undo",
|
||||
test_state.windows[0]._closedTabs.length
|
||||
);
|
||||
await setWindowState(newWin, test_state, true);
|
||||
|
||||
let closedTabs = SessionStore.getClosedTabDataForWindow(newWin);
|
||||
|
||||
// Verify that non JSON serialized data is the same as JSON serialized data.
|
||||
is(
|
||||
JSON.stringify(closedTabs),
|
||||
JSON.stringify(SessionStore.getClosedTabDataForWindow(newWin)),
|
||||
"Non-serialized data is the same as serialized data"
|
||||
);
|
||||
|
||||
is(
|
||||
closedTabs.length,
|
||||
test_state.windows[0]._closedTabs.length,
|
||||
"Closed tab list has the expected length"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedTabs, FORGET),
|
||||
test_state.windows[0]._closedTabs.length - remember_count,
|
||||
"The correct amout of tabs are to be forgotten"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedTabs, REMEMBER),
|
||||
remember_count,
|
||||
"Everything is set up"
|
||||
);
|
||||
|
||||
// All of the following calls with illegal arguments should throw NS_ERROR_ILLEGAL_VALUE.
|
||||
ok(
|
||||
testForError(() => ss.forgetClosedTab({}, 0)),
|
||||
"Invalid window for forgetClosedTab throws"
|
||||
);
|
||||
ok(
|
||||
testForError(() => ss.forgetClosedTab(newWin, -1)),
|
||||
"Invalid tab for forgetClosedTab throws"
|
||||
);
|
||||
ok(
|
||||
testForError(() =>
|
||||
ss.forgetClosedTab(newWin, test_state.windows[0]._closedTabs.length + 1)
|
||||
),
|
||||
"Invalid tab for forgetClosedTab throws"
|
||||
);
|
||||
|
||||
// Remove third tab, then first tab.
|
||||
ss.forgetClosedTab(newWin, 2);
|
||||
ss.forgetClosedTab(newWin, null);
|
||||
|
||||
closedTabs = SessionStore.getClosedTabDataForWindow(newWin);
|
||||
|
||||
// Verify that non JSON serialized data is the same as JSON serialized data.
|
||||
is(
|
||||
JSON.stringify(closedTabs),
|
||||
JSON.stringify(SessionStore.getClosedTabDataForWindow(newWin)),
|
||||
"Non-serialized data is the same as serialized data"
|
||||
);
|
||||
|
||||
is(
|
||||
closedTabs.length,
|
||||
remember_count,
|
||||
"The correct amout of tabs was removed"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedTabs, FORGET),
|
||||
0,
|
||||
"All tabs specifically forgotten were indeed removed"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedTabs, REMEMBER),
|
||||
remember_count,
|
||||
"... and tabs not specifically forgetten weren't"
|
||||
);
|
||||
|
||||
// Clean up.
|
||||
Services.prefs.clearUserPref("browser.sessionstore.max_tabs_undo");
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
});
|
||||
53
src/zen/tests/mochitests/sessionstore/browser_461743.js
Normal file
53
src/zen/tests/mochitests/sessionstore/browser_461743.js
Normal file
@@ -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/. */
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 461743 */
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let testURL =
|
||||
"http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_461743_sample.html";
|
||||
|
||||
let frameCount = 0;
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, testURL);
|
||||
tab.linkedBrowser.addEventListener(
|
||||
"load",
|
||||
function loadListener(aEvent) {
|
||||
// Wait for all frames to load completely.
|
||||
if (frameCount++ < 2) {
|
||||
return;
|
||||
}
|
||||
tab.linkedBrowser.removeEventListener("load", loadListener, true);
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener(
|
||||
"461743",
|
||||
function listener() {
|
||||
tab2.linkedBrowser.removeEventListener("461743", listener, true);
|
||||
is(aEvent.data, "done", "XSS injection was attempted");
|
||||
|
||||
executeSoon(function () {
|
||||
let iframes = tab2.linkedBrowser.contentWindow.frames;
|
||||
let innerHTML = iframes[1].document.body.innerHTML;
|
||||
isnot(
|
||||
innerHTML,
|
||||
Cu.reportError.toString(),
|
||||
"chrome access denied!"
|
||||
);
|
||||
|
||||
// Clean up.
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
finish();
|
||||
});
|
||||
},
|
||||
true,
|
||||
true
|
||||
);
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<!-- Testcase originally by <moz_bug_r_a4@yahoo.com> -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<title>Test for bug 461743</title>
|
||||
|
||||
<body>
|
||||
<iframe src="data:text/html;charset=utf-8,empty"></iframe>
|
||||
<iframe></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
var chromeUrl = "chrome://global/content/mozilla.html";
|
||||
var exploitUrl = "javascript:try { document.body.innerHTML = Components.utils.reportError; } catch (ex) { }";
|
||||
|
||||
var loadCount = 0;
|
||||
frames[0].addEventListener("DOMContentLoaded", handleLoad);
|
||||
frames[1].addEventListener("DOMContentLoaded", handleLoad);
|
||||
function handleLoad() {
|
||||
if (++loadCount < 2)
|
||||
return;
|
||||
frames[0].removeEventListener("DOMContentLoaded", handleLoad);
|
||||
frames[1].removeEventListener("DOMContentLoaded", handleLoad);
|
||||
|
||||
var flip = 0;
|
||||
MutationEvent.prototype.toString = function() {
|
||||
return flip++ == 0 ? chromeUrl : exploitUrl;
|
||||
};
|
||||
|
||||
var href = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(frames[1].location), "href").get;
|
||||
var loadChrome = { handleEvent: href };
|
||||
var loadExploit = { handleEvent: href };
|
||||
|
||||
function delay() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", location.href, false);
|
||||
xhr.send(null);
|
||||
}
|
||||
function done() {
|
||||
var event = new MessageEvent("461743", { bubbles: true, cancelable: false,
|
||||
data: "done", origin: location.href,
|
||||
source: window });
|
||||
document.dispatchEvent(event);
|
||||
frames[0].document.removeEventListener("DOMNodeInserted", loadChrome, true);
|
||||
frames[0].document.removeEventListener("DOMNodeInserted", delay, true);
|
||||
frames[0].document.removeEventListener("DOMNodeInserted", loadExploit, true);
|
||||
frames[0].document.removeEventListener("DOMNodeInserted", done, true);
|
||||
}
|
||||
|
||||
frames[0].document.addEventListener("DOMNodeInserted", loadChrome, true);
|
||||
frames[0].document.addEventListener("DOMNodeInserted", delay, true);
|
||||
frames[0].document.addEventListener("DOMNodeInserted", loadExploit, true);
|
||||
frames[0].document.addEventListener("DOMNodeInserted", done, true);
|
||||
|
||||
frames[0].document.designMode = "on";
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
40
src/zen/tests/mochitests/sessionstore/browser_463205.js
Normal file
40
src/zen/tests/mochitests/sessionstore/browser_463205.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const URL = ROOT + "browser_463205_sample.html";
|
||||
|
||||
/**
|
||||
* Bug 463205 - Check URLs before restoring form data to make sure a malicious
|
||||
* website can't modify frame URLs and make us inject form data into the wrong
|
||||
* web pages.
|
||||
*/
|
||||
add_task(async function test_check_urls_before_restoring() {
|
||||
// Add a blank tab.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:blank");
|
||||
let browser = tab.linkedBrowser;
|
||||
await BrowserTestUtils.browserLoaded(browser, { wantLoad: "about:blank" });
|
||||
|
||||
// Restore form data with a valid URL.
|
||||
await promiseTabState(tab, getState(URL));
|
||||
|
||||
let value = await getPropertyOfFormField(browser, "#text", "value");
|
||||
is(value, "foobar", "value was restored");
|
||||
|
||||
// Restore form data with an invalid URL.
|
||||
await promiseTabState(tab, getState("http://example.com/"));
|
||||
|
||||
value = await getPropertyOfFormField(browser, "#text", "value");
|
||||
is(value, "", "value was not restored");
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
function getState(url) {
|
||||
return JSON.stringify({
|
||||
entries: [{ url: URL, triggeringPrincipal_base64 }],
|
||||
formdata: { url, id: { text: "foobar" } },
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>bug 463205</title>
|
||||
|
||||
<body>
|
||||
<input type="text" id="text" />
|
||||
</body>
|
||||
120
src/zen/tests/mochitests/sessionstore/browser_463206.js
Normal file
120
src/zen/tests/mochitests/sessionstore/browser_463206.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const MOCHI_ROOT = ROOT.replace(
|
||||
"chrome://mochitests/content/",
|
||||
"http://mochi.test:8888/"
|
||||
);
|
||||
if (gFissionBrowser) {
|
||||
addCoopTask(
|
||||
"browser_463206_sample.html",
|
||||
test_restore_text_data_subframes,
|
||||
HTTPSROOT
|
||||
);
|
||||
}
|
||||
addNonCoopTask(
|
||||
"browser_463206_sample.html",
|
||||
test_restore_text_data_subframes,
|
||||
HTTPSROOT
|
||||
);
|
||||
addNonCoopTask(
|
||||
"browser_463206_sample.html",
|
||||
test_restore_text_data_subframes,
|
||||
HTTPROOT
|
||||
);
|
||||
addNonCoopTask(
|
||||
"browser_463206_sample.html",
|
||||
test_restore_text_data_subframes,
|
||||
MOCHI_ROOT
|
||||
);
|
||||
|
||||
async function test_restore_text_data_subframes(aURL) {
|
||||
// Add a new tab.
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, aURL);
|
||||
|
||||
await setPropertyOfFormField(
|
||||
tab.linkedBrowser,
|
||||
"#out1",
|
||||
"value",
|
||||
Date.now().toString(16)
|
||||
);
|
||||
|
||||
await setPropertyOfFormField(
|
||||
tab.linkedBrowser,
|
||||
"input[name='1|#out2']",
|
||||
"value",
|
||||
Math.random()
|
||||
);
|
||||
|
||||
await setPropertyOfFormField(
|
||||
tab.linkedBrowser.browsingContext.children[0].children[1],
|
||||
"#in1",
|
||||
"value",
|
||||
new Date()
|
||||
);
|
||||
|
||||
// Duplicate the tab.
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
let browser2 = tab2.linkedBrowser;
|
||||
await promiseTabRestored(tab2);
|
||||
|
||||
isnot(
|
||||
await getPropertyOfFormField(browser2, "#out1", "value"),
|
||||
await getPropertyOfFormField(
|
||||
browser2.browsingContext.children[1],
|
||||
"#out1",
|
||||
"value"
|
||||
),
|
||||
"text isn't reused for frames"
|
||||
);
|
||||
|
||||
isnot(
|
||||
await getPropertyOfFormField(browser2, "input[name='1|#out2']", "value"),
|
||||
"",
|
||||
"text containing | and # is correctly restored"
|
||||
);
|
||||
|
||||
is(
|
||||
await getPropertyOfFormField(
|
||||
browser2.browsingContext.children[1],
|
||||
"#out2",
|
||||
"value"
|
||||
),
|
||||
"",
|
||||
"id prefixes can't be faked"
|
||||
);
|
||||
|
||||
// Query a few values from the top and its child frames.
|
||||
await SpecialPowers.spawn(tab2.linkedBrowser, [], async function () {
|
||||
// Bug 588077
|
||||
// XXX(farre): disabling this, because it started passing more heavily on Windows.
|
||||
/*
|
||||
let in1ValFrame0_1 = await SpecialPowers.spawn(
|
||||
content.frames[0],
|
||||
[],
|
||||
async function() {
|
||||
return SpecialPowers.spawn(content.frames[1], [], async function() {
|
||||
return content.document.getElementById("in1").value;
|
||||
});
|
||||
}
|
||||
);
|
||||
todo_is(in1ValFrame0_1, "", "id prefixes aren't mixed up");
|
||||
*/
|
||||
});
|
||||
|
||||
is(
|
||||
await getPropertyOfFormField(
|
||||
browser2.browsingContext.children[1].children[0],
|
||||
"#in1",
|
||||
"value"
|
||||
),
|
||||
"",
|
||||
"id prefixes aren't mixed up"
|
||||
);
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<!-- Testcase originally by <moz_bug_r_a4@yahoo.com> -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for bug 463206</title>
|
||||
|
||||
<iframe src="data:text/html;charset=utf-8,<iframe></iframe><iframe%20src='data:text/html;charset=utf-8,<input%2520id=%2522in1%2522>'></iframe>"></iframe>
|
||||
<iframe src="data:text/html;charset=utf-8,<input%20id='out1'><input%20id='out2'><iframe%20src='data:text/html;charset=utf-8,<input%2520id=%2522in1%2522>'>"></iframe>
|
||||
|
||||
<input id="out1">
|
||||
<input name="1|#out2">
|
||||
176
src/zen/tests/mochitests/sessionstore/browser_464199.js
Normal file
176
src/zen/tests/mochitests/sessionstore/browser_464199.js
Normal file
@@ -0,0 +1,176 @@
|
||||
/* 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/. */
|
||||
|
||||
let { ForgetAboutSite } = ChromeUtils.importESModule(
|
||||
"moz-src:///toolkit/components/forgetaboutsite/ForgetAboutSite.sys.mjs"
|
||||
);
|
||||
|
||||
function promiseClearHistory() {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe() {
|
||||
Services.obs.removeObserver(
|
||||
this,
|
||||
"browser:purge-session-history-for-domain"
|
||||
);
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
Services.obs.addObserver(
|
||||
observer,
|
||||
"browser:purge-session-history-for-domain"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function () {
|
||||
/** Test for Bug 464199 */
|
||||
|
||||
const REMEMBER = Date.now(),
|
||||
FORGET = Math.random();
|
||||
let test_state = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [{ entries: [] }],
|
||||
_closedTabs: [
|
||||
{
|
||||
state: { entries: [{ url: "http://www.example.net/" }] },
|
||||
title: FORGET,
|
||||
},
|
||||
{
|
||||
state: { entries: [{ url: "http://www.example.org/" }] },
|
||||
title: REMEMBER,
|
||||
},
|
||||
{
|
||||
state: {
|
||||
entries: [
|
||||
{ url: "http://www.example.net/" },
|
||||
{ url: "http://www.example.org/" },
|
||||
],
|
||||
},
|
||||
title: FORGET,
|
||||
},
|
||||
{
|
||||
state: { entries: [{ url: "http://example.net/" }] },
|
||||
title: FORGET,
|
||||
},
|
||||
{
|
||||
state: { entries: [{ url: "http://sub.example.net/" }] },
|
||||
title: FORGET,
|
||||
},
|
||||
{
|
||||
state: { entries: [{ url: "http://www.example.net:8080/" }] },
|
||||
title: FORGET,
|
||||
},
|
||||
{ state: { entries: [{ url: "about:license" }] }, title: REMEMBER },
|
||||
{
|
||||
state: {
|
||||
entries: [
|
||||
{
|
||||
url: "http://www.example.org/frameset",
|
||||
children: [
|
||||
{ url: "http://www.example.org/frame" },
|
||||
{ url: "http://www.example.org:8080/frame2" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
title: REMEMBER,
|
||||
},
|
||||
{
|
||||
state: {
|
||||
entries: [
|
||||
{
|
||||
url: "http://www.example.org/frameset",
|
||||
children: [
|
||||
{ url: "http://www.example.org/frame" },
|
||||
{ url: "http://www.example.net/frame" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
title: FORGET,
|
||||
},
|
||||
{
|
||||
state: {
|
||||
entries: [
|
||||
{
|
||||
url: "http://www.example.org/form",
|
||||
formdata: { id: { url: "http://www.example.net/" } },
|
||||
},
|
||||
],
|
||||
},
|
||||
title: REMEMBER,
|
||||
},
|
||||
{
|
||||
state: {
|
||||
entries: [{ url: "http://www.example.org/form" }],
|
||||
extData: { setCustomTabValue: "http://example.net:80" },
|
||||
},
|
||||
title: REMEMBER,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
let remember_count = 5;
|
||||
|
||||
function countByTitle(aClosedTabList, aTitle) {
|
||||
return aClosedTabList.filter(aData => aData.title == aTitle).length;
|
||||
}
|
||||
|
||||
// open a window and add the above closed tab list
|
||||
let newWin = openDialog(location, "", "chrome,all,dialog=no");
|
||||
await promiseWindowLoaded(newWin);
|
||||
Services.prefs.setIntPref(
|
||||
"browser.sessionstore.max_tabs_undo",
|
||||
test_state.windows[0]._closedTabs.length
|
||||
);
|
||||
|
||||
let restoring = promiseWindowRestoring(newWin);
|
||||
let restored = promiseWindowRestored(newWin);
|
||||
ss.setWindowState(newWin, JSON.stringify(test_state), true);
|
||||
await restoring;
|
||||
await restored;
|
||||
|
||||
let closedTabs = ss.getClosedTabDataForWindow(newWin);
|
||||
is(
|
||||
closedTabs.length,
|
||||
test_state.windows[0]._closedTabs.length,
|
||||
"Closed tab list has the expected length"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedTabs, FORGET),
|
||||
test_state.windows[0]._closedTabs.length - remember_count,
|
||||
"The correct amout of tabs are to be forgotten"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedTabs, REMEMBER),
|
||||
remember_count,
|
||||
"Everything is set up."
|
||||
);
|
||||
|
||||
let promise = promiseClearHistory();
|
||||
await ForgetAboutSite.removeDataFromBaseDomain("example.net");
|
||||
await promise;
|
||||
closedTabs = ss.getClosedTabDataForWindow(newWin);
|
||||
is(
|
||||
closedTabs.length,
|
||||
remember_count,
|
||||
"The correct amout of tabs was removed"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedTabs, FORGET),
|
||||
0,
|
||||
"All tabs to be forgotten were indeed removed"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedTabs, REMEMBER),
|
||||
remember_count,
|
||||
"... and tabs to be remembered weren't."
|
||||
);
|
||||
// clean up
|
||||
Services.prefs.clearUserPref("browser.sessionstore.max_tabs_undo");
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
});
|
||||
54
src/zen/tests/mochitests/sessionstore/browser_464620_a.html
Normal file
54
src/zen/tests/mochitests/sessionstore/browser_464620_a.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<!-- Testcase originally by <moz_bug_r_a4@yahoo.com> -->
|
||||
|
||||
<title>Test for bug 464620 (injection on input)</title>
|
||||
|
||||
<iframe></iframe>
|
||||
<iframe onload="setup()"></iframe>
|
||||
|
||||
<script>
|
||||
var targetUrl = "http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_464620_xd.html";
|
||||
var firstPass;
|
||||
|
||||
function setup() {
|
||||
if (firstPass !== undefined)
|
||||
return;
|
||||
firstPass = frames[1].location.href == "about:blank";
|
||||
if (firstPass) {
|
||||
frames[0].location = 'data:text/html;charset=utf-8,<body onload="if (parent.firstPass) parent.step();"><input id="x" oninput="parent.xss()">XXX</body>';
|
||||
}
|
||||
frames[1].location = targetUrl;
|
||||
}
|
||||
|
||||
function step() {
|
||||
var x = frames[0].document.getElementById("x");
|
||||
if (x.value == "")
|
||||
x.value = "ready";
|
||||
x.style.display = "none";
|
||||
frames[0].document.designMode = "on";
|
||||
}
|
||||
|
||||
function xss() {
|
||||
step();
|
||||
|
||||
var documentInjected = false;
|
||||
document.getElementsByTagName("iframe")[0].onload =
|
||||
function() { documentInjected = true; };
|
||||
frames[0].location = targetUrl;
|
||||
|
||||
for (var c = 0; !documentInjected && c < 20; c++) {
|
||||
var r = new XMLHttpRequest();
|
||||
r.open("GET", location.href, false);
|
||||
r.overrideMimeType("text/plain");
|
||||
r.send(null);
|
||||
}
|
||||
document.getElementById("state").textContent = "done";
|
||||
|
||||
var event = new MessageEvent("464620_a", { bubbles: true, cancelable: false,
|
||||
data: "done", origin: location.href,
|
||||
source: window });
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
</script>
|
||||
|
||||
<p id="state">pending</p>
|
||||
64
src/zen/tests/mochitests/sessionstore/browser_464620_a.js
Normal file
64
src/zen/tests/mochitests/sessionstore/browser_464620_a.js
Normal file
@@ -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/. */
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 464620 (injection on input) */
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let testURL =
|
||||
"http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_464620_a.html";
|
||||
|
||||
var frameCount = 0;
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, testURL);
|
||||
tab.linkedBrowser.addEventListener(
|
||||
"load",
|
||||
function loadListener(aEvent) {
|
||||
// wait for all frames to load completely
|
||||
if (frameCount++ < 4) {
|
||||
return;
|
||||
}
|
||||
this.removeEventListener("load", loadListener, true);
|
||||
|
||||
executeSoon(function () {
|
||||
frameCount = 0;
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener(
|
||||
"464620_a",
|
||||
function listener() {
|
||||
tab2.linkedBrowser.removeEventListener("464620_a", listener, true);
|
||||
is(aEvent.data, "done", "XSS injection was attempted");
|
||||
|
||||
// let form restoration complete and take into account the
|
||||
// setTimeout(..., 0) in sss_restoreDocument_proxy
|
||||
executeSoon(function () {
|
||||
setTimeout(function () {
|
||||
let win = tab2.linkedBrowser.contentWindow;
|
||||
isnot(
|
||||
win.frames[0].document.location,
|
||||
testURL,
|
||||
"cross domain document was loaded"
|
||||
);
|
||||
ok(
|
||||
!/XXX/.test(win.frames[0].document.body.innerHTML),
|
||||
"no content was injected"
|
||||
);
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
finish();
|
||||
}, 0);
|
||||
});
|
||||
},
|
||||
true,
|
||||
true
|
||||
);
|
||||
});
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
57
src/zen/tests/mochitests/sessionstore/browser_464620_b.html
Normal file
57
src/zen/tests/mochitests/sessionstore/browser_464620_b.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<!-- Testcase originally by <moz_bug_r_a4@yahoo.com> -->
|
||||
|
||||
<title>Test for bug 464620 (injection on DOM node insertion)</title>
|
||||
|
||||
<iframe></iframe>
|
||||
<iframe></iframe>
|
||||
<iframe onload="setup()"></iframe>
|
||||
|
||||
<script>
|
||||
var targetUrl = "http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_464620_xd.html";
|
||||
var firstPass;
|
||||
|
||||
function setup() {
|
||||
if (firstPass !== undefined)
|
||||
return;
|
||||
firstPass = frames[2].location.href == "about:blank";
|
||||
if (firstPass) {
|
||||
frames[0].location = 'data:text/html;charset=utf-8,<body onload="parent.step()">a</body>';
|
||||
frames[1].location = 'data:text/html;charset=utf-8,<body onload="document.designMode=\'on\';">XXX</body>';
|
||||
}
|
||||
frames[2].location = targetUrl;
|
||||
}
|
||||
|
||||
function step() {
|
||||
frames[0].document.designMode = "on";
|
||||
if (firstPass)
|
||||
return;
|
||||
|
||||
var body = frames[0].document.body;
|
||||
body.addEventListener("DOMNodeInserted", function() {
|
||||
xss();
|
||||
}, {capture: true, once: true});
|
||||
}
|
||||
|
||||
function xss() {
|
||||
var documentInjected = false;
|
||||
document.getElementsByTagName("iframe")[1].onload =
|
||||
function() { documentInjected = true; };
|
||||
frames[1].location = targetUrl;
|
||||
|
||||
for (var c = 0; !documentInjected && c < 20; c++) {
|
||||
var r = new XMLHttpRequest();
|
||||
r.open("GET", location.href, false);
|
||||
r.overrideMimeType("text/plain");
|
||||
r.send(null);
|
||||
}
|
||||
document.getElementById("state").textContent = "done";
|
||||
|
||||
var event = new MessageEvent("464620_b", { bubbles: true, cancelable: false,
|
||||
data: "done", origin: location.href,
|
||||
source: window });
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
</script>
|
||||
|
||||
<p id="state">pending</p>
|
||||
64
src/zen/tests/mochitests/sessionstore/browser_464620_b.js
Normal file
64
src/zen/tests/mochitests/sessionstore/browser_464620_b.js
Normal file
@@ -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/. */
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 464620 (injection on DOM node insertion) */
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let testURL =
|
||||
"http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_464620_b.html";
|
||||
|
||||
var frameCount = 0;
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, testURL);
|
||||
tab.linkedBrowser.addEventListener(
|
||||
"load",
|
||||
function loadListener(aEvent) {
|
||||
// wait for all frames to load completely
|
||||
if (frameCount++ < 6) {
|
||||
return;
|
||||
}
|
||||
this.removeEventListener("load", loadListener, true);
|
||||
|
||||
executeSoon(function () {
|
||||
frameCount = 0;
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener(
|
||||
"464620_b",
|
||||
function listener() {
|
||||
tab2.linkedBrowser.removeEventListener("464620_b", listener, true);
|
||||
is(aEvent.data, "done", "XSS injection was attempted");
|
||||
|
||||
// let form restoration complete and take into account the
|
||||
// setTimeout(..., 0) in sss_restoreDocument_proxy
|
||||
executeSoon(function () {
|
||||
setTimeout(function () {
|
||||
let win = tab2.linkedBrowser.contentWindow;
|
||||
isnot(
|
||||
win.frames[1].document.location,
|
||||
testURL,
|
||||
"cross domain document was loaded"
|
||||
);
|
||||
ok(
|
||||
!/XXX/.test(win.frames[1].document.body.innerHTML),
|
||||
"no content was injected"
|
||||
);
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
finish();
|
||||
}, 0);
|
||||
});
|
||||
},
|
||||
true,
|
||||
true
|
||||
);
|
||||
});
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<title>Cross Document File for bug 464620</title>
|
||||
|
||||
<body onload="document.designMode='on';" bgcolor="red">
|
||||
This document is editable.
|
||||
</body>
|
||||
38
src/zen/tests/mochitests/sessionstore/browser_465215.js
Normal file
38
src/zen/tests/mochitests/sessionstore/browser_465215.js
Normal file
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
|
||||
var uniqueName = "bug 465215";
|
||||
var uniqueValue1 = "as good as unique: " + Date.now();
|
||||
var uniqueValue2 = "as good as unique: " + Math.random();
|
||||
|
||||
add_task(async function () {
|
||||
// set a unique value on a new, blank tab
|
||||
let tab1 = BrowserTestUtils.addTab(gBrowser, "about:blank");
|
||||
await BrowserTestUtils.browserLoaded(tab1.linkedBrowser, {
|
||||
wantLoad: "about:blank",
|
||||
});
|
||||
ss.setCustomTabValue(tab1, uniqueName, uniqueValue1);
|
||||
|
||||
// duplicate the tab with that value
|
||||
let tab2 = ss.duplicateTab(window, tab1);
|
||||
await promiseTabRestored(tab2);
|
||||
is(
|
||||
ss.getCustomTabValue(tab2, uniqueName),
|
||||
uniqueValue1,
|
||||
"tab value was duplicated"
|
||||
);
|
||||
|
||||
ss.setCustomTabValue(tab2, uniqueName, uniqueValue2);
|
||||
isnot(
|
||||
ss.getCustomTabValue(tab1, uniqueName),
|
||||
uniqueValue2,
|
||||
"tab values aren't sync'd"
|
||||
);
|
||||
|
||||
// overwrite the tab with the value which should remove it
|
||||
await promiseTabState(tab1, { entries: [] });
|
||||
is(ss.getCustomTabValue(tab1, uniqueName), "", "tab value was cleared");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab1);
|
||||
});
|
||||
51
src/zen/tests/mochitests/sessionstore/browser_465223.js
Normal file
51
src/zen/tests/mochitests/sessionstore/browser_465223.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
add_task(async function test_clearWindowValues() {
|
||||
/** Test for Bug 465223 */
|
||||
|
||||
let uniqueKey1 = "bug 465223.1";
|
||||
let uniqueKey2 = "bug 465223.2";
|
||||
let uniqueValue1 = "unik" + Date.now();
|
||||
let uniqueValue2 = "pi != " + Math.random();
|
||||
|
||||
// open a window and set a value on it
|
||||
let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
|
||||
await promiseWindowLoaded(newWin);
|
||||
ss.setCustomWindowValue(newWin, uniqueKey1, uniqueValue1);
|
||||
|
||||
let newState = { windows: [{ tabs: [{ entries: [] }], extData: {} }] };
|
||||
newState.windows[0].extData[uniqueKey2] = uniqueValue2;
|
||||
await setWindowState(newWin, newState);
|
||||
|
||||
is(newWin.gBrowser.tabs.length, 2, "original tab wasn't overwritten");
|
||||
is(
|
||||
ss.getCustomWindowValue(newWin, uniqueKey1),
|
||||
uniqueValue1,
|
||||
"window value wasn't overwritten when the tabs weren't"
|
||||
);
|
||||
is(
|
||||
ss.getCustomWindowValue(newWin, uniqueKey2),
|
||||
uniqueValue2,
|
||||
"new window value was correctly added"
|
||||
);
|
||||
|
||||
newState.windows[0].extData[uniqueKey2] = uniqueValue1;
|
||||
await setWindowState(newWin, newState, true);
|
||||
|
||||
is(newWin.gBrowser.tabs.length, 1, "original tabs were overwritten");
|
||||
is(
|
||||
ss.getCustomWindowValue(newWin, uniqueKey1),
|
||||
"",
|
||||
"window value was cleared"
|
||||
);
|
||||
is(
|
||||
ss.getCustomWindowValue(newWin, uniqueKey2),
|
||||
uniqueValue1,
|
||||
"window value was correctly overwritten"
|
||||
);
|
||||
|
||||
// clean up
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
});
|
||||
51
src/zen/tests/mochitests/sessionstore/browser_466937.js
Normal file
51
src/zen/tests/mochitests/sessionstore/browser_466937.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const URL = ROOT + "browser_466937_sample.html";
|
||||
|
||||
/**
|
||||
* Bug 466937 - Prevent file stealing with sessionstore.
|
||||
*/
|
||||
add_task(async function test_prevent_file_stealing() {
|
||||
// Add a tab with some file input fields.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, URL);
|
||||
let browser = tab.linkedBrowser;
|
||||
await promiseBrowserLoaded(browser);
|
||||
|
||||
// Generate a path to a 'secret' file.
|
||||
let file = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
file.append("466937_test.file");
|
||||
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
|
||||
let testPath = file.path;
|
||||
|
||||
// Fill in form values.
|
||||
await setPropertyOfFormField(
|
||||
browser,
|
||||
"#reverse_thief",
|
||||
"value",
|
||||
"/home/user/secret2"
|
||||
);
|
||||
await setPropertyOfFormField(browser, "#bystander", "value", testPath);
|
||||
|
||||
// Duplicate and check form values.
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
let browser2 = tab2.linkedBrowser;
|
||||
await promiseTabRestored(tab2);
|
||||
|
||||
let thief = await getPropertyOfFormField(browser2, "#thief", "value");
|
||||
is(thief, "", "file path wasn't set to text field value");
|
||||
let reverse_thief = await getPropertyOfFormField(
|
||||
browser2,
|
||||
"#reverse_thief",
|
||||
"value"
|
||||
);
|
||||
is(reverse_thief, "", "text field value wasn't set to full file path");
|
||||
let bystander = await getPropertyOfFormField(browser2, "#bystander", "value");
|
||||
is(bystander, testPath, "normal case: file path was correctly preserved");
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab);
|
||||
gBrowser.removeTab(tab2);
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
<!-- Testcase originally by <moz_bug_r_a4@yahoo.com> -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for bug 466937</title>
|
||||
|
||||
<input id="thief" value="/home/user/secret">
|
||||
<input type="file" id="reverse_thief">
|
||||
<input type="file" id="bystander">
|
||||
|
||||
<script>
|
||||
window.addEventListener("DOMContentLoaded", function() {
|
||||
if (!document.location.hash) {
|
||||
document.location.hash = "#ready";
|
||||
} else {
|
||||
document.getElementById("thief").type = "file";
|
||||
document.getElementById("reverse_thief").type = "text";
|
||||
}
|
||||
}, {once: true});
|
||||
</script>
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test Summary:
|
||||
// 1. Open about:sessionrestore where formdata is a JS object, not a string
|
||||
// 1a. Check that #sessionData on the page is readable after JSON.parse (skipped, checking formdata is sufficient)
|
||||
// 1b. Check that there are no backslashes in the formdata
|
||||
// 1c. Check that formdata doesn't require JSON.parse
|
||||
//
|
||||
// 2. Use the current state (currently about:sessionrestore with data) and then open that in a new instance of about:sessionrestore
|
||||
// 2a. Check that there are no backslashes in the formdata
|
||||
// 2b. Check that formdata doesn't require JSON.parse
|
||||
//
|
||||
// 3. [backwards compat] Use a stringified state as formdata when opening about:sessionrestore
|
||||
// 3a. Make sure there are nodes in the tree on about:sessionrestore (skipped, checking formdata is sufficient)
|
||||
// 3b. Check that there are no backslashes in the formdata
|
||||
// 3c. Check that formdata doesn't require JSON.parse
|
||||
|
||||
const CRASH_STATE = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{ entries: [{ url: "about:mozilla", triggeringPrincipal_base64 }] },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const STATE = createEntries(CRASH_STATE);
|
||||
const STATE2 = createEntries({ windows: [{ tabs: [STATE] }] });
|
||||
const STATE3 = createEntries(JSON.stringify(CRASH_STATE));
|
||||
|
||||
function createEntries(sessionData) {
|
||||
return {
|
||||
entries: [{ url: "about:sessionrestore", triggeringPrincipal_base64 }],
|
||||
formdata: { id: { sessionData }, url: "about:sessionrestore" },
|
||||
};
|
||||
}
|
||||
|
||||
add_task(async function test_nested_about_sessionrestore() {
|
||||
// Prepare a blank tab.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:blank");
|
||||
let browser = tab.linkedBrowser;
|
||||
await BrowserTestUtils.browserLoaded(browser, { wantLoad: "about:blank" });
|
||||
|
||||
// test 1
|
||||
await promiseTabState(tab, STATE);
|
||||
await checkState("test1", tab);
|
||||
|
||||
// test 2
|
||||
await promiseTabState(tab, STATE2);
|
||||
await checkState("test2", tab);
|
||||
|
||||
// test 3
|
||||
await promiseTabState(tab, STATE3);
|
||||
await checkState("test3", tab);
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
async function checkState(prefix, tab) {
|
||||
// Flush and query tab state.
|
||||
await TabStateFlusher.flush(tab.linkedBrowser);
|
||||
let { formdata } = JSON.parse(ss.getTabState(tab));
|
||||
|
||||
ok(
|
||||
formdata.id.sessionData,
|
||||
prefix + ": we have form data for about:sessionrestore"
|
||||
);
|
||||
|
||||
let sessionData_raw = JSON.stringify(formdata.id.sessionData);
|
||||
ok(
|
||||
!/\\/.test(sessionData_raw),
|
||||
prefix + ": #sessionData contains no backslashes"
|
||||
);
|
||||
info(sessionData_raw);
|
||||
|
||||
let gotError = false;
|
||||
try {
|
||||
JSON.parse(formdata.id.sessionData);
|
||||
} catch (e) {
|
||||
info(prefix + ": got error: " + e);
|
||||
gotError = true;
|
||||
}
|
||||
ok(gotError, prefix + ": attempting to JSON.parse form data threw error");
|
||||
}
|
||||
80
src/zen/tests/mochitests/sessionstore/browser_477657.js
Normal file
80
src/zen/tests/mochitests/sessionstore/browser_477657.js
Normal file
@@ -0,0 +1,80 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
add_task(async function test_sizemodeDefaults() {
|
||||
/** Test for Bug 477657 */
|
||||
let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
|
||||
await promiseWindowLoaded(newWin);
|
||||
let newState = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [{ entries: [] }],
|
||||
_closedTabs: [
|
||||
{
|
||||
state: { entries: [{ url: "about:" }] },
|
||||
title: "About:",
|
||||
},
|
||||
],
|
||||
sizemode: "maximized",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let uniqueKey = "bug 477657";
|
||||
let uniqueValue = "unik" + Date.now();
|
||||
|
||||
ss.setCustomWindowValue(newWin, uniqueKey, uniqueValue);
|
||||
is(
|
||||
ss.getCustomWindowValue(newWin, uniqueKey),
|
||||
uniqueValue,
|
||||
"window value was set before the window was overwritten"
|
||||
);
|
||||
|
||||
await setWindowState(newWin, newState, true);
|
||||
// use newWin.setTimeout(..., 0) to mirror sss_restoreWindowFeatures
|
||||
await new Promise(resolve => newWin.setTimeout(resolve, 0));
|
||||
|
||||
is(
|
||||
ss.getCustomWindowValue(newWin, uniqueKey),
|
||||
"",
|
||||
"window value was implicitly cleared"
|
||||
);
|
||||
|
||||
is(newWin.windowState, newWin.STATE_MAXIMIZED, "the window was maximized");
|
||||
|
||||
is(
|
||||
ss.getClosedTabDataForWindow(newWin).length,
|
||||
1,
|
||||
"the closed tab was added before the window was overwritten"
|
||||
);
|
||||
delete newState.windows[0]._closedTabs;
|
||||
delete newState.windows[0].sizemode;
|
||||
|
||||
await setWindowState(newWin, newState, true);
|
||||
await new Promise(resolve => newWin.setTimeout(resolve, 0));
|
||||
|
||||
is(
|
||||
ss.getClosedTabDataForWindow(newWin).length,
|
||||
0,
|
||||
"closed tabs were implicitly cleared"
|
||||
);
|
||||
|
||||
is(
|
||||
newWin.windowState,
|
||||
newWin.STATE_MAXIMIZED,
|
||||
"the window remains maximized"
|
||||
);
|
||||
newState.windows[0].sizemode = "normal";
|
||||
|
||||
await setWindowState(newWin, newState, true);
|
||||
await new Promise(resolve => newWin.setTimeout(resolve, 0));
|
||||
|
||||
isnot(
|
||||
newWin.windowState,
|
||||
newWin.STATE_MAXIMIZED,
|
||||
"the window was explicitly unmaximized"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
});
|
||||
45
src/zen/tests/mochitests/sessionstore/browser_480893.js
Normal file
45
src/zen/tests/mochitests/sessionstore/browser_480893.js
Normal file
@@ -0,0 +1,45 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests that we get sent to the right page when the user clicks
|
||||
* the "Close" button in about:sessionrestore
|
||||
*/
|
||||
add_task(async function () {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.startup.page", 0]],
|
||||
});
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:sessionrestore");
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
await BrowserTestUtils.browserLoaded(browser, false, "about:sessionrestore");
|
||||
|
||||
let doc = browser.contentDocument;
|
||||
|
||||
// Click on the "Close" button after about:sessionrestore is loaded.
|
||||
doc.getElementById("errorCancel").click();
|
||||
|
||||
await BrowserTestUtils.browserLoaded(browser, false, "about:blank");
|
||||
|
||||
// Test that starting a new session loads the homepage (set to http://mochi.test:8888)
|
||||
// if Firefox is configured to display a homepage at startup (browser.startup.page = 1)
|
||||
let homepage = "http://mochi.test:8888/";
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.startup.homepage", homepage],
|
||||
["browser.startup.page", 1],
|
||||
],
|
||||
});
|
||||
|
||||
BrowserTestUtils.startLoadingURIString(browser, "about:sessionrestore");
|
||||
await BrowserTestUtils.browserLoaded(browser, false, "about:sessionrestore");
|
||||
doc = browser.contentDocument;
|
||||
|
||||
// Click on the "Close" button after about:sessionrestore is loaded.
|
||||
doc.getElementById("errorCancel").click();
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
is(browser.currentURI.spec, homepage, "loaded page is the homepage");
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
76
src/zen/tests/mochitests/sessionstore/browser_485482.js
Normal file
76
src/zen/tests/mochitests/sessionstore/browser_485482.js
Normal file
@@ -0,0 +1,76 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
if (gFissionBrowser) {
|
||||
addCoopTask(
|
||||
"browser_485482_sample.html",
|
||||
test_xpath_exp_for_strange_documents,
|
||||
HTTPSROOT
|
||||
);
|
||||
}
|
||||
addNonCoopTask(
|
||||
"browser_485482_sample.html",
|
||||
test_xpath_exp_for_strange_documents,
|
||||
ROOT
|
||||
);
|
||||
addNonCoopTask(
|
||||
"browser_485482_sample.html",
|
||||
test_xpath_exp_for_strange_documents,
|
||||
HTTPSROOT
|
||||
);
|
||||
addNonCoopTask(
|
||||
"browser_485482_sample.html",
|
||||
test_xpath_exp_for_strange_documents,
|
||||
HTTPROOT
|
||||
);
|
||||
|
||||
/**
|
||||
* Bug 485482 - Make sure that we produce valid XPath expressions even for very
|
||||
* weird HTML documents.
|
||||
*/
|
||||
async function test_xpath_exp_for_strange_documents(aURL) {
|
||||
// Load a page with weird tag names.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, aURL);
|
||||
let browser = tab.linkedBrowser;
|
||||
await promiseBrowserLoaded(browser);
|
||||
|
||||
// Fill in some values.
|
||||
let uniqueValue = Math.random();
|
||||
await setPropertyOfFormField(
|
||||
browser,
|
||||
"input[type=text]",
|
||||
"value",
|
||||
uniqueValue
|
||||
);
|
||||
await setPropertyOfFormField(
|
||||
browser,
|
||||
"input[type=checkbox]",
|
||||
"checked",
|
||||
true
|
||||
);
|
||||
|
||||
// Duplicate the tab.
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
let browser2 = tab2.linkedBrowser;
|
||||
await promiseTabRestored(tab2);
|
||||
|
||||
// Check that we generated valid XPath expressions to restore form values.
|
||||
let text = await getPropertyOfFormField(
|
||||
browser2,
|
||||
"input[type=text]",
|
||||
"value"
|
||||
);
|
||||
is("" + text, "" + uniqueValue, "generated XPath expression was valid");
|
||||
let checkbox = await getPropertyOfFormField(
|
||||
browser2,
|
||||
"input[type=checkbox]",
|
||||
"checked"
|
||||
);
|
||||
ok(checkbox, "generated XPath expression was valid");
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<title>Test for bug 485482</title>
|
||||
|
||||
<bad=name>
|
||||
<input type="text">
|
||||
</bad=name>
|
||||
|
||||
<worse=name>
|
||||
<l0c@l+na~e"'<27>>
|
||||
<input type="checkbox" name="check"> Check
|
||||
</l0c@l+na~e"'<27>>
|
||||
</worse=name>
|
||||
35
src/zen/tests/mochitests/sessionstore/browser_485563.js
Normal file
35
src/zen/tests/mochitests/sessionstore/browser_485563.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/* 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() {
|
||||
/** Test for Bug 485563 */
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let uniqueValue =
|
||||
Math.random() + "\u2028Second line\u2029Second paragraph\u2027";
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser);
|
||||
BrowserTestUtils.browserLoaded(tab.linkedBrowser, {
|
||||
wantLoad: "about:blank",
|
||||
}).then(() => {
|
||||
ss.setCustomTabValue(tab, "bug485563", uniqueValue);
|
||||
let tabState = JSON.parse(ss.getTabState(tab));
|
||||
is(
|
||||
tabState.extData.bug485563,
|
||||
uniqueValue,
|
||||
"unicode line separator wasn't over-encoded"
|
||||
);
|
||||
ss.deleteCustomTabValue(tab, "bug485563");
|
||||
ss.setTabState(tab, JSON.stringify(tabState));
|
||||
is(
|
||||
ss.getCustomTabValue(tab, "bug485563"),
|
||||
uniqueValue,
|
||||
"unicode line separator was correctly preserved"
|
||||
);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
107
src/zen/tests/mochitests/sessionstore/browser_490040.js
Normal file
107
src/zen/tests/mochitests/sessionstore/browser_490040.js
Normal file
@@ -0,0 +1,107 @@
|
||||
/* 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/. */
|
||||
|
||||
// Only windows with open tabs are restorable. Windows where a lone tab is
|
||||
// detached may have _closedTabs, but is left with just an empty tab.
|
||||
const STATES = [
|
||||
{
|
||||
shouldBeAdded: true,
|
||||
windowState: {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com",
|
||||
triggeringPrincipal_base64,
|
||||
title: "example.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
selected: 1,
|
||||
_closedTabs: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
shouldBeAdded: false,
|
||||
windowState: {
|
||||
windows: [
|
||||
{
|
||||
tabs: [{ entries: [] }],
|
||||
_closedTabs: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
shouldBeAdded: false,
|
||||
windowState: {
|
||||
windows: [
|
||||
{
|
||||
tabs: [{ entries: [] }],
|
||||
_closedTabs: [
|
||||
{
|
||||
state: {
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com",
|
||||
triggeringPrincipal_base64,
|
||||
index: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
shouldBeAdded: false,
|
||||
windowState: {
|
||||
windows: [
|
||||
{
|
||||
tabs: [{ entries: [] }],
|
||||
_closedTabs: [],
|
||||
extData: { keyname: "pi != " + Math.random() },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function test_bug_490040() {
|
||||
for (let state of STATES) {
|
||||
// Ensure we can store the window if needed.
|
||||
let startingClosedWindowCount = ss.getClosedWindowCount();
|
||||
await pushPrefs([
|
||||
"browser.sessionstore.max_windows_undo",
|
||||
startingClosedWindowCount + 1,
|
||||
]);
|
||||
|
||||
let curClosedWindowCount = ss.getClosedWindowCount();
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
await setWindowState(win, state.windowState, true);
|
||||
if (state.windowState.windows[0].tabs.length) {
|
||||
await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser, {
|
||||
wantLoad: () => true,
|
||||
});
|
||||
}
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
is(
|
||||
ss.getClosedWindowCount(),
|
||||
curClosedWindowCount + (state.shouldBeAdded ? 1 : 0),
|
||||
"That window should " +
|
||||
(state.shouldBeAdded ? "" : "not ") +
|
||||
"be restorable"
|
||||
);
|
||||
}
|
||||
});
|
||||
113
src/zen/tests/mochitests/sessionstore/browser_491168.js
Normal file
113
src/zen/tests/mochitests/sessionstore/browser_491168.js
Normal file
@@ -0,0 +1,113 @@
|
||||
"use strict";
|
||||
|
||||
const REFERRER1 = "http://example.org/?" + Date.now();
|
||||
const REFERRER2 = "http://example.org/?" + Math.random();
|
||||
const REFERRER3 = "http://example.org/?" + Math.random();
|
||||
|
||||
add_task(async function () {
|
||||
function getExpectedReferrer(referrer) {
|
||||
let defaultPolicy = Services.prefs.getIntPref(
|
||||
"network.http.referer.defaultPolicy"
|
||||
);
|
||||
Assert.greater(
|
||||
[2, 3].indexOf(defaultPolicy),
|
||||
-1,
|
||||
"default referrer policy should be either strict-origin-when-cross-origin(2) or no-referrer-when-downgrade(3)"
|
||||
);
|
||||
if (defaultPolicy == 2) {
|
||||
return referrer.match(/https?:\/\/[^\/]+\/?/i)[0];
|
||||
}
|
||||
return referrer;
|
||||
}
|
||||
|
||||
async function checkDocumentReferrer(referrer, msg) {
|
||||
await SpecialPowers.spawn(
|
||||
gBrowser.selectedBrowser,
|
||||
[{ referrer, msg }],
|
||||
async function (args) {
|
||||
Assert.equal(content.document.referrer, args.referrer, args.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let ReferrerInfo = Components.Constructor(
|
||||
"@mozilla.org/referrer-info;1",
|
||||
"nsIReferrerInfo",
|
||||
"init"
|
||||
);
|
||||
// Add a new tab.
|
||||
let tab = (gBrowser.selectedTab = BrowserTestUtils.addTab(
|
||||
gBrowser,
|
||||
"about:blank"
|
||||
));
|
||||
let browser = tab.linkedBrowser;
|
||||
await BrowserTestUtils.browserLoaded(browser, { wantLoad: "about:blank" });
|
||||
|
||||
// Load a new URI with a specific referrer.
|
||||
let referrerInfo1 = new ReferrerInfo(
|
||||
Ci.nsIReferrerInfo.EMPTY,
|
||||
true,
|
||||
Services.io.newURI(REFERRER1)
|
||||
);
|
||||
browser.loadURI(Services.io.newURI("http://example.org"), {
|
||||
referrerInfo: referrerInfo1,
|
||||
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({}),
|
||||
});
|
||||
await promiseBrowserLoaded(browser);
|
||||
|
||||
await TabStateFlusher.flush(browser);
|
||||
let tabState = JSON.parse(ss.getTabState(tab));
|
||||
let actualReferrerInfo = E10SUtils.deserializeReferrerInfo(
|
||||
tabState.entries[0].referrerInfo
|
||||
);
|
||||
is(
|
||||
actualReferrerInfo.originalReferrer.spec,
|
||||
REFERRER1,
|
||||
"Referrer retrieved via getTabState matches referrer set via loadURI."
|
||||
);
|
||||
|
||||
let referrerInfo2 = new ReferrerInfo(
|
||||
Ci.nsIReferrerInfo.EMPTY,
|
||||
true,
|
||||
Services.io.newURI(REFERRER2)
|
||||
);
|
||||
|
||||
tabState.entries[0].referrerInfo =
|
||||
E10SUtils.serializeReferrerInfo(referrerInfo2);
|
||||
await promiseTabState(tab, tabState);
|
||||
|
||||
await checkDocumentReferrer(
|
||||
getExpectedReferrer(REFERRER2),
|
||||
"document.referrer matches referrer set via setTabState using referrerInfo."
|
||||
);
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
// Restore the closed tab.
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
await promiseTabRestored(tab);
|
||||
|
||||
await checkDocumentReferrer(
|
||||
getExpectedReferrer(REFERRER2),
|
||||
"document.referrer is still correct after closing and reopening the tab."
|
||||
);
|
||||
|
||||
tabState.entries[0].referrerInfo = null;
|
||||
tabState.entries[0].referrer = REFERRER3;
|
||||
await promiseTabState(tab, tabState);
|
||||
|
||||
await checkDocumentReferrer(
|
||||
getExpectedReferrer(REFERRER3),
|
||||
"document.referrer matches referrer set via setTabState using referrer."
|
||||
);
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
// Restore the closed tab.
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
await promiseTabRestored(tab);
|
||||
|
||||
await checkDocumentReferrer(
|
||||
getExpectedReferrer(REFERRER3),
|
||||
"document.referrer is still correct after closing and reopening the tab."
|
||||
);
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
212
src/zen/tests/mochitests/sessionstore/browser_491577.js
Normal file
212
src/zen/tests/mochitests/sessionstore/browser_491577.js
Normal file
@@ -0,0 +1,212 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
add_task(async function test_deleteClosedWindow() {
|
||||
/** Test for Bug 491577 */
|
||||
|
||||
const REMEMBER = Date.now(),
|
||||
FORGET = Math.random();
|
||||
let test_state = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{ url: "http://example.com/", triggeringPrincipal_base64 },
|
||||
],
|
||||
},
|
||||
],
|
||||
selected: 1,
|
||||
},
|
||||
],
|
||||
_closedWindows: [
|
||||
// _closedWindows[0]
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com/",
|
||||
triggeringPrincipal_base64,
|
||||
title: "title",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://mozilla.org/",
|
||||
triggeringPrincipal_base64,
|
||||
title: "title",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
selected: 2,
|
||||
title: FORGET,
|
||||
_closedTabs: [],
|
||||
},
|
||||
// _closedWindows[1]
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://mozilla.org/",
|
||||
triggeringPrincipal_base64,
|
||||
title: "title",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com/",
|
||||
triggeringPrincipal_base64,
|
||||
title: "title",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://mozilla.org/",
|
||||
triggeringPrincipal_base64,
|
||||
title: "title",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
selected: 3,
|
||||
title: REMEMBER,
|
||||
_closedTabs: [],
|
||||
},
|
||||
// _closedWindows[2]
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com/",
|
||||
triggeringPrincipal_base64,
|
||||
title: "title",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
selected: 1,
|
||||
title: FORGET,
|
||||
_closedTabs: [
|
||||
{
|
||||
state: {
|
||||
entries: [
|
||||
{
|
||||
url: "http://mozilla.org/",
|
||||
triggeringPrincipal_base64,
|
||||
title: "title",
|
||||
},
|
||||
{
|
||||
url: "http://mozilla.org/again",
|
||||
triggeringPrincipal_base64,
|
||||
title: "title",
|
||||
},
|
||||
],
|
||||
},
|
||||
pos: 1,
|
||||
title: "title",
|
||||
},
|
||||
{
|
||||
state: {
|
||||
entries: [
|
||||
{
|
||||
url: "http://example.com",
|
||||
triggeringPrincipal_base64,
|
||||
title: "title",
|
||||
},
|
||||
],
|
||||
},
|
||||
title: "title",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
let remember_count = 1;
|
||||
|
||||
function countByTitle(aClosedWindowList, aTitle) {
|
||||
return aClosedWindowList.filter(aData => aData.title == aTitle).length;
|
||||
}
|
||||
|
||||
function testForError(aFunction) {
|
||||
try {
|
||||
aFunction();
|
||||
return false;
|
||||
} catch (ex) {
|
||||
return ex.name == "NS_ERROR_ILLEGAL_VALUE";
|
||||
}
|
||||
}
|
||||
|
||||
// open a window and add the above closed window list
|
||||
let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
|
||||
await promiseWindowLoaded(newWin);
|
||||
Services.prefs.setIntPref(
|
||||
"browser.sessionstore.max_windows_undo",
|
||||
test_state._closedWindows.length
|
||||
);
|
||||
await setWindowState(newWin, test_state, true);
|
||||
|
||||
let closedWindows = ss.getClosedWindowData();
|
||||
is(
|
||||
closedWindows.length,
|
||||
test_state._closedWindows.length,
|
||||
"Closed window list has the expected length"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedWindows, FORGET),
|
||||
test_state._closedWindows.length - remember_count,
|
||||
"The correct amount of windows are to be forgotten"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedWindows, REMEMBER),
|
||||
remember_count,
|
||||
"Everything is set up."
|
||||
);
|
||||
|
||||
// all of the following calls with illegal arguments should throw NS_ERROR_ILLEGAL_VALUE
|
||||
ok(
|
||||
testForError(() => ss.forgetClosedWindow(-1)),
|
||||
"Invalid window for forgetClosedWindow throws"
|
||||
);
|
||||
ok(
|
||||
testForError(() =>
|
||||
ss.forgetClosedWindow(test_state._closedWindows.length + 1)
|
||||
),
|
||||
"Invalid window for forgetClosedWindow throws"
|
||||
);
|
||||
|
||||
// Remove third window, then first window
|
||||
ss.forgetClosedWindow(2);
|
||||
ss.forgetClosedWindow(null);
|
||||
|
||||
closedWindows = ss.getClosedWindowData();
|
||||
is(
|
||||
closedWindows.length,
|
||||
remember_count,
|
||||
"The correct amount of windows were removed"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedWindows, FORGET),
|
||||
0,
|
||||
"All windows specifically forgotten were indeed removed"
|
||||
);
|
||||
is(
|
||||
countByTitle(closedWindows, REMEMBER),
|
||||
remember_count,
|
||||
"... and windows not specifically forgetten weren't."
|
||||
);
|
||||
|
||||
// clean up
|
||||
Services.prefs.clearUserPref("browser.sessionstore.max_windows_undo");
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
});
|
||||
47
src/zen/tests/mochitests/sessionstore/browser_495495.js
Normal file
47
src/zen/tests/mochitests/sessionstore/browser_495495.js
Normal file
@@ -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/. */
|
||||
|
||||
add_task(async function test_urlbarFocus() {
|
||||
/** Test for Bug 495495 */
|
||||
|
||||
let newWin = openDialog(
|
||||
location,
|
||||
"_blank",
|
||||
"chrome,all,dialog=no,toolbar=yes"
|
||||
);
|
||||
await promiseWindowLoaded(newWin);
|
||||
let state1 = ss.getWindowState(newWin);
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
|
||||
newWin = openDialog(
|
||||
location,
|
||||
"_blank",
|
||||
"chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar=no,location,personal,directories,dialog=no"
|
||||
);
|
||||
await promiseWindowLoaded(newWin);
|
||||
let state2 = ss.getWindowState(newWin);
|
||||
|
||||
async function testState(state, expected) {
|
||||
let win = openDialog(location, "_blank", "chrome,all,dialog=no");
|
||||
await promiseWindowLoaded(win);
|
||||
|
||||
is(
|
||||
win.gURLBar.readOnly,
|
||||
false,
|
||||
"URL bar should not be read-only before setting the state"
|
||||
);
|
||||
await setWindowState(win, state, true);
|
||||
is(
|
||||
win.gURLBar.readOnly,
|
||||
expected.readOnly,
|
||||
"URL bar read-only state should be restored correctly"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
}
|
||||
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
await testState(state1, { readOnly: false });
|
||||
await testState(state2, { readOnly: true });
|
||||
});
|
||||
132
src/zen/tests/mochitests/sessionstore/browser_500328.js
Normal file
132
src/zen/tests/mochitests/sessionstore/browser_500328.js
Normal file
@@ -0,0 +1,132 @@
|
||||
/* 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/. */
|
||||
|
||||
async function checkState(browser) {
|
||||
await SpecialPowers.spawn(browser, [], () => {
|
||||
// Go back and then forward, and make sure that the state objects received
|
||||
// from the popState event are as we expect them to be.
|
||||
//
|
||||
// We also add a node to the document's body when after going back and make
|
||||
// sure it's still there after we go forward -- this is to test that the two
|
||||
// history entries correspond to the same document.
|
||||
|
||||
// Set some state in the page's window. When we go back(), the page should
|
||||
// be retrieved from bfcache, and this state should still be there.
|
||||
content.testState = "foo";
|
||||
});
|
||||
|
||||
// Now go back. This should trigger the popstate event handler.
|
||||
let popstatePromise = SpecialPowers.spawn(browser, [], async () => {
|
||||
let event = await ContentTaskUtils.waitForEvent(content, "popstate", true);
|
||||
ok(event.state, "Event should have a state property.");
|
||||
|
||||
is(content.testState, "foo", "testState after going back");
|
||||
is(
|
||||
JSON.stringify(content.history.state),
|
||||
JSON.stringify({ obj1: 1 }),
|
||||
"first popstate object."
|
||||
);
|
||||
|
||||
// Add a node with id "new-elem" to the document.
|
||||
let doc = content.document;
|
||||
ok(
|
||||
!doc.getElementById("new-elem"),
|
||||
"doc shouldn't contain new-elem before we add it."
|
||||
);
|
||||
let elem = doc.createElement("div");
|
||||
elem.id = "new-elem";
|
||||
doc.body.appendChild(elem);
|
||||
});
|
||||
|
||||
// Ensure that the message manager has processed the previous task before
|
||||
// going back to prevent racing with it in non-e10s mode.
|
||||
await SpecialPowers.spawn(browser, [], () => {});
|
||||
browser.goBack();
|
||||
|
||||
await popstatePromise;
|
||||
|
||||
popstatePromise = SpecialPowers.spawn(browser, [], async () => {
|
||||
let event = await ContentTaskUtils.waitForEvent(content, "popstate", true);
|
||||
|
||||
// When content fires a PopStateEvent and we observe it from a chrome event
|
||||
// listener (as we do here, and, thankfully, nowhere else in the tree), the
|
||||
// state object will be a cross-compartment wrapper to an object that was
|
||||
// deserialized in the content scope. And in this case, since RegExps are
|
||||
// not currently Xrayable (see bug 1014991), trying to pull |obj3| (a RegExp)
|
||||
// off of an Xrayed Object won't work. So we need to waive.
|
||||
Assert.equal(
|
||||
Cu.waiveXrays(event.state).obj3.toString(),
|
||||
"/^a$/",
|
||||
"second popstate object."
|
||||
);
|
||||
|
||||
// Make sure that the new-elem node is present in the document. If it's
|
||||
// not, then this history entry has a different doc identifier than the
|
||||
// previous entry, which is bad.
|
||||
let doc = content.document;
|
||||
let newElem = doc.getElementById("new-elem");
|
||||
ok(newElem, "doc should contain new-elem.");
|
||||
newElem.remove();
|
||||
ok(!doc.getElementById("new-elem"), "new-elem should be removed.");
|
||||
});
|
||||
|
||||
// Ensure that the message manager has processed the previous task before
|
||||
// going forward to prevent racing with it in non-e10s mode.
|
||||
await SpecialPowers.spawn(browser, [], () => {});
|
||||
browser.goForward();
|
||||
await popstatePromise;
|
||||
}
|
||||
|
||||
add_task(async function test() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.navigation.requireUserInteraction", false]],
|
||||
});
|
||||
|
||||
// Tests session restore functionality of history.pushState and
|
||||
// history.replaceState(). (Bug 500328)
|
||||
|
||||
// We open a new blank window, let it load, and then load in
|
||||
// http://example.com. We need to load the blank window first, otherwise the
|
||||
// docshell gets confused and doesn't have a current history entry.
|
||||
let state;
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: "about:blank" },
|
||||
async function (browser) {
|
||||
BrowserTestUtils.startLoadingURIString(browser, "http://example.com");
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
// After these push/replaceState calls, the window should have three
|
||||
// history entries:
|
||||
// testURL (state object: null) <-- oldest
|
||||
// testURL (state object: {obj1:1})
|
||||
// testURL?page2 (state object: {obj3:/^a$/}) <-- newest
|
||||
function contentTest() {
|
||||
let history = content.window.history;
|
||||
history.pushState({ obj1: 1 }, "title-obj1");
|
||||
history.pushState({ obj2: 2 }, "title-obj2", "?page2");
|
||||
history.replaceState({ obj3: /^a$/ }, "title-obj3");
|
||||
}
|
||||
await SpecialPowers.spawn(browser, [], contentTest);
|
||||
await TabStateFlusher.flush(browser);
|
||||
|
||||
state = ss.getTabState(gBrowser.getTabForBrowser(browser));
|
||||
}
|
||||
);
|
||||
|
||||
// Restore the state into a new tab. Things don't work well when we
|
||||
// restore into the old tab, but that's not a real use case anyway.
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: "about:blank" },
|
||||
async function (browser) {
|
||||
let tab2 = gBrowser.getTabForBrowser(browser);
|
||||
|
||||
let tabRestoredPromise = promiseTabRestored(tab2);
|
||||
ss.setTabState(tab2, state, true);
|
||||
|
||||
// Run checkState() once the tab finishes loading its restored state.
|
||||
await tabRestoredPromise;
|
||||
await checkState(browser);
|
||||
}
|
||||
);
|
||||
});
|
||||
78
src/zen/tests/mochitests/sessionstore/browser_506482.js
Normal file
78
src/zen/tests/mochitests/sessionstore/browser_506482.js
Normal file
@@ -0,0 +1,78 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 506482 */
|
||||
|
||||
// test setup
|
||||
waitForExplicitFinish();
|
||||
|
||||
// read the sessionstore.js mtime (picked from browser_248970_a.js)
|
||||
let profilePath = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
function getSessionstoreFile() {
|
||||
let sessionStoreJS = profilePath.clone();
|
||||
sessionStoreJS.append("sessionstore.jsonlz4");
|
||||
return sessionStoreJS;
|
||||
}
|
||||
function getSessionstorejsModificationTime() {
|
||||
let file = getSessionstoreFile();
|
||||
if (file.exists()) {
|
||||
return file.lastModifiedTime;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// delete existing sessionstore.js, to make sure we're not reading
|
||||
// the mtime of an old one initially.
|
||||
let sessionStoreJS = getSessionstoreFile();
|
||||
if (sessionStoreJS.exists()) {
|
||||
sessionStoreJS.remove(false);
|
||||
}
|
||||
|
||||
// test content URL
|
||||
const TEST_URL =
|
||||
"data:text/html;charset=utf-8," +
|
||||
"<body style='width: 100000px; height: 100000px;'><p>top</p></body>";
|
||||
|
||||
// preferences that we use
|
||||
const PREF_INTERVAL = "browser.sessionstore.interval";
|
||||
|
||||
// make sure sessionstore.js is saved ASAP on all events
|
||||
Services.prefs.setIntPref(PREF_INTERVAL, 0);
|
||||
|
||||
// get the initial sessionstore.js mtime (-1 if it doesn't exist yet)
|
||||
let mtime0 = getSessionstorejsModificationTime();
|
||||
|
||||
// create and select a first tab
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, TEST_URL);
|
||||
promiseBrowserLoaded(tab.linkedBrowser).then(() => {
|
||||
// step1: the above has triggered some saveStateDelayed(), sleep until
|
||||
// it's done, and get the initial sessionstore.js mtime
|
||||
setTimeout(function step1() {
|
||||
let mtime1 = getSessionstorejsModificationTime();
|
||||
isnot(mtime1, mtime0, "initial sessionstore.js update");
|
||||
|
||||
// step2: test sessionstore.js is not updated on tab selection
|
||||
// or content scrolling
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.linkedBrowser.contentWindow.scrollTo(1100, 1200);
|
||||
setTimeout(function step2() {
|
||||
let mtime2 = getSessionstorejsModificationTime();
|
||||
is(
|
||||
mtime2,
|
||||
mtime1,
|
||||
"tab selection and scrolling: sessionstore.js not updated"
|
||||
);
|
||||
|
||||
// ok, done, cleanup and finish
|
||||
if (Services.prefs.prefHasUserValue(PREF_INTERVAL)) {
|
||||
Services.prefs.clearUserPref(PREF_INTERVAL);
|
||||
}
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
}, 3500); // end of sleep after tab selection and scrolling
|
||||
}, 3500); // end of sleep after initial saveStateDelayed()
|
||||
});
|
||||
}
|
||||
41
src/zen/tests/mochitests/sessionstore/browser_514751.js
Normal file
41
src/zen/tests/mochitests/sessionstore/browser_514751.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
add_task(async function test_malformedURI() {
|
||||
/** Test for Bug 514751 (Wallpaper) */
|
||||
|
||||
let state = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
url: "about:mozilla",
|
||||
triggeringPrincipal_base64,
|
||||
title: "Mozilla",
|
||||
},
|
||||
{},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
var theWin = openDialog(location, "", "chrome,all,dialog=no");
|
||||
await promiseWindowLoaded(theWin);
|
||||
|
||||
var gotError = false;
|
||||
try {
|
||||
await setWindowState(theWin, state, true);
|
||||
} catch (e) {
|
||||
if (/NS_ERROR_MALFORMED_URI/.test(e)) {
|
||||
gotError = true;
|
||||
}
|
||||
}
|
||||
|
||||
ok(!gotError, "Didn't get a malformed URI error.");
|
||||
await BrowserTestUtils.closeWindow(theWin);
|
||||
});
|
||||
25
src/zen/tests/mochitests/sessionstore/browser_522375.js
Normal file
25
src/zen/tests/mochitests/sessionstore/browser_522375.js
Normal file
@@ -0,0 +1,25 @@
|
||||
function test() {
|
||||
var startup_info = Services.startup.getStartupInfo();
|
||||
// No .process info on mac
|
||||
|
||||
Assert.lessOrEqual(
|
||||
startup_info.process,
|
||||
startup_info.main,
|
||||
"process created before main is run " + uneval(startup_info)
|
||||
);
|
||||
|
||||
// on linux firstPaint can happen after everything is loaded (especially with remote X)
|
||||
if (startup_info.firstPaint) {
|
||||
Assert.lessOrEqual(
|
||||
startup_info.main,
|
||||
startup_info.firstPaint,
|
||||
"main ran before first paint " + uneval(startup_info)
|
||||
);
|
||||
}
|
||||
|
||||
Assert.less(
|
||||
startup_info.main,
|
||||
startup_info.sessionRestored,
|
||||
"Session restored after main " + uneval(startup_info)
|
||||
);
|
||||
}
|
||||
443
src/zen/tests/mochitests/sessionstore/browser_522545.js
Normal file
443
src/zen/tests/mochitests/sessionstore/browser_522545.js
Normal file
@@ -0,0 +1,443 @@
|
||||
/* 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() {
|
||||
/** Test for Bug 522545 */
|
||||
|
||||
waitForExplicitFinish();
|
||||
requestLongerTimeout(4);
|
||||
|
||||
// This tests the following use case:
|
||||
// User opens a new tab which gets focus. The user types something into the
|
||||
// address bar, then crashes or quits.
|
||||
function test_newTabFocused() {
|
||||
let state = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{ entries: [{ url: "about:mozilla", triggeringPrincipal_base64 }] },
|
||||
{ entries: [], userTypedValue: "example.com", userTypedClear: 0 },
|
||||
],
|
||||
selected: 2,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
waitForBrowserState(state, function () {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
is(
|
||||
browser.currentURI.spec,
|
||||
"about:blank",
|
||||
"No history entries still sets currentURI to about:blank"
|
||||
);
|
||||
is(
|
||||
browser.userTypedValue,
|
||||
"example.com",
|
||||
"userTypedValue was correctly restored"
|
||||
);
|
||||
ok(
|
||||
!browser.didStartLoadSinceLastUserTyping(),
|
||||
"We still know that no load is ongoing"
|
||||
);
|
||||
is(
|
||||
gURLBar.value,
|
||||
"example.com",
|
||||
"Address bar's value correctly restored"
|
||||
);
|
||||
|
||||
// Change tabs to make sure address bar value gets updated. If tab is
|
||||
// lazy, wait for SSTabRestored to ensure address bar has time to update.
|
||||
let tabToSelect = gBrowser.tabContainer.getItemAtIndex(0);
|
||||
if (tabToSelect.linkedBrowser.isConnected) {
|
||||
gBrowser.selectedTab = tabToSelect;
|
||||
is(
|
||||
gURLBar.value,
|
||||
"about:mozilla",
|
||||
"Address bar's value correctly updated"
|
||||
);
|
||||
runNextTest();
|
||||
} else {
|
||||
gBrowser.tabContainer.addEventListener(
|
||||
"SSTabRestored",
|
||||
function SSTabRestored(event) {
|
||||
if (event.target == tabToSelect) {
|
||||
gBrowser.tabContainer.removeEventListener(
|
||||
"SSTabRestored",
|
||||
SSTabRestored,
|
||||
true
|
||||
);
|
||||
is(
|
||||
gURLBar.value,
|
||||
"about:mozilla",
|
||||
"Address bar's value correctly updated"
|
||||
);
|
||||
runNextTest();
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
gBrowser.selectedTab = tabToSelect;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// This tests the following use case:
|
||||
// User opens a new tab which gets focus. The user types something into the
|
||||
// address bar, switches back to the first tab, then crashes or quits.
|
||||
function test_newTabNotFocused() {
|
||||
let state = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{ entries: [{ url: "about:mozilla", triggeringPrincipal_base64 }] },
|
||||
{ entries: [], userTypedValue: "example.org", userTypedClear: 0 },
|
||||
],
|
||||
selected: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
waitForBrowserState(state, function () {
|
||||
let browser = gBrowser.getBrowserAtIndex(1);
|
||||
is(
|
||||
browser.currentURI.spec,
|
||||
"about:blank",
|
||||
"No history entries still sets currentURI to about:blank"
|
||||
);
|
||||
is(
|
||||
browser.userTypedValue,
|
||||
"example.org",
|
||||
"userTypedValue was correctly restored"
|
||||
);
|
||||
// didStartLoadSinceLastUserTyping does not exist on lazy tabs.
|
||||
if (browser.didStartLoadSinceLastUserTyping) {
|
||||
ok(
|
||||
!browser.didStartLoadSinceLastUserTyping(),
|
||||
"We still know that no load is ongoing"
|
||||
);
|
||||
}
|
||||
is(
|
||||
gURLBar.value,
|
||||
"about:mozilla",
|
||||
"Address bar's value correctly restored"
|
||||
);
|
||||
|
||||
// Change tabs to make sure address bar value gets updated. If tab is
|
||||
// lazy, wait for SSTabRestored to ensure address bar has time to update.
|
||||
let tabToSelect = gBrowser.tabContainer.getItemAtIndex(1);
|
||||
if (tabToSelect.linkedBrowser.isConnected) {
|
||||
gBrowser.selectedTab = tabToSelect;
|
||||
is(
|
||||
gURLBar.value,
|
||||
"example.org",
|
||||
"Address bar's value correctly updated"
|
||||
);
|
||||
runNextTest();
|
||||
} else {
|
||||
gBrowser.tabContainer.addEventListener(
|
||||
"SSTabRestored",
|
||||
function SSTabRestored(event) {
|
||||
if (event.target == tabToSelect) {
|
||||
gBrowser.tabContainer.removeEventListener(
|
||||
"SSTabRestored",
|
||||
SSTabRestored,
|
||||
true
|
||||
);
|
||||
is(
|
||||
gURLBar.value,
|
||||
"example.org",
|
||||
"Address bar's value correctly updated"
|
||||
);
|
||||
runNextTest();
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
gBrowser.selectedTab = tabToSelect;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// This tests the following use case:
|
||||
// User is in a tab with session history, then types something in the
|
||||
// address bar, then crashes or quits.
|
||||
function test_existingSHEnd_noClear() {
|
||||
let state = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{ url: "about:mozilla", triggeringPrincipal_base64 },
|
||||
{ url: "about:config", triggeringPrincipal_base64 },
|
||||
],
|
||||
index: 2,
|
||||
userTypedValue: "example.com",
|
||||
userTypedClear: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
waitForBrowserState(state, function () {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
is(
|
||||
browser.currentURI.spec,
|
||||
"about:config",
|
||||
"browser.currentURI set to current entry in SH"
|
||||
);
|
||||
is(
|
||||
browser.userTypedValue,
|
||||
"example.com",
|
||||
"userTypedValue was correctly restored"
|
||||
);
|
||||
ok(
|
||||
!browser.didStartLoadSinceLastUserTyping(),
|
||||
"We still know that no load is ongoing"
|
||||
);
|
||||
is(
|
||||
gURLBar.value,
|
||||
"example.com",
|
||||
"Address bar's value correctly restored to userTypedValue"
|
||||
);
|
||||
runNextTest();
|
||||
});
|
||||
}
|
||||
|
||||
// This tests the following use case:
|
||||
// User is in a tab with session history, presses back at some point, then
|
||||
// types something in the address bar, then crashes or quits.
|
||||
function test_existingSHMiddle_noClear() {
|
||||
let state = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [
|
||||
{ url: "about:mozilla", triggeringPrincipal_base64 },
|
||||
{ url: "about:config", triggeringPrincipal_base64 },
|
||||
],
|
||||
index: 1,
|
||||
userTypedValue: "example.org",
|
||||
userTypedClear: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
waitForBrowserState(state, function () {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
is(
|
||||
browser.currentURI.spec,
|
||||
"about:mozilla",
|
||||
"browser.currentURI set to current entry in SH"
|
||||
);
|
||||
is(
|
||||
browser.userTypedValue,
|
||||
"example.org",
|
||||
"userTypedValue was correctly restored"
|
||||
);
|
||||
ok(
|
||||
!browser.didStartLoadSinceLastUserTyping(),
|
||||
"We still know that no load is ongoing"
|
||||
);
|
||||
is(
|
||||
gURLBar.value,
|
||||
"example.org",
|
||||
"Address bar's value correctly restored to userTypedValue"
|
||||
);
|
||||
runNextTest();
|
||||
});
|
||||
}
|
||||
|
||||
// This test simulates lots of tabs opening at once and then quitting/crashing.
|
||||
function test_getBrowserState_lotsOfTabsOpening() {
|
||||
gBrowser.stop();
|
||||
|
||||
let uris = [];
|
||||
for (let i = 0; i < 25; i++) {
|
||||
uris.push("http://example.com/" + i);
|
||||
}
|
||||
|
||||
// We're waiting for the first location change, which should indicate
|
||||
// one of the tabs has loaded and the others haven't. So one should
|
||||
// be in a non-userTypedValue case, while others should still have
|
||||
// userTypedValue and userTypedClear set.
|
||||
gBrowser.addTabsProgressListener({
|
||||
onLocationChange(aBrowser) {
|
||||
if (uris.indexOf(aBrowser.currentURI.spec) > -1) {
|
||||
gBrowser.removeTabsProgressListener(this);
|
||||
firstLocationChange();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function firstLocationChange() {
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
let hasUTV = state.windows[0].tabs.some(function (aTab) {
|
||||
return (
|
||||
aTab.userTypedValue && aTab.userTypedClear && !aTab.entries.length
|
||||
);
|
||||
});
|
||||
|
||||
ok(
|
||||
hasUTV,
|
||||
"At least one tab has a userTypedValue with userTypedClear with no loaded URL"
|
||||
);
|
||||
|
||||
BrowserTestUtils.waitForMessage(
|
||||
gBrowser.selectedBrowser.messageManager,
|
||||
"SessionStore:update"
|
||||
).then(firstLoad);
|
||||
}
|
||||
|
||||
function firstLoad() {
|
||||
let state = JSON.parse(ss.getTabState(gBrowser.selectedTab));
|
||||
let hasSH = !("userTypedValue" in state) && state.entries[0].url;
|
||||
ok(hasSH, "The selected tab has its entry in SH");
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
gBrowser.loadTabs(uris, {
|
||||
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
});
|
||||
}
|
||||
|
||||
// This simulates setting a userTypedValue and ensures that just typing in the
|
||||
// URL bar doesn't set userTypedClear as well.
|
||||
function test_getBrowserState_userTypedValue() {
|
||||
let state = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [{ entries: [] }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
waitForBrowserState(state, function () {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
// Make sure this tab isn't loading and state is clear before we test.
|
||||
is(browser.userTypedValue, null, "userTypedValue is empty to start");
|
||||
ok(
|
||||
!browser.didStartLoadSinceLastUserTyping(),
|
||||
"Initially, no load should be ongoing"
|
||||
);
|
||||
|
||||
let inputText = "example.org";
|
||||
gURLBar.focus();
|
||||
gURLBar.value = inputText.slice(0, -1);
|
||||
EventUtils.sendString(inputText.slice(-1));
|
||||
|
||||
executeSoon(function () {
|
||||
is(
|
||||
browser.userTypedValue,
|
||||
"example.org",
|
||||
"userTypedValue was set when changing URLBar value"
|
||||
);
|
||||
ok(
|
||||
!browser.didStartLoadSinceLastUserTyping(),
|
||||
"No load started since changing URLBar value"
|
||||
);
|
||||
|
||||
// Now make sure ss gets these values too
|
||||
let newState = JSON.parse(ss.getBrowserState());
|
||||
is(
|
||||
newState.windows[0].tabs[0].userTypedValue,
|
||||
"example.org",
|
||||
"sessionstore got correct userTypedValue"
|
||||
);
|
||||
is(
|
||||
newState.windows[0].tabs[0].userTypedClear,
|
||||
0,
|
||||
"sessionstore got correct userTypedClear"
|
||||
);
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// test_getBrowserState_lotsOfTabsOpening tested userTypedClear in a few cases,
|
||||
// but not necessarily any that had legitimate URIs in the state of loading
|
||||
// (eg, "http://example.com"), so this test will cover that case.
|
||||
function test_userTypedClearLoadURI() {
|
||||
let state = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [],
|
||||
userTypedValue: "http://example.com",
|
||||
userTypedClear: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
waitForBrowserState(state, function () {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
is(
|
||||
browser.currentURI.spec,
|
||||
"http://example.com/",
|
||||
"userTypedClear=2 caused userTypedValue to be loaded"
|
||||
);
|
||||
is(
|
||||
browser.userTypedValue,
|
||||
null,
|
||||
"userTypedValue was null after loading a URI"
|
||||
);
|
||||
ok(
|
||||
!browser.didStartLoadSinceLastUserTyping(),
|
||||
"We should have reset the load state when the tab loaded"
|
||||
);
|
||||
is(
|
||||
gURLBar.value,
|
||||
BrowserUIUtils.trimURL("http://example.com/"),
|
||||
"Address bar's value set after loading URI"
|
||||
);
|
||||
runNextTest();
|
||||
});
|
||||
}
|
||||
|
||||
let tests = [
|
||||
test_newTabFocused,
|
||||
test_newTabNotFocused,
|
||||
test_existingSHEnd_noClear,
|
||||
test_existingSHMiddle_noClear,
|
||||
test_getBrowserState_lotsOfTabsOpening,
|
||||
test_getBrowserState_userTypedValue,
|
||||
test_userTypedClearLoadURI,
|
||||
];
|
||||
let originalState = JSON.parse(ss.getBrowserState());
|
||||
let state = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{ entries: [{ url: "about:blank", triggeringPrincipal_base64 }] },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
function runNextTest() {
|
||||
if (tests.length) {
|
||||
waitForBrowserState(state, function () {
|
||||
gBrowser.selectedBrowser.userTypedValue = null;
|
||||
gURLBar.setURI();
|
||||
tests.shift()();
|
||||
});
|
||||
} else {
|
||||
waitForBrowserState(originalState, function () {
|
||||
gBrowser.selectedBrowser.userTypedValue = null;
|
||||
gURLBar.setURI();
|
||||
finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Run the tests!
|
||||
runNextTest();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user