/* * Test that Windows alert notifications generate expected XML.
*/
var { AppConstants } = ChromeUtils.importESModule( "resource://gre/modules/AppConstants.sys.mjs"
);
let gProfD = do_get_profile();
// Setup that allows to use the profile service in xpcshell tests, // lifted from `toolkit/profile/xpcshell/head.js`. function setupProfileService() {
let gDataHome = gProfD.clone();
gDataHome.append("data");
gDataHome.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
let gDataHomeLocal = gProfD.clone();
gDataHomeLocal.append("local");
gDataHomeLocal.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
/** * Take a `key1\nvalue1\n...` string encoding as used by the Windows native * notification server DLL, and split it into an object, keeping `action\n...` * intact. * * @param {string} t string encoding. * @returns {object} an object with keys and values.
*/ function parseOneEncoded(t) { var launch = {};
var lines = t.split("\n"); while (lines.length) { var key = lines.shift(); var value; if (key === "action") {
value = lines.join("\n");
lines = [];
} else {
value = lines.shift();
}
launch[key] = value;
}
return launch;
}
/** * This complicated-looking function takes a (XML) string representation of a * Windows alert (toast notification), parses it into XML, extracts and further * parses internal data, and returns a simplified XML representation together * with the parsed internals. * * Doing this lets us compare JSON objects rather than stringified-JSON further * encoded as XML strings, which have lots of slashes and `"` characters to * contend with. * * @param {string} s XML string for Windows alert.
* @returns {Array} a pair of a simplified XML string and an object with * `launch` and `actions` keys.
*/ function parseLaunchAndActions(s) { var document = new DOMParser().parseFromString(s, "text/xml"); var root = document.documentElement;
var launchString = root.getAttribute("launch");
root.setAttribute("launch", "launch"); var launch = parseOneEncoded(launchString);
// `actions` is keyed by "content" attribute.
let actions = {}; for (var actionElement of root.querySelectorAll("action")) { // `activationType="system"` is special. Leave them alone.
let systemActivationType =
actionElement.getAttribute("activationType") === "system";
let action = {};
let names = [...actionElement.attributes].map(attribute => attribute.name);
for (var name of names) {
let value = actionElement.getAttribute(name);
// Here is where we parse stringified-JSON to simplify comparisons. if (value.startsWith("{")) {
value = JSON.parse(value); if ("opaqueRelaunchData" in value) {
value.opaqueRelaunchData = JSON.parse(value.opaqueRelaunchData);
}
}
function escape(s) { return s
.replace(/&/g, "&")
.replace(/"/g, """)
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/\n/g, "
");
}
function unescape(s) { return s
.replace(/&/g, "&")
.replace(/"/g, '"')
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/
/g, "\n");
}
function testAlert(when, { serverEnabled, profD, isBackgroundTaskMode } = {}) {
let argumentString = action => { //
is "\n".
let s = ``; if (serverEnabled) {
s += `program
${AppConstants.MOZ_APP_NAME}`;
} else {
s += `invalid key
invalid value`;
} if (serverEnabled && profD) {
s += `
profile
${profD.path}`;
} if (serverEnabled) {
s += "
windowsTag
";
} if (action) {
s += `
action
${escape(JSON.stringify(action))}`;
}
return s;
};
let parsedArgumentString = action =>
parseOneEncoded(unescape(argumentString(action)));
let settingsAction = isBackgroundTaskMode
? ""
: `<action content="Notification settings"/>`;
let alertsService = Cc["@mozilla.org/system-alerts-service;1"]
.getService(Ci.nsIAlertsService)
.QueryInterface(Ci.nsIWindowsAlertsService);
let name = "name";
let title = "title";
let text = "text";
let imageURL = "file:///image.png";
let actions = [
{ action: "action1", title: "title1", iconURL: "file:///iconURL1.png" },
{ action: "action2", title: "title2", iconURL: "file:///iconURL2.png" },
];
let opaqueRelaunchData = { foo: 1, bar: "two" };
let alert = makeAlert({ name, title, text });
let expected = `<toast launch="launch"><visual><binding template="ToastText03"><text id="1">title</text><text id="2">text</text></binding></visual><actions>${settingsAction}</actions></toast>`; Assert.deepEqual(
[
expected.replace("", ""),
{
launch: parsedArgumentString({ action: "" }),
actions: Object.fromEntries(
[parsedSettingsAction()].filter(x => x.length)
),
},
],
parseLaunchAndActions(alertsService.getXmlStringForWindowsAlert(alert)),
when
);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.