Loading toolkit/components/cookiebanners/test/browser/browser.ini +1 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ [browser_bannerClicking.js] support-files = file_banner.html file_banner_b.html file_delayed_banner.html [browser_cookiebannerservice.js] [browser_cookieinjector.js] Loading toolkit/components/cookiebanners/test/browser/browser_bannerClicking.js +203 −19 Original line number Diff line number Diff line Loading @@ -18,6 +18,12 @@ const TEST_PATH = getRootDirectory(gTestPath).replace( const TEST_PAGE_A = TEST_ORIGIN_A + TEST_PATH + "file_banner.html"; const TEST_PAGE_B = TEST_ORIGIN_B + TEST_PATH + "file_banner.html"; // Page C has a different banner element ID than A and B. const TEST_PAGE_C = TEST_ORIGIN_C + TEST_PATH + "file_banner_b.html"; function genUUID() { return Services.uuid.generateUUID().number.slice(1, -1); } /** * A helper function returns a promise which resolves when the banner clicking Loading Loading @@ -47,12 +53,16 @@ function promiseBannerClickingFinish(domain) { * @param {BrowsingContext} bc - the browsing context * @param {boolean} visible - if the banner should be visible. * @param {boolean} expected - the expected banner click state. * @param {string} [bannerId] - id of the cookie banner element. */ async function verifyBannerState(bc, visible, expected) { async function verifyBannerState(bc, visible, expected, bannerId = "banner") { info("Verify the cookie banner state."); await SpecialPowers.spawn(bc, [visible, expected], (visible, expected) => { let banner = content.document.getElementById("banner"); await SpecialPowers.spawn( bc, [visible, expected, bannerId], (visible, expected, bannerId) => { let banner = content.document.getElementById(bannerId); is( banner.checkVisibility({ Loading @@ -66,19 +76,28 @@ async function verifyBannerState(bc, visible, expected) { let result = content.document.getElementById("result"); is(result.textContent, expected, "The build click state is correct."); }); } ); } /** * A helper function to open the test page and verify the banner state. * * @param {Window} win - the chrome window object. * @param {Window} [win] - the chrome window object. * @param {String} domain - the domain of the testing page. * @param {String} testURL - the url of the testing page. * @param {boolean} visible - if the banner should be visible. * @param {boolean} expected - the expected banner click state. * @param {string} [bannerId] - id of the cookie banner element. */ async function openPageAndVerify({ win, domain, testURL, visible, expected }) { async function openPageAndVerify({ win = window, domain, testURL, visible, expected, bannerId = "banner", }) { info(`Opening ${testURL}`); let promise = promiseBannerClickingFinish(domain); Loading @@ -86,7 +105,7 @@ async function openPageAndVerify({ win, domain, testURL, visible, expected }) { await promise; await verifyBannerState(tab.linkedBrowser, visible, expected); await verifyBannerState(tab.linkedBrowser, visible, expected, bannerId); BrowserTestUtils.removeTab(tab); } Loading Loading @@ -143,27 +162,56 @@ function insertTestRules() { info("Inserting test rules."); info("Add opt-out click rule for DOMAIN_A."); let ruleA = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleA.id = genUUID(); ruleA.domain = TEST_DOMAIN_A; ruleA.addClickRule("div#banner", null, "button#optOut", "button#optIn"); Services.cookieBanners.insertRule(ruleA); // An opt-in click rule for DOMAIN_B. info("Add opt-in click rule for DOMAIN_B."); let ruleB = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleB.id = genUUID(); ruleB.domain = TEST_DOMAIN_B; ruleB.addClickRule("div#banner", null, null, "button#optIn"); Services.cookieBanners.insertRule(ruleB); info("Add global ruleC which targets a non-existing banner (presence)."); let ruleC = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleC.id = genUUID(); ruleC.domain = "*"; ruleC.addClickRule("div#nonExistingBanner", null, null, "button#optIn"); Services.cookieBanners.insertRule(ruleC); info("Add global ruleD which targets a non-existing banner (presence)."); let ruleD = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleD.id = genUUID(); ruleD.domain = "*"; ruleD.addClickRule( "div#nonExistingBanner2", null, "button#optOut", "button#optIn" ); Services.cookieBanners.insertRule(ruleD); } add_setup(async function() { await SpecialPowers.pushPrefEnv({ set: [ // Enable debug logging. ["cookiebanners.listService.logLevel", "Debug"], ["cookiebanners.bannerClicking.logLevel", "Debug"], ["cookiebanners.bannerClicking.testing", true], ["cookiebanners.bannerClicking.timeout", 500], ["cookiebanners.bannerClicking.enabled", true], Loading Loading @@ -383,3 +431,139 @@ add_task(async function test_embedded_iframe_pbm() { await BrowserTestUtils.closeWindow(pbmWindow); }); /** * Test the banner clicking with global rules and MODE_REJECT. */ add_task(async function test_clicking_global_rules() { await SpecialPowers.pushPrefEnv({ set: [ ["cookiebanners.service.mode", Ci.nsICookieBannerService.MODE_REJECT], ["cookiebanners.service.enableGlobalRules", true], ], }); info("Clearing existing rules"); Services.cookieBanners.resetRules(false); info("Inserting global test rules."); info( "Add global ruleA which targets an existing banner (presence) with existing buttons. This rule should handle the banner." ); let ruleA = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleA.id = genUUID(); ruleA.domain = "*"; ruleA.addClickRule("div#banner", null, "button#optOut", "button#optIn"); Services.cookieBanners.insertRule(ruleA); info( "Add global ruleC which targets an existing banner (presence) but non-existing buttons." ); let ruleC = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleC.id = genUUID(); ruleC.domain = "*"; ruleC.addClickRule( "div#banner", null, "button#nonExistingOptOut", "button#nonExistingOptIn" ); Services.cookieBanners.insertRule(ruleC); info("Add global ruleD which targets a non-existing banner (presence)."); let ruleD = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleD.id = genUUID(); ruleD.domain = "*"; ruleD.addClickRule("div#nonExistingBanner", null, null, "button#optIn"); Services.cookieBanners.insertRule(ruleD); info("The global rule ruleA should handle both test pages with div#banner."); await openPageAndVerify({ domain: TEST_DOMAIN_A, testURL: TEST_PAGE_A, visible: false, expected: "OptOut", }); await openPageAndVerify({ domain: TEST_DOMAIN_B, testURL: TEST_PAGE_B, visible: false, expected: "OptOut", }); info("No global rule should handle TEST_PAGE_C with div#bannerB."); await openPageAndVerify({ domain: TEST_DOMAIN_C, testURL: TEST_PAGE_C, visible: true, expected: "NoClick", bannerId: "bannerB", }); info("Test delayed banner handling with global rules."); let TEST_PAGE = TEST_ORIGIN_A + TEST_PATH + "file_delayed_banner.html?delay=100"; await openPageAndVerify({ domain: TEST_DOMAIN_A, testURL: TEST_PAGE, visible: false, expected: "OptOut", }); }); /** * Test that domain-specific rules take precedence over global rules. */ add_task(async function test_clicking_global_rules_precedence() { await SpecialPowers.pushPrefEnv({ set: [ [ "cookiebanners.service.mode", Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT, ], ["cookiebanners.service.enableGlobalRules", true], ], }); info("Clearing existing rules"); Services.cookieBanners.resetRules(false); info("Inserting global test rules."); info( "Add global ruleA which targets an existing banner (presence) with existing buttons." ); let ruleGlobal = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleGlobal.id = genUUID(); ruleGlobal.domain = "*"; ruleGlobal.addClickRule("div#banner", null, "button#optOut", null); Services.cookieBanners.insertRule(ruleGlobal); info("Add domain specific rule which also targets the existing banner."); let ruleDomain = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleDomain.id = genUUID(); ruleDomain.domain = TEST_DOMAIN_A; ruleDomain.addClickRule("div#banner", null, null, "button#optIn"); Services.cookieBanners.insertRule(ruleDomain); info("Test that the domain-specific rule applies, not the global one."); await openPageAndVerify({ domain: TEST_DOMAIN_A, testURL: TEST_PAGE_A, visible: false, // Because of the way the rules are setup OptOut would mean the global rule // applies, opt-in means the domain specific rule applies. expected: "OptIn", }); }); toolkit/components/cookiebanners/test/browser/browser_cookiebannerservice.js +200 −9 Original line number Diff line number Diff line Loading @@ -3,6 +3,10 @@ "use strict"; function genUUID() { return Services.uuid.generateUUID().number.slice(1, -1); } add_setup(async function() { registerCleanupFunction(() => { Services.prefs.clearUserPref("cookiebanners.service.mode"); Loading Loading @@ -47,6 +51,7 @@ add_task(async function test_enabled_pref() { let rule = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); rule.id = genUUID(); rule.domain = "example.com"; Assert.throws( Loading @@ -54,15 +59,15 @@ add_task(async function test_enabled_pref() { Services.cookieBanners.insertRule(rule); }, /NS_ERROR_NOT_AVAILABLE/, "Should have thrown NS_ERROR_NOT_AVAILABLE for rules insertRule." "Should have thrown NS_ERROR_NOT_AVAILABLE for insertRule." ); Assert.throws( () => { Services.cookieBanners.removeRuleForDomain("example.com"); Services.cookieBanners.removeRule(rule); }, /NS_ERROR_NOT_AVAILABLE/, "Should have thrown NS_ERROR_NOT_AVAILABLE for rules removeRuleForDomain." "Should have thrown NS_ERROR_NOT_AVAILABLE for removeRule." ); Assert.throws( Loading @@ -76,7 +81,7 @@ add_task(async function test_enabled_pref() { ); Assert.throws( () => { Services.cookieBanners.getClickRuleForDomain("example.com"); Services.cookieBanners.getClickRulesForDomain("example.com"); }, /NS_ERROR_NOT_AVAILABLE/, "Should have thrown NS_ERROR_NOT_AVAILABLE for rules getClickRuleForDomain." Loading Loading @@ -272,7 +277,14 @@ add_task(async function test_insertAndGetRule() { is(rule.cookiesOptIn.length, 0, "Should have no opt-in cookies."); info("Getting the click rule for example.com."); let clickRule = Services.cookieBanners.getClickRuleForDomain("example.com"); let clickRules = Services.cookieBanners.getClickRulesForDomain("example.com"); is( clickRules.length, 1, "There should be one domain-specific click rule for example.com" ); let [clickRule] = clickRules; is( clickRule.presence, "div#presence", Loading Loading @@ -301,7 +313,15 @@ add_task(async function test_insertAndGetRule() { ); info("Getting the click rule for example.org."); let clickRule2 = Services.cookieBanners.getClickRuleForDomain("example.org"); let clickRules2 = Services.cookieBanners.getClickRulesForDomain( "example.org" ); is( clickRules2.length, 1, "There should be one domain-specific click rule for example.org" ); let [clickRule2] = clickRules2; is( clickRule2.presence, "div#presence", Loading Loading @@ -368,6 +388,7 @@ add_task(async function test_removeRule() { let rule = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); rule.id = genUUID(); rule.domain = "example.com"; Services.cookieBanners.insertRule(rule); Loading @@ -375,6 +396,7 @@ add_task(async function test_removeRule() { let rule2 = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); rule2.id = genUUID(); rule2.domain = "example.org"; Services.cookieBanners.insertRule(rule2); Loading @@ -386,7 +408,12 @@ add_task(async function test_removeRule() { ); info("Removing rule for non existent example.net"); Services.cookieBanners.removeRuleForDomain("example.net"); let ruleExampleNet = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleExampleNet.id = genUUID(); ruleExampleNet.domain = "example.net"; Services.cookieBanners.removeRule(ruleExampleNet); is( Services.cookieBanners.rules.length, Loading @@ -394,8 +421,22 @@ add_task(async function test_removeRule() { "Cookie banner service still has two rules." ); info("Removing rule for non example.com"); Services.cookieBanners.removeRuleForDomain("example.com"); info("Removing rule for non existent global rule."); let ruleGlobal = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleGlobal.id = genUUID(); ruleGlobal.domain = "*"; Services.cookieBanners.removeRule(ruleGlobal); is( Services.cookieBanners.rules.length, 2, "Cookie banner service still has two rules." ); info("Removing rule for example.com"); Services.cookieBanners.removeRule(rule); is( Services.cookieBanners.rules.length, Loading Loading @@ -497,3 +538,153 @@ add_task(async function test_overwriteRule() { // Cleanup. Services.cookieBanners.resetRules(false); }); add_task(async function test_globalRules() { info("Enabling cookie banner service with MODE_REJECT"); await SpecialPowers.pushPrefEnv({ set: [ ["cookiebanners.service.mode", Ci.nsICookieBannerService.MODE_REJECT], ["cookiebanners.service.enableGlobalRules", true], ], }); info("Clear any preexisting rules"); Services.cookieBanners.resetRules(false); is( Services.cookieBanners.rules.length, 0, "Cookie banner service has no rules initially." ); info("Insert a site-specific rule for example.com"); let rule = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); rule.id = genUUID(); rule.domain = "example.com"; rule.addCookie( true, "foo", "new", "example.com", "/", 3600, "", false, false, false, 0, 0 ); rule.addClickRule("#cookieBannerExample", "#btnOptOut", "#btnOptIn"); Services.cookieBanners.insertRule(rule); info( "Insert a global rule with a cookie and a click rule. The cookie rule shouldn't be used." ); let ruleGlobalA = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleGlobalA.id = genUUID(); ruleGlobalA.domain = "*"; ruleGlobalA.addCookie( true, "foo", "new", "example.net", "/", 3600, "", false, false, false, 0, 0 ); ruleGlobalA.addClickRule("#globalCookieBanner", "#btnOptOut", "#btnOptIn"); Services.cookieBanners.insertRule(ruleGlobalA); info("Insert a second global rule"); let ruleGlobalB = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleGlobalB.id = genUUID(); ruleGlobalB.domain = "*"; ruleGlobalB.addClickRule("#globalCookieBannerB", "#btnOptOutB", "#btnOptIn"); Services.cookieBanners.insertRule(ruleGlobalB); is( Services.cookieBanners.rules.length, 3, "Cookie Banner Service has three rules." ); is( Services.cookieBanners.getCookiesForURI( Services.io.newURI("http://example.com") ).length, 1, "There should be a cookie rule for example.com" ); is( Services.cookieBanners.getClickRulesForDomain("example.com").length, 1, "There should be a a click rule for example.com" ); is( Services.cookieBanners.getCookiesForURI( Services.io.newURI("http://thishasnorule.com") ).length, 0, "There should be no cookie rule for thishasnorule.com" ); let clickRules = Services.cookieBanners.getClickRulesForDomain( Services.io.newURI("http://thishasnorule.com") ); is( clickRules.length, 2, "There should be two click rules for thishasnorule.com" ); ok( clickRules.every(rule => rule.presence.startsWith("#globalCookieBanner")), "The returned click rules should be global rules." ); info("Disabling global rules"); await SpecialPowers.pushPrefEnv({ set: [["cookiebanners.service.enableGlobalRules", false]], }); is( Services.cookieBanners.rules.length, 1, "Cookie Banner Service has 1 rule." ); is( Services.cookieBanners.rules[0].id, rule.id, "It should be the domain specific rule" ); is( Services.cookieBanners.getCookiesForURI( Services.io.newURI("http://thishasnorule.com") ).length, 0, "There should be no cookie rule for thishasnorule.com" ); is( Services.cookieBanners.getClickRulesForDomain( Services.io.newURI("http://thishasnorule.com") ).length, 0, "There should be no click rules for thishasnorule.com since global rules are disabled" ); }); toolkit/components/cookiebanners/test/browser/file_banner_b.html 0 → 100644 +22 −0 Original line number Diff line number Diff line <html> <head> <title>A top-level page with cookie banner</title> <script> function clickOptOut() { document.getElementById("result").textContent = "OptOut"; } function clickOptIn() { document.getElementById("result").textContent = "OptIn"; } </script> </head> <body> <h1>This is the top-level page</h1> <div id="bannerB"> <button id="optOut" onclick="clickOptOut()">OptOut</button> <button id="optIn" onclick="clickOptIn()">OptIn</button> </div> <p id="result">NoClick</p> </body> </html> toolkit/components/cookiebanners/test/unit/test_cookiebannerlistservice.js +48 −18 Original line number Diff line number Diff line Loading @@ -19,8 +19,12 @@ let rulesInserted = []; let rulesRemoved = []; let insertCallback = null; function genUUID() { return Services.uuid.generateUUID().number.slice(1, -1); } const RULE_A_ORIGINAL = { id: "example.com", id: genUUID(), click: { optOut: "#fooOut", presence: "#foobar", Loading @@ -39,7 +43,7 @@ const RULE_A_ORIGINAL = { }; const RULE_B = { id: "example.org", id: genUUID(), click: { optOut: "#fooOutB", presence: "#foobarB", Loading @@ -57,7 +61,7 @@ const RULE_B = { }; const RULE_C = { id: "example.net", id: genUUID(), click: { optOut: "#fooOutC", presence: "#foobarC", Loading @@ -76,7 +80,7 @@ const RULE_C = { }; const RULE_A_UPDATED = { id: "example.com", id: RULE_A_ORIGINAL, click: { optOut: "#fooOut", optIn: "#barIn", Loading @@ -99,7 +103,7 @@ const RULE_A_UPDATED = { }; const INVALID_RULE_CLICK = { id: "foobar.com", id: genUUID(), domain: "foobar.com", click: { presence: 1, Loading @@ -109,6 +113,26 @@ const INVALID_RULE_CLICK = { const INVALID_RULE_EMPTY = {}; const RULE_D_GLOBAL = { id: genUUID(), click: { optOut: "#globalOptOutD", presence: "#globalBannerD", }, domain: "*", cookies: {}, }; const RULE_E_GLOBAL = { id: genUUID(), click: { optOut: "#globalOptOutE", presence: "#globalBannerE", }, domain: "*", cookies: {}, }; // Testing with RemoteSettings requires a profile. do_get_profile(); Loading @@ -117,8 +141,8 @@ add_setup(async () => { Services.prefs.setStringPref("cookiebanners.listService.logLevel", "Debug"); // Stub some nsICookieBannerService methods for easy testing. let removeRuleForDomain = sinon.stub().callsFake(domain => { rulesRemoved.push(domain); let removeRule = sinon.stub().callsFake(rule => { rulesRemoved.push(rule); }); let insertRule = sinon.stub().callsFake(rule => { Loading @@ -127,7 +151,7 @@ add_setup(async () => { }); let oldCookieBanners = Services.cookieBanners; Services.cookieBanners = { insertRule, removeRuleForDomain, resetRules() {} }; Services.cookieBanners = { insertRule, removeRule, resetRules() {} }; // Remove stubs on test end. registerCleanupFunction(() => { Loading Loading @@ -247,10 +271,10 @@ add_task(async function test_remotesettings_sync() { await cookieBannerListService.initForTest(); const payload = { current: [RULE_A_ORIGINAL, RULE_C], created: [RULE_B], current: [RULE_A_ORIGINAL, RULE_C, RULE_D_GLOBAL], created: [RULE_B, RULE_E_GLOBAL], updated: [{ old: RULE_A_ORIGINAL, new: RULE_A_UPDATED }], deleted: [RULE_C], deleted: [RULE_C, RULE_D_GLOBAL], }; Assert.equal(rulesInserted.length, 0, "No inserted rules initially."); Loading @@ -259,12 +283,13 @@ add_task(async function test_remotesettings_sync() { info("Dispatching artificial RemoteSettings sync event"); await RemoteSettings(COLLECTION_NAME).emit("sync", { data: payload }); Assert.equal(rulesInserted.length, 2, "Two inserted rules after sync."); Assert.equal(rulesRemoved.length, 1, "One removed rules after sync."); Assert.equal(rulesInserted.length, 3, "Three inserted rules after sync."); Assert.equal(rulesRemoved.length, 2, "Two removed rules after sync."); let ruleA = rulesInserted.find(rule => rule.domain == RULE_A_UPDATED.domain); let ruleB = rulesInserted.find(rule => rule.domain == RULE_B.domain); let ruleCDomain = rulesRemoved[0]; let ruleA = rulesInserted.find(rule => rule.id == RULE_A_UPDATED.id); let ruleB = rulesInserted.find(rule => rule.id == RULE_B.id); let ruleE = rulesInserted.find(rule => rule.id == RULE_E_GLOBAL.id); let ruleC = rulesRemoved[0]; info("Testing that service inserted updated version of RULE_A."); Assert.equal( Loading Loading @@ -292,8 +317,13 @@ add_task(async function test_remotesettings_sync() { ); } Assert.equal(ruleB.domain, RULE_B.domain, "Should have inserted RULE_B"); Assert.equal(ruleCDomain, RULE_C.domain, "Should have removed RULE_C"); Assert.equal(ruleB.id, RULE_B.id, "Should have inserted RULE_B"); Assert.equal(ruleC.id, RULE_C.id, "Should have removed RULE_C"); Assert.equal( ruleE.id, RULE_E_GLOBAL.id, "Should have inserted RULE_E_GLOBAL" ); // Cleanup cookieBannerListService.shutdown(); Loading Loading
toolkit/components/cookiebanners/test/browser/browser.ini +1 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ [browser_bannerClicking.js] support-files = file_banner.html file_banner_b.html file_delayed_banner.html [browser_cookiebannerservice.js] [browser_cookieinjector.js] Loading
toolkit/components/cookiebanners/test/browser/browser_bannerClicking.js +203 −19 Original line number Diff line number Diff line Loading @@ -18,6 +18,12 @@ const TEST_PATH = getRootDirectory(gTestPath).replace( const TEST_PAGE_A = TEST_ORIGIN_A + TEST_PATH + "file_banner.html"; const TEST_PAGE_B = TEST_ORIGIN_B + TEST_PATH + "file_banner.html"; // Page C has a different banner element ID than A and B. const TEST_PAGE_C = TEST_ORIGIN_C + TEST_PATH + "file_banner_b.html"; function genUUID() { return Services.uuid.generateUUID().number.slice(1, -1); } /** * A helper function returns a promise which resolves when the banner clicking Loading Loading @@ -47,12 +53,16 @@ function promiseBannerClickingFinish(domain) { * @param {BrowsingContext} bc - the browsing context * @param {boolean} visible - if the banner should be visible. * @param {boolean} expected - the expected banner click state. * @param {string} [bannerId] - id of the cookie banner element. */ async function verifyBannerState(bc, visible, expected) { async function verifyBannerState(bc, visible, expected, bannerId = "banner") { info("Verify the cookie banner state."); await SpecialPowers.spawn(bc, [visible, expected], (visible, expected) => { let banner = content.document.getElementById("banner"); await SpecialPowers.spawn( bc, [visible, expected, bannerId], (visible, expected, bannerId) => { let banner = content.document.getElementById(bannerId); is( banner.checkVisibility({ Loading @@ -66,19 +76,28 @@ async function verifyBannerState(bc, visible, expected) { let result = content.document.getElementById("result"); is(result.textContent, expected, "The build click state is correct."); }); } ); } /** * A helper function to open the test page and verify the banner state. * * @param {Window} win - the chrome window object. * @param {Window} [win] - the chrome window object. * @param {String} domain - the domain of the testing page. * @param {String} testURL - the url of the testing page. * @param {boolean} visible - if the banner should be visible. * @param {boolean} expected - the expected banner click state. * @param {string} [bannerId] - id of the cookie banner element. */ async function openPageAndVerify({ win, domain, testURL, visible, expected }) { async function openPageAndVerify({ win = window, domain, testURL, visible, expected, bannerId = "banner", }) { info(`Opening ${testURL}`); let promise = promiseBannerClickingFinish(domain); Loading @@ -86,7 +105,7 @@ async function openPageAndVerify({ win, domain, testURL, visible, expected }) { await promise; await verifyBannerState(tab.linkedBrowser, visible, expected); await verifyBannerState(tab.linkedBrowser, visible, expected, bannerId); BrowserTestUtils.removeTab(tab); } Loading Loading @@ -143,27 +162,56 @@ function insertTestRules() { info("Inserting test rules."); info("Add opt-out click rule for DOMAIN_A."); let ruleA = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleA.id = genUUID(); ruleA.domain = TEST_DOMAIN_A; ruleA.addClickRule("div#banner", null, "button#optOut", "button#optIn"); Services.cookieBanners.insertRule(ruleA); // An opt-in click rule for DOMAIN_B. info("Add opt-in click rule for DOMAIN_B."); let ruleB = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleB.id = genUUID(); ruleB.domain = TEST_DOMAIN_B; ruleB.addClickRule("div#banner", null, null, "button#optIn"); Services.cookieBanners.insertRule(ruleB); info("Add global ruleC which targets a non-existing banner (presence)."); let ruleC = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleC.id = genUUID(); ruleC.domain = "*"; ruleC.addClickRule("div#nonExistingBanner", null, null, "button#optIn"); Services.cookieBanners.insertRule(ruleC); info("Add global ruleD which targets a non-existing banner (presence)."); let ruleD = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleD.id = genUUID(); ruleD.domain = "*"; ruleD.addClickRule( "div#nonExistingBanner2", null, "button#optOut", "button#optIn" ); Services.cookieBanners.insertRule(ruleD); } add_setup(async function() { await SpecialPowers.pushPrefEnv({ set: [ // Enable debug logging. ["cookiebanners.listService.logLevel", "Debug"], ["cookiebanners.bannerClicking.logLevel", "Debug"], ["cookiebanners.bannerClicking.testing", true], ["cookiebanners.bannerClicking.timeout", 500], ["cookiebanners.bannerClicking.enabled", true], Loading Loading @@ -383,3 +431,139 @@ add_task(async function test_embedded_iframe_pbm() { await BrowserTestUtils.closeWindow(pbmWindow); }); /** * Test the banner clicking with global rules and MODE_REJECT. */ add_task(async function test_clicking_global_rules() { await SpecialPowers.pushPrefEnv({ set: [ ["cookiebanners.service.mode", Ci.nsICookieBannerService.MODE_REJECT], ["cookiebanners.service.enableGlobalRules", true], ], }); info("Clearing existing rules"); Services.cookieBanners.resetRules(false); info("Inserting global test rules."); info( "Add global ruleA which targets an existing banner (presence) with existing buttons. This rule should handle the banner." ); let ruleA = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleA.id = genUUID(); ruleA.domain = "*"; ruleA.addClickRule("div#banner", null, "button#optOut", "button#optIn"); Services.cookieBanners.insertRule(ruleA); info( "Add global ruleC which targets an existing banner (presence) but non-existing buttons." ); let ruleC = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleC.id = genUUID(); ruleC.domain = "*"; ruleC.addClickRule( "div#banner", null, "button#nonExistingOptOut", "button#nonExistingOptIn" ); Services.cookieBanners.insertRule(ruleC); info("Add global ruleD which targets a non-existing banner (presence)."); let ruleD = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleD.id = genUUID(); ruleD.domain = "*"; ruleD.addClickRule("div#nonExistingBanner", null, null, "button#optIn"); Services.cookieBanners.insertRule(ruleD); info("The global rule ruleA should handle both test pages with div#banner."); await openPageAndVerify({ domain: TEST_DOMAIN_A, testURL: TEST_PAGE_A, visible: false, expected: "OptOut", }); await openPageAndVerify({ domain: TEST_DOMAIN_B, testURL: TEST_PAGE_B, visible: false, expected: "OptOut", }); info("No global rule should handle TEST_PAGE_C with div#bannerB."); await openPageAndVerify({ domain: TEST_DOMAIN_C, testURL: TEST_PAGE_C, visible: true, expected: "NoClick", bannerId: "bannerB", }); info("Test delayed banner handling with global rules."); let TEST_PAGE = TEST_ORIGIN_A + TEST_PATH + "file_delayed_banner.html?delay=100"; await openPageAndVerify({ domain: TEST_DOMAIN_A, testURL: TEST_PAGE, visible: false, expected: "OptOut", }); }); /** * Test that domain-specific rules take precedence over global rules. */ add_task(async function test_clicking_global_rules_precedence() { await SpecialPowers.pushPrefEnv({ set: [ [ "cookiebanners.service.mode", Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT, ], ["cookiebanners.service.enableGlobalRules", true], ], }); info("Clearing existing rules"); Services.cookieBanners.resetRules(false); info("Inserting global test rules."); info( "Add global ruleA which targets an existing banner (presence) with existing buttons." ); let ruleGlobal = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleGlobal.id = genUUID(); ruleGlobal.domain = "*"; ruleGlobal.addClickRule("div#banner", null, "button#optOut", null); Services.cookieBanners.insertRule(ruleGlobal); info("Add domain specific rule which also targets the existing banner."); let ruleDomain = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleDomain.id = genUUID(); ruleDomain.domain = TEST_DOMAIN_A; ruleDomain.addClickRule("div#banner", null, null, "button#optIn"); Services.cookieBanners.insertRule(ruleDomain); info("Test that the domain-specific rule applies, not the global one."); await openPageAndVerify({ domain: TEST_DOMAIN_A, testURL: TEST_PAGE_A, visible: false, // Because of the way the rules are setup OptOut would mean the global rule // applies, opt-in means the domain specific rule applies. expected: "OptIn", }); });
toolkit/components/cookiebanners/test/browser/browser_cookiebannerservice.js +200 −9 Original line number Diff line number Diff line Loading @@ -3,6 +3,10 @@ "use strict"; function genUUID() { return Services.uuid.generateUUID().number.slice(1, -1); } add_setup(async function() { registerCleanupFunction(() => { Services.prefs.clearUserPref("cookiebanners.service.mode"); Loading Loading @@ -47,6 +51,7 @@ add_task(async function test_enabled_pref() { let rule = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); rule.id = genUUID(); rule.domain = "example.com"; Assert.throws( Loading @@ -54,15 +59,15 @@ add_task(async function test_enabled_pref() { Services.cookieBanners.insertRule(rule); }, /NS_ERROR_NOT_AVAILABLE/, "Should have thrown NS_ERROR_NOT_AVAILABLE for rules insertRule." "Should have thrown NS_ERROR_NOT_AVAILABLE for insertRule." ); Assert.throws( () => { Services.cookieBanners.removeRuleForDomain("example.com"); Services.cookieBanners.removeRule(rule); }, /NS_ERROR_NOT_AVAILABLE/, "Should have thrown NS_ERROR_NOT_AVAILABLE for rules removeRuleForDomain." "Should have thrown NS_ERROR_NOT_AVAILABLE for removeRule." ); Assert.throws( Loading @@ -76,7 +81,7 @@ add_task(async function test_enabled_pref() { ); Assert.throws( () => { Services.cookieBanners.getClickRuleForDomain("example.com"); Services.cookieBanners.getClickRulesForDomain("example.com"); }, /NS_ERROR_NOT_AVAILABLE/, "Should have thrown NS_ERROR_NOT_AVAILABLE for rules getClickRuleForDomain." Loading Loading @@ -272,7 +277,14 @@ add_task(async function test_insertAndGetRule() { is(rule.cookiesOptIn.length, 0, "Should have no opt-in cookies."); info("Getting the click rule for example.com."); let clickRule = Services.cookieBanners.getClickRuleForDomain("example.com"); let clickRules = Services.cookieBanners.getClickRulesForDomain("example.com"); is( clickRules.length, 1, "There should be one domain-specific click rule for example.com" ); let [clickRule] = clickRules; is( clickRule.presence, "div#presence", Loading Loading @@ -301,7 +313,15 @@ add_task(async function test_insertAndGetRule() { ); info("Getting the click rule for example.org."); let clickRule2 = Services.cookieBanners.getClickRuleForDomain("example.org"); let clickRules2 = Services.cookieBanners.getClickRulesForDomain( "example.org" ); is( clickRules2.length, 1, "There should be one domain-specific click rule for example.org" ); let [clickRule2] = clickRules2; is( clickRule2.presence, "div#presence", Loading Loading @@ -368,6 +388,7 @@ add_task(async function test_removeRule() { let rule = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); rule.id = genUUID(); rule.domain = "example.com"; Services.cookieBanners.insertRule(rule); Loading @@ -375,6 +396,7 @@ add_task(async function test_removeRule() { let rule2 = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); rule2.id = genUUID(); rule2.domain = "example.org"; Services.cookieBanners.insertRule(rule2); Loading @@ -386,7 +408,12 @@ add_task(async function test_removeRule() { ); info("Removing rule for non existent example.net"); Services.cookieBanners.removeRuleForDomain("example.net"); let ruleExampleNet = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleExampleNet.id = genUUID(); ruleExampleNet.domain = "example.net"; Services.cookieBanners.removeRule(ruleExampleNet); is( Services.cookieBanners.rules.length, Loading @@ -394,8 +421,22 @@ add_task(async function test_removeRule() { "Cookie banner service still has two rules." ); info("Removing rule for non example.com"); Services.cookieBanners.removeRuleForDomain("example.com"); info("Removing rule for non existent global rule."); let ruleGlobal = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleGlobal.id = genUUID(); ruleGlobal.domain = "*"; Services.cookieBanners.removeRule(ruleGlobal); is( Services.cookieBanners.rules.length, 2, "Cookie banner service still has two rules." ); info("Removing rule for example.com"); Services.cookieBanners.removeRule(rule); is( Services.cookieBanners.rules.length, Loading Loading @@ -497,3 +538,153 @@ add_task(async function test_overwriteRule() { // Cleanup. Services.cookieBanners.resetRules(false); }); add_task(async function test_globalRules() { info("Enabling cookie banner service with MODE_REJECT"); await SpecialPowers.pushPrefEnv({ set: [ ["cookiebanners.service.mode", Ci.nsICookieBannerService.MODE_REJECT], ["cookiebanners.service.enableGlobalRules", true], ], }); info("Clear any preexisting rules"); Services.cookieBanners.resetRules(false); is( Services.cookieBanners.rules.length, 0, "Cookie banner service has no rules initially." ); info("Insert a site-specific rule for example.com"); let rule = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); rule.id = genUUID(); rule.domain = "example.com"; rule.addCookie( true, "foo", "new", "example.com", "/", 3600, "", false, false, false, 0, 0 ); rule.addClickRule("#cookieBannerExample", "#btnOptOut", "#btnOptIn"); Services.cookieBanners.insertRule(rule); info( "Insert a global rule with a cookie and a click rule. The cookie rule shouldn't be used." ); let ruleGlobalA = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleGlobalA.id = genUUID(); ruleGlobalA.domain = "*"; ruleGlobalA.addCookie( true, "foo", "new", "example.net", "/", 3600, "", false, false, false, 0, 0 ); ruleGlobalA.addClickRule("#globalCookieBanner", "#btnOptOut", "#btnOptIn"); Services.cookieBanners.insertRule(ruleGlobalA); info("Insert a second global rule"); let ruleGlobalB = Cc["@mozilla.org/cookie-banner-rule;1"].createInstance( Ci.nsICookieBannerRule ); ruleGlobalB.id = genUUID(); ruleGlobalB.domain = "*"; ruleGlobalB.addClickRule("#globalCookieBannerB", "#btnOptOutB", "#btnOptIn"); Services.cookieBanners.insertRule(ruleGlobalB); is( Services.cookieBanners.rules.length, 3, "Cookie Banner Service has three rules." ); is( Services.cookieBanners.getCookiesForURI( Services.io.newURI("http://example.com") ).length, 1, "There should be a cookie rule for example.com" ); is( Services.cookieBanners.getClickRulesForDomain("example.com").length, 1, "There should be a a click rule for example.com" ); is( Services.cookieBanners.getCookiesForURI( Services.io.newURI("http://thishasnorule.com") ).length, 0, "There should be no cookie rule for thishasnorule.com" ); let clickRules = Services.cookieBanners.getClickRulesForDomain( Services.io.newURI("http://thishasnorule.com") ); is( clickRules.length, 2, "There should be two click rules for thishasnorule.com" ); ok( clickRules.every(rule => rule.presence.startsWith("#globalCookieBanner")), "The returned click rules should be global rules." ); info("Disabling global rules"); await SpecialPowers.pushPrefEnv({ set: [["cookiebanners.service.enableGlobalRules", false]], }); is( Services.cookieBanners.rules.length, 1, "Cookie Banner Service has 1 rule." ); is( Services.cookieBanners.rules[0].id, rule.id, "It should be the domain specific rule" ); is( Services.cookieBanners.getCookiesForURI( Services.io.newURI("http://thishasnorule.com") ).length, 0, "There should be no cookie rule for thishasnorule.com" ); is( Services.cookieBanners.getClickRulesForDomain( Services.io.newURI("http://thishasnorule.com") ).length, 0, "There should be no click rules for thishasnorule.com since global rules are disabled" ); });
toolkit/components/cookiebanners/test/browser/file_banner_b.html 0 → 100644 +22 −0 Original line number Diff line number Diff line <html> <head> <title>A top-level page with cookie banner</title> <script> function clickOptOut() { document.getElementById("result").textContent = "OptOut"; } function clickOptIn() { document.getElementById("result").textContent = "OptIn"; } </script> </head> <body> <h1>This is the top-level page</h1> <div id="bannerB"> <button id="optOut" onclick="clickOptOut()">OptOut</button> <button id="optIn" onclick="clickOptIn()">OptIn</button> </div> <p id="result">NoClick</p> </body> </html>
toolkit/components/cookiebanners/test/unit/test_cookiebannerlistservice.js +48 −18 Original line number Diff line number Diff line Loading @@ -19,8 +19,12 @@ let rulesInserted = []; let rulesRemoved = []; let insertCallback = null; function genUUID() { return Services.uuid.generateUUID().number.slice(1, -1); } const RULE_A_ORIGINAL = { id: "example.com", id: genUUID(), click: { optOut: "#fooOut", presence: "#foobar", Loading @@ -39,7 +43,7 @@ const RULE_A_ORIGINAL = { }; const RULE_B = { id: "example.org", id: genUUID(), click: { optOut: "#fooOutB", presence: "#foobarB", Loading @@ -57,7 +61,7 @@ const RULE_B = { }; const RULE_C = { id: "example.net", id: genUUID(), click: { optOut: "#fooOutC", presence: "#foobarC", Loading @@ -76,7 +80,7 @@ const RULE_C = { }; const RULE_A_UPDATED = { id: "example.com", id: RULE_A_ORIGINAL, click: { optOut: "#fooOut", optIn: "#barIn", Loading @@ -99,7 +103,7 @@ const RULE_A_UPDATED = { }; const INVALID_RULE_CLICK = { id: "foobar.com", id: genUUID(), domain: "foobar.com", click: { presence: 1, Loading @@ -109,6 +113,26 @@ const INVALID_RULE_CLICK = { const INVALID_RULE_EMPTY = {}; const RULE_D_GLOBAL = { id: genUUID(), click: { optOut: "#globalOptOutD", presence: "#globalBannerD", }, domain: "*", cookies: {}, }; const RULE_E_GLOBAL = { id: genUUID(), click: { optOut: "#globalOptOutE", presence: "#globalBannerE", }, domain: "*", cookies: {}, }; // Testing with RemoteSettings requires a profile. do_get_profile(); Loading @@ -117,8 +141,8 @@ add_setup(async () => { Services.prefs.setStringPref("cookiebanners.listService.logLevel", "Debug"); // Stub some nsICookieBannerService methods for easy testing. let removeRuleForDomain = sinon.stub().callsFake(domain => { rulesRemoved.push(domain); let removeRule = sinon.stub().callsFake(rule => { rulesRemoved.push(rule); }); let insertRule = sinon.stub().callsFake(rule => { Loading @@ -127,7 +151,7 @@ add_setup(async () => { }); let oldCookieBanners = Services.cookieBanners; Services.cookieBanners = { insertRule, removeRuleForDomain, resetRules() {} }; Services.cookieBanners = { insertRule, removeRule, resetRules() {} }; // Remove stubs on test end. registerCleanupFunction(() => { Loading Loading @@ -247,10 +271,10 @@ add_task(async function test_remotesettings_sync() { await cookieBannerListService.initForTest(); const payload = { current: [RULE_A_ORIGINAL, RULE_C], created: [RULE_B], current: [RULE_A_ORIGINAL, RULE_C, RULE_D_GLOBAL], created: [RULE_B, RULE_E_GLOBAL], updated: [{ old: RULE_A_ORIGINAL, new: RULE_A_UPDATED }], deleted: [RULE_C], deleted: [RULE_C, RULE_D_GLOBAL], }; Assert.equal(rulesInserted.length, 0, "No inserted rules initially."); Loading @@ -259,12 +283,13 @@ add_task(async function test_remotesettings_sync() { info("Dispatching artificial RemoteSettings sync event"); await RemoteSettings(COLLECTION_NAME).emit("sync", { data: payload }); Assert.equal(rulesInserted.length, 2, "Two inserted rules after sync."); Assert.equal(rulesRemoved.length, 1, "One removed rules after sync."); Assert.equal(rulesInserted.length, 3, "Three inserted rules after sync."); Assert.equal(rulesRemoved.length, 2, "Two removed rules after sync."); let ruleA = rulesInserted.find(rule => rule.domain == RULE_A_UPDATED.domain); let ruleB = rulesInserted.find(rule => rule.domain == RULE_B.domain); let ruleCDomain = rulesRemoved[0]; let ruleA = rulesInserted.find(rule => rule.id == RULE_A_UPDATED.id); let ruleB = rulesInserted.find(rule => rule.id == RULE_B.id); let ruleE = rulesInserted.find(rule => rule.id == RULE_E_GLOBAL.id); let ruleC = rulesRemoved[0]; info("Testing that service inserted updated version of RULE_A."); Assert.equal( Loading Loading @@ -292,8 +317,13 @@ add_task(async function test_remotesettings_sync() { ); } Assert.equal(ruleB.domain, RULE_B.domain, "Should have inserted RULE_B"); Assert.equal(ruleCDomain, RULE_C.domain, "Should have removed RULE_C"); Assert.equal(ruleB.id, RULE_B.id, "Should have inserted RULE_B"); Assert.equal(ruleC.id, RULE_C.id, "Should have removed RULE_C"); Assert.equal( ruleE.id, RULE_E_GLOBAL.id, "Should have inserted RULE_E_GLOBAL" ); // Cleanup cookieBannerListService.shutdown(); Loading