let testURL = "https://example.com/browser/" + "uriloader/exthandler/tests/mochitest/protocolHandler.html"; add_task(async function () { await SpecialPowers.pushPrefEnv({ set: [["security.external_protocol_requires_permission", false]], }); // Load a page registering a protocol handler. let browser = gBrowser.selectedBrowser; BrowserTestUtils.loadURIString(browser, testURL); await BrowserTestUtils.browserLoaded(browser, false, testURL); // Register the protocol handler by clicking the notificationbar button. let notificationValue = "Protocol Registration: web+testprotocol"; let getNotification = () => gBrowser.getNotificationBox().getNotificationWithValue(notificationValue); await BrowserTestUtils.waitForCondition(getNotification); let notification = getNotification(); let button = notification.buttonContainer.querySelector("button"); ok(button, "got registration button"); button.click(); // Set the new handler as default. const protoSvc = Cc[ "@mozilla.org/uriloader/external-protocol-service;1" ].getService(Ci.nsIExternalProtocolService); let protoInfo = protoSvc.getProtocolHandlerInfo("web+testprotocol"); is( protoInfo.preferredAction, protoInfo.useHelperApp, "using a helper application is the preferred action" ); ok(!protoInfo.preferredApplicationHandler, "no preferred handler is set"); let handlers = protoInfo.possibleApplicationHandlers; is(1, handlers.length, "only one handler registered for web+testprotocol"); let handler = handlers.queryElementAt(0, Ci.nsIHandlerApp); ok(handler instanceof Ci.nsIWebHandlerApp, "the handler is a web handler"); is( handler.uriTemplate, "https://example.com/foobar?uri=%s", "correct url template" ); protoInfo.preferredApplicationHandler = handler; protoInfo.alwaysAskBeforeHandling = false; const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService( Ci.nsIHandlerService ); handlerSvc.store(protoInfo); const expectedURL = "https://example.com/foobar?uri=web%2Btestprotocol%3Atest"; // Create a framed link: await SpecialPowers.spawn(browser, [], async function () { let iframe = content.document.createElement("iframe"); iframe.src = `data:text/html,Click me`; content.document.body.append(iframe); // Can't return this promise because it resolves to the event object. await ContentTaskUtils.waitForEvent(iframe, "load"); iframe.contentDocument.querySelector("a").click(); }); let kidContext = browser.browsingContext.children[0]; await TestUtils.waitForCondition(() => { let spec = kidContext.currentWindowGlobal?.documentURI?.spec || ""; return spec == expectedURL; }); is( kidContext.currentWindowGlobal.documentURI.spec, expectedURL, "Should load in frame." ); // Middle-click a testprotocol link and check the new tab is correct let link = "#link"; let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, expectedURL); await BrowserTestUtils.synthesizeMouseAtCenter(link, { button: 1 }, browser); let tab = await promiseTabOpened; gBrowser.selectedTab = tab; is( gURLBar.value, expectedURL, "the expected URL is displayed in the location bar" ); BrowserTestUtils.removeTab(tab); // Shift-click the testprotocol link and check the new window. let newWindowPromise = BrowserTestUtils.waitForNewWindow({ url: expectedURL, }); await BrowserTestUtils.synthesizeMouseAtCenter( link, { shiftKey: true }, browser ); let win = await newWindowPromise; await BrowserTestUtils.waitForCondition( () => win.gBrowser.currentURI.spec == expectedURL ); is( win.gURLBar.value, expectedURL, "the expected URL is displayed in the location bar" ); await BrowserTestUtils.closeWindow(win); // Click the testprotocol link and check the url in the current tab. let loadPromise = BrowserTestUtils.browserLoaded(browser); await BrowserTestUtils.synthesizeMouseAtCenter(link, {}, browser); await loadPromise; await BrowserTestUtils.waitForCondition(() => gURLBar.value != testURL); is( gURLBar.value, expectedURL, "the expected URL is displayed in the location bar" ); // Cleanup. protoInfo.preferredApplicationHandler = null; handlers.removeElementAt(0); handlerSvc.store(protoInfo); });