Source code
Revision control
Copy as Markdown
Other Tools
/* Any copyright is dedicated to the Public Domain.
"use strict";
// Load anti-tracking test utilities
Services.scriptloader.loadSubScript(
this
);
const BLOCKED_STATE = "Blocked 🛑";
const NOT_BLOCKED_STATE = "Not Blocked";
/**
* Creates and loads a tracker iframe in the current page.
* Similar to the approach used in browser_siteSpecificWorkAroundsComplex.js
*/
async function loadTracker(
browser,
) {
const blockedPromise = waitForContentBlockingEvent(window).then(
() => "blocked"
);
const loadPromise = SpecialPowers.spawn(
browser,
[trackerUrl],
async function (url) {
// Create a unique iframe ID to avoid conflicts
const iframe = content.document.createElement("iframe");
const iframeLoadPromise = ContentTaskUtils.waitForEvent(
iframe,
"load"
).then(() => "loaded");
iframe.src = url;
content.document.body.appendChild(iframe);
return iframeLoadPromise;
}
);
return Promise.race([loadPromise, blockedPromise]);
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.category", "strict"],
["privacy.trackingprotection.enabled", true],
["privacy.trackingprotection.allow_list.baseline.enabled", false],
["privacy.trackingprotection.allow_list.convenience.enabled", false],
[
"urlclassifier.trackingTable.testEntries",
"tracking.example.org,social-tracking.example.org",
],
[
"urlclassifier.trackingAnnotationTable.testEntries",
"tracking.example.org,social-tracking.example.org",
],
],
});
await UrlClassifierTestUtils.addTestTrackers();
registerCleanupFunction(async () => {
UrlClassifierTestUtils.cleanupTestTrackers();
});
});
async function cleanup(toolbox) {
await closeToolboxAndTab(toolbox);
}
/**
* Test that a single blocked request is shown in the panel
*/
add_task(async function test_single_blocked_request_shown() {
const toolbox = await openToolboxForTab(tab, "antitracking");
const panel = toolbox.getCurrentPanel();
const panelWindow = panel.panelWin;
const webcompatDebugger = panelWindow.AntiTracking.debugger;
const result = await loadTracker(tab.linkedBrowser);
is(result, "blocked", "Tracker should be blocked");
const hasTrackers = !!Object.keys(webcompatDebugger.allTrackers).length;
ok(hasTrackers, "There should be at least one tracker in the debugger");
const trackerRows = panelWindow.document.querySelectorAll(
"#tracker-table tbody tr"
);
Assert.equal(
trackerRows.length,
1,
"There should be one tracker shown in the panel"
);
// Check that the blocked tracker is displayed
const blockedColumn = trackerRows[0].querySelector("td:nth-child(2)");
is(
blockedColumn.textContent,
BLOCKED_STATE,
"The tracker should be marked as blocked"
);
// Check hostname is displayed
const hostnameColumn = trackerRows[0].querySelector("td:nth-child(3)");
ok(
hostnameColumn.textContent.includes("tracking.example.org"),
"Tracker hostname should be displayed"
);
await cleanup(toolbox);
});
/**
* Test that when no requests are blocked, nothing is shown in the panel
*/
add_task(async function test_no_blocked_requests_shown() {
const toolbox = await openToolboxForTab(tab, "antitracking");
const panel = toolbox.getCurrentPanel();
const panelWindow = panel.panelWin;
const table = panelWindow.document.getElementById("tracker-table");
const trackerRows = table.querySelectorAll("tbody tr");
is(
trackerRows.length,
0,
"No trackers should be shown when none are blocked"
);
// Should show the "no content" message
const noContentMessage = panelWindow.document.querySelector(
".no-content-message"
);
ok(
noContentMessage &&
noContentMessage.textContent.includes("No blocked resources"),
"Should show no blocked resources message"
);
await cleanup(toolbox);
});
/**
* Test that unblocking a tracker works correctly
*/
add_task(async function test_unblock_single_request() {
const toolbox = await openToolboxForTab(tab, "antitracking");
const panel = toolbox.getCurrentPanel();
const panelWindow = panel.panelWin;
const webcompatDebugger = panelWindow.AntiTracking.debugger;
let result = await loadTracker(tab.linkedBrowser);
is(result, "blocked", "Tracker should be blocked initially");
const trackerRows = panelWindow.document.querySelectorAll(
"#tracker-table tbody tr"
);
Assert.equal(
trackerRows.length,
1,
"There should be one tracker shown in the panel"
);
const firstRow = trackerRows[0];
const blockedColumn = firstRow.querySelector("td:nth-child(2)");
is(
blockedColumn.textContent,
BLOCKED_STATE,
"Tracker should initially be blocked"
);
const unblockButton = firstRow.querySelector("td:last-child button");
is(unblockButton.textContent, "Unblock", "Button should say 'Unblock'");
const browserLoadedPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser
);
unblockButton.click();
await browserLoadedPromise;
const updatedTrackerRows = panelWindow.document.querySelectorAll(
"#tracker-table tbody tr"
);
const updatedFirstRow = updatedTrackerRows[0];
const updatedBlockedColumn = updatedFirstRow.querySelector("td:nth-child(2)");
is(
updatedBlockedColumn.textContent,
NOT_BLOCKED_STATE,
"Tracker should now be unblocked in UI"
);
const updatedButton = updatedFirstRow.querySelector("td:last-child button");
is(updatedButton.textContent, "Block", "Button should now say 'Block'");
ok(
webcompatDebugger.unblockedChannels.has("tracking.example.org"),
"Tracker should now be unblocked in debugger state"
);
await reloadBrowser(tab.linkedBrowser);
// Test that the tracker would now load
result = await loadTracker(tab.linkedBrowser);
is(result, "loaded", "Tracker should load successfully after unblocking");
await cleanup(toolbox);
});
/**
* Test that clicking the "block" button for a request blocks it
*/
add_task(async function test_block_unblocked_channel() {
const toolbox = await openToolboxForTab(tab, "antitracking");
const panel = toolbox.getCurrentPanel();
const panelWindow = panel.panelWin;
const webcompatDebugger = panelWindow.AntiTracking.debugger;
// Set up the debugger state to simulate an unblocked tracker
webcompatDebugger.unblockedChannels = new Set(["tracking.example.org"]);
webcompatDebugger.allTrackers = {
"tracking.example.org": "Tracking Protection",
};
webcompatDebugger.populateTrackerTable();
const firstRow = panelWindow.document.querySelectorAll(
"#tracker-table tbody tr"
)[0];
const blockButton = firstRow.querySelector("td:last-child button");
ok(blockButton, "Block button should be present");
is(blockButton.textContent, "Block", "Button should say 'Block'");
const browserLoadedPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser
);
blockButton.click();
await browserLoadedPromise;
const updatedTrackerRows = panelWindow.document.querySelectorAll(
"#tracker-table tbody tr"
);
const updatedFirstRow = updatedTrackerRows[0];
const updatedBlockedColumn = updatedFirstRow.querySelector("td:nth-child(2)");
is(
updatedBlockedColumn.textContent,
BLOCKED_STATE,
"Tracker should now be blocked in UI"
);
const updatedButton = updatedFirstRow.querySelector("td:last-child button");
is(updatedButton.textContent, "Unblock", "Button should now say 'Unblock'");
ok(
!webcompatDebugger.unblockedChannels.has("tracking.example.org"),
"Tracker should now be blocked (removed from unblockedChannels)"
);
const result = await loadTracker(tab.linkedBrowser);
is(
result,
"blocked",
"Tracker should be blocked after clicking block button"
);
await cleanup(toolbox);
});
/**
* Test when there are multiple trackers and one is unblocked, the others are still blocked
*/
add_task(async function test_multiple_trackers_one_unblocked() {
const toolbox = await openToolboxForTab(tab, "antitracking");
const panel = toolbox.getCurrentPanel();
const panelWindow = panel.panelWin;
// Load multiple trackers
let result = await loadTracker(
tab.linkedBrowser,
);
is(result, "blocked", "First tracker should be blocked");
result = await loadTracker(
tab.linkedBrowser,
);
is(result, "blocked", "Second tracker should also be blocked");
const trackerRows = panelWindow.document.querySelectorAll(
"#tracker-table tbody tr"
);
Assert.equal(
trackerRows.length,
2,
"Two trackers should be shown in the panel"
);
const firstRow = trackerRows[0];
const unblockButton = firstRow.querySelector("td:last-child button");
const browserLoadedPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser
);
unblockButton.click();
await browserLoadedPromise;
const updatedTrackerRows = panelWindow.document.querySelectorAll(
"#tracker-table tbody tr"
);
const updatedFirstRow = updatedTrackerRows[0];
const updatedBlockedColumn = updatedFirstRow.querySelector("td:nth-child(2)");
is(
updatedBlockedColumn.textContent,
NOT_BLOCKED_STATE,
"First tracker should now be unblocked in UI"
);
is(result, "loaded", "First tracker should be loaded");
await cleanup(toolbox);
});
/**
* Test the "unblock selected" button functionality with multiple selected trackers
*/
add_task(async function test_unblock_selected_button() {
const toolbox = await openToolboxForTab(tab, "antitracking");
const panel = toolbox.getCurrentPanel();
const panelWindow = panel.panelWin;
const webcompatDebugger = panelWindow.AntiTracking.debugger;
// Load two trackers
let result = await loadTracker(
tab.linkedBrowser,
);
is(result, "blocked", "First tracker should be blocked");
result = await loadTracker(
tab.linkedBrowser,
);
is(result, "blocked", "Second tracker should also be blocked");
const rowCheckboxes = panelWindow.document.querySelectorAll(
"#tracker-table tbody .row-checkbox"
);
is(rowCheckboxes.length, 2, "Two row checkboxes should be present");
rowCheckboxes[0].click();
rowCheckboxes[1].click();
const unblockSelectedButton =
panelWindow.document.getElementById("unblock-selected");
ok(unblockSelectedButton, "Unblock selected button should be present");
const browserLoadedPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser
);
unblockSelectedButton.click();
await browserLoadedPromise;
// Verify both trackers are now unblocked in the debugger state
ok(
webcompatDebugger.unblockedChannels.has("tracking.example.org"),
"First tracker should be unblocked in debugger state"
);
ok(
webcompatDebugger.unblockedChannels.has("social-tracking.example.org"),
"Second tracker should be unblocked in debugger state"
);
// Verify UI shows both trackers as unblocked
const updatedTrackerRows = panelWindow.document.querySelectorAll(
"#tracker-table tbody tr"
);
// Verify buttons changed to "Block"
const firstRowButton = updatedTrackerRows[0].querySelector(
"td:last-child button"
);
const secondRowButton = updatedTrackerRows[1].querySelector(
"td:last-child button"
);
is(
firstRowButton.textContent,
"Block",
"First tracker button should say 'Block'"
);
is(
secondRowButton.textContent,
"Block",
"Second tracker button should say 'Block'"
);
// Test that both trackers now load successfully
await reloadBrowser(tab.linkedBrowser);
is(result, "loaded", "First tracker should load after bulk unblock");
result = await loadTracker(
tab.linkedBrowser,
);
is(result, "loaded", "Second tracker should load after bulk unblock");
await cleanup(toolbox);
});