UNPKG

25.1 kBMarkdownView Raw
1Got Scripts? Test’em!
2=================
3
4[![Build Status](https://github.com/testem/testem/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/testem/testem/actions/workflows/ci.yml?query=branch%3Amaster) [![npm version](https://badge.fury.io/js/testem.svg)](http://badge.fury.io/js/testem)
5
6Unit testing in Javascript can be tedious and painful, but Testem makes it so easy that you will actually *want* to write tests.
7
8Features
9--------
10
11* Test-framework agnostic. Support for
12 - [Jasmine](http://jasmine.github.io/)
13 - [QUnit](http://qunitjs.com/)
14 - [Mocha](http://mochajs.org/)
15 - Others, through custom test framework adapters.
16* Run tests in all major browsers as well as [Node](http://nodejs.org) and [PhantomJS](http://phantomjs.org/)
17* Two distinct use-cases:
18 - Test-Driven-Development(TDD) — designed to streamline the TDD workflow
19 - Continuous Integration(CI) — designed to work well with popular CI servers like Jenkins or Teamcity
20* Cross-platform support
21 - OS X
22 - Windows
23 - Linux
24* Preprocessor support
25 - CoffeeScript
26 - Browserify
27 - JSHint/JSLint
28 - everything else
29
30Screencasts
31-----------
32
33* Watch this **[introductory screencast (11:39)](http://www.youtube.com/watch?v=-1mjv4yk5JM)** to see it in action! This one demonstrates the TDD workflow.
34* [Launchers (12:10)](http://www.youtube.com/watch?v=Up0lVjWk9Rk) — more detail about launchers: how to specify what to auto-launch and how to configure one yourself to run tests in **Node**.
35* [Continuous Integration (CI) Mode (4:24)](http://www.youtube.com/watch?v=Js16Cj80HKY) — details about how CI mode works.
36* [Making JavaScript Testing Fun With Testem (22:53)](http://net.tutsplus.com/tutorials/javascript-ajax/make-javascript-testing-fun-with-testem/) — a thorough screencast by NetTuts+'s Jeffery Way covering the basics, Jasmine, Mocha/Chai, CoffeeScript and more!
37
38Installation
39------------
40You need [Node](http://nodejs.org/) version 0.10+ or iojs installed on your system. Node is extremely easy to install and has a small footprint, and is really awesome otherwise too, so [just do it](http://nodejs.org/).
41
42Once you have Node installed:
43
44 npm install testem -g
45
46This will install the `testem` executable globally on your system.
47
48Usage
49-----
50
51As stated before, Testem supports two use cases: test-driven-development and continuous integration. Let's go over each one.
52
53Development Mode
54----------------
55
56The simplest way to use Testem, in the TDD spirit, is to start in an empty directory and run the command
57
58 testem
59
60You will see a terminal-based interface which looks like this
61
62![Initial interface](https://github.com/testem/testem/raw/master/images/initial.png)
63
64Now open your browser and go to the specified URL. You should now see
65
66![Zero of zero](https://github.com/testem/testem/raw/master/images/zeros.png)
67
68We see 0/0 for tests because at this point we haven't written any code. As we write them, Testem will pick up any `.js` files
69that were added, include them, and if there are tests, run them automatically. So let's first write `hello_spec.js` in the spirit of "test first" (written in Jasmine)
70
71```javascript
72describe('hello', function(){
73 it('should say hello', function(){
74 expect(hello()).toBe('hello world');
75 });
76});
77```
78Save that file and now you should see
79
80![Red](https://github.com/testem/testem/raw/master/images/red.png)
81
82Testem should automatically pick up the new files you've added and also any changes that you make to them and rerun the tests. The test fails as we'd expect. Now we implement the spec like so in `hello.js`
83
84```javascript
85function hello(){
86 return "hello world";
87}
88```
89
90So you should now see
91
92![Green](https://github.com/testem/testem/raw/master/images/green.png)
93
94### Using the Text User Interface
95
96In development mode, Testem has a text-based graphical user interface which uses keyboard-based controls. Here is a list of the control keys
97
98* ENTER : Run the tests
99* q : Quit
100* ← LEFT ARROW : Move to the next browser tab on the left
101* → RIGHT ARROW : Move to the next browser tab on the right
102* TAB : switch the target text panel between the top and bottom halves of the split panel (if a split is present)
103* ↑ UP ARROW : scroll up in the target text panel
104* ↓ DOWN ARROW : scroll down in the target text panel
105* SPACE : page down in the target text panel
106* b : page up in the target text panel
107* d : half a page down target text panel
108* u : half a page up target text panel
109
110### Command line options
111
112To see all command line options
113
114 testem --help
115
116Continuous Integration Mode
117---------------------------
118
119To use Testem for continuous integration
120
121 testem ci
122
123In CI mode, Testem runs your tests on all the browsers that are available on the system one after another.
124
125You can run multiple browsers in parallel in CI mode by specifying the `--parallel` (or `-P`) option to be the number of concurrent running browsers.
126
127 testem ci -P 5 # run 5 browser in parallel
128
129To find out what browsers are currently available - those that Testem knows about and can make use of
130
131 testem launchers
132
133Will print them out. The output might look like
134
135 $ testem launchers
136 Browsers available on this system:
137 IE7
138 IE8
139 IE9
140 Chrome
141 Firefox
142 Safari
143 Safari Technology Preview
144 Opera
145 PhantomJS
146
147Did you notice that this system has IE versions 7-9? Yes, actually it has only IE9 installed, but Testem uses IE's compatibility mode feature to emulate IE 7 and 8.
148
149When you run `testem ci` to run tests, it outputs the results in the [TAP](http://testanything.org/) format by default, which looks like
150
151 ok 1 Chrome 16.0 - hello should say hello.
152
153 1..1
154 # tests 1
155 # pass 1
156
157 # ok
158
159TAP is a human-readable and language-agnostic test result format. TAP plugins exist for popular CI servers
160
161* [Jenkins TAP plugin](https://wiki.jenkins-ci.org/display/JENKINS/TAP+Plugin) - I've added [detailed instructions](https://github.com/testem/testem/blob/master/docs/use_with_jenkins.md) for setup with Jenkins.
162* [TeamCity TAP plugin](https://github.com/pavelsher/teamcity-tap-parser)
163
164## TAP Options
165
166By default, the TAP reporter outputs all test results to the console, whether pass or fail. You can disable this behavior in order to make it easier to see which tests fail (i.e. only output failing tests) using:
167
168```json
169{
170 "tap_failed_tests_only": true
171}
172```
173
174By default, the TAP reporter outputs _console logs_ (distinct from pass/fail information) from all tests that emit logs to the console. You can disable this behavior and _only_ emit logs for failed tests using:
175
176```json
177{
178 "tap_quiet_logs": true
179}
180```
181
182For improved ergonomics, TAP reporter does not actually strictly adhere to the SPEC by default, reporting 'skip' as a possible status instead of as a directive. To strictly follow the spec use:
183
184```json
185{
186 "tap_strict_spec_compliance": true
187}
188```
189
190## Other Test Reporters
191
192Testem has other test reporters besides TAP: `dot`, `xunit` and `teamcity`. You can use the `-R` to specify them
193
194 testem ci -R dot
195
196You can also [add your own reporter](docs/custom_reporter.md).
197
198### Example xunit reporter output
199
200Note that the real output is not pretty printed.
201```xml
202<testsuite name="Testem Tests" tests="4" failures="1" timestamp="Wed Apr 01 2015 11:56:20 GMT+0100 (GMT Daylight Time)" time="9">
203 <testcase classname="PhantomJS 1.9" name="myFunc returns true when input is valid" time="0"/>
204 <testcase classname="PhantomJS 1.9" name="myFunc returns false when user tickles it" time="0"/>
205 <testcase classname="Chrome" name="myFunc returns true when input is valid" time="0"/>
206 <testcase classname="Chrome" name="myFunc returns false when user tickles it" time="0">
207 <failure name="myFunc returns false when user tickles it" message="function is not ticklish">
208 <![CDATA[
209 Callstack...
210 ]]>
211 </failure>
212 </testcase>
213</testsuite>
214```
215
216### Example teamcity reporter output
217
218 ##teamcity[testStarted name='PhantomJS 1.9 - hello should say hello']
219 ##teamcity[testFinished name='PhantomJS 1.9 - hello should say hello']
220 ##teamcity[testStarted name='PhantomJS 1.9 - hello should say hello to person']
221 ##teamcity[testFinished name='PhantomJS 1.9 - hello should say hello to person']
222 ##teamcity[testStarted name='PhantomJS 1.9 - goodbye should say goodbye']
223 ##teamcity[testFailed name='PhantomJS 1.9 - goodbye should say goodbye' message='expected |'hello world|' to equal |'goodbye world|'' details='AssertionError: expected |'hello world|' to equal |'goodbye world|'|n at http://localhost:7357/testem/chai.js:873|n at assertEqual (http://localhost:7357/testem/chai.js:1386)|n at http://localhost:7357/testem/chai.js:3627|n at http://localhost:7357/hello_spec.js:14|n at callFn (http://localhost:7357/testem/mocha.js:4338)|n at http://localhost:7357/testem/mocha.js:4331|n at http://localhost:7357/testem/mocha.js:4728|n at http://localhost:7357/testem/mocha.js:4819|n at next (http://localhost:7357/testem/mocha.js:4653)|n at http://localhost:7357/testem/mocha.js:4663|n at next (http://localhost:7357/testem/mocha.js:4601)|n at http://localhost:7357/testem/mocha.js:4630|n at timeslice (http://localhost:7357/testem/mocha.js:5761)']
224 ##teamcity[testFinished name='PhantomJS 1.9 - goodbye should say goodbye']
225
226 ##teamcity[testSuiteFinished name='mocha.suite' duration='11091']
227
228### Command line options
229
230To see all command line options for CI
231
232 testem ci --help
233
234Configuration File
235------------------
236
237For the simplest JavaScript projects, the TDD workflow described above will work fine. There are times when you want
238to structure your source files into separate directories, or want to have finer control over what files to include.
239This calls for the `testem.json` configuration file (you can also alternatively use the YAML format with a `testem.yml` file). It looks like
240
241```json
242{
243 "framework": "jasmine",
244 "src_files": [
245 "hello.js",
246 "hello_spec.js"
247 ]
248}
249```
250
251The `src_files` can also be unix glob patterns.
252
253```json
254{
255 "src_files": [
256 "js/**/*.js",
257 "spec/**/*.js"
258 ]
259}
260```
261
262You can also ignore certain files using `src_files_ignore`.
263***Update: I've removed the ability to use a space-separated list of globs as a string in the `src_files` property because it disallowed matching files or directories with spaces in them.***
264
265```json
266{
267 "src_files": [
268 "js/**/*.js",
269 "spec/**/*.js"
270 ],
271 "src_files_ignore": "js/toxic/*.js"
272}
273```
274
275Read [more details](docs/config_file.md) about the config options.
276
277Custom Test Pages
278-----------------
279
280You can also use a custom page for testing. To do this, first you need to specify `test_page` to point to your test page in the config file (`framework` and `src_files` are irrelevant in this case)
281
282```json
283{
284 "test_page": "tests.html",
285 "launch_in_dev": [
286 "Chrome"
287 ]
288}
289```
290
291Next, the test page you use needs to have the adapter code installed on them, as specified in the next section.
292
293### Include Snippet
294
295Include this snippet directly after your `jasmine.js`, `qunit.js` or `mocha.js` scripts to enable *Testem* with your test page.
296
297```html
298<script src="/testem.js"></script>
299```
300
301Or if you are using require.js or another loader, just make sure you load `/testem.js` as the next script after the test framework.
302
303'/testem.js' here is dynamically generated to be used client-side and it should not be confused with server-side 'testem.js'.
304
305### Dynamic Substitution
306
307To enable dynamic substitutions within the Javascript files in your custom test page, you must
308
3091. name your test page using `.mustache` as the extension
3102. use `{{#serve_files}}` to loop over the set of Javascript files to be served, and then reference its `src` property to access their path (or `{{#css_files}}` for stylesheets)
311
312Example:
313
314 {{#serve_files}}
315 <script src="{{src}}"></script>
316 {{/serve_files}}
317
318 {{#css_files}}
319 <link rel="stylesheet" href="{{src}}">
320 {{/css_files}}
321
322### Multiple Test Pages
323
324You can also specify multiple test pages to run by passing an array to the `test_page` option.
325
326```json
327{
328 "test_page": [
329 "unit-tests.html",
330 "integration-tests.html"
331 ]
332}
333```
334
335This will cause Testem to run each test page in a separate launcher instance for each launcher you are using. This means that if you define 2 test pages and are using 3 launchers you will get 6 unique runs (2 per launcher).
336
337Launchers
338---------
339
340Testem has the ability to automatically launch browsers or processes for you. To see the list of launchers Testem knows about, you can use the command
341
342 testem launchers
343
344This will display something like the following
345
346 Have 5 launchers available; auto-launch info displayed on the right.
347
348 Launcher Type CI Dev
349 ------------ ------------ -- ---
350 Chrome browser ✔
351 Firefox browser ✔
352 Safari browser ✔
353 Opera browser ✔
354 Mocha process(TAP) ✔
355
356This displays the current list of launchers that are available. Launchers can launch either a browser or a custom process &mdash; as shown in the "Type" column. Custom launchers can be defined to launch custom processes. The "CI" column indicates the launchers which will be automatically launched in CI-mode. Similarly, the "Dev" column lists those that will automatically launch in dev-mode.
357
358Customizing Browser Paths
359-----------------------------
360You can add your own custom paths to browser binaries by including `browser_paths` and/or `browser_exes` options in your Testem configuration. For example:
361
362```javascript
363"browser_paths": {
364 "Chromium": "./node_modules/puppeteer/.local-chromium/mac-549031/chrome-mac/Chromium.app/Contents/MacOS/Chromium"
365}
366"browser_exes": {
367 "Chromium": "chrome-custom-binary"
368}
369```
370
371Adding a browser_path for a browser will override all default places for testem to look for the browser. So if the browser doesn't exist at the path you provided, you will get failures.
372
373Customizing Browser Arguments
374-----------------------------
375
376Testem passes its own list of arguments to some of the browsers it launches. You can add your own custom arguments to these lists by including the `browser_args` option in your Testem configuration. For example:
377
378```javascript
379"browser_args": {
380 "Chrome": [
381 "--auto-open-devtools-for-tabs"
382 ]
383}
384```
385
386You can supply arguments to any number of browsers Testem has available by using the launcher name as a key in `browser_args`. Values may be an array of string arguments, a single string, or an object of arguments by mode.
387
388Read [more details](docs/browser_args.md) about the browser argument options.
389
390Running Tests in Node and Custom Process Launchers
391--------------------------------------------------
392
393To run tests in Node you need to create a custom launcher which launches a process which will run your tests. This is nice because it means you can use any test framework - or lack thereof. For example, to make a launcher that runs mocha tests, you would write the following in the config file `testem.json`
394
395```javascript
396"launchers": {
397 "Mocha": {
398 "command": "mocha tests/*_tests.js"
399 }
400}
401```
402
403When you run `testem`, it will auto-launch the mocha process based on the specified command every time the tests are run. It will display the stdout and well as the stderr of the process inside of the "Mocha" tab in the UI. It will base the pass/fail status on the exit code of the process. In fact, because Testem can launch any arbitrary process for you, you could very well be using it to run programs in other languages.
404
405Processes with TAP Output
406-------------------------
407
408If your process outputs test results in [TAP](http://en.wikipedia.org/wiki/Test_Anything_Protocol) format, you can tell that to testem via the `protocol` property. For example
409
410```javascript
411"launchers": {
412 "Mocha": {
413 "command": "mocha tests/*_tests.js -R tap",
414 "protocol": "tap"
415 }
416}
417```
418
419When this is done, Testem will read in the process's stdout and parse it as TAP, and then display the test results in Testem's normal format. It will also hide the process's stdout output from the console log panel, although it will still display the stderr.
420
421PhantomJS
422---------
423
424PhantomJS is a Webkit-based headless browser. It's fast and it's awesome! Testem will pick it up if you have [PhantomJS](http://www.phantomjs.org/) installed in your system and the `phantomjs` executable is in your path. Run
425
426 testem launchers
427
428And verify that it's in the list.
429
430If you want to debug tests in PhantomJS, include the `phantomjs_debug_port` option in your testem configuration, referencing an available port number. Once testem has started PhantomJS, navigate (with a traditional browser) to http://localhost:<port> and attach to one of PhantomJS's browser tabs (probably the second one in the list). `debugger` statements will now break in the debugging console.
431
432If you want to use any of the [PhantomJS command line options](http://phantomjs.org/api/command-line.html), include the `phantomjs_args` option in your testem configuration. For example:
433
434```javascript
435"phantomjs_args": [
436 "--ignore-ssl-errors=true"
437]
438```
439
440You can also customize the phantomjs launcher file by specifying the `phantomjs_launch_script` option.
441In this launcher you can change options like the `viewPortSize`. See `assets/phantom.js` for the default launcher.
442
443Preprocessors (CoffeeScript, LESS, Sass, Browserify, etc)
444---------------------------------------------------------
445
446If you need to run a preprocessor (or indeed any shell command before the start of the tests) use the `before_tests` option, such as
447
448 "before_tests": "coffee -c *.coffee"
449
450And Testem will run it before each test run. For file watching, you may still use the `src_files` option
451
452```javascript
453"src_files": [
454 "*.coffee"
455]
456```
457
458Since you want to be serving the `.js` files that are generated and not the `.coffee` files, you want to specify the `serve_files` option to tell it that
459
460```javascript
461"serve_files": [
462 "*.js"
463]
464```
465
466Testem will throw up a big ol' error dialog if the preprocessor command exits with an error code, so code checkers like jshint can be used here as well.
467
468If you need to run a command after your tests have completed (such as removing compiled `.js` files), use the `after_tests` option.
469
470```javascript
471"after_tests": "rm *.js"
472```
473
474If you would prefer simply to clean up when Testem exits, you can use the `on_exit` option.
475
476Running browser code after tests complete
477-------------
478It is possible to send coverage reports or run other JavaScript in the browser by using the `afterTests` method.
479
480```javascript
481Testem.afterTests(
482 function(config, data, callback) {
483 var coverage = window.__coverage__;
484 var postBody = JSON.stringify(coverage);
485 if (postBody) {
486 var xhr = new XMLHttpRequest();
487 xhr.onreadystatechange = function() {
488 if (xhr.readyState === 4) {
489 callback();
490 }
491 };
492 xhr.open('POST', 'http://localhost:7358/', true);
493 xhr.send(postBody);
494 }
495});
496```
497
498
499Custom Routes
500-------------
501
502Sometimes you may want to re-map a URL to a different directory on the file system. Maybe you have the following file structure:
503
504 + src
505 + hello.js
506 + tests.js
507 + css
508 + styles.css
509 + public
510 + tests.html
511
512Let's say you want to serve `tests.html` at the top level url `/tests.html`, all the Javascripts under `/js` and all the css under `/css`. You can use the "routes" option to do that
513
514```javascript
515"routes": {
516 "/tests.html": "public/tests.html",
517 "/js": "src",
518 "/css": "css"
519}
520```
521
522DIY: Use Any Test Framework
523---------------------------
524
525If you want to use Testem with a test framework that's not supported out of the box, you can write your own custom test framework adapter. See [customAdapter.js](https://github.com/testem/testem/blob/master/examples/custom_adapter/customAdapter.js) for an example of how to write a custom adapter.
526
527Then, to use it, in your config file simply set
528
529```javascript
530"framework": "custom"
531```
532
533And then make sure you include the adapter code in your test suite and you are ready to go. See here for the [full example](https://github.com/testem/testem/tree/master/examples/custom_adapter).
534
535Native notifications
536--------------------------------
537
538If you'd prefer not to be looking at the terminal while developing, you can enable native notifications (e.g. notification center, growl) using the `-g` option.
539
540API Proxy
541--------------------------------
542
543The proxy option allows you to transparently forward HTTP requests to an external endpoint.
544
545Simply add a `proxies` section to the `testem.json` configuration file.
546
547```json
548{
549 "proxies": {
550 "/api": {
551 "target": "http://localhost:4200",
552 "onlyContentTypes": ["xml", "json"]
553 },
554 "/xmlapi": {
555 "target": "https://localhost:8000",
556 "secure": false
557 }
558 }
559}
560```
561
562This functionality is implemented as a *transparent proxy*, hence a request to
563`http://localhost:7357/api/posts.json` will be proxied to `http://localhost:4200/api/posts.json` without removing the `/api` prefix. Setting the `secure` option to `false` as in the above `/xmlapi` configuration block will ignore TLS certificate validation and allow tests to successfully reach that URL even if testem was launched over HTTP. Other available options can be found here: https://github.com/nodejitsu/node-http-proxy#options
564
565To limit the functionality to only certain content types, use "onlyContentTypes".
566
567Example Projects
568----------------
569
570I've created [examples](https://github.com/testem/testem/tree/master/examples/) for various setups
571
572* [Simple QUnit project](https://github.com/testem/testem/tree/master/examples/qunit_simple)
573* [Simple Jasmine project](https://github.com/testem/testem/tree/master/examples/jasmine_simple)
574* [Jasmine 2](https://github.com/testem/testem/tree/master/examples/jasmine2)
575* [Custom Jasmine project](https://github.com/testem/testem/tree/master/examples/jasmine_custom)
576* [Custom Jasmine project using Require.js](https://github.com/testem/testem/tree/master/examples/jasmine_requirejs)
577* [Simple Mocha Project](https://github.com/testem/testem/tree/master/examples/mocha_simple)
578* [Mocha + Chai](https://github.com/testem/testem/tree/master/examples/mocha_chai_simple)
579* [Hybrid Project](https://github.com/testem/testem/tree/master/examples/hybrid_simple) - Mocha tests running in both the browser and Node.
580* [Coffeescript Project](https://github.com/testem/testem/tree/master/examples/coffeescript)
581* [Browserify Project](https://github.com/testem/testem/tree/master/examples/browserify)
582* [JSHint Example](https://github.com/testem/testem/tree/master/examples/jshint)
583* [Custom Test Framework](https://github.com/testem/testem/tree/master/examples/custom_adapter)
584* [Tape Example](https://github.com/testem/testem/tree/master/examples/tape_example)
585* [BrowserStack Integration](https://github.com/testem/testem/tree/master/examples/browserstack) **bleeding edge**
586* [SauceLabs Integration](https://github.com/testem/testem/tree/master/examples/saucelabs) **bleeding edge**
587* [Code Coverage with Istanbul](https://github.com/testem/testem/tree/master/examples/coverage_istanbul) **bleeding edge**
588
589Known Issues
590------------
591
5921. On Windows, Mocha fails to run under Testem due to an [issue](https://github.com/joyent/node/issues/3871) in Node core. Until that gets resolved, I've made a [workaround](https://github.com/airportyh/mocha/tree/windowsfix) for Mocha. To install this fork of Mocha, do
593
594 npm install https://github.com/airportyh/mocha/tarball/windowsfix -g
595
5962. If you are using prototype.js version 1.6.3 or below, you will [encounter issues](https://github.com/testem/testem/issues/130).
597
598Contributing
599------------
600
601If you want to [contribute to the project](https://github.com/testem/testem/blob/master/CONTRIBUTING.md), I am going to do my best to stay out of your way.
602
603Roadmap
604-------
605
6061. [BrowserStack](http://www.browserstack.com/user/dashboard) integration - following [Bunyip](http://www.thecssninja.com/javascript/bunyip)'s example
6072. Figure out a happy path for testing on mobile browsers (maybe BrowserStack).
608
609Core Maintainer(s)
610------------------
611
612* [Johannes Würbach](https://github.com/johanneswuerbach)
613
614Community
615---------
616
617* **Mailing list**: <https://groups.google.com/forum/?fromgroups#!forum/testem-users>
618
619Credits
620-------
621
622Testem depends on the following great software
623
624* [Jasmine](http://jasmine.github.io/)
625* [QUnit](http://code.google.com/p/jqunit/)
626* [Mocha](http://mochajs.org/)
627* [Node](http://nodejs.org/)
628* [Socket.IO](http://socket.io/)
629* [PhantomJS](http://www.phantomjs.org/)
630* [Node-Tap](https://github.com/isaacs/node-tap)
631* [Node-Charm](https://github.com/substack/node-charm)
632* [Node Commander](http://tjholowaychuk.com/post/9103188408/commander-js-nodejs-command-line-interfaces-made-easy)
633* [JS-Yaml](https://github.com/nodeca/js-yaml)
634* [Express](http://expressjs.com/)
635* [jQuery](http://jquery.com/)
636* [Backbone](http://backbonejs.org/)