mirror of
https://github.com/servo/servo.git
synced 2025-10-17 16:59:27 +01:00
209 lines
No EOL
7.1 KiB
JavaScript
209 lines
No EOL
7.1 KiB
JavaScript
/**
|
|
* TestCase
|
|
*
|
|
* A generic template for test cases
|
|
* Is intended to be overloaded with subclasses that override testObject, testFunction and argOrder
|
|
* The testObject is the default arguments for the testFunction
|
|
* The default testObject can be modified with the modify() method, making it easy to create new tests based on the default
|
|
* The testFunction is the target of the test and is called by the test() method. test() applies the testObject as arguments via toArgs()
|
|
* toArgs() uses argOrder to make sure the resulting array is in the right order of the arguments for the testFunction
|
|
*/
|
|
class TestCase {
|
|
constructor() {
|
|
this.testFunction = function() {
|
|
throw new Error("Test Function not implemented");
|
|
};
|
|
this.testObject = {};
|
|
this.argOrder = [];
|
|
}
|
|
|
|
/**
|
|
* toObject
|
|
*
|
|
* return a copy of the testObject
|
|
*/
|
|
toObject() {
|
|
return JSON.parse(JSON.stringify(this.testObject)); // cheap clone
|
|
}
|
|
|
|
/**
|
|
* toArgs
|
|
*
|
|
* converts test object to an array that is ordered in the same way as the arguments to the test function
|
|
*/
|
|
toArgs() {
|
|
var ret = [];
|
|
// XXX, TODO: this won't necessarily produce the args in the right order
|
|
for (let idx of this.argOrder) {
|
|
ret.push(this.testObject[idx]);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* modify
|
|
*
|
|
* update the internal object by a path / value combination
|
|
* e.g. :
|
|
* modify ("foo.bar", 3)
|
|
* accepts three types of args:
|
|
* "foo.bar", 3
|
|
* {path: "foo.bar", value: 3}
|
|
* [{path: "foo.bar", value: 3}, ...]
|
|
*/
|
|
modify(arg1, arg2) {
|
|
var mods;
|
|
|
|
// check for the two argument scenario
|
|
if (typeof arg1 === "string" && arg2 !== undefined) {
|
|
mods = {
|
|
path: arg1,
|
|
value: arg2
|
|
};
|
|
} else {
|
|
mods = arg1;
|
|
}
|
|
|
|
// accept a single modification object instead of an array
|
|
if (!Array.isArray(mods) && typeof mods === "object") {
|
|
mods = [mods];
|
|
}
|
|
|
|
// iterate through each of the desired modifications, and call recursiveSetObject on them
|
|
var obj = this.testObject;
|
|
for (let idx in mods) {
|
|
var mod = mods[idx];
|
|
let paths = mod.path.split(".");
|
|
recursiveSetObject(this.testObject, paths, mod.value);
|
|
}
|
|
|
|
// iterates through nested `obj` using the `pathArray`, creating the path if it doesn't exist
|
|
// when the final leaf of the path is found, it is assigned the specified value
|
|
function recursiveSetObject(obj, pathArray, value) {
|
|
var currPath = pathArray.shift();
|
|
if (typeof obj[currPath] !== "object") {
|
|
obj[currPath] = {};
|
|
}
|
|
if (pathArray.length > 0) {
|
|
return recursiveSetObject(obj[currPath], pathArray, value);
|
|
}
|
|
obj[currPath] = value;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* test
|
|
*
|
|
* run the test function with the top-level properties of the test object applied as arguments
|
|
*/
|
|
test() {
|
|
return this.testFunction(...this.toArgs());
|
|
}
|
|
|
|
/**
|
|
* testArgs
|
|
*
|
|
* calls test() with testObject() and expects it to fail with a TypeError()
|
|
*/
|
|
testBadArgs(testDesc) {
|
|
promise_test(function(t) {
|
|
return promise_rejects(t, new TypeError(), this.test());
|
|
}.bind(this), testDesc);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* MakeCredentialTest
|
|
*
|
|
* tests the WebAuthn makeCredential() interface
|
|
*/
|
|
class MakeCredentialTest extends TestCase {
|
|
constructor() {
|
|
// initialize the parent class
|
|
super();
|
|
|
|
// the function to be tested
|
|
this.testFunction = navigator.authentication.makeCredential;
|
|
|
|
// the default object to pass to makeCredential, to be modified with modify() for various tests
|
|
// var challenge = Uint8Array.from("Y2xpbWIgYSBtb3VudGFpbg");
|
|
this.testObject = {
|
|
accountInformation: {
|
|
rpDisplayName: "ACME",
|
|
displayName: "John P. Smith",
|
|
name: "johnpsmith@example.com",
|
|
id: "1098237235409872",
|
|
imageUri: "https://pics.acme.com/00/p/aBjjjpqPb.png"
|
|
},
|
|
cryptoParameters: [{
|
|
type: "ScopedCred",
|
|
algorithm: "RSASSA-PKCS1-v1_5",
|
|
}],
|
|
attestationChallenge: Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]).buffer
|
|
};
|
|
|
|
// how to order the properties of testObject when passing them to makeCredential
|
|
this.argOrder = [
|
|
"accountInformation",
|
|
"cryptoParameters",
|
|
"attestationChallenge",
|
|
"options"
|
|
];
|
|
|
|
// enable the constructor to modify the default testObject
|
|
// would prefer to do this in the super class, but have to call super() before using `this.*`
|
|
if (arguments.length) this.modify(...arguments);
|
|
}
|
|
}
|
|
|
|
//************* BEGIN DELETE AFTER 1/1/2017 *************** //
|
|
// XXX for development mode only!!
|
|
// debug() for debugging purposes... we can drop this later if it is considered ugly
|
|
// note that debug is currently an empty function (i.e. - prints no output)
|
|
// and debug only prints output if the polyfill is loaded
|
|
var debug = function() {};
|
|
// if the WebAuthn API doesn't exist load a polyfill for testing
|
|
// note that the polyfill only gets loaded if navigator.authentication doesn't exist
|
|
// AND if the polyfill script is found at the right path (i.e. - the polyfill is opt-in)
|
|
function ensureInterface() {
|
|
return new Promise(function(resolve, reject) {
|
|
if (typeof navigator.authentication !== "object") {
|
|
debug = console.log;
|
|
|
|
// dynamic loading of polyfill script by creating new <script> tag and seeing the src=
|
|
var scriptElem = document.createElement("script");
|
|
if (typeof scriptElem !== "object") {
|
|
debug("ensureInterface: Error creating script element while attempting loading polyfill");
|
|
return reject(new Error("ensureInterface: Error creating script element while loading polyfill"));
|
|
}
|
|
scriptElem.type = "application/javascript";
|
|
scriptElem.onload = function() {
|
|
debug("!!! XXX - LOADING POLYFILL FOR WEBAUTHN TESTING - XXX !!!");
|
|
return resolve();
|
|
};
|
|
scriptElem.onerror = function() {
|
|
return reject(new Error("navigator.authentication does not exist"));
|
|
};
|
|
scriptElem.src = "/webauthn/webauthn-polyfill/webauthn-polyfill.js";
|
|
if (document.body) {
|
|
document.body.appendChild(scriptElem);
|
|
} else {
|
|
debug("ensureInterface: DOM has no body");
|
|
return reject(new Error("ensureInterface: DOM has no body"));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function standardSetup(cb) {
|
|
return ensureInterface()
|
|
.then(() => {
|
|
if (cb) return cb();
|
|
})
|
|
.catch((err) => {
|
|
return (err);
|
|
});
|
|
}
|
|
//************* END DELETE AFTER 1/1/2017 *************** //
|