133 lines
6 KiB
Markdown
133 lines
6 KiB
Markdown
# JavaScript Objects test framework
|
|
|
|
`JSObjectsTestUtils.sys.mjs` exposes xpcshell and mochitest test helpers to easily test all the
|
|
arbitrary JavaScript object types that Gecko can spawn in JavaScript.
|
|
|
|
This includes:
|
|
* any JavaScript type that Spidermonkey supports,
|
|
* any JavaScript type exposed to Web Page from Gecko (All the DOM APIs),
|
|
* any JavaScript type only exposed to Worker threads,
|
|
* any privileged JavaScript type used in parent or content processes,
|
|
* ...
|
|
|
|
This test framework consists in:
|
|
* a manifest file, [AllJavaScriptTypes.mjs](https://searchfox.org/mozilla-central/source/devtools/shared/tests/objects/AllJavaScriptTypes.mjs) which defines all the JS objects that gecko can spawn
|
|
* one xpcshell or one mochitest file, using [JSObjectTestUtils](https://searchfox.org/mozilla-central/source/devtools/shared/tests/objects/JSObjectTestUtils.sys.mjs) helper to evaluate all the JS Objects and generate a value for each of them.
|
|
* a snapshot file, read and written by JSObjectTestUtils, specific to each xpcshell/mochitest and storing all its the generated values.
|
|
|
|
You can run your test to execute the assertions:
|
|
```bash
|
|
$ ./mach test my/browser_test.js
|
|
```
|
|
|
|
And you can update the snapshot by running:
|
|
```bash
|
|
$ ./mach test my/browser_test.js --setenv UPDATE_SNAPSHOT=true
|
|
```
|
|
|
|
## JSObjectsTestUtils APIs
|
|
|
|
This test helper is available to all xpcshell and mochitest tests from `resource://testing-common/JSObjectsTestUtils.sys.mjs`.
|
|
It exposes only two methods:
|
|
* `JSOBjectsTestUtils.init(testScope)`
|
|
|
|
Which is meant to be called early in the test run, before the test page is loaded.
|
|
This will update all preferences which helps enable all the experimental types
|
|
or ease instantiating them.
|
|
|
|
The global scope for the current test should be passed as argument.
|
|
This will be used to retrieve the current test location in order to
|
|
load the expected values from an ES Module located in the same folder as the current test.
|
|
|
|
* `JSOBjectsTestUtils.runTest(expectedValuesFileName, testFunction)`
|
|
|
|
This is the main method, which will call the `testFunction` for each JavaScript object example.
|
|
|
|
This method will receive a single argument which is an object with two attributes:
|
|
* `context`
|
|
A string whose value can be one of [AllJavaScriptTypes.mjs](https://searchfox.org/mozilla-central/source/devtools/shared/tests/objects/AllJavaScriptTypes.mjs) `CONTEXTS` dictionary:
|
|
* "js": Basic JS value available from any possible JavaScript context (worker, page, chrome scopes)
|
|
* "page": Values only available from a Web page global
|
|
* "chrome": Privileged values, only available from a chrome, privileged scope
|
|
|
|
* `expression`
|
|
A string which should be evaled in order to instantiate the object example to cover.
|
|
|
|
For example, it may receive as argument:
|
|
`{ type: "js", expression: "42" }`
|
|
`{ type: "js", expression: "[42]" }`
|
|
`{ type: "js", expression: "let a = new BigInt64Array(1); a[0] = BigInt(42); a;" }`
|
|
`{ type: "page", expression: "document.body" }`
|
|
`{ type: "chrome", expression: "ChromeUtils.domProcessChild" }`
|
|
|
|
This method should return the value which represents the given object example.
|
|
|
|
### Mochitest Example
|
|
|
|
```js
|
|
const { JSObjectsTestUtils, CONTEXTS } = ChromeUtils.importESModule(
|
|
"resource://testing-common/JSObjectsTestUtils.sys.mjs"
|
|
);
|
|
// We have to manually initialize the test helper module from the parent process
|
|
JSObjectsTestUtils.init(this);
|
|
|
|
// Name of your snapshot file, next to this test, to be registered in the .toml file in a support-files rule
|
|
const EXPECTED_VALUES_FILE = "browser_mytest.snapshot.mjs";
|
|
|
|
add_task(async function () {
|
|
// Open the test page suitable to spawn all the expected JS Objects in a new tab
|
|
//
|
|
// nsHttpServer does not support https
|
|
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
|
const tab = await addTab("http://example.com");
|
|
|
|
await JSObjectsTestUtils.runTest(
|
|
EXPECTED_VALUES_FILE,
|
|
async function ({ context, expression }) {
|
|
// In this test, we ignore the privileged objects
|
|
if (context == CONTEXTS.CHROME) {
|
|
return;
|
|
}
|
|
|
|
// Then, execute the key runTest method from the tab's content process
|
|
await SpecialPowsers.spawn(tab.linkedBrowser, [expression], async function (expressionString) {
|
|
|
|
// This is the most important part, where we evaluate the `expression` provided by the test framework
|
|
// in the test page and return the value we would like to assert over time.
|
|
// We have to ensure handling exception, which we expect to interpret as a returned value.
|
|
let value;
|
|
try {
|
|
value = content.eval(expressionString);
|
|
} catch(e) {
|
|
value = e;
|
|
}
|
|
|
|
// Here we cover the native stringification of all the JS Objects.
|
|
return String(value);
|
|
}
|
|
);
|
|
});
|
|
```
|
|
|
|
|
|
## AllJavaScriptTypes manifest
|
|
|
|
All the JavaScript object examples are stored in a manifest file located in the current folder: AllJavaScriptTypes.mjs.
|
|
|
|
This module exports an array of objects descriptions, which are objects with the two following attributes:
|
|
* `context`:
|
|
A String to designate the context into which this expression could be evaluated.
|
|
See the first paragraph for the list of all contexts.
|
|
* `expression`:
|
|
The JavaScript expression to evaluate, which can either be:
|
|
* a string representing a piece of JavaScript value.
|
|
* a function, which would be stringified and evaluated in many scopes.
|
|
This is to be used when you need intermediate value before spawning another specific JS Value.
|
|
If the expression throws, the thrown exception will be considered as the value to assert.
|
|
|
|
The object descriptions can also have a couple of optional attributes:
|
|
* `prefs`: An array of arrays. The nested array are made of two elements: a string and a value.
|
|
The string represents a preference name and the value, the preference value.
|
|
This is used to set preference before starting the test.
|
|
This helps enable as well as ease instantiating the related JS value.
|
|
* `disabled`: A boolean to be set to true if the value can't be instantiated on the current runtime.
|