Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Errors

/* 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/. */
"use strict";
/**
* Tests that can show multiple auth prompts in different tabs and handle them
* correctly.
*/
const ORIGIN1 = "https://example.com";
const ORIGIN2 = "https://example.org";
const AUTH_PATH =
"/browser/toolkit/components/passwordmgr/test/browser/authenticate.sjs";
/**
* Opens a tab and navigates to the auth test path.
* @param {String} origin - Origin to open with test path.
* @param {Object} authOptions - Authentication options to pass to server and
* test for.
* @param {String} authOptions.user - Expected username.
* @param {String} authOptions.pass - Expected password.
* @param {String} authOptions.realm - Realm to return on auth request.
* @returns {Object} - An object containing passed origin and authOptions,
* opened tab, a promise which resolves once the tab loads, a promise which
* resolves once the prompt has been opened.
*/
async function openTabWithAuthPrompt(origin, authOptions) {
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
);
let promptPromise = PromptTestUtils.waitForPrompt(tab.linkedBrowser, {
modalType: Services.prompt.MODAL_TYPE_TAB,
promptType: "promptUserAndPass",
});
let url = new URL(origin + AUTH_PATH);
Object.entries(authOptions).forEach(([key, value]) =>
url.searchParams.append(key, value)
);
let loadPromise = BrowserTestUtils.browserLoaded(
tab.linkedBrowser,
false,
url.toString()
);
info("Loading " + url.toString());
BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, url.toString());
return { origin, tab, authOptions, loadPromise, promptPromise };
}
/**
* Waits for tab to load and tests for expected auth state.
* @param {boolean} expectAuthed - true: auth success, false otherwise.
* @param {Object} tabInfo - Information about the tab as generated by
* openTabWithAuthPrompt.
*/
async function testTabAuthed(expectAuthed, { tab, loadPromise, authOptions }) {
// Wait for tab to load after auth.
await loadPromise;
Assert.ok(true, "Tab loads after auth");
// Fetch auth results from body (set by authenticate.sjs).
let { loginResult, user, pass } = await SpecialPowers.spawn(
tab.linkedBrowser,
[],
() => {
let result = {};
result.loginResult = content.document.getElementById("ok").innerText;
result.user = content.document.getElementById("user").innerText;
result.pass = content.document.getElementById("pass").innerText;
return result;
}
);
Assert.equal(
loginResult == "PASS",
expectAuthed,
"Site has expected auth state"
);
Assert.equal(user, expectAuthed ? authOptions.user : "", "Sent correct user");
Assert.equal(
pass,
expectAuthed ? authOptions.pass : "",
"Sent correct password"
);
}
add_task(async function test() {
let tabA = await openTabWithAuthPrompt(ORIGIN1, {
user: "userA",
pass: "passA",
realm: "realmA",
});
// Tab B and C share realm and credentials.
// However, since the auth happens in separate tabs we should get two prompts.
let tabB = await openTabWithAuthPrompt(ORIGIN2, {
user: "userB",
pass: "passB",
realm: "realmB",
});
let tabC = await openTabWithAuthPrompt(ORIGIN2, {
user: "userB",
pass: "passB",
realm: "realmB",
});
let tabs = [tabA, tabB, tabC];
info(`Opening ${tabs.length} tabs with auth prompts`);
let prompts = await Promise.all(tabs.map(tab => tab.promptPromise));
Assert.equal(prompts.length, tabs.length, "Should have one prompt per tab");
for (let i = 0; i < prompts.length; i++) {
let titleEl = prompts[i].ui.prompt.document.querySelector("#titleText");
Assert.equal(
titleEl.textContent,
new URL(tabs[i].origin).host,
"Prompt matches the tab's host"
);
}
// Interact with the prompts. This is deliberately done out of order
// (no FIFO, LIFO).
let [promptA, promptB, promptC] = prompts;
// Accept prompt B with correct login details.
await PromptTestUtils.handlePrompt(promptB, {
loginInput: tabB.authOptions.user,
passwordInput: tabB.authOptions.pass,
});
await testTabAuthed(true, tabB);
// Accept prompt A with correct login details
await PromptTestUtils.handlePrompt(promptA, {
loginInput: tabA.authOptions.user,
passwordInput: tabA.authOptions.pass,
});
await testTabAuthed(true, tabA);
// Cancel prompt C
await PromptTestUtils.handlePrompt(promptC, {
buttonNumClick: 1,
});
await testTabAuthed(false, tabC);
// Cleanup tabs
tabs.forEach(({ tab }) => BrowserTestUtils.removeTab(tab));
});