824 lines
30 KiB
ReStructuredText
824 lines
30 KiB
ReStructuredText
XPCShell tests
|
|
==============
|
|
|
|
xpcshell tests are quick-to-run tests, that are generally used to write
|
|
unit tests. They do not have access to the full browser chrome like
|
|
``browser chrome tests``, and so have much
|
|
lower overhead. They are typical run by using ``./mach xpcshell-test``
|
|
which initiates a new ``xpcshell`` session with
|
|
the xpcshell testing harness. Anything available to the XPCOM layer
|
|
(through scriptable interfaces) can be tested with xpcshell. See
|
|
``Mozilla automated testing`` and ``pages
|
|
tagged "automated testing"`` for more
|
|
information.
|
|
|
|
Introducing xpcshell testing
|
|
----------------------------
|
|
|
|
xpcshell test filenames must start with ``test_``.
|
|
|
|
Creating a new test directory
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
If you need to create a new test directory, then follow the steps here.
|
|
The test runner needs to know about the existence of the tests and how
|
|
to configure them through the use of the ``xpcshell.toml`` manifest file.
|
|
|
|
First add a ``XPCSHELL_TESTS_MANIFESTS += ['xpcshell.toml']`` declaration
|
|
(with the correct relative ``xpcshell.toml`` path) to the ``moz.build``
|
|
file located in or above the directory.
|
|
|
|
Then create an empty ``xpcshell.toml`` file to tell the build system
|
|
about the individual tests, and provide any additional configuration
|
|
options.
|
|
|
|
Creating a new test in an existing directory
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
If you're creating a new test in an existing directory, you can simply
|
|
run:
|
|
|
|
.. code:: bash
|
|
|
|
$ ./mach addtest path/to/test/test_example.js
|
|
$ hg add path/to/test/test_example.js
|
|
|
|
This will automatically create the test file and add it to
|
|
``xpcshell.toml``, the second line adds it to your commit.
|
|
|
|
The test file contains an empty test which will give you an idea of how
|
|
to write a test. There are plenty more examples throughout
|
|
mozilla-central.
|
|
|
|
Running tests
|
|
-------------
|
|
|
|
To run the test, execute it by running the ``mach`` command from the
|
|
root of the Gecko source code directory.
|
|
|
|
.. code:: bash
|
|
|
|
# Run a single test:
|
|
$ ./mach xpcshell-test path/to/tests/test_example.js
|
|
|
|
# Test an entire test suite in a folder:
|
|
$ ./mach xpcshell-test path/to/tests/
|
|
|
|
# Or run any type of test, including both xpcshell and browser chrome tests:
|
|
$ ./mach test path/to/tests/test_example.js
|
|
|
|
The test is executed by the testing harness. It will call in turn:
|
|
|
|
- ``run_test`` (if it exists).
|
|
- Any functions added with ``add_task`` or ``add_test`` in the order
|
|
they were defined in the file.
|
|
|
|
See also the notes below around ``add_task`` and ``add_test``.
|
|
|
|
xpcshell Testing API
|
|
--------------------
|
|
|
|
xpcshell tests have access to the following functions. They are defined
|
|
in
|
|
:searchfox:`testing/xpcshell/head.js <testing/xpcshell/head.js>`
|
|
and
|
|
:searchfox:`testing/modules/Assert.sys.mjs <testing/modules/Assert.sys.mjs>`.
|
|
|
|
Assertions
|
|
^^^^^^^^^^
|
|
|
|
- ``Assert.ok(truthyOrFalsy[, message])``
|
|
- ``Assert.equal(actual, expected[, message])``
|
|
- ``Assert.notEqual(actual, expected[, message])``
|
|
- ``Assert.deepEqual(actual, expected[, message])``
|
|
- ``Assert.notDeepEqual(actual, expected[, message])``
|
|
- ``Assert.strictEqual(actual, expected[, message])``
|
|
- ``Assert.notStrictEqual(actual, expected[, message])``
|
|
- ``Assert.rejects(actual, expected[, message])``
|
|
- ``Assert.greater(actual, expected[, message])``
|
|
- ``Assert.greaterOrEqual(actual, expected[, message])``
|
|
- ``Assert.less(actual, expected[, message])``
|
|
- ``Assert.lessOrEqual(actual, expected[, message])``
|
|
|
|
|
|
These assertion methods are provided by
|
|
:searchfox:`testing/modules/Assert.sys.mjs <testing/modules/Assert.sys.mjs>`.
|
|
It implements the `CommonJS Unit Testing specification version
|
|
1.1 <http://wiki.commonjs.org/wiki/Unit_Testing/1.1>`__, which
|
|
provides a basic, standardized interface for performing in-code
|
|
logical assertions with optional, customizable error reporting. It is
|
|
*highly* recommended to use these assertion methods, instead of the
|
|
ones mentioned below. You can on all these methods remove the
|
|
``Assert.`` from the beginning of the name, e.g. ``ok(true)`` rather
|
|
than ``Assert.ok(true)``, however keeping the ``Assert.`` prefix may
|
|
be seen as more descriptive and easier to spot where the tests are.
|
|
``Assert.throws(callback, expectedException[, message])``
|
|
``Assert.throws(callback[, message])``
|
|
Asserts that the provided callback function throws an exception. The
|
|
``expectedException`` argument can be an ``Error`` instance, or a
|
|
regular expression matching part of the error message (like in
|
|
``Assert.throws(() => a.b, /is not defined/``).
|
|
``Assert.rejects(promise, expectedException[, message])``
|
|
Asserts that the provided promise is rejected. Note: that this should
|
|
be called prefixed with an ``await``. The ``expectedException``
|
|
argument can be an ``Error`` instance, or a regular expression
|
|
matching part of the error message. Example:
|
|
``await Assert.rejects(myPromise, /bad response/);``
|
|
|
|
Test case registration and execution
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
``add_task([condition, ]testFunc)``
|
|
Add an asynchronous function or to the list of tests that are to be
|
|
run asynchronously. Whenever the function ``await``\ s a
|
|
`Promise <https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise>`__,
|
|
the test runner waits until the promise is resolved or rejected
|
|
before proceeding. Rejected promises are converted into exceptions,
|
|
and resolved promises are converted into values.
|
|
You can optionally specify a condition which causes the test function
|
|
to be skipped; see `Adding conditions through the add_task or
|
|
add_test
|
|
function <#adding-conditions-through-the-add-task-or-add-test-function>`__
|
|
for details.
|
|
For tests that use ``add_task()``, the ``run_test()`` function is
|
|
optional, but if present, it should also call ``run_next_test()`` to
|
|
start execution of all asynchronous test functions. The test cases
|
|
must not call ``run_next_test()``, it is called automatically when
|
|
the task finishes. See `Async tests <#async-tests>`__, below, for
|
|
more information.
|
|
``add_test([condition, ]testFunction)``
|
|
Add a test function to the list of tests that are to be run
|
|
asynchronously.
|
|
You can optionally specify a condition which causes the test function
|
|
to be skipped; see `Adding conditions through the add_task or
|
|
add_test
|
|
function <#adding-conditions-through-the-add-task-or-add-test-function>`__
|
|
for details.
|
|
Each test function must call ``run_next_test()`` when it's done. For
|
|
tests that use ``add_test()``, ``the run_test()`` function is
|
|
optional, but if present, it should also call ``run_next_test()`` to
|
|
start execution of all asynchronous test functions. In most cases,
|
|
you should rather use the more readable variant ``add_task()``. See
|
|
`Async tests <#async-tests>`__, below, for more information.
|
|
``run_next_test()``
|
|
Run the next test function from the list of asynchronous tests. Each
|
|
test function must call ``run_next_test()`` when it's done.
|
|
``run_test()`` should also call ``run_next_test()`` to start
|
|
execution of all asynchronous test functions. See `Async
|
|
tests <#async-tests>`__, below, for more information.
|
|
**``registerCleanupFunction``**\ ``(callback)``
|
|
Executes the function ``callback`` after the current JS test file has
|
|
finished running, regardless of whether the tests inside it pass or
|
|
fail. You can use this to clean up anything that might otherwise
|
|
cause problems between test runs.
|
|
If ``callback`` returns a ``Promise``, the test will not finish until
|
|
the promise is fulfilled or rejected (making the termination function
|
|
asynchronous).
|
|
Cleanup functions are called in reverse order of registration.
|
|
``do_test_pending()``
|
|
Delay exit of the test until do_test_finished() is called.
|
|
do_test_pending() may be called multiple times, and
|
|
do_test_finished() must be paired with each before the unit test will
|
|
exit.
|
|
``do_test_finished()``
|
|
Call this function to inform the test framework that an asynchronous
|
|
operation has completed. If all asynchronous operations have
|
|
completed (i.e., every do_test_pending() has been matched with a
|
|
do_test_finished() in execution), then the unit test will exit.
|
|
|
|
Environment
|
|
^^^^^^^^^^^
|
|
|
|
``do_get_file(testdirRelativePath, allowNonexistent)``
|
|
Returns an ``nsILocalFile`` object representing the given file (or
|
|
directory) in the test directory. For example, if your test is
|
|
unit/test_something.js, and you need to access unit/data/somefile,
|
|
you would call ``do_get_file('data/somefile')``. The given path must
|
|
be delimited with forward slashes. You can use this to access
|
|
test-specific auxiliary files if your test requires access to
|
|
external files. Note that you can also use this function to get
|
|
directories.
|
|
|
|
.. note::
|
|
|
|
**Note:** If your test needs access to one or more files that
|
|
aren't in the test directory, you should install those files to
|
|
the test directory in the Makefile where you specify
|
|
``XPCSHELL_TESTS``. For an example, see
|
|
``netwerk/test/Makefile.in#117``.
|
|
``do_get_profile()``
|
|
Registers a directory with the profile service and returns an
|
|
``nsILocalFile`` object representing that directory. It also makes
|
|
sure that the **profile-change-net-teardown**,
|
|
**profile-change-teardown**, and **profile-before-change** `observer
|
|
notifications </en/Observer_Notifications#Application_shutdown>`__
|
|
are sent before the test finishes. This is useful if the components
|
|
loaded in the test observe them to do cleanup on shutdown (e.g.,
|
|
places).
|
|
|
|
.. note::
|
|
|
|
**Note:** ``do_register_cleanup`` will perform any cleanup
|
|
operation *before* the profile and the network is shut down by the
|
|
observer notifications.
|
|
``do_get_idle()``
|
|
By default xpcshell tests will disable the idle service, so that idle
|
|
time will always be reported as 0. Calling this function will
|
|
re-enable the service and return a handle to it; the idle time will
|
|
then be correctly requested to the underlying OS. The idle-daily
|
|
notification could be fired when requesting idle service. It is
|
|
suggested to always get the service through this method if the test
|
|
has to use idle.
|
|
``do_get_cwd()``
|
|
Returns an ``nsILocalFile`` object representing the test directory.
|
|
This is the directory containing the test file when it is currently
|
|
being run. Your test can write to this directory as well as read any
|
|
files located alongside your test. Your test should be careful to
|
|
ensure that it will not fail if a file it intends to write already
|
|
exists, however.
|
|
``load(testdirRelativePath)``
|
|
Imports the JavaScript file referenced by ``testdirRelativePath``
|
|
into the global script context, executing the code inside it. The
|
|
file specified is a file within the test directory. For example, if
|
|
your test is unit/test_something.js and you have another file
|
|
unit/extra_helpers.js, you can load the second file from the first by
|
|
calling ``load('extra_helpers.js')``.
|
|
|
|
Utility
|
|
^^^^^^^
|
|
|
|
``do_parse_document(path, type)``
|
|
Parses and returns a DOM document.
|
|
``executeSoon(callback)``
|
|
Executes the function ``callback`` on a later pass through the event
|
|
loop. Use this when you want some code to execute after the current
|
|
function has finished executing, but you don't care about a specific
|
|
time delay. This function will automatically insert a
|
|
``do_test_pending`` / ``do_test_finished`` pair for you.
|
|
``do_timeout(delay, fun)``
|
|
Call this function to schedule a timeout. The given function will be
|
|
called with no arguments provided after the specified delay (in
|
|
milliseconds). Note that you must call ``do_test_pending`` so that
|
|
the test isn't completed before your timer fires, and you must call
|
|
``do_test_finished`` when the actions you perform in the timeout
|
|
complete, if you have no other functionality to test. (Note: the
|
|
function argument used to be a string argument to be passed to eval,
|
|
and some older branches support only a string argument or support
|
|
both string and function.)
|
|
|
|
Multiprocess communication
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
``do_send_remote_message(name, optionalData)``
|
|
Asynchronously send a message to all remote processes. Pairs with
|
|
``do_await_remote_message`` or equivalent ProcessMessageManager
|
|
listeners.
|
|
``do_await_remote_message(name, optionalCallback)``
|
|
Returns a promise that is resolved when the message is received. Must
|
|
be paired with\ ``do_send_remote_message`` or equivalent
|
|
ProcessMessageManager calls. If **optionalCallback** is provided, the
|
|
callback must call ``do_test_finished``. If optionalData is passed
|
|
to ``do_send_remote_message`` then that data is the first argument to
|
|
**optionalCallback** or the value to which the promise resolves.
|
|
|
|
|
|
xpcshell.toml manifest
|
|
----------------------
|
|
|
|
The manifest controls what tests are included in a test suite, and the
|
|
configuration of the tests. It is loaded via the \`moz.build\` property
|
|
configuration property.
|
|
|
|
The following are all of the configuration options for a test suite as
|
|
listed under the ``[DEFAULT]`` section of the manifest.
|
|
|
|
``tags``
|
|
Tests can be filtered by tags when running multiple tests. The
|
|
command for mach is ``./mach xpcshell-test --tag TAGNAME``
|
|
``head``
|
|
The relative path to the head JavaScript file, which is run once
|
|
before a test suite is run. The variables declared in the root scope
|
|
are available as globals in the test files. See `Test head and
|
|
support files <#test-head-and-support-files>`__ for more information
|
|
and usage.
|
|
``firefox-appdir``
|
|
Set this to "browser" if your tests need access to things in the
|
|
browser/ directory (e.g. additional XPCOM services that live there)
|
|
``skip-if`` ``run-if`` ``fail-if``
|
|
For this entire test suite, run the tests only if they meet certain
|
|
conditions. See `Adding conditions in the xpcshell.toml
|
|
manifest <#adding-conditions-through-the-add-task-or-add-test-function>`__ for how
|
|
to use these properties.
|
|
``support-files``
|
|
Make files available via the ``resource://test/[filename]`` path to
|
|
the tests. The path can be relative to other directories, but it will
|
|
be served only with the filename. See `Test head and support
|
|
files <#test-head-and-support-files>`__ for more information and
|
|
usage.
|
|
``[test_*]``
|
|
Test file names must start with ``test_`` and are listed in square
|
|
brackets
|
|
|
|
|
|
Creating a new xpcshell.toml file
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
When creating a new directory and new xpcshell.toml manifest file, the
|
|
following must be added to a moz.build file near that file in the
|
|
directory hierarchy:
|
|
|
|
.. code:: bash
|
|
|
|
XPCSHELL_TESTS_MANIFESTS += ['path/to/xpcshell.toml']
|
|
|
|
Typically, the moz.build containing *XPCSHELL_TESTS_MANIFESTS* is not in
|
|
the same directory as *xpcshell.toml*, but rather in a parent directory.
|
|
Common directory structures look like:
|
|
|
|
.. code:: bash
|
|
|
|
feature
|
|
├──moz.build
|
|
└──tests/xpcshell
|
|
└──xpcshell.toml
|
|
|
|
# or
|
|
|
|
feature
|
|
├──moz.build
|
|
└──tests
|
|
├──moz.build
|
|
└──xpcshell
|
|
└──xpcshell.toml
|
|
|
|
|
|
Test head and support files
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Typically in a test suite, similar setup code and dependencies will need
|
|
to be loaded in across each test. This can be done through the test
|
|
head, which is the file declared in the ``xpcshell.toml`` manifest file
|
|
under the ``head`` property. The file itself is typically called
|
|
``head.js``. Any variable declared in the test head will be in the
|
|
global scope of each test in that test suite.
|
|
|
|
In addition to the test head, other support files can be declared in the
|
|
``xpcshell.toml`` manifest file. This is done through the
|
|
``support-files`` declaration. These files will be made available
|
|
through the url ``resource://test`` plus the name of the file. These
|
|
files can then be loaded in using the
|
|
``ChromeUtils.importESModule`` function
|
|
or other loaders. The support files can be located in other directory as
|
|
well, and they will be made available by their filename.
|
|
|
|
.. code:: bash
|
|
|
|
# File structure:
|
|
|
|
path/to/tests
|
|
├──head.js
|
|
├──module.mjs
|
|
├──moz.build
|
|
├──test_example.js
|
|
└──xpcshell.toml
|
|
|
|
.. code:: toml
|
|
|
|
# xpcshell.toml
|
|
[DEFAULT]
|
|
head = head.js
|
|
support-files =
|
|
./module.mjs
|
|
../../some/other/file.js
|
|
[test_component_state.js]
|
|
|
|
.. code:: js
|
|
|
|
// head.js
|
|
var globalValue = "A global value.";
|
|
|
|
// Import support-files.
|
|
const { foo } = ChromeUtils.importESModule("resource://test/module.mjs");
|
|
const { bar } = ChromeUtils.importESModule("resource://test/file.mjs");
|
|
|
|
.. code:: js
|
|
|
|
// test_example.js
|
|
function run_test() {
|
|
equal(globalValue, "A global value.", "Declarations in head.js can be accessed");
|
|
}
|
|
|
|
|
|
Additional testing considerations
|
|
---------------------------------
|
|
|
|
Async tests
|
|
^^^^^^^^^^^
|
|
|
|
Asynchronous tests (that is, those whose success cannot be determined
|
|
until after ``run_test`` finishes) can be written in a variety of ways.
|
|
|
|
Task-based asynchronous tests
|
|
-----------------------------
|
|
|
|
The easiest is using the ``add_task`` helper. ``add_task`` can take an
|
|
asynchronous function as a parameter. ``add_task`` tests are run
|
|
automatically if you don't have a ``run_test`` function.
|
|
|
|
.. code:: js
|
|
|
|
add_task(async function test_foo() {
|
|
let foo = await makeFoo(); // makeFoo() returns a Promise<foo>
|
|
equal(foo, expectedFoo, "Should have received the expected object");
|
|
});
|
|
|
|
add_task(async function test_bar() {
|
|
let foo = await makeBar(); // makeBar() returns a Promise<bar>
|
|
Assert.equal(bar, expectedBar, "Should have received the expected object");
|
|
});
|
|
|
|
Callback-based asynchronous tests
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
You can also use ``add_test``, which takes a function and adds it to the
|
|
list of asynchronously-run functions. Each function given to
|
|
``add_test`` must also call ``run_next_test`` at its end. You should
|
|
normally use ``add_task`` instead of ``add_test``, but you may see
|
|
``add_test`` in existing tests.
|
|
|
|
.. code:: js
|
|
|
|
add_test(function test_foo() {
|
|
makeFoo(function callback(foo) { // makeFoo invokes a callback<foo> once completed
|
|
equal(foo, expectedFoo);
|
|
run_next_test();
|
|
});
|
|
});
|
|
|
|
add_test(function test_bar() {
|
|
makeBar(function callback(bar) {
|
|
equal(bar, expectedBar);
|
|
run_next_test();
|
|
});
|
|
});
|
|
|
|
|
|
Other tests
|
|
^^^^^^^^^^^
|
|
|
|
We can also tell the test harness not to kill the test process once
|
|
``run_test()`` is finished, but to keep spinning the event loop until
|
|
our callbacks have been called and our test has completed. Newer tests
|
|
prefer the use of ``add_task`` rather than this method. This can be
|
|
achieved with ``do_test_pending()`` and ``do_test_finished()``:
|
|
|
|
.. code:: js
|
|
|
|
function run_test() {
|
|
// Tell the harness to keep spinning the event loop at least
|
|
// until the next do_test_finished() call.
|
|
do_test_pending();
|
|
|
|
someAsyncProcess(function callback(result) {
|
|
equal(result, expectedResult);
|
|
|
|
// Close previous do_test_pending() call.
|
|
do_test_finished();
|
|
});
|
|
}
|
|
|
|
|
|
Testing in child processeses
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
By default xpcshell tests run in the parent process. If you wish to run
|
|
test logic in the child, you have several ways to do it:
|
|
|
|
#. Create a regular test_foo.js test, and then write a wrapper
|
|
test_foo_wrap.js file that uses the ``run_test_in_child()`` function
|
|
to run an entire script file in the child. This is an easy way to
|
|
arrange for a test to be run twice, once in chrome and then later
|
|
(via the \_wrap.js file) in content. See /network/test/unit_ipc for
|
|
examples. The ``run_test_in_child()`` function takes a callback, so
|
|
you should be able to call it multiple times with different files, if
|
|
that's useful.
|
|
#. For tests that need to run logic in both the parent + child processes
|
|
during a single test run, you may use the poorly documented
|
|
``sendCommand()`` function, which takes a code string to be executed
|
|
on the child, and a callback function to be run on the parent when it
|
|
has completed. You will want to first call
|
|
do_load_child_test_harness() to set up a reasonable test environment
|
|
on the child. ``sendCommand`` returns immediately, so you will
|
|
generally want to use ``do_test_pending``/``do_test_finished`` with
|
|
it. NOTE: this method of test has not been used much, and your level
|
|
of pain may be significant. Consider option #1 if possible.
|
|
|
|
See the documentation for ``run_test_in_child()`` and
|
|
``do_load_child_test_harness()`` in testing/xpcshell/head.js for more
|
|
information.
|
|
|
|
|
|
Platform-specific tests
|
|
^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Sometimes you might want a test to know what platform it's running on
|
|
(to test platform-specific features, or allow different behaviors). Unit
|
|
tests are not normally invoked from a Makefile (unlike Mochitests), or
|
|
preprocessed (so not #ifdefs), so platform detection with those methods
|
|
isn't trivial.
|
|
|
|
|
|
Runtime detection
|
|
^^^^^^^^^^^^^^^^^
|
|
|
|
Some tests will want to only execute certain portions on specific
|
|
platforms. Use
|
|
`AppConstants.sys.mjs <https://searchfox.org/mozilla-central/rev/5f0a7ca8968ac5cef8846e1d970ef178b8b76dcc/toolkit/modules/AppConstants.sys.mjs#158>`__
|
|
for determining the platform, for example:
|
|
|
|
.. code:: js
|
|
|
|
let { AppConstants } =
|
|
ChromeUtils.importESModule("resource://gre/modules/AppConstants.mjs");
|
|
|
|
let isMac = AppConstants.platform == "macosx";
|
|
|
|
|
|
Conditionally running a test
|
|
----------------------------
|
|
|
|
There are two different ways to conditional skip a test, either through
|
|
|
|
|
|
Adding conditions through the ``add_task`` or ``add_test`` function
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
You can use conditionals on individual test functions instead of entire
|
|
files. The condition is provided as an optional first parameter passed
|
|
into ``add_task()`` or ``add_test()``. The condition is an object which
|
|
contains a function named ``skip_if()``, which is an `arrow
|
|
function </en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions>`__
|
|
returning a boolean value which is **``true``** if the test should be
|
|
skipped.
|
|
|
|
For example, you can provide a test which only runs on Mac OS X like
|
|
this:
|
|
|
|
.. code:: js
|
|
|
|
let { AppConstants } =
|
|
ChromeUtils.importESModule("resource://gre/modules/AppConstants.sys.mjs");
|
|
|
|
add_task({
|
|
skip_if: () => AppConstants.platform != "mac"
|
|
}, async function some_test() {
|
|
// Test code goes here
|
|
});
|
|
|
|
Since ``AppConstants.platform != "mac"`` is ``true`` only when testing
|
|
on Mac OS X, the test will be skipped on all other platforms.
|
|
|
|
.. note::
|
|
|
|
**Note:** Arrow functions are ideal here because if your condition
|
|
compares constants, it will already have been evaluated before the
|
|
test is even run, meaning your output will not be able to show the
|
|
specifics of what the condition is.
|
|
|
|
|
|
Adding conditions in the xpcshell.toml manifest
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Sometimes you may want to add conditions to specify that a test should
|
|
be skipped in certain configurations, or that a test is known to fail on
|
|
certain platforms. You can do this in xpcshell manifests by adding
|
|
annotations below the test file entry in the manifest, for example:
|
|
|
|
.. code:: ini
|
|
|
|
[test_example.js]
|
|
skip-if = os == 'win'
|
|
|
|
This example would skip running ``test_example.js`` on Windows.
|
|
|
|
.. note::
|
|
|
|
**Note:** Starting with Gecko (Firefox 40 / Thunderbird 40 /
|
|
SeaMonkey 2.37), you can use conditionals on individual test
|
|
functions instead of on entire files. See `Adding conditions through
|
|
the add_task or add_test
|
|
function <#adding-conditions-through-the-add-task-or-add-test-function>`__
|
|
above for details.
|
|
|
|
There are currently four conditionals you can specify:
|
|
|
|
skip-if
|
|
"""""""
|
|
|
|
``skip-if`` tells the harness to skip running this test if the condition
|
|
evaluates to true. You should use this only if the test has no meaning
|
|
on a certain platform, or causes undue problems like hanging the test
|
|
suite for a long time.
|
|
|
|
run-if
|
|
''''''
|
|
|
|
``run-if`` tells the harness to only run this test if the condition
|
|
evaluates to true. It functions as the inverse of ``skip-if``.
|
|
|
|
fail-if
|
|
"""""""
|
|
|
|
``fail-if`` tells the harness that this test is expected to fail if the
|
|
condition is true. If you add this to a test, make sure you file a bug
|
|
on the failure and include the bug number in a comment in the manifest,
|
|
like:
|
|
|
|
.. code:: ini
|
|
|
|
[test_example.js]
|
|
# bug xxxxxx
|
|
fail-if = os == 'linux'
|
|
|
|
run-sequentially
|
|
""""""""""""""""
|
|
|
|
``run-sequentially``\ basically tells the harness to run the respective
|
|
test in isolation. This is required for tests that are not
|
|
"thread-safe". You should do all you can to avoid using this option,
|
|
since this will kill performance. However, we understand that there are
|
|
some cases where this is imperative, so we made this option available.
|
|
If you add this to a test, make sure you specify a reason and possibly
|
|
even a bug number, like:
|
|
|
|
.. code:: ini
|
|
|
|
[test_example.js]
|
|
run-sequentially = Has to launch Firefox binary, bug 123456.
|
|
|
|
|
|
Manifest conditional expressions
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
For a more detailed description of the syntax of the conditional
|
|
expressions, as well as what variables are available, `see this
|
|
page </en/XPCshell_Test_Manifest_Expressions`.
|
|
|
|
|
|
Running a specific test only
|
|
----------------------------
|
|
|
|
When working on a specific feature or issue, it is convenient to only
|
|
run a specific task from a whole test suite. Use ``.only()`` for that
|
|
purpose:
|
|
|
|
.. code:: js
|
|
|
|
add_task(async function some_test() {
|
|
// Some test.
|
|
});
|
|
|
|
add_task(async function some_interesting_test() {
|
|
// Only this test will be executed.
|
|
}).only();
|
|
|
|
|
|
Problems with pending events and shutdown
|
|
-----------------------------------------
|
|
|
|
Events are not processed during test execution if not explicitly
|
|
triggered. This sometimes causes issues during shutdown, when code is
|
|
run that expects previously created events to have been already
|
|
processed. In such cases, this code at the end of a test can help:
|
|
|
|
.. code:: js
|
|
|
|
let thread = gThreadManager.currentThread;
|
|
while (thread.hasPendingEvents())
|
|
thread.processNextEvent(true);
|
|
|
|
|
|
Debugging xpcshell-tests
|
|
------------------------
|
|
|
|
|
|
Running unit tests under the javascript debugger
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
Via --jsdebugger
|
|
^^^^^^^^^^^^^^^^
|
|
|
|
You can specify flags when issuing the ``xpcshell-test`` command that
|
|
will cause your test to stop right before running so you can attach the
|
|
`javascript debugger </docs/Tools/Tools_Toolbox>`__.
|
|
|
|
Example:
|
|
|
|
.. code:: bash
|
|
|
|
$ ./mach xpcshell-test --jsdebugger browser/components/tests/unit/test_browserGlue_pingcentre.js
|
|
0:00.50 INFO Running tests sequentially.
|
|
...
|
|
0:00.68 INFO ""
|
|
0:00.68 INFO "*******************************************************************"
|
|
0:00.68 INFO "Waiting for the debugger to connect on port 6000"
|
|
0:00.68 INFO ""
|
|
0:00.68 INFO "To connect the debugger, open a Firefox instance, select 'Connect'"
|
|
0:00.68 INFO "from the Developer menu and specify the port as 6000"
|
|
0:00.68 INFO "*******************************************************************"
|
|
0:00.68 INFO ""
|
|
0:00.71 INFO "Still waiting for debugger to connect..."
|
|
...
|
|
|
|
At this stage in a running Firefox instance:
|
|
|
|
- Go to the three-bar menu, then select ``More tools`` ->
|
|
``Remote Debugging``
|
|
- A new tab is opened. In the Network Location box, enter
|
|
``localhost:6000`` and select ``Connect``
|
|
- You should then get a link to *``Main Process``*, click it and the
|
|
Developer Tools debugger window will open.
|
|
- It will be paused at the start of the test, so you can add
|
|
breakpoints, or start running as appropriate.
|
|
|
|
If you get a message such as:
|
|
|
|
::
|
|
|
|
0:00.62 ERROR Failed to initialize debugging: Error: resource://devtools appears to be inaccessible from the xpcshell environment.
|
|
This can usually be resolved by adding:
|
|
firefox-appdir = browser
|
|
to the xpcshell.toml manifest.
|
|
It is possible for this to alter test behevior by triggering additional browser code to run, so check test behavior after making this change.
|
|
|
|
This is typically a test in core code. You can attempt to add that to
|
|
the xpcshell.toml, however as it says, it might affect how the test runs
|
|
and cause failures. Generally the firefox-appdir should only be left in
|
|
xpcshell.toml for tests that are in the browser/ directory, or are
|
|
Firefox-only.
|
|
|
|
|
|
Running unit tests under a C++ debugger
|
|
---------------------------------------
|
|
|
|
|
|
Via ``--debugger and -debugger-interactive``
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
You can specify flags when issuing the ``xpcshell-test`` command that
|
|
will launch xpcshell in the specified debugger (implemented in
|
|
`bug 382682 <https://bugzilla.mozilla.org/show_bug.cgi?id=382682>`__).
|
|
Provide the full path to the debugger, or ensure that the named debugger
|
|
is in your system PATH.
|
|
|
|
Example:
|
|
|
|
.. code:: bash
|
|
|
|
$ ./mach xpcshell-test --debugger gdb --debugger-interactive netwerk/test/unit/test_resumable_channel.js
|
|
# js>_execute_test();
|
|
...failure or success messages are printed to the console...
|
|
# js>quit();
|
|
|
|
On Windows with the VS debugger:
|
|
|
|
.. code:: bash
|
|
|
|
$ ./mach xpcshell-test --debugger devenv --debugger-interactive netwerk/test/test_resumable_channel.js
|
|
|
|
Or with WinDBG:
|
|
|
|
.. code:: bash
|
|
|
|
$ ./mach xpcshell-test --debugger windbg --debugger-interactive netwerk/test/test_resumable_channel.js
|
|
|
|
Or with modern WinDbg (WinDbg Preview as of April 2020):
|
|
|
|
.. code:: bash
|
|
|
|
$ ./mach xpcshell-test --debugger WinDbgX --debugger-interactive netwerk/test/test_resumable_channel.js
|
|
|
|
|
|
Debugging xpcshell tests in a child process
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
To debug the child process, where code is often being run in a project,
|
|
set MOZ_DEBUG_CHILD_PROCESS=1 in your environment (or on the command
|
|
line) and run the test. You will see the child process emit a printf
|
|
with its process ID, then sleep. Attach a debugger to the child's pid,
|
|
and when it wakes up you can debug it:
|
|
|
|
.. code:: bash
|
|
|
|
$ MOZ_DEBUG_CHILD_PROCESS=1 ./mach xpcshell-test test_simple_wrap.js
|
|
CHILDCHILDCHILDCHILD
|
|
debug me @13476
|
|
|
|
|
|
Debug both parent and child processes
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Use MOZ_DEBUG_CHILD_PROCESS=1 to attach debuggers to each process. (For
|
|
gdb at least, this means running separate copies of gdb, one for each
|
|
process.)
|