SlideShare a Scribd company logo
Testing Javascript from a
Frontend perspective
Frederic Cabassut - Campanda
The basics of test-driven development
TDD Cycle - Rule #1
You must write a failing test
before you write any production
code.
TDD Cycle - Rule #2
You must not write more of a
test than is sufficient to fail, or
fail to compile.
TDD Cycle - Rule #3
You must not write more
production code than is
sufficient to make the currently
failing test pass.
TDD Cycle
// tests // production code
TDD Cycle
// tests
var expected = "Hello, Fred!";
// production code
TDD Cycle
// tests
var expected = "Hello, Fred!";
// production code
✓
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
// production code
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
// production code
Uncaught ReferenceError: getMyObj is not defined
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
// production code
function getMyObj() {
}
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
// production code
function getMyObj() {
}
Uncaught TypeError: Cannot read property 'greet' of undefined
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
// production code
function getMyObj() {
return {};
}
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
// production code
function getMyObj() {
return {};
}
Uncaught TypeError: getMyObj(...).greet is not a function
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
// production code
function getMyObj() {
return {
greet: function() {
}
};
}
}
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
// production code
function getMyObj() {
return {
greet: function () {
}
};
}
✓
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
assert.equal(expected, actual);
// production code
function getMyObj() {
return {
greet: function() {
}
};
}
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
assert.equal(expected, actual);
// production code
function getMyObj() {
return {
greet: function() {
}
};
}
AssertionError: "Hello, Fred!" == undefined
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
assert.equal(expected, actual);
// production code
function getMyObj() {
return {
greet: function() {
return "Hello, Fred!";
}
};
}
TDD Cycle
// tests
var expected = "Hello, Fred!";
var actual = getMyObj().greet("Fred");
assert.equal(expected, actual);
// production code
function getMyObj() {
return {
greet: function() {
return "Hello, Fred!";
}
};
}
✓
Why Testing ?
- Increase code quality
- Deploy with confidence
- Self-explaining documentation
- Easy to refactor
What do we have to test ?
- User interaction / events
- Manipulating the DOM
- Client-side business logic
- Ajax request (retrieve/send data)
My favorite testing stack:
- Mochajs https://mochajs.org/
- Chaijs http://chaijs.com/
- Sinonjs: http://sinonjs.org/
- My browser (+ livereload)
Let’s create a DatePicker!
Let’s create a DatePicker!
Let’s create a DatePicker!
Let’s create a DatePicker!
Let’s create a DatePicker!
User interaction / events
// tests
it('should initialize a datepicker with
a given element', function() {
var input =
document.createElement('input');
DatePicker.init(input);
});
// production code
window.DatePicker = {
init: function() {}
}
User interaction / events
// tests
it('should initialize a datepicker with
a given element', function() {
var input =
document.createElement('input');
DatePicker.init(input);
});
// production code
window.DatePicker = {
init: function() {}
}
✓
User interaction / events
// tests
it('should show a datepicker on input
focus', function() {
});
// production code
window.DatePicker = {
init: function() {}
}
User interaction / events
// tests
it('should show a datepicker on input
focus', function() {
var input =
document.createElement('input');
DatePicker.init(input);
});
// production code
window.DatePicker = {
init: function() {}
}
User interaction / events
// tests
it('should show a datepicker on input
focus', function() {
var input =
document.createElement('input');
DatePicker.init(input);
});
// production code
window.DatePicker = {
init: function() {}
}
✓
User interaction / events
// tests
it('should show a datepicker on input
focus', function() {
[...]
});
// production code
window.DatePicker = {
init: function() {}
}
User interaction / events
// tests
it('should show a datepicker on input
focus', function() {
[...]
var event = new Event('focus');
input.dispatchEvent(event);
});
// production code
window.DatePicker = {
init: function() {}
}
User interaction / events
// tests
it('should show a datepicker on input
focus', function() {
[...]
var event = new Event('focus');
input.dispatchEvent(event);
});
// production code
window.DatePicker = {
init: function() {}
}
✓
User interaction / events
// tests
it('should show a datepicker on input
focus', function() {
[...]
var event = new Event('focus');
input.dispatchEvent(event);
var element =
document.getElementById('datePicker');
expect(element).to.be.ok;
});
// production code
window.DatePicker = {
init: function() {}
}
User interaction / events
// tests
it('should show a datepicker on input
focus', function() {
[...]
var event = new Event('focus');
input.dispatchEvent(event);
var element =
document.getElementById('datePicker');
expect(element).to.be.ok;
});
// production code
window.DatePicker = {
init: function() {}
}
AssertionError: expected null to be truthy
User interaction / events
// tests
it('should show a datepicker on input
focus', function() {
[...]
var event = new Event('focus');
input.dispatchEvent(event);
var element =
document.getElementById('datePicker');
expect(element).to.be.ok;
});
// production code
window.DatePicker = {
init: function(input) {
[...]
}
}
User interaction / events
// tests
it('should show a datepicker on input
focus', function() {
[...]
var event = new Event('focus');
input.dispatchEvent(event);
var element =
document.getElementById('datePicker');
expect(element).to.be.ok;
});
// production code
[...]
input.addEventListener('focus',
function() {
var element =
document.createElement('div');
element.id = 'datePicker';
document.body.appendChild(element);
}
[...]
User interaction / events
// tests
it('should show a datepicker on input
focus', function() {
[...]
var event = new Event('focus');
input.dispatchEvent(event);
var element =
document.getElementById('datePicker');
expect(element).to.be.ok;
});
// production code
[...]
input.addEventListener('focus',
function() {
var element =
document.createElement('div');
element.id = 'datePicker';
document.body.appendChild(element);
}
[...]
✓
User interaction / events
// tests
it('should stop event propagation',
function() {
});
// production code
[...]
input.addEventListener('focus',
function() {
var element =
document.createElement('div');
element.id = 'datePicker';
document.body.appendChild(element);
}
[...]
User interaction / events
// tests
it('should stop event propagation',
function() {
[...]
var event = new Event('focus');
var spy = sinon.spy(event,
'stopPropagation');
input.dispatchEvent(event);
expect(spy).to.have.been.calledOnce;
});
// production code
[...]
input.addEventListener('focus',
function() {
var element =
document.createElement('div');
element.id = 'datePicker';
document.body.appendChild(element);
}
[...]
User interaction / events
// tests
it('should stop event propagation',
function() {
[...]
var event = new Event('focus');
var spy = sinon.spy(event,
'stopPropagation');
input.dispatchEvent(event);
expect(spy).to.have.been.calledOnce;
});
// production code
[...]
input.addEventListener('focus',
function() {
var element =
document.createElement('div');
element.id = 'datePicker';
document.body.appendChild(element);
}
[...]
expected stopPropagation to have been called exactly once ...
User interaction / events
// tests
it('should stop event propagation',
function() {
[...]
var event = new Event('focus');
var spy = sinon.spy(event,
'stopPropagation');
input.dispatchEvent(event);
expect(spy).to.have.been.calledOnce;
});
// production code
[...]
input.addEventListener('focus',
function(e) {
e.stopPropagation();
var element =
document.createElement('div');
element.id = 'datePicker';
document.body.appendChild(element);
}
[...]
User interaction / events
// tests
it('should stop event propagation',
function() {
[...]
var event = new Event('focus');
var spy = sinon.spy(event,
'stopPropagation');
input.dispatchEvent(event);
expect(spy).to.have.been.calledOnce;
});
// production code
[...]
input.addEventListener('focus',
function(e) {
e.stopPropagation();
var element =
document.createElement('div');
element.id = 'datePicker';
document.body.appendChild(element);
}
[...]
✓
Manipulating the DOM
// tests
it('should add class "selected" on a day when it is clicked',
function(){
});
Manipulating the DOM
// tests
it('should add class "selected" on a day when it is clicked',
function(){
[...]
var day = document.querySelector('#datePicker .day');
day.click();
});
Manipulating the DOM
// tests
it('adds class "selected" on a day when clicked', function() {
[...]
var day = document.querySelector('#datePicker .day');
day.click();
var i = day.className.indexOf('selected');
expect(i > -1).to.be.true;
});
Mocking Time, tick tick tick
// tests
Mocking Time
// tests
it('should hide datePicker after 300ms', function(){
[...]
var clock = sinon.useFakeTimers();
day.click();
clock.tick(299);
expect(datePicker.className.indexOf('hidden') > -1).to.be.false;
clock.tick(2);
expect(datePicker.className.indexOf('hidden') > -1).to.be.true;
clock.restore();
});
Mocking Browser methods
// tests
Mocking Browser methods
// tests
beforeEach(function() {
this.dateNowStub = sinon.stub(Date, 'now', function() {
return new Date('2016-01-13').getTime();
});
});
afterEach(function(){
this.dateNowStub.restore();
});
Testing Javascript for the Browser
In a browser
Take it to the next level
Headless browser testing (phantomjs, zombie, electron...)
Continuous Integration: automate your tests in jenkins, travis

A few more tips
- Find a BUG ? Write a TEST!
- Do TDD while PAIRING
- Use the Web APIs in your TESTS
- Don’t try to test the browser
- You don’t need to test libraries
THANK YOU
And HAPPY Testing!

More Related Content

What's hot (20)

JavaScript Test-Driven Development with Jasmine 2.0 and Karma
JavaScript Test-Driven Development with Jasmine 2.0 and Karma
Christopher Bartling
 
Testing JS with Jasmine
Testing JS with Jasmine
Evgeny Gurin
 
AngularJS Unit Testing w/Karma and Jasmine
AngularJS Unit Testing w/Karma and Jasmine
foxp2code
 
Quick tour to front end unit testing using jasmine
Quick tour to front end unit testing using jasmine
Gil Fink
 
Jasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishy
Igor Napierala
 
Jasmine BDD for Javascript
Jasmine BDD for Javascript
Luis Alfredo Porras PĂĄez
 
Night Watch with QA
Night Watch with QA
Carsten Sandtner
 
Intro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJS
Jim Lynch
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
All Things Open
 
Unit testing in JavaScript with Jasmine and Karma
Unit testing in JavaScript with Jasmine and Karma
Andrey Kolodnitsky
 
Unit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJS
Knoldus Inc.
 
Angular testing
Angular testing
Raissa Ferreira
 
Test-Driven Development of AngularJS Applications
Test-Driven Development of AngularJS Applications
FITC
 
ХДргДĐč Đ‘ĐŸĐ»ŃŒŃ‰ĐžĐșĐŸĐČ "Protractor Tips & Tricks"
ХДргДĐč Đ‘ĐŸĐ»ŃŒŃ‰ĐžĐșĐŸĐČ "Protractor Tips & Tricks"
Fwdays
 
Testing in AngularJS
Testing in AngularJS
Peter Drinnan
 
Unit Testing JavaScript Applications
Unit Testing JavaScript Applications
Ynon Perek
 
Javascript TDD with Jasmine, Karma, and Gulp
Javascript TDD with Jasmine, Karma, and Gulp
All Things Open
 
PL/SQL Unit Testing Can Be Fun!
PL/SQL Unit Testing Can Be Fun!
Raimonds Simanovskis
 
Vuejs testing
Vuejs testing
Greg TAPPERO
 
AngularJS Unit Test
AngularJS Unit Test
Chiew Carol
 
JavaScript Test-Driven Development with Jasmine 2.0 and Karma
JavaScript Test-Driven Development with Jasmine 2.0 and Karma
Christopher Bartling
 
Testing JS with Jasmine
Testing JS with Jasmine
Evgeny Gurin
 
AngularJS Unit Testing w/Karma and Jasmine
AngularJS Unit Testing w/Karma and Jasmine
foxp2code
 
Quick tour to front end unit testing using jasmine
Quick tour to front end unit testing using jasmine
Gil Fink
 
Jasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishy
Igor Napierala
 
Intro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJS
Jim Lynch
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
All Things Open
 
Unit testing in JavaScript with Jasmine and Karma
Unit testing in JavaScript with Jasmine and Karma
Andrey Kolodnitsky
 
Unit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJS
Knoldus Inc.
 
Test-Driven Development of AngularJS Applications
Test-Driven Development of AngularJS Applications
FITC
 
ХДргДĐč Đ‘ĐŸĐ»ŃŒŃ‰ĐžĐșĐŸĐČ "Protractor Tips & Tricks"
ХДргДĐč Đ‘ĐŸĐ»ŃŒŃ‰ĐžĐșĐŸĐČ "Protractor Tips & Tricks"
Fwdays
 
Testing in AngularJS
Testing in AngularJS
Peter Drinnan
 
Unit Testing JavaScript Applications
Unit Testing JavaScript Applications
Ynon Perek
 
Javascript TDD with Jasmine, Karma, and Gulp
Javascript TDD with Jasmine, Karma, and Gulp
All Things Open
 
PL/SQL Unit Testing Can Be Fun!
PL/SQL Unit Testing Can Be Fun!
Raimonds Simanovskis
 
Vuejs testing
Vuejs testing
Greg TAPPERO
 
AngularJS Unit Test
AngularJS Unit Test
Chiew Carol
 

Viewers also liked (13)

The Developer Experience
The Developer Experience
Atlassian
 
Unit Testing Lightning Components with Jasmine
Unit Testing Lightning Components with Jasmine
Keir Bowden
 
Developer Experience to Testing
Developer Experience to Testing
Mozaic Works
 
JavaScript Unit Testing
JavaScript Unit Testing
Keir Bowden
 
Introducing Sencha Touch 2
Introducing Sencha Touch 2
Sencha
 
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
Gavin Pickin
 
Javascript testing: tools of the trade
Javascript testing: tools of the trade
Juanma Orta
 
Javascript Unit Testing Tools
Javascript Unit Testing Tools
PixelCrayons
 
JAVASCRIPT Test Driven Development & Jasmine
JAVASCRIPT Test Driven Development & Jasmine
Anup Singh
 
Unit-testing and E2E testing in JS
Unit-testing and E2E testing in JS
Michael Haberman
 
SenchaCon 2016: The Changing Landscape of JavaScript Testing - Joel Watson an...
SenchaCon 2016: The Changing Landscape of JavaScript Testing - Joel Watson an...
Sencha
 
jasmine
jasmine
Asanka Indrajith
 
ĐœĐžŃ…Đ°ĐžĐ» Đ‘ĐŸĐŽĐœĐ°Ń€Ń‡ŃƒĐș "Acceptance Testing in NodeJS: Tools & Approaches"
ĐœĐžŃ…Đ°ĐžĐ» Đ‘ĐŸĐŽĐœĐ°Ń€Ń‡ŃƒĐș "Acceptance Testing in NodeJS: Tools & Approaches"
Fwdays
 
The Developer Experience
The Developer Experience
Atlassian
 
Unit Testing Lightning Components with Jasmine
Unit Testing Lightning Components with Jasmine
Keir Bowden
 
Developer Experience to Testing
Developer Experience to Testing
Mozaic Works
 
JavaScript Unit Testing
JavaScript Unit Testing
Keir Bowden
 
Introducing Sencha Touch 2
Introducing Sencha Touch 2
Sencha
 
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
Gavin Pickin
 
Javascript testing: tools of the trade
Javascript testing: tools of the trade
Juanma Orta
 
Javascript Unit Testing Tools
Javascript Unit Testing Tools
PixelCrayons
 
JAVASCRIPT Test Driven Development & Jasmine
JAVASCRIPT Test Driven Development & Jasmine
Anup Singh
 
Unit-testing and E2E testing in JS
Unit-testing and E2E testing in JS
Michael Haberman
 
SenchaCon 2016: The Changing Landscape of JavaScript Testing - Joel Watson an...
SenchaCon 2016: The Changing Landscape of JavaScript Testing - Joel Watson an...
Sencha
 
ĐœĐžŃ…Đ°ĐžĐ» Đ‘ĐŸĐŽĐœĐ°Ń€Ń‡ŃƒĐș "Acceptance Testing in NodeJS: Tools & Approaches"
ĐœĐžŃ…Đ°ĐžĐ» Đ‘ĐŸĐŽĐœĐ°Ń€Ń‡ŃƒĐș "Acceptance Testing in NodeJS: Tools & Approaches"
Fwdays
 
Ad

Similar to Testing javascript in the frontend (20)

In search of JavaScript code quality: unit testing
In search of JavaScript code quality: unit testing
Anna Khabibullina
 
ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)
David Rodenas
 
Unit testing with Jasmine
Unit testing with Jasmine
simonKenyonShepard
 
TDD CrashCourse Part3: TDD Techniques
TDD CrashCourse Part3: TDD Techniques
David Rodenas
 
Test-driven Development (TDD)
Test-driven Development (TDD)
Bran van der Meer
 
Stop Making Excuses and Start Testing Your JavaScript
Stop Making Excuses and Start Testing Your JavaScript
Ryan Anklam
 
Zero to Testing in JavaScript
Zero to Testing in JavaScript
pamselle
 
MidwestJS Zero to Testing
MidwestJS Zero to Testing
pamselle
 
Intro to JavaScript Testing
Intro to JavaScript Testing
Ran Mizrahi
 
Js ć•ć…ƒæ”‹èŻ•æĄ†æž¶ä»‹ç»
Js ć•ć…ƒæ”‹èŻ•æĄ†æž¶ä»‹ç»
louieuser
 
Unit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and Hows
atesgoral
 
Js fwdays unit tesing javascript(by Anna Khabibullina)
Js fwdays unit tesing javascript(by Anna Khabibullina)
Anna Khabibullina
 
JS Frameworks Day April,26 of 2014
JS Frameworks Day April,26 of 2014
DA-14
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
Ran Mizrahi
 
Advanced JavaScript
Advanced JavaScript
Zsolt Mészårovics
 
Testing, Performance Analysis, and jQuery 1.4
Testing, Performance Analysis, and jQuery 1.4
jeresig
 
Writing better tests for your java script app
Writing better tests for your java script app
JakeGinnivan
 
Understanding JavaScript Testing
Understanding JavaScript Testing
jeresig
 
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
Anup Singh
 
Writing useful automated tests for the single page applications you build
Writing useful automated tests for the single page applications you build
Andrei Sebastian CĂźmpean
 
In search of JavaScript code quality: unit testing
In search of JavaScript code quality: unit testing
Anna Khabibullina
 
ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)
David Rodenas
 
Unit testing with Jasmine
Unit testing with Jasmine
simonKenyonShepard
 
TDD CrashCourse Part3: TDD Techniques
TDD CrashCourse Part3: TDD Techniques
David Rodenas
 
Test-driven Development (TDD)
Test-driven Development (TDD)
Bran van der Meer
 
Stop Making Excuses and Start Testing Your JavaScript
Stop Making Excuses and Start Testing Your JavaScript
Ryan Anklam
 
Zero to Testing in JavaScript
Zero to Testing in JavaScript
pamselle
 
MidwestJS Zero to Testing
MidwestJS Zero to Testing
pamselle
 
Intro to JavaScript Testing
Intro to JavaScript Testing
Ran Mizrahi
 
Js ć•ć…ƒæ”‹èŻ•æĄ†æž¶ä»‹ç»
Js ć•ć…ƒæ”‹èŻ•æĄ†æž¶ä»‹ç»
louieuser
 
Unit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and Hows
atesgoral
 
Js fwdays unit tesing javascript(by Anna Khabibullina)
Js fwdays unit tesing javascript(by Anna Khabibullina)
Anna Khabibullina
 
JS Frameworks Day April,26 of 2014
JS Frameworks Day April,26 of 2014
DA-14
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
Ran Mizrahi
 
Testing, Performance Analysis, and jQuery 1.4
Testing, Performance Analysis, and jQuery 1.4
jeresig
 
Writing better tests for your java script app
Writing better tests for your java script app
JakeGinnivan
 
Understanding JavaScript Testing
Understanding JavaScript Testing
jeresig
 
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
Anup Singh
 
Writing useful automated tests for the single page applications you build
Writing useful automated tests for the single page applications you build
Andrei Sebastian CĂźmpean
 
Ad

Recently uploaded (20)

Integration Ignited Redefining Event-Driven Architecture at Wix - EventCentric
Integration Ignited Redefining Event-Driven Architecture at Wix - EventCentric
Natan Silnitsky
 
How Insurance Policy Management Software Streamlines Operations
How Insurance Policy Management Software Streamlines Operations
Insurance Tech Services
 
IBM Rational Unified Process For Software Engineering - Introduction
IBM Rational Unified Process For Software Engineering - Introduction
Gaurav Sharma
 
Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...
Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...
SheenBrisals
 
Rebuilding Cadabra Studio: AI as Our Core Foundation
Rebuilding Cadabra Studio: AI as Our Core Foundation
Cadabra Studio
 
Generative Artificial Intelligence and its Applications
Generative Artificial Intelligence and its Applications
SandeepKS52
 
Key AI Technologies Used by Indian Artificial Intelligence Companies
Key AI Technologies Used by Indian Artificial Intelligence Companies
Mypcot Infotech
 
The rise of e-commerce has redefined how retailers operate—and reconciliation...
The rise of e-commerce has redefined how retailers operate—and reconciliation...
Prachi Desai
 
FME as an Orchestration Tool - Peak of Data & AI 2025
FME as an Orchestration Tool - Peak of Data & AI 2025
Safe Software
 
OpenTelemetry 101 Cloud Native Barcelona
OpenTelemetry 101 Cloud Native Barcelona
Imma Valls Bernaus
 
How Insurance Policy Administration Streamlines Policy Lifecycle for Agile Op...
How Insurance Policy Administration Streamlines Policy Lifecycle for Agile Op...
Insurance Tech Services
 
Artificial Intelligence Applications Across Industries
Artificial Intelligence Applications Across Industries
SandeepKS52
 
iOS Developer Resume 2025 | Pramod Kumar
iOS Developer Resume 2025 | Pramod Kumar
Pramod Kumar
 
Software Engineering Process, Notation & Tools Introduction - Part 4
Software Engineering Process, Notation & Tools Introduction - Part 4
Gaurav Sharma
 
How AI Can Improve Media Quality Testing Across Platforms (1).pptx
How AI Can Improve Media Quality Testing Across Platforms (1).pptx
kalichargn70th171
 
Providing Better Biodiversity Through Better Data
Providing Better Biodiversity Through Better Data
Safe Software
 
Top 5 Task Management Software to Boost Productivity in 2025
Top 5 Task Management Software to Boost Productivity in 2025
Orangescrum
 
Design by Contract - Building Robust Software with Contract-First Development
Design by Contract - Building Robust Software with Contract-First Development
Par-Tec S.p.A.
 
Software Engineering Process, Notation & Tools Introduction - Part 3
Software Engineering Process, Notation & Tools Introduction - Part 3
Gaurav Sharma
 
Agile Software Engineering Methodologies
Agile Software Engineering Methodologies
Gaurav Sharma
 
Integration Ignited Redefining Event-Driven Architecture at Wix - EventCentric
Integration Ignited Redefining Event-Driven Architecture at Wix - EventCentric
Natan Silnitsky
 
How Insurance Policy Management Software Streamlines Operations
How Insurance Policy Management Software Streamlines Operations
Insurance Tech Services
 
IBM Rational Unified Process For Software Engineering - Introduction
IBM Rational Unified Process For Software Engineering - Introduction
Gaurav Sharma
 
Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...
Eliminate the complexities of Event-Driven Architecture with Domain-Driven De...
SheenBrisals
 
Rebuilding Cadabra Studio: AI as Our Core Foundation
Rebuilding Cadabra Studio: AI as Our Core Foundation
Cadabra Studio
 
Generative Artificial Intelligence and its Applications
Generative Artificial Intelligence and its Applications
SandeepKS52
 
Key AI Technologies Used by Indian Artificial Intelligence Companies
Key AI Technologies Used by Indian Artificial Intelligence Companies
Mypcot Infotech
 
The rise of e-commerce has redefined how retailers operate—and reconciliation...
The rise of e-commerce has redefined how retailers operate—and reconciliation...
Prachi Desai
 
FME as an Orchestration Tool - Peak of Data & AI 2025
FME as an Orchestration Tool - Peak of Data & AI 2025
Safe Software
 
OpenTelemetry 101 Cloud Native Barcelona
OpenTelemetry 101 Cloud Native Barcelona
Imma Valls Bernaus
 
How Insurance Policy Administration Streamlines Policy Lifecycle for Agile Op...
How Insurance Policy Administration Streamlines Policy Lifecycle for Agile Op...
Insurance Tech Services
 
Artificial Intelligence Applications Across Industries
Artificial Intelligence Applications Across Industries
SandeepKS52
 
iOS Developer Resume 2025 | Pramod Kumar
iOS Developer Resume 2025 | Pramod Kumar
Pramod Kumar
 
Software Engineering Process, Notation & Tools Introduction - Part 4
Software Engineering Process, Notation & Tools Introduction - Part 4
Gaurav Sharma
 
How AI Can Improve Media Quality Testing Across Platforms (1).pptx
How AI Can Improve Media Quality Testing Across Platforms (1).pptx
kalichargn70th171
 
Providing Better Biodiversity Through Better Data
Providing Better Biodiversity Through Better Data
Safe Software
 
Top 5 Task Management Software to Boost Productivity in 2025
Top 5 Task Management Software to Boost Productivity in 2025
Orangescrum
 
Design by Contract - Building Robust Software with Contract-First Development
Design by Contract - Building Robust Software with Contract-First Development
Par-Tec S.p.A.
 
Software Engineering Process, Notation & Tools Introduction - Part 3
Software Engineering Process, Notation & Tools Introduction - Part 3
Gaurav Sharma
 
Agile Software Engineering Methodologies
Agile Software Engineering Methodologies
Gaurav Sharma
 

Testing javascript in the frontend

  • 1. Testing Javascript from a Frontend perspective Frederic Cabassut - Campanda
  • 2. The basics of test-driven development
  • 3. TDD Cycle - Rule #1 You must write a failing test before you write any production code.
  • 4. TDD Cycle - Rule #2 You must not write more of a test than is sufficient to fail, or fail to compile.
  • 5. TDD Cycle - Rule #3 You must not write more production code than is sufficient to make the currently failing test pass.
  • 6. TDD Cycle // tests // production code
  • 7. TDD Cycle // tests var expected = "Hello, Fred!"; // production code
  • 8. TDD Cycle // tests var expected = "Hello, Fred!"; // production code ✓
  • 9. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); // production code
  • 10. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); // production code Uncaught ReferenceError: getMyObj is not defined
  • 11. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); // production code function getMyObj() { }
  • 12. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); // production code function getMyObj() { } Uncaught TypeError: Cannot read property 'greet' of undefined
  • 13. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); // production code function getMyObj() { return {}; }
  • 14. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); // production code function getMyObj() { return {}; } Uncaught TypeError: getMyObj(...).greet is not a function
  • 15. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); // production code function getMyObj() { return { greet: function() { } }; } }
  • 16. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); // production code function getMyObj() { return { greet: function () { } }; } ✓
  • 17. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); assert.equal(expected, actual); // production code function getMyObj() { return { greet: function() { } }; }
  • 18. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); assert.equal(expected, actual); // production code function getMyObj() { return { greet: function() { } }; } AssertionError: "Hello, Fred!" == undefined
  • 19. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); assert.equal(expected, actual); // production code function getMyObj() { return { greet: function() { return "Hello, Fred!"; } }; }
  • 20. TDD Cycle // tests var expected = "Hello, Fred!"; var actual = getMyObj().greet("Fred"); assert.equal(expected, actual); // production code function getMyObj() { return { greet: function() { return "Hello, Fred!"; } }; } ✓
  • 21. Why Testing ? - Increase code quality - Deploy with confidence - Self-explaining documentation - Easy to refactor
  • 22. What do we have to test ? - User interaction / events - Manipulating the DOM - Client-side business logic - Ajax request (retrieve/send data)
  • 23. My favorite testing stack: - Mochajs https://mochajs.org/ - Chaijs http://chaijs.com/ - Sinonjs: http://sinonjs.org/ - My browser (+ livereload)
  • 24. Let’s create a DatePicker!
  • 25. Let’s create a DatePicker!
  • 26. Let’s create a DatePicker!
  • 27. Let’s create a DatePicker!
  • 28. Let’s create a DatePicker!
  • 29. User interaction / events // tests it('should initialize a datepicker with a given element', function() { var input = document.createElement('input'); DatePicker.init(input); }); // production code window.DatePicker = { init: function() {} }
  • 30. User interaction / events // tests it('should initialize a datepicker with a given element', function() { var input = document.createElement('input'); DatePicker.init(input); }); // production code window.DatePicker = { init: function() {} } ✓
  • 31. User interaction / events // tests it('should show a datepicker on input focus', function() { }); // production code window.DatePicker = { init: function() {} }
  • 32. User interaction / events // tests it('should show a datepicker on input focus', function() { var input = document.createElement('input'); DatePicker.init(input); }); // production code window.DatePicker = { init: function() {} }
  • 33. User interaction / events // tests it('should show a datepicker on input focus', function() { var input = document.createElement('input'); DatePicker.init(input); }); // production code window.DatePicker = { init: function() {} } ✓
  • 34. User interaction / events // tests it('should show a datepicker on input focus', function() { [...] }); // production code window.DatePicker = { init: function() {} }
  • 35. User interaction / events // tests it('should show a datepicker on input focus', function() { [...] var event = new Event('focus'); input.dispatchEvent(event); }); // production code window.DatePicker = { init: function() {} }
  • 36. User interaction / events // tests it('should show a datepicker on input focus', function() { [...] var event = new Event('focus'); input.dispatchEvent(event); }); // production code window.DatePicker = { init: function() {} } ✓
  • 37. User interaction / events // tests it('should show a datepicker on input focus', function() { [...] var event = new Event('focus'); input.dispatchEvent(event); var element = document.getElementById('datePicker'); expect(element).to.be.ok; }); // production code window.DatePicker = { init: function() {} }
  • 38. User interaction / events // tests it('should show a datepicker on input focus', function() { [...] var event = new Event('focus'); input.dispatchEvent(event); var element = document.getElementById('datePicker'); expect(element).to.be.ok; }); // production code window.DatePicker = { init: function() {} } AssertionError: expected null to be truthy
  • 39. User interaction / events // tests it('should show a datepicker on input focus', function() { [...] var event = new Event('focus'); input.dispatchEvent(event); var element = document.getElementById('datePicker'); expect(element).to.be.ok; }); // production code window.DatePicker = { init: function(input) { [...] } }
  • 40. User interaction / events // tests it('should show a datepicker on input focus', function() { [...] var event = new Event('focus'); input.dispatchEvent(event); var element = document.getElementById('datePicker'); expect(element).to.be.ok; }); // production code [...] input.addEventListener('focus', function() { var element = document.createElement('div'); element.id = 'datePicker'; document.body.appendChild(element); } [...]
  • 41. User interaction / events // tests it('should show a datepicker on input focus', function() { [...] var event = new Event('focus'); input.dispatchEvent(event); var element = document.getElementById('datePicker'); expect(element).to.be.ok; }); // production code [...] input.addEventListener('focus', function() { var element = document.createElement('div'); element.id = 'datePicker'; document.body.appendChild(element); } [...] ✓
  • 42. User interaction / events // tests it('should stop event propagation', function() { }); // production code [...] input.addEventListener('focus', function() { var element = document.createElement('div'); element.id = 'datePicker'; document.body.appendChild(element); } [...]
  • 43. User interaction / events // tests it('should stop event propagation', function() { [...] var event = new Event('focus'); var spy = sinon.spy(event, 'stopPropagation'); input.dispatchEvent(event); expect(spy).to.have.been.calledOnce; }); // production code [...] input.addEventListener('focus', function() { var element = document.createElement('div'); element.id = 'datePicker'; document.body.appendChild(element); } [...]
  • 44. User interaction / events // tests it('should stop event propagation', function() { [...] var event = new Event('focus'); var spy = sinon.spy(event, 'stopPropagation'); input.dispatchEvent(event); expect(spy).to.have.been.calledOnce; }); // production code [...] input.addEventListener('focus', function() { var element = document.createElement('div'); element.id = 'datePicker'; document.body.appendChild(element); } [...] expected stopPropagation to have been called exactly once ...
  • 45. User interaction / events // tests it('should stop event propagation', function() { [...] var event = new Event('focus'); var spy = sinon.spy(event, 'stopPropagation'); input.dispatchEvent(event); expect(spy).to.have.been.calledOnce; }); // production code [...] input.addEventListener('focus', function(e) { e.stopPropagation(); var element = document.createElement('div'); element.id = 'datePicker'; document.body.appendChild(element); } [...]
  • 46. User interaction / events // tests it('should stop event propagation', function() { [...] var event = new Event('focus'); var spy = sinon.spy(event, 'stopPropagation'); input.dispatchEvent(event); expect(spy).to.have.been.calledOnce; }); // production code [...] input.addEventListener('focus', function(e) { e.stopPropagation(); var element = document.createElement('div'); element.id = 'datePicker'; document.body.appendChild(element); } [...] ✓
  • 47. Manipulating the DOM // tests it('should add class "selected" on a day when it is clicked', function(){ });
  • 48. Manipulating the DOM // tests it('should add class "selected" on a day when it is clicked', function(){ [...] var day = document.querySelector('#datePicker .day'); day.click(); });
  • 49. Manipulating the DOM // tests it('adds class "selected" on a day when clicked', function() { [...] var day = document.querySelector('#datePicker .day'); day.click(); var i = day.className.indexOf('selected'); expect(i > -1).to.be.true; });
  • 50. Mocking Time, tick tick tick // tests
  • 51. Mocking Time // tests it('should hide datePicker after 300ms', function(){ [...] var clock = sinon.useFakeTimers(); day.click(); clock.tick(299); expect(datePicker.className.indexOf('hidden') > -1).to.be.false; clock.tick(2); expect(datePicker.className.indexOf('hidden') > -1).to.be.true; clock.restore(); });
  • 53. Mocking Browser methods // tests beforeEach(function() { this.dateNowStub = sinon.stub(Date, 'now', function() { return new Date('2016-01-13').getTime(); }); }); afterEach(function(){ this.dateNowStub.restore(); });
  • 54. Testing Javascript for the Browser In a browser
  • 55. Take it to the next level Headless browser testing (phantomjs, zombie, electron...) Continuous Integration: automate your tests in jenkins, travis

  • 56. A few more tips - Find a BUG ? Write a TEST! - Do TDD while PAIRING - Use the Web APIs in your TESTS - Don’t try to test the browser - You don’t need to test libraries