diff options
Diffstat (limited to 'comm/mail/base/test/browser/browser_linkHandler.js')
-rw-r--r-- | comm/mail/base/test/browser/browser_linkHandler.js | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/comm/mail/base/test/browser/browser_linkHandler.js b/comm/mail/base/test/browser/browser_linkHandler.js new file mode 100644 index 0000000000..38cb8e5b05 --- /dev/null +++ b/comm/mail/base/test/browser/browser_linkHandler.js @@ -0,0 +1,294 @@ +/* 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 @microsoft/sdl/no-insecure-url */ + +let { MockRegistrar } = ChromeUtils.importESModule( + "resource://testing-common/MockRegistrar.sys.mjs" +); + +const TEST_DOMAIN = "http://example.org"; +const TEST_IP = "http://127.0.0.1:8888"; +const TEST_PATH = "/browser/comm/mail/base/test/browser/files/links.html"; + +let links = new Map([ + ["#this-hash", `${TEST_PATH}#hash`], + ["#this-nohash", `${TEST_PATH}`], + [ + "#local-here", + "/browser/comm/mail/base/test/browser/files/sampleContent.html", + ], + [ + "#local-elsewhere", + "/browser/comm/mail/components/extensions/test/browser/data/content.html", + ], + ["#other-https", `https://example.org${TEST_PATH}`], + ["#other-port", `http://example.org:8000${TEST_PATH}`], + ["#other-subdomain", `http://test1.example.org${TEST_PATH}`], + ["#other-subsubdomain", `http://sub1.test1.example.org${TEST_PATH}`], + ["#other-domain", `http://mochi.test:8888${TEST_PATH}`], +]); + +/** @implements {nsIWebProgressListener} */ +let webProgressListener = { + QueryInterface: ChromeUtils.generateQI([ + "nsIWebProgressListener", + "nsISupportsWeakReference", + ]), + + _browser: null, + _deferred: null, + + onStateChange(webProgress, request, stateFlags, status) { + if ( + !(stateFlags & Ci.nsIWebProgressListener.STATE_STOP) || + this._browser?.currentURI.spec == "about:blank" + ) { + return; + } + + if (this._deferred) { + let deferred = this._deferred; + let url = this._browser.currentURI.spec; + this.cancelPromise(); + + deferred.resolve(url); + } else { + this.cancelPromise(); + Assert.ok(false, "unexpected state change"); + } + }, + + onLocationChange(webProgress, request, location, flags) { + if (!(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_HASHCHANGE)) { + return; + } + + if (this._deferred) { + let deferred = this._deferred; + let url = this._browser.currentURI.spec; + this.cancelPromise(); + + deferred.resolve(url); + } else { + this.cancelPromise(); + Assert.ok(false, "unexpected location change"); + } + }, + + promiseEvent(browser) { + this._browser = browser; + browser.webProgress.addProgressListener( + this, + Ci.nsIWebProgress.NOTIFY_STATE_ALL | Ci.nsIWebProgress.NOTIFY_LOCATION + ); + + this._deferred = PromiseUtils.defer(); + return this._deferred.promise; + }, + + cancelPromise() { + this._deferred = null; + this._browser.removeProgressListener(this); + this._browser = null; + }, +}; + +/** @implements {nsIExternalProtocolService} */ +let mockExternalProtocolService = { + QueryInterface: ChromeUtils.generateQI(["nsIExternalProtocolService"]), + + _deferred: null, + + loadURI(aURI, aWindowContext) { + if (this._deferred) { + let deferred = this._deferred; + this._deferred = null; + + deferred.resolve(aURI.spec); + } else { + this.cancelPromise(); + Assert.ok(false, "unexpected call to external protocol service"); + } + }, + + promiseEvent() { + this._deferred = PromiseUtils.defer(); + return this._deferred.promise; + }, + + cancelPromise() { + this._deferred = null; + }, +}; + +let mockExternalProtocolServiceCID = MockRegistrar.register( + "@mozilla.org/uriloader/external-protocol-service;1", + mockExternalProtocolService +); + +registerCleanupFunction(() => { + let tabmail = document.getElementById("tabmail"); + Assert.equal(tabmail.tabInfo.length, 1); + + while (tabmail.tabInfo.length > 1) { + tabmail.closeTab(tabmail.tabInfo[1]); + } + + MockRegistrar.unregister(mockExternalProtocolServiceCID); +}); + +async function clickOnLink( + browser, + selector, + url, + pageURL, + shouldLoadInternally +) { + if ( + browser.webProgress?.isLoadingDocument || + browser.currentURI?.spec == "about:blank" + ) { + await BrowserTestUtils.browserLoaded(browser); + + // Clear the event queue. + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(r => setTimeout(r, 250)); + } + Assert.equal( + browser.currentURI?.spec, + pageURL, + "original URL should be loaded" + ); + + let webProgressPromise = webProgressListener.promiseEvent(browser); + let externalProtocolPromise = mockExternalProtocolService.promiseEvent(); + + info(`clicking on ${selector}`); + await BrowserTestUtils.synthesizeMouseAtCenter(selector, {}, browser); + + await Promise.any([webProgressPromise, externalProtocolPromise]); + + if (selector == "#this-hash") { + await SpecialPowers.spawn(browser, [], () => { + let doc = content.document; + let target = doc.querySelector("#hash"); + let targetRect = target.getBoundingClientRect(); + Assert.less( + targetRect.bottom, + doc.documentElement.clientHeight, + "page did scroll" + ); + }); + } + + if (shouldLoadInternally) { + Assert.equal( + await webProgressPromise, + url, + `${url} should load internally` + ); + mockExternalProtocolService.cancelPromise(); + } else { + Assert.equal( + await externalProtocolPromise, + url, + `${url} should load externally` + ); + webProgressListener.cancelPromise(); + } + + if (browser.currentURI?.spec != pageURL) { + let promise = webProgressListener.promiseEvent(browser); + browser.browsingContext.goBack(); + await promise; + Assert.equal(browser.currentURI?.spec, pageURL, "should have gone back"); + } +} + +async function subtest(pagePrePath, group, shouldLoadCB) { + let tabmail = document.getElementById("tabmail"); + let tab = window.openContentTab( + `${pagePrePath}${TEST_PATH}`, + undefined, + group + ); + + let expectedGroup = group; + if (group === null) { + expectedGroup = "browsers"; + } else if (group === undefined) { + expectedGroup = "single-site"; + } + Assert.equal(tab.browser.getAttribute("messagemanagergroup"), expectedGroup); + + try { + for (let [selector, url] of links) { + if (url.startsWith("/")) { + url = `${pagePrePath}${url}`; + } + await clickOnLink( + tab.browser, + selector, + url, + `${pagePrePath}${TEST_PATH}`, + shouldLoadCB(selector) + ); + } + } finally { + tabmail.closeTab(tab); + } +} + +add_task(function testNoGroup() { + return subtest( + TEST_DOMAIN, + undefined, + selector => selector != "#other-domain" + ); +}); + +add_task(function testBrowsersGroup() { + return subtest(TEST_DOMAIN, null, selector => true); +}); + +add_task(function testSingleSiteGroup() { + return subtest( + TEST_DOMAIN, + "single-site", + selector => selector != "#other-domain" + ); +}); + +add_task(function testSinglePageGroup() { + return subtest(TEST_DOMAIN, "single-page", selector => + selector.startsWith("#this") + ); +}); + +add_task(function testNoGroupWithIP() { + return subtest( + TEST_IP, + undefined, + selector => selector.startsWith("#this") || selector.startsWith("#local") + ); +}); + +add_task(function testBrowsersGroupWithIP() { + return subtest(TEST_IP, null, selector => true); +}); + +add_task(function testSingleSiteGroupWithIP() { + return subtest( + TEST_IP, + "single-site", + selector => selector.startsWith("#this") || selector.startsWith("#local") + ); +}); + +add_task(function testSinglePageGroupWithIP() { + return subtest(TEST_IP, "single-page", selector => + selector.startsWith("#this") + ); +}); |