The Bad Old Days
The JavaScript Tests have been the red headed stepchild of mozilla testing for some time. At least some of the reasons are:
-
The tests date to pre-mozilla days and do not follow the style of any of the other test suites.
-
The tests were originally designed to be run only in the JavaScript shell and had the ability to be run in the browser tacked on to them like a bad toupe
-
Not all of the tests pass and keeping track of the known failures has been a time consuming and error prone task.
-
Not having a good method of tracking failures, excluding long running tests or excluding tests which crashed the browser resulted in unacceptable run times for developers thus leaving a gap in the testing developers could perform prior to checking in changes to the JavaScript engine.
-
The automation used to run the tests in the shell and browser was not appropriate for running on the tinderboxes. As a result, the JavaScript engine did not benefit from immediate, cross-platform testing for each checkin but instead had to wait on me to detect regressions and file bugs.
-
The tests were not specialized for each branch but were instead maintained identically across branches. As the JavaScript engine has evolved, the differences between passing behavior on the branches has been problematic.
-
A single person was responsible for adding new tests causing the addition of new tests to increasingly lag behind new patches.
All of that has come to and end, because…
The Good Times have arrived!
(at least for the browser on tracemonkey)
David Baron’s reftest framework provides the solution to many of the problems of the Bad Old Days. It provides:
-
Familiar test invocation.
-
Relatively quick run times compared to the old Sisyphus-based browser JavaScript tests.
-
The reftest style manifests provide an excellent means of tracking obsolete tests, test failures, tests which take too long to run or tests which crash
-
Easy (hopefully) integration into the automated tests running on Tinderbox by leveraging the same approaches used to run the layout reftests
Currently, only the browser jsreftests are implemented. The same approach is planned to be implemented for the shell tests.
Running Browser JavaScript reftests
Running the jsreftests in the browser is familiar to anyone who has run the layout reftests or crash tests. Simply invoke make
in the object directory with the target jstestbrowser
.
$ make -C $(OBJDIR) jstestbrowser
This executes the following command.
$ python $(OBJDIR)/_tests/reftest/runreftest.py \
--extra-profile-file=js/src/tests/user.js js/src/tests/jstests.list
The user.js
file is added to the run time profile to enable UniveralXPConnect and other privileges required for running the JavaScript tests. You can customize user.js to set other preferences you wish.
You can see example logs here:
No longer will you have to perform base-line
runs to determine the known failures prior to testing your patches. If the jsreftests run to completion without crashing and without generating any UNEXPECTED
results, your patch is good to go.
jsreftest manifests
jstests.list
is the reftest manifest file used to tell the test runner which tests to execute. jstests.list
is to be used for both the JavaScript shell tests and the JavaScript browser tests. url-prefix, a new feature for reftest manifests, is used to provide a single manifest file for both the shell and browser tests.
The manifest files are organized into a 3-level hierarchy.
The top level manifest files live in js/src/tests/
. They incorporate the individual suites through the include
manifest keyword. Whenever a new suite is added, the top level manifest files must be updated to include it. New suites must also be listed in js/src/tests/Makefile.in
in order to be packaged with the other tests.
The second level manifest files are contained in the suite directories. They also include the sub-suites through the use of the include
manifest keyword. Whenever a new sub-suite is added to a suite, the suite’s manifest files must be updated to include it.
The third and final level manifest files are contained in the sub-suite directories. These manifest files list each test using the script manifest keyword
. This keyword tells the test runner to obtain the actual test results from the array returned by the getTestCases()
function in the testcase. In order for the test results to be properly recorded in the test case results array, you must use one of the standard reporting functions, such as reportCompare()
, reportMatch()
, etc., to record the result of the test. If you do not use reportCompare()
or one of its cousins, your test will fail with the message that No test results reported
.
The first line of the manifest file contains a “url-prefix” which tells the reftest extension to prefix each test file with the url-prefix value before attempting to load it. The shell test driver will ignore the url-prefix, thus allowing a single manifest file to be used by both the shell and browser. The remainder of the manifest lists each test file preceded by the script
keyword.
For example, js/src/tests/ecma_5/Date/jstests.list
:
url-prefix ../../jsreftest.html?test=ecma_5/Date/ script 15.9.4.2.js
The truly great thing about the reftest manifest files are their ability to give tests a failure-type
. Each test can be marked as either:
- fails
-
Tests marked with
fails
will be executed and will be marked asTEST-KNOWN-FAIL
if they fail. However if they pass, they will be marked asTEST-UNEXPECTED-PASS
. - random
-
Tests marked with
random
will be executed and will be marked asTEST-KNOWN-FAIL(EXPECTED RANDOM)
if they fail orTEST-PASS(EXPECTED RANDOM)
if they pass. This is useful for tests which may not reliably report a test failure but which you wish to continue to execute in the event they may find a regression through a crash or assertion.random
results are also used in the event that a test that returns multiple test results is marked with the failure-typefails
. In that case, failures are marked withTEST-KNOWN-FAIL
while successes are marked withTEST-PASS(EXPECTED RANDOM)
. This is necessary since it is not possible to mark the individual test case results in a multi-result test as either passing or failing. - skip
-
Tests marked with
skip
will not be executed at all.skip
can be used for obsolete tests, for tests which are known to crash the browser, tests which do not terminate or tests which take too much time.
The even greater thing about the reftest manifest files are their ability to make the failure-types conditional. These means that you can conditionally mark tests as failing or to be skipped depending on the build type (whether you are testing a debug build), the operating system, or even the cpu type. The variables which can be used in the failure-type conditional are described in the reftest sandbox implementation. You can also find examples in the tree.
You can read more about the reftest manifests in the reftest README.txt
Checklist when adding New Tests
-
New suites should be added to the top level
jstests.list
, andMakefile.in
files injs/src/tests
. -
New sub-suites should be added to the suite level
jstests.list
file. -
New tests should be listed in the appropriate sub-suite’s
jstests.list
file. Each sub-suite’s jstests.list manifest must begin with a url-prefix.url-prefix ../../jsreftest.html?test=suitedir/subsuitedir/
Tests must call the
reportCompare()
function (or its cousins) to record test results.
Updated September 26, 2009
The original patch had to be backed out due to failures in the SpiderMonkey shell. As a result, the js/tests were moved to js/src/tests to facilitate their integration into the build system. There was some pushback also about the two different manifest files required by the original design. With a modification to reftest.js to allow the use of a url-prefix, the browser specific manifest was dropped.
See bug 469718 for more background.