062 Mocha

25 Oct 2014

Mocha is a JavaScript testing library for node and browser. In this episode we will learn how to use mocha with the assertion library chai and use it with hooks, asynchronous test, various reporters and options. Finally we will also learn how to do a stub, calculate test coverage and open up a standalone browser for testing!

Download video: mp4

Sample code: Github

Version: 2.0.1

Similar episodes: 058 RSpec

##Background on Mocha

  1. Mocha website

##Things to learn with Mocha

###1. install

  1. setup file package.json with npm init
    • install mocha

    npm install mocha --save-dev - check the local installed version

    ``` $ mocha –version 2.0.1

    $ mocha –help 2.0.1 ```

###2. first test

  1. create file indexSpec.js with contents:

    describe('Sanitize', function() { it('returns lowercase of a string'); it('removes any hyphen'); }) - run mocha indexSpec.js in the command line:

    ``` $ mocha indexSpec.js

    Sanitize - returns lowercase of a string - removes any hyphen

    0 passing (7ms) 2 pending ```

###3. assertion library

  1. integrate an assertion library e.g. chai (plugin directory) with

    npm install chai --save-dev - require expect in file indexSpec.js

    var expect = require('chai').expect; - include the assertion

    ``` var expect = require(‘chai’).expect;

    describe(‘Sanitize’, function() { it(‘returns lowercase of a string’, function() { expect(‘HELLO WORLD’).to.equal(‘hello world’); });

    it(‘removes any hyphen’); }); ```

    and run it - it should fail

    ``` $ mocha indexSpec.js Sanitize 1) returns lowercase of a string - removes any hyphen

    0 passing (12ms) 1 pending 1 failing

    1) Sanitize returns lowercase of a string:

     AssertionError: expected 'HELLO WORLD' to equal 'hello world'
     + expected - actual
    
     +"hello world"
     -"HELLO WORLD"  ``` - make it pass
    

    ... expect('hello world').to.equal('hello world'); ... - try with other assertions

    ``` … it(‘returns lowercase of a string’, function() { var word = ‘hello world’;

     expect(word).to.equal('hello world');
     expect(word).to.not.equal('hello earth');
     expect(word).to.be.a('string');
     expect(word).to.not.be.a('number');
     expect(word).to.contain('hello');  });   ...  ```
    

###4. integrate the file to be tested

  1. make the origina function in file index.js

    exports.sanitize = function(word) { return word.toLowerCase(); } - require the original file in the test file indexSpec.js

    ``` var word = require(‘./index’);

    … it(‘returns lowercase of a string’, function() { var inputWord = ‘HELLO WORLD’; var sanitizedWord = word.sanitize(inputWord);

     expect(sanitizedWord).to.equal('hello world');
     expect(sanitizedWord).to.not.equal('hello earth');
     expect(sanitizedWord).to.be.a('string');
     expect(sanitizedWord).to.not.be.a('number');
     expect(sanitizedWord).to.contain('hello');  });  ...  ``` - complete the second test by creating the failing test
    

    ``` … it(‘removes any hyphen’, function() { var inputWord = ‘HELLO-WORLD’; var sanitizedWord = word.sanitize(inputWord);

     expect(sanitizedWord).to.equal('hello world');  });  ...  ``` - pass the test by implementing the feature in `index.js`
    

    exports.sanitize = function(word) { return word.toLowerCase().replace(/-/g, ' '); }

###5. hooks, exclusive, include

  1. before, beforeEach, after and afterEach

    afterEach(function() { console.log('after!'); }); - run only

    it.only(...)

###6. mocha options

  1. reporters

    $ mocha --reporters $ mocha indexSpec.js --reporter dot $ mocha indexSpec.js --reporter doc $ mocha indexSpec.js --reporter doc > out.html - create folder test and move indexSpec.js - create file mocha.opts

    --reporter nyan --recursive

    and run mocha with folder name mocha test or simply mocha

###7. test coverage

  1. create an untested function in index.js

    npm install blanket --save-dev - setup blanket with mocha by editing package.json

    "config": { "blanket": { "pattern": [ "index.js" ], "data-cover-never": "node_modules" } } - edit key script.test in file package.json

    "scripts": { "test": "mocha && mocha test --require blanket --reporter html-cov > coverage.html" },

###8. async

  1. implement a new function in index.js

    ``` exports.info = function(callback) { var https = require(‘https’); var options = { host: ‘api.github.com’, path: ‘/repos/sayanee/build-podcast’, method: ‘GET’, headers: { ‘User-Agent’: ‘sayanee’ } }; var str = ‘’;

    https.request(options, function(response) { response.on(‘data’, function(data) { str += data; });

     response.on('end', function() {
       callback(JSON.parse(str));
     })
    
     response.on('error', function(error) {
       console.log(error);
       callback();
     })    })    .end();
    

    } ``` - implement the test

    describe('Github info', function() { it('returns repo info from github', function() { word.info(function(reply) { expect(reply.language).to.equal('JavaScript'); expect(reply.watchers).to.equal(157); console.log('RECEIVED'); }); console.log('HELLO'); }) }) - test passes, but ‘RECEIVED’ is not printed out - pass in a done argument

    it('returns repo info from github', function(done) { word.info(function(reply) { expect(reply.language).to.equal('JavaScript'); expect(reply.watchers).to.equal(157); console.log('RECEIVED'); done(); }); console.log('HELLO'); }) - test passes and ‘RECEIVED’ is printed out

###9. stubs

  1. with sinon.js with docs
    • create the function

    exports.infoLang = function(infoFunc, callback) { infoFunc(function(reply) { callback('Language: ' + reply.language); }) }

###10. browser testing

  1. with selenium webdriver and javascript docs

    java -jar <name_of_jar_file>.jar - download the executable chromedriver and copy to PATH E.g. /usr/bin - write the test in indexSpec.js

    ``` var webdriver = require(‘selenium-webdriver’); var client = new webdriver.Builder().withCapabilities({ ‘browserName’: ‘chrome’ }).build(); var chai = require(‘chai’); var expect = chai.expect;

    describe(‘from Homepage’, function() { var url = ‘http://localhost:8000’;

    beforeEach(function(done) { client.get(url).then(function() { done(); }); });

    after(function(done) { client.quit().then(function(){ done(); }); });

    it(‘return the title of the page’, function(done) { client.getTitle().then(function(title){ expect(title).to.equal(‘Browser testing’); done(); }); })

    it(‘returns the header 1 of the page’, function(done) { client.findElement(webdriver.By.id(‘header’)).getText().then(function(text) { expect(text).to.equal(‘Hey there!’); done(); }); }); }) ``` - run the test with mocha indexSpec.js --timeout 5000

##More Resources on Mocha 1. Testing frontend javascript code using mocha, chai and sinon

##Build Link of this episode

Papers We Love