# JavaScript unit tests As an alternative to the black-box whole-app testing, you can unit test individual JavaScript files. You can run tests as follow: ``` tools/test-js-with-node ``` The JS unit tests are written to work with node. You can find them in `frontend_tests/node_tests`. Here is an example test from `frontend_tests/node_tests/stream_data.js`: ``` (function test_get_by_id() { stream_data.clear_subscriptions(); var id = 42; var sub = { name: 'Denmark', subscribed: true, color: 'red', stream_id: id }; stream_data.add_sub('Denmark', sub); sub = stream_data.get_sub('Denmark'); assert.equal(sub.color, 'red'); sub = stream_data.get_sub_by_id(id); assert.equal(sub.color, 'red'); }()); ``` The names of the node tests generally align with the names of the modules they test. If you modify a JS module in `static/js` you should 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 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. ## Handling dependencies in unit tests The following scheme helps avoid tests leaking globals between each other. You want to categorize each module as follows: - Exercise the module's real code for deeper, more realistic testing? - Stub out the module's interface for more control, speed, and isolation? - Do some combination of the above? For all the modules where you want to run actual code, add statements like the following toward the top of your test file: > zrequire('util'); > zrequire('stream_data'); > zrequire('Filter', 'js/filter'); For modules that you want to completely stub out, please use a pattern like this: > set_global('page_params', { > email: 'bob@zulip.com' > }); > > // 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: > // Import real code. > zrequire('narrow'); > > // And later... > narrow.stream = function () { > return 'office'; > }; ## Creating new test modules The test runner (`index.js`) automatically runs all .js files in the `frontend_tests/node directory`, so you can simply start editing a file in that directory to create a new test. The nodes tests rely on JS files that use the module pattern. For example, to test the `foobar.js` file, you would first ensure that code like below is at the bottom of `foobar.js`: > if (typeof module !== 'undefined') { > module.exports = foobar; > } This means `foobar.js` follow the CommonJS module pattern, so it can be required in Node.js, which runs our tests.