Bug 1315872: Add browser.test.assertRejects and assertThrows. r=aswan

MozReview-Commit-ID: DKUlSVS2EvA

--HG--
extra : rebase_source : f8e2b6cd1734fee55fa38ce8d5d683b174fe493f
extra : histedit_source : 6c34cdab5ade5130d382983ecad8d4d56f49d27e
This commit is contained in:
Kris Maglione 2016-11-07 22:03:15 -08:00
Родитель 9c000b319d
Коммит 0ed479cc9c
5 изменённых файлов: 195 добавлений и 20 удалений

Просмотреть файл

@ -1037,7 +1037,12 @@ class ObjectType extends Type {
// Parse "additionalProperties" schema.
let additionalProperties = null;
if (schema.additionalProperties) {
additionalProperties = Schemas.parseSchema(schema.additionalProperties, path);
let type = schema.additionalProperties;
if (type === true) {
type = {"type": "any"};
}
additionalProperties = Schemas.parseSchema(type, path);
}
return new this(schema, properties, additionalProperties, patternProperties, schema.isInstanceOf || null);
@ -1386,7 +1391,7 @@ class FunctionType extends Type {
this.checkSchemaProperties(schema, path, extraProperties);
let isAsync = !!schema.async;
let isExpectingCallback = isAsync;
let isExpectingCallback = typeof schema.async === "string";
let parameters = null;
if ("parameters" in schema) {
parameters = [];
@ -1412,9 +1417,10 @@ class FunctionType extends Type {
let hasAsyncCallback = false;
if (isAsync) {
if (parameters && parameters.length && parameters[parameters.length - 1].name == schema.async) {
hasAsyncCallback = true;
}
hasAsyncCallback = (parameters &&
parameters.length &&
parameters[parameters.length - 1].name == schema.async);
if (schema.returns) {
throw new Error("Internal error: Async functions must not have return values.");
}
@ -1955,7 +1961,11 @@ this.Schemas = {
});
for (let json of this.schemaJSON.values()) {
this.loadSchema(json);
try {
this.loadSchema(json);
} catch (e) {
Cu.reportError(e);
}
}
return this.namespaces;

Просмотреть файл

@ -1,6 +1,80 @@
"use strict";
function testApiFactory(context) {
/**
* Checks whether the given error matches the given expectations.
*
* @param {*} error
* The error to check.
* @param {string|RegExp|function|null} expectedError
* The expectation to check against. If this parameter is:
*
* - a string, the error message must exactly equal the string.
* - a regular expression, it must match the error message.
* - a function, it is called with the error object and its
* return value is returned.
* - null, the function always returns true.
* @param {BaseContext} context
*
* @returns {boolean}
* True if the error matches the expected error.
*/
function errorMatches(error, expectedError, context) {
if (expectedError === null) {
return true;
}
if (typeof expectedError === "function") {
return context.runSafeWithoutClone(expectedError, error);
}
if (typeof error !== "object" || error == null ||
typeof error.message !== "string") {
return false;
}
if (typeof expectedError === "string") {
return error.message === expectedError;
}
try {
return expectedError.test(error.message);
} catch (e) {
Cu.reportError(e);
}
return false;
}
/**
* Calls .toSource() on the given value, but handles null, undefined,
* and errors.
*
* @param {*} value
* @returns {string}
*/
function toSource(value) {
if (value === null) {
return null;
}
if (value === undefined) {
return null;
}
if (typeof value === "string") {
return JSON.stringify(value);
}
try {
return String(value.toSource());
} catch (e) {
return "<unknown>";
}
}
function makeTestAPI(context) {
function assertTrue(...args) {
context.childManager.callParentFunctionNoReturn("test.assertTrue", args);
}
return {
test: {
// These functions accept arbitrary values. Convert the parameters to
@ -40,9 +114,46 @@ function testApiFactory(context) {
String(msg),
]);
},
assertRejects(promise, expectedError, msg) {
// Wrap in a native promise for consistency.
promise = Promise.resolve(promise);
if (msg) {
msg = `: ${msg}`;
}
return promise.then(result => {
assertTrue(false, `Promise resolved, expected rejection${msg}`);
}, error => {
let errorMessage = toSource(error && error.message);
assertTrue(errorMatches(error, expectedError, context),
`Promise rejected, expecting rejection to match ${toSource(expectedError)}, ` +
`got ${errorMessage}${msg}`);
});
},
assertThrows(func, expectedError, msg) {
if (msg) {
msg = `: ${msg}`;
}
try {
func();
assertTrue(false, `Function did not throw, expected error${msg}`);
} catch (error) {
let errorMessage = toSource(error && error.message);
assertTrue(errorMatches(error, expectedError, context),
`Promise rejected, expecting rejection to match ${toSource(expectedError)}` +
`got ${errorMessage}${msg}`);
}
},
},
};
}
extensions.registerSchemaAPI("test", "addon_child", testApiFactory);
extensions.registerSchemaAPI("test", "content_child", testApiFactory);
extensions.registerSchemaAPI("test", "addon_child", makeTestAPI);
extensions.registerSchemaAPI("test", "content_child", makeTestAPI);

Просмотреть файл

@ -25,7 +25,7 @@ extensions.on("test-message", (type, extension, ...args) => {
});
/* eslint-enable mozilla/balanced-listeners */
function testApiFactory(context) {
function makeTestAPI(context) {
let {extension} = context;
return {
test: {
@ -82,5 +82,5 @@ function testApiFactory(context) {
},
};
}
extensions.registerSchemaAPI("test", "addon_parent", testApiFactory);
extensions.registerSchemaAPI("test", "content_parent", testApiFactory);
extensions.registerSchemaAPI("test", "addon_parent", makeTestAPI);
extensions.registerSchemaAPI("test", "content_parent", makeTestAPI);

Просмотреть файл

@ -126,19 +126,71 @@
]
},
{
"name": "assertThrows",
"name": "assertRejects",
"type": "function",
"unsupported": true,
"async": true,
"parameters": [
{"type": "function", "name": "fn"},
{
"type": "object",
"name": "self",
"additionalProperties": {"type": "any"},
"name": "promise",
"$ref": "Promise"
},
{
"name": "expectedError",
"$ref": "ExpectedError",
"optional": true
},
{"type": "array", "items": {"type": "any"}, "name": "args", "optional": true},
{"choices": [ {"type": "string"}, {"type": "object", "isInstanceOf": "RegExp"} ], "name": "message", "optional": true}
{
"name": "message",
"type": "string",
"optional": true
}
]
},
{
"name": "assertThrows",
"type": "function",
"parameters": [
{
"name": "func",
"type": "function"
},
{
"name": "expectedError",
"$ref": "ExpectedError",
"optional": true
},
{
"name": "message",
"type": "string",
"optional": true
}
]
}
],
"types": [
{
"id": "ExpectedError",
"choices": [
{"type": "string"},
{"type": "object", "isInstanceOf": "RegExp", "additionalProperties": true},
{"type": "function"}
]
},
{
"id": "Promise",
"choices": [
{
"type": "object",
"properties": {
"then": {"type": "function"}
},
"additionalProperties": true
},
{
"type": "object",
"isInstanceOf": "Promise",
"additionalProperties": true
}
]
}
],

Просмотреть файл

@ -39,6 +39,8 @@ let expectedCommonApis = [
// If you want to add a new powerful test API, please see bug 1287233.
"test.assertEq",
"test.assertFalse",
"test.assertRejects",
"test.assertThrows",
"test.assertTrue",
"test.fail",
"test.log",