diff --git a/browser/base/content/browser-trackingprotection.js b/browser/base/content/browser-trackingprotection.js
index b14b1268a8db..28d4c52a3bb1 100644
--- a/browser/base/content/browser-trackingprotection.js
+++ b/browser/base/content/browser-trackingprotection.js
@@ -144,11 +144,25 @@ var TrackingProtection = {
let isBlocking = state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT;
let isAllowing = state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT;
+ // Check whether the user has added an exception for this site.
+ let hasException = false;
+ if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
+ hasException = PrivateBrowsingUtils.existsInTrackingAllowlist(this._baseURIForChannelClassifier);
+ } else {
+ hasException = Services.perms.testExactPermission(this._baseURIForChannelClassifier,
+ "trackingprotection") == Services.perms.ALLOW_ACTION;
+ }
+
+ if (hasException) {
+ this.content.setAttribute("hasException", "true");
+ } else {
+ this.content.removeAttribute("hasException");
+ }
+
if (isBlocking && this.enabled) {
this.icon.setAttribute("tooltiptext", this.activeTooltipText);
this.icon.setAttribute("state", "blocked-tracking-content");
this.content.setAttribute("state", "blocked-tracking-content");
- this.content.removeAttribute("hasException");
// Open the tracking protection introduction panel, if applicable.
if (this.enabledGlobally) {
@@ -162,21 +176,6 @@ var TrackingProtection = {
this.shieldHistogramAdd(2);
} else if (isAllowing) {
- // Check whether the user has added an exception for this site.
- let hasException = false;
- if (PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser)) {
- hasException = PrivateBrowsingUtils.existsInTrackingAllowlist(this._baseURIForChannelClassifier);
- } else {
- hasException = Services.perms.testExactPermission(this._baseURIForChannelClassifier,
- "trackingprotection") == Services.perms.ALLOW_ACTION;
- }
-
- if (hasException) {
- this.content.setAttribute("hasException", "true");
- } else {
- this.content.removeAttribute("hasException");
- }
-
// Only show the shield when TP is enabled for now.
if (this.enabled) {
this.icon.setAttribute("tooltiptext", this.disabledTooltipText);
@@ -194,7 +193,6 @@ var TrackingProtection = {
this.icon.removeAttribute("tooltiptext");
this.icon.removeAttribute("state");
this.content.removeAttribute("state");
- this.content.removeAttribute("hasException");
// We didn't show the shield
this.shieldHistogramAdd(0);
diff --git a/browser/base/content/test/general/browser_trackingUI_5.js b/browser/base/content/test/general/browser_trackingUI_5.js
index 7e5b84f98306..c9da03898630 100644
--- a/browser/base/content/test/general/browser_trackingUI_5.js
+++ b/browser/base/content/test/general/browser_trackingUI_5.js
@@ -50,6 +50,7 @@ function testTrackingPage(window) {
// Make sure that the blocked tracking elements message appears
ok(hidden("#tracking-not-detected"), "labelNoTracking is hidden");
ok(hidden("#tracking-loaded"), "labelTrackingLoaded is hidden");
+ ok(hidden("#tracking-loaded-exception"), "labelTrackingLoadedException is hidden");
ok(!hidden("#tracking-blocked"), "labelTrackingBlocked is visible");
}
@@ -67,7 +68,7 @@ function testTrackingPageUnblocked() {
// Make sure that the blocked tracking elements message appears
ok(hidden("#tracking-not-detected"), "labelNoTracking is hidden");
- ok(!hidden("#tracking-loaded"), "labelTrackingLoaded is visible");
+ ok(!hidden("#tracking-loaded-exception"), "labelTrackingLoadedException is visible");
ok(hidden("#tracking-blocked"), "labelTrackingBlocked is hidden");
}
diff --git a/browser/base/content/test/trackingUI/browser_trackingUI_state.js b/browser/base/content/test/trackingUI/browser_trackingUI_state.js
index 48cb490c05dd..1675466552d8 100644
--- a/browser/base/content/test/trackingUI/browser_trackingUI_state.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_state.js
@@ -65,6 +65,27 @@ function testBenignPage() {
ok(hidden("#tracking-blocked"), "labelTrackingBlocked is hidden");
}
+function testBenignPageWithException() {
+ info("Non-tracking content must not be blocked");
+ ok(!TrackingProtection.container.hidden, "The container is visible");
+ ok(!TrackingProtection.content.hasAttribute("state"), "content: no state");
+ ok(!TrackingProtection.icon.hasAttribute("state"), "icon: no state");
+ ok(!TrackingProtection.icon.hasAttribute("tooltiptext"), "icon: no tooltip");
+
+ ok(hidden("#tracking-protection-icon"), "icon is hidden");
+ is(!hidden("#tracking-action-block"), TrackingProtection.enabled,
+ "blockButton is visible if TP is on");
+ ok(hidden("#tracking-action-unblock"), "unblockButton is hidden");
+ ok(!hidden("#tracking-protection-preferences-button"), "preferences button is visible");
+
+ is(!hidden("#tracking-not-detected-exception"), TrackingProtection.enabled,
+ "labelNoTrackingException is visible if TP is on");
+ is(hidden("#tracking-not-detected"), TrackingProtection.enabled,
+ "labelNoTracking is visible if TP is off");
+ ok(hidden("#tracking-loaded"), "labelTrackingLoaded is hidden");
+ ok(hidden("#tracking-blocked"), "labelTrackingBlocked is hidden");
+}
+
function testTrackingPage(window) {
info("Tracking content must be blocked");
ok(!TrackingProtection.container.hidden, "The container is visible");
@@ -91,6 +112,7 @@ function testTrackingPage(window) {
// Make sure that the blocked tracking elements message appears
ok(hidden("#tracking-not-detected"), "labelNoTracking is hidden");
ok(hidden("#tracking-loaded"), "labelTrackingLoaded is hidden");
+ ok(hidden("#tracking-loaded-exception"), "labelTrackingLoadedException is hidden");
ok(!hidden("#tracking-blocked"), "labelTrackingBlocked is visible");
}
@@ -113,15 +135,38 @@ function testTrackingPageUnblocked() {
// Make sure that the blocked tracking elements message appears
ok(hidden("#tracking-not-detected"), "labelNoTracking is hidden");
- ok(!hidden("#tracking-loaded"), "labelTrackingLoaded is visible");
+ is(hidden("#tracking-loaded"), TrackingProtection.enabled,
+ "labelTrackingLoaded is visible if TP is off");
+ is(!hidden("#tracking-loaded-exception"), TrackingProtection.enabled,
+ "labelTrackingLoadedException is visible if TP is on");
ok(hidden("#tracking-blocked"), "labelTrackingBlocked is hidden");
}
async function testTrackingProtectionEnabled(tab) {
+ info("Testing with Tracking Protection ENABLED.");
+
info("Load a test page not containing tracking elements");
await promiseTabLoadEvent(tab, BENIGN_PAGE);
testBenignPage();
+ info("Load a test page not containing tracking elements which has an exception.");
+ let isPrivateBrowsing = PrivateBrowsingUtils.isWindowPrivate(tab.ownerGlobal);
+ let uri = Services.io.newURI("https://example.org/");
+ if (isPrivateBrowsing) {
+ PrivateBrowsingUtils.addToTrackingAllowlist(uri);
+ } else {
+ Services.perms.add(uri, "trackingprotection", Services.perms.ALLOW_ACTION);
+ }
+
+ await promiseTabLoadEvent(tab, uri.spec);
+ testBenignPageWithException();
+
+ if (isPrivateBrowsing) {
+ PrivateBrowsingUtils.removeFromTrackingAllowlist(uri);
+ } else {
+ Services.perms.remove(uri, "trackingprotection");
+ }
+
info("Load a test page containing tracking elements");
await promiseTabLoadEvent(tab, TRACKING_PAGE);
testTrackingPage(tab.ownerGlobal);
@@ -140,10 +185,19 @@ async function testTrackingProtectionEnabled(tab) {
}
async function testTrackingProtectionDisabled(tab) {
+ info("Testing with Tracking Protection DISABLED.");
+
info("Load a test page not containing tracking elements");
await promiseTabLoadEvent(tab, BENIGN_PAGE);
testBenignPage();
+ info("Load a test page not containing tracking elements which has an exception.");
+ let uri = Services.io.newURI("https://example.org/");
+ Services.perms.add(uri, "trackingprotection", Services.perms.ALLOW_ACTION);
+ await promiseTabLoadEvent(tab, uri.spec);
+ testBenignPageWithException();
+ Services.perms.remove(uri, "trackingprotection");
+
info("Load a test page containing tracking elements");
await promiseTabLoadEvent(tab, TRACKING_PAGE);
testTrackingPageUnblocked();
@@ -158,7 +212,7 @@ add_task(async function testNormalBrowsing() {
TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
ok(TrackingProtection, "TP is attached to the browser window");
is(TrackingProtection.enabled, Services.prefs.getBoolPref(PREF),
- "TP.enabled is based on the original pref value");
+ "TP.enabled is based on the original pref value");
Services.prefs.setBoolPref(PREF, true);
ok(TrackingProtection.enabled, "TP is enabled after setting the pref");
@@ -179,7 +233,7 @@ add_task(async function testPrivateBrowsing() {
TrackingProtection = tabbrowser.ownerGlobal.TrackingProtection;
ok(TrackingProtection, "TP is attached to the private window");
is(TrackingProtection.enabled, Services.prefs.getBoolPref(PB_PREF),
- "TP.enabled is based on the pb pref value");
+ "TP.enabled is based on the pb pref value");
Services.prefs.setBoolPref(PB_PREF, true);
ok(TrackingProtection.enabled, "TP is enabled after setting the pref");
diff --git a/browser/components/controlcenter/content/panel.inc.xul b/browser/components/controlcenter/content/panel.inc.xul
index 3d3c10308a37..e772fe8be795 100644
--- a/browser/components/controlcenter/content/panel.inc.xul
+++ b/browser/components/controlcenter/content/panel.inc.xul
@@ -78,6 +78,10 @@
crop="end">&trackingProtection.detectedNotBlocked4;
&trackingProtection.notDetected4;
+ &trackingProtection.detectedException;
+ &trackingProtection.notDetectedException;
&trackingProtection.reloadRequired;
diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd
index eabc65b87286..df6518f3538c 100644
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -909,6 +909,9 @@ you can use these alternative items. Otherwise, their values should be empty. -
+
+
+