mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 21:43:21 +00:00
docs: Improve documentation on node test suite.
The most important part of this is encouraging folks to read the zjquery documentation.
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
# JavaScript unit tests
|
||||
|
||||
As an alternative to the black-box whole-app testing, you can unit test
|
||||
individual JavaScript files.
|
||||
Our node-based JavaScript unit tests system is the preferred way to
|
||||
test JavaScript code in Zulip. We prefer it over the
|
||||
[Casper black-box whole-app testing](../testing/testing-with-casper.html),
|
||||
system since it is much (>100x) faster and also easier to do correctly
|
||||
than the Casper system.
|
||||
|
||||
You can run tests as follow:
|
||||
```
|
||||
@@ -36,32 +39,46 @@ see if there are corresponding test in `frontend_tests/node_tests`. If
|
||||
there are, you should strive to follow the patterns of the existing tests
|
||||
and add your own tests.
|
||||
|
||||
## Coverage reports
|
||||
## How the node tests work
|
||||
|
||||
You can automatically generate coverage reports for the JavaScript unit
|
||||
tests like this:
|
||||
Unlike the [casper unit tests](../testing/testing-with-casper.html),
|
||||
which use the `phantomjs` browser connected to a running Zulip
|
||||
deveopment server, our node unit tests don't have a browser, don't
|
||||
talk to a server, and generally don't use a complete virtual DOM (a
|
||||
handful of tests use the `jsdom` library for this purpose) because
|
||||
those slow down the tests a lot, and often don't add much value.
|
||||
|
||||
```
|
||||
tools/test-js-with-node --coverage
|
||||
```
|
||||
Instead, the preferred model for our unit tests is to mock DOM
|
||||
manipulations (which in Zulip are almost exclusively done via
|
||||
`jQuery`) using a custom library
|
||||
[zjquery](https://github.com/zulip/zulip/blob/master/frontend_tests/zjsunit/zjquery.js).
|
||||
|
||||
If tests pass, you will get instructions to view coverage reports
|
||||
in your browser.
|
||||
The
|
||||
[unit test file](https://github.com/zulip/zulip/blob/master/frontend_tests/node_tests/zjquery.js)
|
||||
for `zjquery` is designed to be also serve as nice documentation for
|
||||
how to use `zjquery`, and is **highly recommended reading** for anyone
|
||||
working on or debugging the Zulip node tests.
|
||||
|
||||
Note that modules that
|
||||
we don't test *at all* aren't listed in the report, so this tends to
|
||||
overstate how good our overall coverage is, but it's accurate for
|
||||
individual files. You can also click a filename to see the specific
|
||||
statements and branches not tested. 100% branch coverage isn't
|
||||
necessarily possible, but getting to at least 80% branch coverage is a
|
||||
good goal.
|
||||
Conceptually, the `zjquery` library provides minimal versions of most
|
||||
`jQuery` DOM manipulation functions, and has a convenient system for
|
||||
letting you setup return values for more complex functions. For
|
||||
example, if the code you'd like to test calls `$obj.find()`, you can
|
||||
use `$obj.set_find_results(selector, $value)` to setup `zjquery` so
|
||||
that calls to `$obj.find(selector)` will return `$value`. See the
|
||||
unit test file for details.
|
||||
|
||||
The `zjquery` library itself is only about 500 lines of code, and can
|
||||
also be a useful resource if you're having trouble debugging DOM
|
||||
access in the unit tests.
|
||||
|
||||
## Handling dependencies in unit tests
|
||||
|
||||
The following scheme helps avoid tests leaking globals between each
|
||||
other.
|
||||
|
||||
You want to categorize each module as follows:
|
||||
The other big challenge with doing unit tests for a JavaScript project
|
||||
is that often one wants to limit the scope the production code being
|
||||
run, just to avoid doing extra setup work that isn't relevant to the
|
||||
code you're trying to test. For that reason, each unit test file
|
||||
explicitly declares all of the modules it depends on, with a few
|
||||
different types of declarations depending on whether we want to:
|
||||
|
||||
- Exercise the module's real code for deeper, more realistic testing?
|
||||
- Stub out the module's interface for more control, speed, and
|
||||
@@ -75,8 +92,8 @@ like the following toward the top of your test file:
|
||||
> zrequire('stream_data');
|
||||
> zrequire('Filter', 'js/filter');
|
||||
|
||||
For modules that you want to completely stub out, please use a pattern
|
||||
like this:
|
||||
For modules that you want to completely stub out, use a pattern like
|
||||
this:
|
||||
|
||||
> set_global('page_params', {
|
||||
> email: 'bob@zulip.com'
|
||||
@@ -85,17 +102,20 @@ like this:
|
||||
> // then maybe further down
|
||||
> page_params.email = 'alice@zulip.com';
|
||||
|
||||
Finally, there's the hybrid situation, where you want to borrow some of
|
||||
a module's real functionality but stub out other pieces. Obviously, this
|
||||
is a pretty strong smell that the other module might be lacking in
|
||||
cohesion, but that code might be outside your jurisdiction. The pattern
|
||||
here is this:
|
||||
One can similarly stub out functions in a module's exported interface
|
||||
with either `noop` functions or actual code.
|
||||
|
||||
Finally, there's the hybrid situation, where you want to borrow some
|
||||
of a module's real functionality but stub out other pieces. Obviously,
|
||||
this is a pretty strong code smell that the other module might be
|
||||
lacking in cohesion, but sometimes it's not worth going down the
|
||||
rabbit hole of trying to improve that. The pattern here is this:
|
||||
|
||||
> // Import real code.
|
||||
> zrequire('narrow');
|
||||
> zrequire('narrow_state');
|
||||
>
|
||||
> // And later...
|
||||
> narrow.stream = function () {
|
||||
> narrow_state.stream = function () {
|
||||
> return 'office';
|
||||
> };
|
||||
|
||||
@@ -116,3 +136,24 @@ is at the bottom of `foobar.js`:
|
||||
This means `foobar.js` follow the CommonJS module pattern, so it can be
|
||||
required in Node.js, which runs our tests.
|
||||
|
||||
## Coverage reports
|
||||
|
||||
You can automatically generate coverage reports for the JavaScript unit
|
||||
tests like this:
|
||||
|
||||
```
|
||||
tools/test-js-with-node --coverage
|
||||
```
|
||||
|
||||
If tests pass, you will get instructions to view coverage reports
|
||||
in your browser.
|
||||
|
||||
Note that modules that we don't test *at all* aren't listed in the
|
||||
report, so this tends to overstate how good our overall coverage is,
|
||||
but it's accurate for individual files. You can also click a filename
|
||||
to see the specific statements and branches not tested. 100% branch
|
||||
coverage isn't necessarily possible, but getting to at least 80%
|
||||
branch coverage is a good goal.
|
||||
|
||||
The overall project goal is to get to 100% node test coverage on all
|
||||
data/logic modules (UI modules are lower priority for unit testing).
|
||||
|
||||
Reference in New Issue
Block a user