forked from mirrors/gecko-dev
227 lines
6.4 KiB
JavaScript
227 lines
6.4 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
const URL = ROOT + "browser_formdata_xpath_sample.html";
|
|
|
|
/**
|
|
* Bug 346337 - Generic form data restoration tests.
|
|
*/
|
|
add_setup(function() {
|
|
// make sure we don't save form data at all (except for tab duplication)
|
|
Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2);
|
|
|
|
registerCleanupFunction(() => {
|
|
Services.prefs.clearUserPref("browser.sessionstore.privacy_level");
|
|
});
|
|
});
|
|
|
|
const FILE1 = createFilePath("346337_test1.file");
|
|
const FILE2 = createFilePath("346337_test2.file");
|
|
|
|
const FIELDS = {
|
|
"//input[@name='input']": Date.now().toString(16),
|
|
"//input[@name='spaced 1']": Math.random().toString(),
|
|
"//input[3]": "three",
|
|
"//input[@type='checkbox']": true,
|
|
"//input[@name='uncheck']": false,
|
|
"//input[@type='radio'][1]": false,
|
|
"//input[@type='radio'][2]": true,
|
|
"//input[@type='radio'][3]": false,
|
|
"//select": 2,
|
|
"//select[@multiple]": [1, 3],
|
|
"//textarea[1]": "",
|
|
"//textarea[2]": "Some text... " + Math.random(),
|
|
"//textarea[3]": "Some more text\n" + new Date(),
|
|
"//input[@type='file'][1]": [FILE1],
|
|
"//input[@type='file'][2]": [FILE1, FILE2],
|
|
};
|
|
|
|
add_task(async function test_form_data_restoration() {
|
|
// Load page with some input fields.
|
|
let tab = BrowserTestUtils.addTab(gBrowser, URL);
|
|
let browser = tab.linkedBrowser;
|
|
await promiseBrowserLoaded(browser);
|
|
|
|
// Fill in some values.
|
|
for (let xpath of Object.keys(FIELDS)) {
|
|
await setFormValue(browser, xpath);
|
|
}
|
|
|
|
// Duplicate the tab.
|
|
let tab2 = gBrowser.duplicateTab(tab);
|
|
let browser2 = tab2.linkedBrowser;
|
|
await promiseTabRestored(tab2);
|
|
|
|
// Check that all form values have been duplicated.
|
|
for (let xpath of Object.keys(FIELDS)) {
|
|
let expected = JSON.stringify(FIELDS[xpath]);
|
|
let actual = JSON.stringify(await getFormValue(browser2, xpath));
|
|
is(
|
|
actual,
|
|
expected,
|
|
'The value for "' + xpath + '" was correctly restored'
|
|
);
|
|
}
|
|
|
|
// Remove all tabs.
|
|
await promiseRemoveTabAndSessionState(tab2);
|
|
await promiseRemoveTabAndSessionState(tab);
|
|
|
|
// Restore one of the tabs again.
|
|
tab = ss.undoCloseTab(window, 0);
|
|
browser = tab.linkedBrowser;
|
|
await promiseTabRestored(tab);
|
|
|
|
// Check that none of the form values have been restored due to the privacy
|
|
// level settings.
|
|
for (let xpath of Object.keys(FIELDS)) {
|
|
let expected = FIELDS[xpath];
|
|
if (expected) {
|
|
let actual = await getFormValue(browser, xpath, expected);
|
|
isnot(
|
|
actual,
|
|
expected,
|
|
'The value for "' + xpath + '" was correctly discarded'
|
|
);
|
|
}
|
|
}
|
|
|
|
// Cleanup.
|
|
BrowserTestUtils.removeTab(tab);
|
|
});
|
|
|
|
function getPropertyOfXPath(browserContext, path, propName) {
|
|
return SpecialPowers.spawn(
|
|
browserContext,
|
|
[path, propName],
|
|
(pathChild, propNameChild) => {
|
|
let doc = content.document;
|
|
let xptype = doc.defaultView.XPathResult.FIRST_ORDERED_NODE_TYPE;
|
|
let node = doc.evaluate(pathChild, doc, null, xptype, null)
|
|
.singleNodeValue;
|
|
return node[propNameChild];
|
|
}
|
|
);
|
|
}
|
|
|
|
function setPropertyOfXPath(browserContext, path, propName, newValue) {
|
|
return SpecialPowers.spawn(
|
|
browserContext,
|
|
[path, propName, newValue],
|
|
(pathChild, propNameChild, newValueChild) => {
|
|
let doc = content.document;
|
|
let xptype = doc.defaultView.XPathResult.FIRST_ORDERED_NODE_TYPE;
|
|
let node = doc.evaluate(pathChild, doc, null, xptype, null)
|
|
.singleNodeValue;
|
|
node[propNameChild] = newValueChild;
|
|
|
|
let event = node.ownerDocument.createEvent("UIEvents");
|
|
event.initUIEvent("input", true, true, node.ownerGlobal, 0);
|
|
node.dispatchEvent(event);
|
|
}
|
|
);
|
|
}
|
|
|
|
function execUsingXPath(browserContext, path, fnName, arg) {
|
|
return SpecialPowers.spawn(
|
|
browserContext,
|
|
[path, fnName, arg],
|
|
(pathChild, fnNameChild, argChild) => {
|
|
let doc = content.document;
|
|
let xptype = doc.defaultView.XPathResult.FIRST_ORDERED_NODE_TYPE;
|
|
let node = doc.evaluate(pathChild, doc, null, xptype, null)
|
|
.singleNodeValue;
|
|
|
|
switch (fnNameChild) {
|
|
case "getMultipleSelected":
|
|
return Array.from(node.options, (opt, idx) => idx).filter(
|
|
idx => node.options[idx].selected
|
|
);
|
|
case "setMultipleSelected":
|
|
Array.prototype.forEach.call(
|
|
node.options,
|
|
(opt, idx) => (opt.selected = argChild.indexOf(idx) > -1)
|
|
);
|
|
break;
|
|
case "getFileNameArray":
|
|
return node.mozGetFileNameArray();
|
|
case "setFileNameArray":
|
|
node.mozSetFileNameArray(argChild, argChild.length);
|
|
break;
|
|
}
|
|
|
|
let event = node.ownerDocument.createEvent("UIEvents");
|
|
event.initUIEvent("input", true, true, node.ownerGlobal, 0);
|
|
node.dispatchEvent(event);
|
|
return undefined;
|
|
}
|
|
);
|
|
}
|
|
|
|
function createFilePath(leaf) {
|
|
let file = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
|
file.append(leaf);
|
|
return file.path;
|
|
}
|
|
|
|
function isArrayOfNumbers(value) {
|
|
return Array.isArray(value) && value.every(n => typeof n === "number");
|
|
}
|
|
|
|
function isArrayOfStrings(value) {
|
|
return Array.isArray(value) && value.every(n => typeof n === "string");
|
|
}
|
|
|
|
function getFormValue(browser, xpath) {
|
|
let value = FIELDS[xpath];
|
|
|
|
if (typeof value == "string") {
|
|
return getPropertyOfXPath(browser, xpath, "value");
|
|
}
|
|
|
|
if (typeof value == "boolean") {
|
|
return getPropertyOfXPath(browser, xpath, "checked");
|
|
}
|
|
|
|
if (typeof value == "number") {
|
|
return getPropertyOfXPath(browser, xpath, "selectedIndex");
|
|
}
|
|
|
|
if (isArrayOfNumbers(value)) {
|
|
return execUsingXPath(browser, xpath, "getMultipleSelected");
|
|
}
|
|
|
|
if (isArrayOfStrings(value)) {
|
|
return execUsingXPath(browser, xpath, "getFileNameArray");
|
|
}
|
|
|
|
throw new Error("unknown input type");
|
|
}
|
|
|
|
function setFormValue(browser, xpath) {
|
|
let value = FIELDS[xpath];
|
|
|
|
if (typeof value == "string") {
|
|
return setPropertyOfXPath(browser, xpath, "value", value);
|
|
}
|
|
|
|
if (typeof value == "boolean") {
|
|
return setPropertyOfXPath(browser, xpath, "checked", value);
|
|
}
|
|
|
|
if (typeof value == "number") {
|
|
return setPropertyOfXPath(browser, xpath, "selectedIndex", value);
|
|
}
|
|
|
|
if (isArrayOfNumbers(value)) {
|
|
return execUsingXPath(browser, xpath, "setMultipleSelected", value);
|
|
}
|
|
|
|
if (isArrayOfStrings(value)) {
|
|
return execUsingXPath(browser, xpath, "setFileNameArray", value);
|
|
}
|
|
|
|
throw new Error("unknown input type");
|
|
}
|