diff options
Diffstat (limited to 'toolkit/components/places/tests/browser')
4 files changed, 408 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/browser/browser.toml b/toolkit/components/places/tests/browser/browser.toml index b7d688c980..aceee48f24 100644 --- a/toolkit/components/places/tests/browser/browser.toml +++ b/toolkit/components/places/tests/browser/browser.toml @@ -117,3 +117,15 @@ support-files = [ "favicon.html", "final.html", ] + +["browser_visituri_restriction.js"] +skip-if = [ + "verify", + "os == 'linux' && (asan || tsan)", # Bug 1891145 +] + +["browser_visituri_restriction_origin.js"] +skip-if = [ + "verify", + "os == 'linux' && (asan || tsan)", # Bug 1891145 +] diff --git a/toolkit/components/places/tests/browser/browser_visituri_restriction.js b/toolkit/components/places/tests/browser/browser_visituri_restriction.js new file mode 100644 index 0000000000..2af41e6f51 --- /dev/null +++ b/toolkit/components/places/tests/browser/browser_visituri_restriction.js @@ -0,0 +1,227 @@ +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +"use strict"; + +const TEST_PAGE = `data:text/html, + <a href="https://example.com/" target="_blank">https://example.com</a> + <a href="http://example.com/" target="_blank">http://example.com</a> + <a href="https://www.example.com/" target="_blank">https://www.example.com</a> + <a href="https://example.org/" target="_blank">https://example.org</a>`; + +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [ + // Enable restriction feature. + ["places.history.floodingPrevention.enabled", true], + // Restrict from the second visit. + ["places.history.floodingPrevention.restrictionCount", 1], + ["places.history.floodingPrevention.restrictionExpireSeconds", 4], + // Not apply flooding prevention until some seconds elapse after user + // interaction begins. + [ + "places.history.floodingPrevention.maxSecondsFromLastUserInteraction", + 4, + ], + // To enable UserActivation by EventUtils.synthesizeMouseAtCenter() in + // ContentTask.spawn() in synthesizeVisitByUser(). + ["test.events.async.enabled", true], + ], + }); + await clearHistoryAndHistoryCache(); +}); + +add_task(async function basic() { + await BrowserTestUtils.withNewTab( + { gBrowser, url: TEST_PAGE }, + async browser => { + info("Sanity check"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 0, + isVisited: false, + }); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 0, + isVisited: false, + }); + await assertLinkVisitedStatus(browser, "https://www.example.com/", { + visitCount: 0, + isVisited: false, + }); + await assertLinkVisitedStatus(browser, "https://example.org/", { + visitCount: 0, + isVisited: false, + }); + + info("Visit https://example.com/ by user"); + await synthesizeVisitByUser(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 1, + isVisited: true, + }); + + info( + "Visit https://example.com/ by script within maxSecondsFromLastUserInteraction" + ); + await synthesizeVisitByScript(browser, "https://example.com/"); + await synthesizeVisitByScript(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 3, + isVisited: true, + }); + + await waitForPrefSeconds("maxSecondsFromLastUserInteraction"); + + info( + "Visit https://example.com/ by script without maxSecondsFromLastUserInteraction" + ); + await synthesizeVisitByScript(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 4, + isVisited: true, + }); + + info("Visit again, but it should be restricted"); + await synthesizeVisitByScript(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 4, + isVisited: true, + }); + + info("Check other"); + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + await assertLinkVisitedStatus(browser, "http://example.com/", { + visitCount: 0, + isVisited: false, + }); + await assertLinkVisitedStatus(browser, "https://www.example.com/", { + visitCount: 0, + isVisited: false, + }); + await assertLinkVisitedStatus(browser, "https://example.org/", { + visitCount: 0, + isVisited: false, + }); + } + ); + + await clearHistoryAndHistoryCache(); +}); + +add_task(async function expireRestriction() { + await BrowserTestUtils.withNewTab( + { gBrowser, url: TEST_PAGE }, + async browser => { + info("Visit https://example.com/ by user"); + await synthesizeVisitByUser(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 1, + isVisited: true, + }); + + info( + "Visit https://example.com/ by script within maxSecondsFromLastUserInteraction" + ); + await synthesizeVisitByScript(browser, "https://example.com/"); + await synthesizeVisitByScript(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 3, + isVisited: true, + }); + + await waitForPrefSeconds("maxSecondsFromLastUserInteraction"); + + info( + "Visit https://example.com/ by script without maxSecondsFromLastUserInteraction" + ); + await synthesizeVisitByScript(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 4, + isVisited: true, + }); + + await waitForPrefSeconds("restrictionExpireSeconds"); + + info("Visit again, it should not be restricted"); + await synthesizeVisitByScript(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 5, + isVisited: true, + }); + } + ); + + await clearHistoryAndHistoryCache(); +}); + +add_task(async function userInputAlwaysAcceptable() { + await BrowserTestUtils.withNewTab( + { gBrowser, url: TEST_PAGE }, + async browser => { + info("Visit by user"); + await synthesizeVisitByUser(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 1, + isVisited: true, + }); + await synthesizeVisitByUser(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 2, + isVisited: true, + }); + + await waitForPrefSeconds("maxSecondsFromLastUserInteraction"); + + info("Visit by user input"); + await synthesizeVisitByUser(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 3, + isVisited: true, + }); + await synthesizeVisitByUser(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 4, + isVisited: true, + }); + } + ); + + await clearHistoryAndHistoryCache(); +}); + +add_task(async function disable() { + await SpecialPowers.pushPrefEnv({ + set: [["places.history.floodingPrevention.enabled", false]], + }); + + await BrowserTestUtils.withNewTab( + { gBrowser, url: TEST_PAGE }, + async browser => { + info("Any visits are stored"); + for (let i = 0; i < 3; i++) { + await synthesizeVisitByScript(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: i + 1, + isVisited: true, + }); + } + } + ); + + await clearHistoryAndHistoryCache(); +}); + +async function waitForPrefSeconds(pref) { + info(`Wait until elapsing ${pref}`); + return new Promise(r => + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + setTimeout( + r, + Services.prefs.getIntPref(`places.history.floodingPrevention.${pref}`) * + 1000 + + 100 + ) + ); +} diff --git a/toolkit/components/places/tests/browser/browser_visituri_restriction_origin.js b/toolkit/components/places/tests/browser/browser_visituri_restriction_origin.js new file mode 100644 index 0000000000..ee691c79e8 --- /dev/null +++ b/toolkit/components/places/tests/browser/browser_visituri_restriction_origin.js @@ -0,0 +1,92 @@ +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +"use strict"; + +const TEST_PAGE = `data:text/html, + <a href="https://example.com/" target="_blank">https://example.com</a> + <a href="http://example.com/" target="_blank">http://example.com</a> + <a href="https://www.example.com/" target="_blank">https://www.example.com</a> + <a href="https://example.org/" target="_blank">https://example.org</a>`; + +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [ + // Enable restriction feature. + ["places.history.floodingPrevention.enabled", true], + // Restrict from the second visit. + ["places.history.floodingPrevention.restrictionCount", 1], + // Stop expiring. + ["places.history.floodingPrevention.restrictionExpireSeconds", 100], + // Always appply flooding preveition. + [ + "places.history.floodingPrevention.maxSecondsFromLastUserInteraction", + 0, + ], + // To enable UserActivation by EventUtils.synthesizeMouseAtCenter() in ContentTask.spawn() in synthesizeVisitByUser(). + ["test.events.async.enabled", true], + ], + }); +}); + +add_task(async function same_origin_but_other() { + await BrowserTestUtils.withNewTab( + { gBrowser, url: TEST_PAGE }, + async browser => { + info("Sanity check"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 0, + isVisited: false, + }); + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + await assertLinkVisitedStatus(browser, "http://example.com/", { + visitCount: 0, + isVisited: false, + }); + await assertLinkVisitedStatus(browser, "https://www.example.com/", { + visitCount: 0, + isVisited: false, + }); + await assertLinkVisitedStatus(browser, "https://example.org/", { + visitCount: 0, + isVisited: false, + }); + + info("Visit https://example.com/ by user"); + await synthesizeVisitByUser(browser, "https://example.com/"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 1, + isVisited: true, + }); + + info("Visit others by Scripts"); + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + await synthesizeVisitByScript(browser, "http://example.com/"); + await synthesizeVisitByScript(browser, "https://www.example.com/"); + await synthesizeVisitByScript(browser, "https://example.org/"); + + info("Check the status"); + await assertLinkVisitedStatus(browser, "https://example.com/", { + visitCount: 1, + isVisited: true, + }); + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + await assertLinkVisitedStatus(browser, "http://example.com/", { + visitCount: 0, + isVisited: true, + }); + await assertLinkVisitedStatus(browser, "https://www.example.com/", { + visitCount: 0, + isVisited: true, + }); + await assertLinkVisitedStatus(browser, "https://example.org/", { + visitCount: 1, + isVisited: true, + }); + } + ); + + await clearHistoryAndHistoryCache(); +}); diff --git a/toolkit/components/places/tests/browser/head.js b/toolkit/components/places/tests/browser/head.js index b1b916ee29..da40a832c6 100644 --- a/toolkit/components/places/tests/browser/head.js +++ b/toolkit/components/places/tests/browser/head.js @@ -17,3 +17,80 @@ function whenNewWindowLoaded(aOptions, aCallback) { BrowserTestUtils.waitForNewWindow().then(aCallback); OpenBrowserWindow(aOptions); } + +async function clearHistoryAndHistoryCache() { + await PlacesUtils.history.clear(); + // Clear HistoryRestiction cache as well. + Cc["@mozilla.org/browser/history;1"] + .getService(Ci.mozIAsyncHistory) + .clearCache(); +} + +async function synthesizeVisitByUser(browser, url) { + let onNewTab = BrowserTestUtils.waitForNewTab(browser.ownerGlobal.gBrowser); + // We intentionally turn off this a11y check, because the following click is + // purposefully sent on an arbitrary web content that is not expected to be + // tested by itself with the browser mochitests, therefore this rule check + // shall be ignored by a11y_checks suite. + AccessibilityUtils.setEnv({ mustHaveAccessibleRule: false }); + await ContentTask.spawn(browser, [url], async ([href]) => { + EventUtils.synthesizeMouseAtCenter( + content.document.querySelector(`a[href='${href}'`), + {}, + content + ); + }); + AccessibilityUtils.resetEnv(); + let tab = await onNewTab; + BrowserTestUtils.removeTab(tab); +} + +async function synthesizeVisitByScript(browser, url) { + let onNewTab = BrowserTestUtils.waitForNewTab(browser.ownerGlobal.gBrowser); + AccessibilityUtils.setEnv({ mustHaveAccessibleRule: false }); + await ContentTask.spawn(browser, [url], async ([href]) => { + let a = content.document.querySelector(`a[href='${href}'`); + a.click(); + }); + AccessibilityUtils.resetEnv(); + let tab = await onNewTab; + BrowserTestUtils.removeTab(tab); +} + +async function assertLinkVisitedStatus( + browser, + url, + { visitCount: expectedVisitCount, isVisited: expectedVisited } +) { + await BrowserTestUtils.waitForCondition(async () => { + let visitCount = + (await PlacesTestUtils.getDatabaseValue("moz_places", "visit_count", { + url, + })) ?? 0; + + if (visitCount != expectedVisitCount) { + return false; + } + + Assert.equal(visitCount, expectedVisitCount, "The visit count is correct"); + return true; + }); + + await ContentTask.spawn( + browser, + [url, expectedVisited], + async ([href, visited]) => { + // ElementState::VISITED + const VISITED_STATE = 1 << 18; + await ContentTaskUtils.waitForCondition(() => { + let isVisited = !!( + content.InspectorUtils.getContentState( + content.document.querySelector(`a[href='${href}']`) + ) & VISITED_STATE + ); + return isVisited == visited; + }); + } + ); + Assert.ok(true, "The visited state is corerct"); +} |