SlideShare a Scribd company logo
Writing testable JS
by Ted Piotrowski
Javascript Ho Chi Minh City
Excuses for not testing
● I know the code
● Test suite is hard to configure and run
● You can’t test UI
● You can’t unit test JS code
$(document).ready(function() {
$('#new-status form').submit(function(e) {
e.preventDefault();
$.ajax({
url: '/status',
type: 'POST',
dataType: 'json',
data: { text: $('#new-status').find('textarea').val() },
success: function(data) {
$('#statuses').append('<li>' + data.text + '</li>');
$('#new-status').find('textarea').val('');
}
});
});
});
source: https://github.com/kjbekkelund/writings/blob/master/published/understanding-backbone.md/
Documentation
● Impossible to write a good test without a
good specification
● If you don’t have time to write a test, at least
write documentation
○ it will allow others to write tests later
/**
* adds two numbers together
*/
function sum(a, b)
assert(sum(1, 2), 3);
/**
* adds two numbers together
*/
function sum(a, b)
assert(sum(1, ‘a’), ?);
/**
* adds two numbers together,
* otherwise returns null
*/
function sum(a, b)
assert(sum(1, ‘a’), null);
Dependencies
● Can’t write good tests unless you
understand what external objects the code
depends on
● loose coupling
● use requirejs, almond.js, squire.js
● move dependencies up the call stack and
inject
Scope
● An assertion should only rely on the method
being tested
● What is a “unit”?
● is $(function() { }) a unit?
// Should we stub addTwo, addOne?
// When we limit scope, we forfeit integration
function addThree(a) {
var x = addTwo(a);
var y = addOne(x);
return y;
}
Testing with the DOM
● Use a DOM fragment / jQuery fragment
● Inject it into the module constructor
function Word() {
this.el = $('.word'); // external dependency
}
Word.prototype.setText = function(text) {
this.el.text(text);
};
var word = new Word();
word.setText('Hello World');
assert(???, 'Hello World');
function Word(el) {
this.el = el; // dependency injection
}
Word.prototype.setText = function(text) {
this.el.text(text);
};
var mockEl = $('<div></div>'); // use a test double
var word = new Word(mockEl); // inject the dependency
word.setText('Hello World');
assert(mockEl.text(), 'Hello World');
function Word(el) {
this.el = el || $('.word'); // optional injection
}
Word.prototype.setText = function(text) {
this.el.text(text);
};
var mockEl = $('<div></div>');
var word = new Word(mockEl);
word.setText('Hello World');
assert(mockEl.text(), 'Hello World');
Dealing with window properties
● You code will likely touch Web API
○ document, Math,
● Can use mocks and stubs for methods
● Many Web API properties are read-only
// If your production code calls alert(), you can mock it
var spy = sinon.spy(window, "alert");
assert(spy.calledWith("My alert message"));
// However, you can't modify read only properties
Math.PI = 3.15; // won’t work
window.History.length = 12;
function Win(windowObj) {
this.window = windowObj || window;
}
Win.prototype.scrollX = function() { return this.window.scrollX };
Win.prototype.scrollY = function() { return this.window.scrollY };
var win = new Win(); // in production
// win.scrollX() => actual value
var win = new Win({ // in testing
scrollX: 50, scrollY: 40, History: { … }
}); // win.scrollX() => 50
Dealing with network calls
● Use sinon fake server
{
"test should fetch comments from server" : function () {
this.server.respondWith("GET", "/some/article/comments.json",
[200, { "Content-Type": "application/json" },
'[{ "id": 12, "comment": "Hey there" }]']);
var callback = sinon.spy();
myLib.getCommentsFor("/some/article", callback);
this.server.respond();
sinon.assert.calledWith(callback, [{ id: 12, comment: "Hey there" }]));
}
}
Code coverage
● Reports what lines of production JS are
executed during testing
● necessary, but not sufficient
● Istanbul is a good tool
○ integrates with Karma
JS integration tests
● main.js file initializes your components and
injects DOM dependencies
● Stub your REST calls
● Just like unit testing, user events are your
input, DOM changes are your output
// Bootstrap your application here
// Inject your DOM dependencies at top of call stack
// Allows you to mock/stub the DOM for each component
$(function() {
var $el = $('.some-element');
var component = new Component($el);
var $el2 = $('.some-element2');
var component2 = new Component($el2);
// initialize more components, global state here
});
Demo time
More information
● Testable Javascript
● Karma test runner
● Sinon.js
● Istanbul
About us
Author: Ted Piotrowski
Find me at: tpiotrowski@atlassian.com
Sample code: https://bitbucket.org/tpiotrowski/js-hcm
Presentation made for Javascript Ho Chi Minh City Meetup Group
You can find us at:
● http://www.meetup.com/JavaScript-Ho-Chi-Minh-City/
● https://www.facebook.com/JavaScriptHCMC
● https://plus.google.com/u/0/communities/116105314977285194967
● http://www.slideshare.net/JavascriptMeetup
Lean Coffee
Discussion topics

More Related Content

What's hot (20)

KEY
jQuery Bay Area Conference 2010
mennovanslooten
 
PDF
GDayX - Advanced Angular.JS
Nicolas Embleton
 
PPTX
AngularJS Internal
Eyal Vardi
 
PPTX
AngularJS $Provide Service
Eyal Vardi
 
PPTX
AngularJS with TypeScript and Windows Azure Mobile Services
Rainer Stropek
 
PPTX
AngularJS Services
Eyal Vardi
 
PDF
10 tips for a reusable architecture
Jorge Ortiz
 
PDF
Angular js - 4developers 12 kwietnia 2013
Marcin Wosinek
 
PDF
AngularJS Basics with Example
Sergey Bolshchikov
 
PPTX
Angular 1.x vs. Angular 2.x
Eyal Vardi
 
PDF
Async js - Nemetschek Presentaion @ HackBulgaria
HackBulgaria
 
PPTX
Modules and injector
Eyal Vardi
 
PPTX
AngularJS Animations
Eyal Vardi
 
PPTX
AngularJs
syam kumar kk
 
PDF
Workshop 12: AngularJS Parte I
Visual Engineering
 
PPTX
Angularjs Basics
Anuradha Bandara
 
PDF
Human Talks - StencilJS
Alexandre Koelsch
 
PPTX
AngulrJS Overview
Eyal Vardi
 
PPTX
Обзор автоматизации тестирования на JavaScript
COMAQA.BY
 
PPTX
Testing JavaScript with Jasmine in Rails Applications
Hector Correa
 
jQuery Bay Area Conference 2010
mennovanslooten
 
GDayX - Advanced Angular.JS
Nicolas Embleton
 
AngularJS Internal
Eyal Vardi
 
AngularJS $Provide Service
Eyal Vardi
 
AngularJS with TypeScript and Windows Azure Mobile Services
Rainer Stropek
 
AngularJS Services
Eyal Vardi
 
10 tips for a reusable architecture
Jorge Ortiz
 
Angular js - 4developers 12 kwietnia 2013
Marcin Wosinek
 
AngularJS Basics with Example
Sergey Bolshchikov
 
Angular 1.x vs. Angular 2.x
Eyal Vardi
 
Async js - Nemetschek Presentaion @ HackBulgaria
HackBulgaria
 
Modules and injector
Eyal Vardi
 
AngularJS Animations
Eyal Vardi
 
AngularJs
syam kumar kk
 
Workshop 12: AngularJS Parte I
Visual Engineering
 
Angularjs Basics
Anuradha Bandara
 
Human Talks - StencilJS
Alexandre Koelsch
 
AngulrJS Overview
Eyal Vardi
 
Обзор автоматизации тестирования на JavaScript
COMAQA.BY
 
Testing JavaScript with Jasmine in Rails Applications
Hector Correa
 

Similar to Writing testable js [by Ted Piotrowski] (20)

PPTX
Beyond DOMReady: Ultra High-Performance Javascript
aglemann
 
PPTX
Javascript first-class citizenery
toddbr
 
PDF
HTML5 for the Silverlight Guy
David Padbury
 
PDF
JavaScript Core
François Sarradin
 
PPTX
the next web now
zulin Gu
 
PDF
Redux vs Alt
Uldis Sturms
 
PPTX
Building High Performance Web Applications and Sites
goodfriday
 
PDF
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
Igor Bronovskyy
 
PDF
Testing javascript in the frontend
Frederic CABASSUT
 
PDF
Testing in JavaScript
Digital Natives
 
PDF
Node.js vs Play Framework (with Japanese subtitles)
Yevgeniy Brikman
 
PDF
Javascript: the important bits
Chris Saylor
 
PDF
Android and the Seven Dwarfs from Devox'15
Murat Yener
 
PDF
Avinash Kundaliya: Javascript and WordPress
wpnepal
 
PPTX
Good karma: UX Patterns and Unit Testing in Angular with Karma
ExoLeaders.com
 
PPTX
Sqladria 2009 SRC
tepsum
 
ODP
Unit Testing and Coverage for AngularJS
Knoldus Inc.
 
PDF
JavaScript straight from the Oracle Database
Dimitri Gielis
 
PPT
Automated javascript unit testing
ryan_chambers
 
PDF
Ajax Basics 2
bhuvanann
 
Beyond DOMReady: Ultra High-Performance Javascript
aglemann
 
Javascript first-class citizenery
toddbr
 
HTML5 for the Silverlight Guy
David Padbury
 
JavaScript Core
François Sarradin
 
the next web now
zulin Gu
 
Redux vs Alt
Uldis Sturms
 
Building High Performance Web Applications and Sites
goodfriday
 
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
Igor Bronovskyy
 
Testing javascript in the frontend
Frederic CABASSUT
 
Testing in JavaScript
Digital Natives
 
Node.js vs Play Framework (with Japanese subtitles)
Yevgeniy Brikman
 
Javascript: the important bits
Chris Saylor
 
Android and the Seven Dwarfs from Devox'15
Murat Yener
 
Avinash Kundaliya: Javascript and WordPress
wpnepal
 
Good karma: UX Patterns and Unit Testing in Angular with Karma
ExoLeaders.com
 
Sqladria 2009 SRC
tepsum
 
Unit Testing and Coverage for AngularJS
Knoldus Inc.
 
JavaScript straight from the Oracle Database
Dimitri Gielis
 
Automated javascript unit testing
ryan_chambers
 
Ajax Basics 2
bhuvanann
 
Ad

More from JavaScript Meetup HCMC (8)

PDF
Building workflow in Javascript: Build the awesome with Gulp.
JavaScript Meetup HCMC
 
PDF
[Js hcm] Java script- Testing the awesome
JavaScript Meetup HCMC
 
PDF
Knockout js (Dennis Haney)
JavaScript Meetup HCMC
 
PDF
Debugging JavaScript (by Thomas Bindzus, Founder, Vinagility & Thanh Loc Vo, ...
JavaScript Meetup HCMC
 
PDF
3D Web Programming [Thanh Loc Vo , CTO Epsilon Mobile ]
JavaScript Meetup HCMC
 
PDF
Nicolas Embleton, Advanced Angular JS
JavaScript Meetup HCMC
 
PDF
Khanh-Nguyen - Gearman - distributed process solution
JavaScript Meetup HCMC
 
PDF
Nicolas-Embleton - Deploying node.js with forever and nginx
JavaScript Meetup HCMC
 
Building workflow in Javascript: Build the awesome with Gulp.
JavaScript Meetup HCMC
 
[Js hcm] Java script- Testing the awesome
JavaScript Meetup HCMC
 
Knockout js (Dennis Haney)
JavaScript Meetup HCMC
 
Debugging JavaScript (by Thomas Bindzus, Founder, Vinagility & Thanh Loc Vo, ...
JavaScript Meetup HCMC
 
3D Web Programming [Thanh Loc Vo , CTO Epsilon Mobile ]
JavaScript Meetup HCMC
 
Nicolas Embleton, Advanced Angular JS
JavaScript Meetup HCMC
 
Khanh-Nguyen - Gearman - distributed process solution
JavaScript Meetup HCMC
 
Nicolas-Embleton - Deploying node.js with forever and nginx
JavaScript Meetup HCMC
 
Ad

Recently uploaded (20)

PDF
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PPTX
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
PDF
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
PPTX
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
PDF
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
PDF
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
PDF
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
PPTX
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
PPTX
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
PDF
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
PPTX
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
PDF
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
PDF
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
PDF
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
PDF
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
PDF
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
PDF
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
PDF
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
PDF
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 

Writing testable js [by Ted Piotrowski]

  • 1. Writing testable JS by Ted Piotrowski Javascript Ho Chi Minh City
  • 2. Excuses for not testing ● I know the code ● Test suite is hard to configure and run ● You can’t test UI ● You can’t unit test JS code
  • 3. $(document).ready(function() { $('#new-status form').submit(function(e) { e.preventDefault(); $.ajax({ url: '/status', type: 'POST', dataType: 'json', data: { text: $('#new-status').find('textarea').val() }, success: function(data) { $('#statuses').append('<li>' + data.text + '</li>'); $('#new-status').find('textarea').val(''); } }); }); }); source: https://github.com/kjbekkelund/writings/blob/master/published/understanding-backbone.md/
  • 4. Documentation ● Impossible to write a good test without a good specification ● If you don’t have time to write a test, at least write documentation ○ it will allow others to write tests later
  • 5. /** * adds two numbers together */ function sum(a, b) assert(sum(1, 2), 3);
  • 6. /** * adds two numbers together */ function sum(a, b) assert(sum(1, ‘a’), ?);
  • 7. /** * adds two numbers together, * otherwise returns null */ function sum(a, b) assert(sum(1, ‘a’), null);
  • 8. Dependencies ● Can’t write good tests unless you understand what external objects the code depends on ● loose coupling ● use requirejs, almond.js, squire.js ● move dependencies up the call stack and inject
  • 9. Scope ● An assertion should only rely on the method being tested ● What is a “unit”? ● is $(function() { }) a unit?
  • 10. // Should we stub addTwo, addOne? // When we limit scope, we forfeit integration function addThree(a) { var x = addTwo(a); var y = addOne(x); return y; }
  • 11. Testing with the DOM ● Use a DOM fragment / jQuery fragment ● Inject it into the module constructor
  • 12. function Word() { this.el = $('.word'); // external dependency } Word.prototype.setText = function(text) { this.el.text(text); }; var word = new Word(); word.setText('Hello World'); assert(???, 'Hello World');
  • 13. function Word(el) { this.el = el; // dependency injection } Word.prototype.setText = function(text) { this.el.text(text); }; var mockEl = $('<div></div>'); // use a test double var word = new Word(mockEl); // inject the dependency word.setText('Hello World'); assert(mockEl.text(), 'Hello World');
  • 14. function Word(el) { this.el = el || $('.word'); // optional injection } Word.prototype.setText = function(text) { this.el.text(text); }; var mockEl = $('<div></div>'); var word = new Word(mockEl); word.setText('Hello World'); assert(mockEl.text(), 'Hello World');
  • 15. Dealing with window properties ● You code will likely touch Web API ○ document, Math, ● Can use mocks and stubs for methods ● Many Web API properties are read-only
  • 16. // If your production code calls alert(), you can mock it var spy = sinon.spy(window, "alert"); assert(spy.calledWith("My alert message")); // However, you can't modify read only properties Math.PI = 3.15; // won’t work window.History.length = 12;
  • 17. function Win(windowObj) { this.window = windowObj || window; } Win.prototype.scrollX = function() { return this.window.scrollX }; Win.prototype.scrollY = function() { return this.window.scrollY }; var win = new Win(); // in production // win.scrollX() => actual value var win = new Win({ // in testing scrollX: 50, scrollY: 40, History: { … } }); // win.scrollX() => 50
  • 18. Dealing with network calls ● Use sinon fake server
  • 19. { "test should fetch comments from server" : function () { this.server.respondWith("GET", "/some/article/comments.json", [200, { "Content-Type": "application/json" }, '[{ "id": 12, "comment": "Hey there" }]']); var callback = sinon.spy(); myLib.getCommentsFor("/some/article", callback); this.server.respond(); sinon.assert.calledWith(callback, [{ id: 12, comment: "Hey there" }])); } }
  • 20. Code coverage ● Reports what lines of production JS are executed during testing ● necessary, but not sufficient ● Istanbul is a good tool ○ integrates with Karma
  • 21. JS integration tests ● main.js file initializes your components and injects DOM dependencies ● Stub your REST calls ● Just like unit testing, user events are your input, DOM changes are your output
  • 22. // Bootstrap your application here // Inject your DOM dependencies at top of call stack // Allows you to mock/stub the DOM for each component $(function() { var $el = $('.some-element'); var component = new Component($el); var $el2 = $('.some-element2'); var component2 = new Component($el2); // initialize more components, global state here });
  • 24. More information ● Testable Javascript ● Karma test runner ● Sinon.js ● Istanbul
  • 25. About us Author: Ted Piotrowski Find me at: [email protected] Sample code: https://bitbucket.org/tpiotrowski/js-hcm Presentation made for Javascript Ho Chi Minh City Meetup Group You can find us at: ● http://www.meetup.com/JavaScript-Ho-Chi-Minh-City/ ● https://www.facebook.com/JavaScriptHCMC ● https://plus.google.com/u/0/communities/116105314977285194967 ● http://www.slideshare.net/JavascriptMeetup