fune/toolkit/components/prompts/test/prompt_common.js
2019-10-21 18:18:02 +00:00

279 lines
8 KiB
JavaScript

const { Cc, Ci } = SpecialPowers;
function hasTabModalPrompts() {
var prefName = "prompts.tab_modal.enabled";
var Services = SpecialPowers.Cu.import("resource://gre/modules/Services.jsm")
.Services;
return (
Services.prefs.getPrefType(prefName) == Services.prefs.PREF_BOOL &&
Services.prefs.getBoolPref(prefName)
);
}
var isTabModal = hasTabModalPrompts();
var isSelectDialog = false;
var isOSX = "nsILocalFileMac" in SpecialPowers.Ci;
var isE10S = SpecialPowers.Services.appinfo.processType == 2;
var gChromeScript = SpecialPowers.loadChromeScript(
SimpleTest.getTestFileURL("chromeScript.js")
);
SimpleTest.registerCleanupFunction(() => gChromeScript.destroy());
function onloadPromiseFor(id) {
var iframe = document.getElementById(id);
return new Promise(resolve => {
iframe.addEventListener(
"load",
function(e) {
resolve(true);
},
{ once: true }
);
});
}
/**
* Take an action on the next prompt that appears without checking the state in advance.
* This is useful when the action doesn't depend on which prompt is shown and you
* are expecting multiple prompts at once in an indeterminate order.
* If you know the state of the prompt you expect you should use `handlePrompt` instead.
* @param {object} action defining how to handle the prompt
* @returns {Promise} resolving with the prompt state.
*/
function handlePromptWithoutChecks(action) {
return new Promise(resolve => {
gChromeScript.addMessageListener("promptHandled", function handled(msg) {
gChromeScript.removeMessageListener("promptHandled", handled);
resolve(msg.promptState);
});
gChromeScript.sendAsyncMessage("handlePrompt", { action, isTabModal });
});
}
async function handlePrompt(state, action) {
let actualState = await handlePromptWithoutChecks(action);
checkPromptState(actualState, state);
}
function checkPromptState(promptState, expectedState) {
info(`checkPromptState: Expected: ${expectedState.msg}`);
// XXX check title? OS X has title in content
is(promptState.msg, expectedState.msg, "Checking expected message");
if (isOSX && !isTabModal) {
ok(!promptState.titleHidden, "Checking title always visible on OS X");
} else {
is(
promptState.titleHidden,
expectedState.titleHidden,
"Checking title visibility"
);
}
is(
promptState.textHidden,
expectedState.textHidden,
"Checking textbox visibility"
);
is(
promptState.passHidden,
expectedState.passHidden,
"Checking passbox visibility"
);
is(
promptState.checkHidden,
expectedState.checkHidden,
"Checking checkbox visibility"
);
is(promptState.checkMsg, expectedState.checkMsg, "Checking checkbox label");
is(promptState.checked, expectedState.checked, "Checking checkbox checked");
if (!isTabModal) {
is(
promptState.iconClass,
expectedState.iconClass,
"Checking expected icon CSS class"
);
}
is(promptState.textValue, expectedState.textValue, "Checking textbox value");
is(promptState.passValue, expectedState.passValue, "Checking passbox value");
if (expectedState.butt0Label) {
is(
promptState.butt0Label,
expectedState.butt0Label,
"Checking accept-button label"
);
}
if (expectedState.butt1Label) {
is(
promptState.butt1Label,
expectedState.butt1Label,
"Checking cancel-button label"
);
}
if (expectedState.butt2Label) {
is(
promptState.butt2Label,
expectedState.butt2Label,
"Checking extra1-button label"
);
}
// For prompts with a time-delay button.
if (expectedState.butt0Disabled) {
is(promptState.butt0Disabled, true, "Checking accept-button is disabled");
is(
promptState.butt1Disabled,
false,
"Checking cancel-button isn't disabled"
);
}
is(
promptState.defButton0,
expectedState.defButton == "button0",
"checking button0 default"
);
is(
promptState.defButton1,
expectedState.defButton == "button1",
"checking button1 default"
);
is(
promptState.defButton2,
expectedState.defButton == "button2",
"checking button2 default"
);
if (
isOSX &&
expectedState.focused &&
expectedState.focused.startsWith("button")
) {
is(
promptState.focused,
"infoBody",
"buttons don't focus on OS X, but infoBody does instead"
);
} else {
is(promptState.focused, expectedState.focused, "Checking focused element");
}
if (expectedState.hasOwnProperty("chrome")) {
is(
promptState.chrome,
expectedState.chrome,
"Dialog should be opened as chrome"
);
}
if (expectedState.hasOwnProperty("dialog")) {
is(
promptState.dialog,
expectedState.dialog,
"Dialog should be opened as a dialog"
);
}
if (expectedState.hasOwnProperty("chromeDependent")) {
is(
promptState.chromeDependent,
expectedState.chromeDependent,
"Dialog should be opened as dependent"
);
}
if (expectedState.hasOwnProperty("isWindowModal")) {
is(
promptState.isWindowModal,
expectedState.isWindowModal,
"Dialog should be modal"
);
}
}
function checkEchoedAuthInfo(expectedState, browsingContext) {
return SpecialPowers.spawn(
browsingContext,
[expectedState.user, expectedState.pass],
(expectedUser, expectedPass) => {
let doc = this.content.document;
// The server echos back the HTTP auth info it received.
let username = doc.getElementById("user").textContent;
let password = doc.getElementById("pass").textContent;
let authok = doc.getElementById("ok").textContent;
Assert.equal(authok, "PASS", "Checking for successful authentication");
Assert.equal(username, expectedUser, "Checking for echoed username");
Assert.equal(password, expectedPass, "Checking for echoed password");
}
);
}
/**
* Create a Proxy to relay method calls on an nsIAuthPrompt[2] prompter to a chrome script which can
* perform the calls in the parent. Out and inout params will be copied back from the parent to
* content.
*
* @param chromeScript The reference to the chrome script that will listen to `proxyPrompter`
* messages in the parent and call the `methodName` method.
* The return value from the message handler should be an object with properties:
* `rv` - containing the return value of the method call.
* `args` - containing the array of arguments passed to the method since out or inout ones could have
* been modified.
*/
function PrompterProxy(chromeScript) {
return new Proxy(
{},
{
get(target, prop, receiver) {
return (...args) => {
// Array of indices of out/inout params to copy from the parent back to the caller.
let outParams = [];
switch (prop) {
case "prompt": {
outParams = [/* result */ 5];
break;
}
case "promptAuth": {
outParams = [];
break;
}
case "promptPassword": {
outParams = [/* pwd */ 4];
break;
}
case "promptUsernameAndPassword": {
outParams = [/* user */ 4, /* pwd */ 5];
break;
}
default: {
throw new Error("Unknown nsIAuthPrompt method");
}
}
let result;
chromeScript
.sendQuery("proxyPrompter", {
args,
methodName: prop,
})
.then(val => {
result = val;
});
SpecialPowers.Services.tm.spinEventLoopUntil(() => result);
for (let outParam of outParams) {
// Copy the out or inout param value over the original
args[outParam].value = result.args[outParam].value;
}
if (prop == "promptAuth") {
args[2].username = result.args[2].username;
args[2].password = result.args[2].password;
args[2].domain = result.args[2].domain;
}
return result.rv;
};
},
}
);
}