https://github.com/web-platform-tests/wpt
Tip revision: d424efcdf70076295d04febf143969f8b57457f9 authored by Anne van Kesteren on 20 May 2016, 08:59:32 UTC
"Source browsing context" tests
"Source browsing context" tests
Tip revision: d424efc
helpers.js
/**
* 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 *************** //