TDD for ToDoMVC
TDD for ToDoMVC¶
In DOM TDD with JSDOM we saw using Mocha and Chai for frontend unit tests, with jsdom as a fake “browser”, to let jQuery work. Let’s write some tests for our ToDoMVC frontend.
Source Code¶
Install dependencies. We need mocha, chai, and jsdom:
$ npm install --save-dev mocha chai jsdom
Small first test. Let’s make a file
tests.js
with one test:import $ from 'jquery'; import {describe, it, beforeEach} from 'mocha'; import {expect} from 'chai'; import ToDos from './todo'; describe('ToDo', () => { it('should import', () => { expect(ToDos).to.be.a('function'); }); });
PyCharm run configuration. Make a
Mocha
run configuration, pointed at thistests
file, withExtra Mocha options
set to:--compilers js:babel-core/register
Run it.
Add test setup. Make a function inside
describe
to setup each test:beforeEach(() => { $('body').html(` <input id="newName"/> <ul id="todoList"></ul> ` ); // Avoid confusion, just reset these. Each test has to set. $.get = null; $.ajax = null; });
Helper module. jQuery wants some globals before import. Let’s make a
helper.js
module which we import before any other imports:import jsdom from 'jsdom'; global.document = jsdom.jsdom('<body></body>'); global.window = document.defaultView;
Import helper.js.
Add tests. Add, one-by-one, each of the tests:
import './helper'; import $ from 'jquery'; import {describe, it, beforeEach} from 'mocha'; import {expect} from 'chai'; import ToDos from './todo'; describe('ToDo', () => { let sampleData = [ {id: 1, name: 'One'}, {id: 2, name: 'Two'} ]; beforeEach(() => { $('body').html(` <input id="newName"/> <ul id="todoList"></ul> ` ); // Avoid confusion, just reset these. Each test has to set. $.get = null; $.ajax = null; }); it('should import', () => { expect(ToDos).to.be.a('function'); }); it('should start with a ul and no li', () => { expect($('#todoList').length).eql(1); expect($('#todoList li').length).eql(0); }); it('should do an initial render', () => { $.get = () => new $.Deferred().resolve({objects: sampleData}); new ToDos(); expect($('#todoList li').length).eql(sampleData.length); }); it('should delete an item', () => { $.get = () => new $.Deferred().resolve({objects: sampleData}); let todos = new ToDos(); expect($('#todoList li').length).eql(sampleData.length); // Wire up $.ajax to simulate HTTP DELETE, then $.get to return // only one item $.ajax = () => new $.Deferred().resolve(); $.get = () => new $.Deferred().resolve({ objects: [sampleData[0]] }); todos.delete(2); expect($('#todoList li').length).eql(sampleData.length - 1); }); });