SlideShare a Scribd company logo
Front End Workshops
VI.JavaScript testing. Client vs.
Server testing. Test Driven
Development
Raúl Delgado Astudillo
rdelgado@visual-engin.com
Mario García Martín
mgarcia@visual-engin.com
JavaScript testing
“Testing is an infinite process of comparing the invisible to the
ambiguous in order to avoid the unthinkable happening to the
anonymous.”
— James Bach
What is a test?
Type some code
Open and load the browser
Prove functionality
A test is (simply) the validation of an expectation.
Manual testing...
...is
NOT
enough!
Can we do better?
Manual testing is...
Time consuming
Error prone
Irreproducible
(Nearly) Impossible if we want to test a
wide set of browsers and platforms
YES!!
Automated
testing
Tests should be
Fast to run
Easy to understand
Isolated
Not reliant on an Internet connection
Benefits and pitfalls of testing
Regression testing
Refactoring
Cross-browser testing
Good documentation
Helps us write cleaner
interfaces (testable code)
Writing good tests can be
challenging
More information in...
● Test-Driven JavaScript Development, by Christian Johansen
● https://en.wikipedia.org/wiki/Software_testing
Client testing
“A passing test doesn't mean no problem. It means no problem
observed. This time. With these inputs. So far. On my machine.”
— Michael Bolton
Frameworks
Jasmine — Scaffolding
describe("A suite with setup and tear-down", function() {
var foo;
beforeAll(function() {});
afterAll(function() {});
beforeEach(function() {
foo = 1;
});
afterEach(function() {
foo = 0;
});
it("can contain specs with one or more expectations", function() {
expect(foo).toBe(1);
expect(true).toBe(true);
});
});
Matchers
expect(3).toBe(3); // Compares with ===
expect({a: 3}).toEqual({a: 3}); // For comparison of objects
expect('barely').toMatch(/bar/); // For regular expressions
expect(null).toBeDefined(); // Compares against undefined
expect(undefined).toBeUndefined(); // Compares against undefined
expect(null).toBeNull(); // Compares against null
expect('hello').toBeTruthy(); // For boolean casting testing
expect('').toBeFalsy(); // For boolean casting testing
expect(['bar', 'foo']).toContain('bar'); // For finding an item in an Array
expect(2).toBeLessThan(3); // For mathematical comparisons
expect(3).toBeGreaterThan(2); // For mathematical comparisons
expect(3.14).toBeCloseTo(3.17, 1); // For precision math comparison
// For testing if a function throws an exception
expect(function() { throw new Error('Error!'); }).toThrow();
// Modifier 'not'
expect(false).not.toBe(true);
Spies
describe("A suite", function() {
var foo, bar = null;
beforeEach(function() {
foo = { setBar: function(value) { bar = value; } };
spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456, 'another param');
});
it("that defines a spy out of the box", function() {
expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called
// tracks all the arguments of its calls
expect(foo.setBar).toHaveBeenCalledWith(123);
expect(foo.setBar).toHaveBeenCalledWith(456, 'another param');
expect(bar).toBeNull(); // stops all execution on a function
});
});
Spies — and.callthrough
describe("A suite", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) { bar = value; }
};
spyOn(foo, 'setBar').and.callThrough();
foo.setBar(123);
});
it("that defines a spy configured to call through", function() {
expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called
expect(bar).toEqual(123); // the spied function has been called
});
});
describe("A suite", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
getBar: function() { return bar; }
};
spyOn(foo, 'getBar').and.returnValue(745);
});
it("that defines a spy configured to fake a return value", function() {
expect(foo.getBar()).toBe(745); // when called returns the requested value
expect(bar).toBeNull(); // should not affect the variable
});
});
Spies — and.returnValue
describe("A suite", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) { bar = value; }
};
spyOn(foo, 'setBar').and.callFake(function() {
console.log('hello');
});
foo.setBar(); // logs hello in the console.
});
it("that defines a spy configured with an alternate implementation", function() {
expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called
expect(bar).toBeNull(); // should not affect the variable
});
});
Spies — and.callFake
Spies — createSpy
describe("A suite", function() {
var spy;
beforeAll(function() {
$(window).on('resize', function() { $(window).trigger('myEvent'); });
});
afterAll(function() {
$(window).off('resize');
});
beforeEach(function() {
spy = jasmine.createSpy();
});
it("that defines a spy created manually", function() {
$(window).on('myEvent', spy);
$(window).trigger('resize');
expect(spy).toHaveBeenCalled(); // tracks that the spy was called
});
});
Spies — Other tracking properties (I)
describe("A spy", function() {
var foo, bar = null;
beforeEach(function() {
foo = { setBar: function(value) { bar = value; } };
spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456, 'baz');
});
it("has a rich set of tracking properties", function() {
expect(foo.setBar.calls.count()).toEqual(2); // tracks the number of calls
// tracks the args of each call
expect(foo.setBar.calls.argsFor(0)).toEqual([123]);
expect(foo.setBar.calls.argsFor(1)).toEqual([456, 'baz']);
// has shortcuts to the first and most recent call
expect(foo.setBar.calls.first().args).toEqual([123]);
expect(foo.setBar.calls.mostRecent().args).toEqual([456, 'baz']);
});
});
Spies — Other tracking properties (II)
describe("A spy", function() {
var foo, bar = null;
beforeEach(function() {
foo = { setBar: function(value) { bar = value; } };
spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456, 'baz');
});
it("has a rich set of tracking properties", function() {
// tracks the context and return values
expect(foo.setBar.calls.first().object).toEqual(foo);
expect(foo.setBar.calls.first().returnValue).toBeUndefined();
// can be reset
foo.setBar.calls.reset();
expect(foo.setBar.calls.count()).toBe(0);
});
});
Asynchronous support
describe("Asynchronous specs", function() {
var value;
beforeEach(function(done) {
setTimeout(function() {
value = 0;
done();
}, 100);
});
it("should support async execution of preparation and expectations", function(done) {
expect(value).toBe(0);
done();
});
});
Clock
describe("Manually ticking the Jasmine Clock", function() {
var timerCallback;
beforeEach(function() {
timerCallback = jasmine.createSpy();
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it("causes a timeout to be called synchronously", function() {
setTimeout(timerCallback, 100);
expect(timerCallback).not.toHaveBeenCalled();
jasmine.clock().tick(101);
expect(timerCallback).toHaveBeenCalled();
});
});
Clock — Mocking the date
describe("Mocking the Date object", function() {
beforeEach(function() {
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it("mocks the Date object and sets it to a given time", function() {
var baseTime = new Date(2013, 9, 23);
jasmine.clock().mockDate(baseTime);
jasmine.clock().tick(50);
expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);
});
});
Sinon — Spies and Stubs
var spy = sinon.spy();
sinon.spy($, 'ajax');
$.ajax.restore();
sinon.stub($, 'ajax');
$.ajax.restore();
sinon.stub($, 'ajax', function(options) {
console.log(options.url);
});
$.ajax.restore();
Sinon — Fake timer
describe("Manually ticking the Clock", function() {
var clock, timerCallback;
beforeEach(function() {
timerCallback = sinon.spy();
clock = sinon.useFakeTimers();
});
afterEach(function() {
clock.restore();
});
it("causes a timeout to be called synchronously", function() {
setTimeout(timerCallback, 100);
expect(timerCallback.callCount).toBe(0);
clock.tick(101);
expect(timerCallback.callCount).toBe(1);
expect(new Date().getTime()).toBe(101);
});
});
Sinon — Fake server
describe("A suite with a sinon fakeServer", function() {
var server;
beforeEach(function() {
server = sinon.fakeServer.create();
server.autoRespond = true;
server.respondWith(function(xhr) {
xhr.respond(200, {'Content-Type':'application/json'}, JSON.stringify({'msg': 'msg'}));
});
server.xhr.useFilters = true;
server.xhr.addFilter(function(method, url) {
return !!url.match(/fixtures|css/); // If returns true the request will not be faked.
});
});
afterEach(function() {
server.restore();
});
});
More information in...
● https://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#JavaScri
pt
● http://stackoverflow.com/questions/300855/javascript-unit-test-tools-
for-tdd
● http://jasmine.github.io/
● http://sinonjs.org/
Workshop 5: JavaScript testing
Workshop 5: JavaScript testing
Workshop 5: JavaScript testing
Workshop 5: JavaScript testing
Workshop 5: JavaScript testing
Workshop 5: JavaScript testing
Workshop 5: JavaScript testing
Workshop 5: JavaScript testing
Workshop 5: JavaScript testing
Workshop 5: JavaScript testing
Workshop 5: JavaScript testing
Test Driven Development
“The best TDD can do is assure that the code does what the
programmer thinks it should do. That is pretty good by the way.”
— James Grenning
The cycle of TDD
Write a test
Run tests. Watch the new test fail
Make the test pass
Refactor to remove duplication
Benefits of TDD
Produces code that works
Honors the Single Responsibility Principle
Forces conscious development
Productivity boost
More information in...
● Test-Driven Development By Example, by Kent Beck.
Jasmine Disabling specs
xdescribe("A disabled suite", function() {
it("where the specs will not be executed", function() {
expect(2).toEqual(1);
});
});
describe("A suite", function() {
xit("with a disabled spec declared with 'xit'", function() {
expect(true).toBe(false);
});
it.only("with a spec that will be executed", function() {
expect(1).toBe(1);
});
it("with another spec that will not be executed", function() {
expect(1).toBe(1);
});
});
Asynchronous support
describe("long asynchronous specs", function() {
beforeEach(function(done) {
done();
}, 1000);
afterEach(function(done) {
done();
}, 1000);
it("takes a long time", function(done) {
setTimeout(done, 9000);
}, 10000);
});
Asynchronous support. Jasmine 1.3
describe("Asynchronous specs", function() {
var value, flag;
it("should support async execution of test preparation and expectations", function() {
flag = false;
value = 0;
setTimeout(function() {
flag = true;
}, 500);
waitsFor(function() {
value++;
return flag;
}, "The Value should be incremented", 750);
runs(function() {
expect(value).toBeGreaterThan(0);
});
});
});
jasmine.Clock v.1.3
it('description', function() {
jasmine.Clock.useMock();
setTimeout(function() {
console.log('print something');
}, 200);
jasmine.Clock.tick(190);
});
it('description', function() {
jasmine.Clock.useMock();
jasmine.Clock.tick(190);
});
Karma
npm install karma --save-dev
npm install karma-jasmine karma-chrome-launcher karma-phantomjs-launcher --save-dev
npm install karma-coverage --save-dev
npm install -g karma-cli
Installation
Configuration
karma init karma.conf.js npm install grunt-karma --save-dev
grunt.loadNpmTasks('grunt-karma');
karma: {
unit: {
configFile: 'karma.conf.js'
}
}
Grunt task
Karma configuration
The files array determines which files are included in the browser and which files are watched and
served by Karma.
Each pattern is either a simple string or an object with four properties:
pattern String, no default value. The pattern to use for matching. This property is mandatory.
watched Boolean (true). If autoWatch is true all files that have set watched to true will be watched
for changes.
included Boolean (true). Should the files be included in the browser using <script> tag? Use false if
you want to load them manually, eg. using Require.js.
served Boolean (true). Should the files be served by Karma's webserver?
THANKS FOR YOUR ATTENTION
Leave your questions on the comments section
Workshop 5: JavaScript testing

More Related Content

PDF
Workshop 10: ECMAScript 6
Visual Engineering
 
PPTX
Workshop 1: Good practices in JavaScript
Visual Engineering
 
PDF
Testing your javascript code with jasmine
Rubyc Slides
 
PDF
Redux Sagas - React Alicante
Ignacio Martín
 
PDF
JavaScript Unit Testing with Jasmine
Raimonds Simanovskis
 
PDF
Javascript: the important bits
Chris Saylor
 
PDF
JavaScript and the AST
Jarrod Overson
 
PDF
Reactive, component 그리고 angular2
Jeado Ko
 
Workshop 10: ECMAScript 6
Visual Engineering
 
Workshop 1: Good practices in JavaScript
Visual Engineering
 
Testing your javascript code with jasmine
Rubyc Slides
 
Redux Sagas - React Alicante
Ignacio Martín
 
JavaScript Unit Testing with Jasmine
Raimonds Simanovskis
 
Javascript: the important bits
Chris Saylor
 
JavaScript and the AST
Jarrod Overson
 
Reactive, component 그리고 angular2
Jeado Ko
 

What's hot (20)

PDF
Say It With Javascript
Giovanni Scerra ☃
 
PDF
Advanced javascript
Doeun KOCH
 
KEY
Object-Oriented Javascript
kvangork
 
PDF
ES2015 workflows
Jarrod Overson
 
PDF
Testing Backbone applications with Jasmine
Leon van der Grient
 
PPTX
Oojs 1.1
Rodica Dada
 
PDF
Practical JavaScript Programming - Session 7/8
Wilson Su
 
KEY
連邦の白いヤツ 「Objective-C」
matuura_core
 
PDF
Practical JavaScript Programming - Session 8/8
Wilson Su
 
PDF
Unit testing with mocha
Revath S Kumar
 
PDF
Inversion Of Control
Chad Hietala
 
PDF
Javascript ES6 generators
RameshNair6
 
PPTX
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Domenic Denicola
 
PDF
Powerful JavaScript Tips and Best Practices
Dragos Ionita
 
PDF
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Raimonds Simanovskis
 
PDF
Java Script Best Practices
Enrique Juan de Dios
 
PDF
To Err Is Human
Alex Liu
 
PDF
06 jQuery #burningkeyboards
Denis Ristic
 
PDF
05 JavaScript #burningkeyboards
Denis Ristic
 
PPTX
Component lifecycle hooks in Angular 2.0
Eyal Vardi
 
Say It With Javascript
Giovanni Scerra ☃
 
Advanced javascript
Doeun KOCH
 
Object-Oriented Javascript
kvangork
 
ES2015 workflows
Jarrod Overson
 
Testing Backbone applications with Jasmine
Leon van der Grient
 
Oojs 1.1
Rodica Dada
 
Practical JavaScript Programming - Session 7/8
Wilson Su
 
連邦の白いヤツ 「Objective-C」
matuura_core
 
Practical JavaScript Programming - Session 8/8
Wilson Su
 
Unit testing with mocha
Revath S Kumar
 
Inversion Of Control
Chad Hietala
 
Javascript ES6 generators
RameshNair6
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Domenic Denicola
 
Powerful JavaScript Tips and Best Practices
Dragos Ionita
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Raimonds Simanovskis
 
Java Script Best Practices
Enrique Juan de Dios
 
To Err Is Human
Alex Liu
 
06 jQuery #burningkeyboards
Denis Ristic
 
05 JavaScript #burningkeyboards
Denis Ristic
 
Component lifecycle hooks in Angular 2.0
Eyal Vardi
 
Ad

Viewers also liked (8)

PDF
Workshop 8: Templating: Handlebars, DustJS
Visual Engineering
 
PDF
Workshop 14: AngularJS Parte III
Visual Engineering
 
PDF
Workshop 13: AngularJS Parte II
Visual Engineering
 
PDF
Workshop 15: Ionic framework
Visual Engineering
 
PDF
Workshop 9: BackboneJS y patrones MVC
Visual Engineering
 
PDF
Workshop 7: Single Page Applications
Visual Engineering
 
PDF
Legal protection in public procurement, Zoran Blazevic, SIGMA regional confer...
Support for Improvement in Governance and Management SIGMA
 
PDF
Workshop 12: AngularJS Parte I
Visual Engineering
 
Workshop 8: Templating: Handlebars, DustJS
Visual Engineering
 
Workshop 14: AngularJS Parte III
Visual Engineering
 
Workshop 13: AngularJS Parte II
Visual Engineering
 
Workshop 15: Ionic framework
Visual Engineering
 
Workshop 9: BackboneJS y patrones MVC
Visual Engineering
 
Workshop 7: Single Page Applications
Visual Engineering
 
Legal protection in public procurement, Zoran Blazevic, SIGMA regional confer...
Support for Improvement in Governance and Management SIGMA
 
Workshop 12: AngularJS Parte I
Visual Engineering
 
Ad

Similar to Workshop 5: JavaScript testing (20)

PDF
Stop Making Excuses and Start Testing Your JavaScript
Ryan Anklam
 
ODP
Introduccion a Jasmin
Rodrigo Quelca Sirpa
 
PDF
Angular promises and http
Alexe Bogdan
 
PDF
Bonnes pratiques de développement avec Node js
Francois Zaninotto
 
PPT
Expert JavaScript tricks of the masters
Ara Pehlivanian
 
PDF
How to test complex SaaS applications - The family july 2014
Guillaume POTIER
 
PDF
The Beauty Of Java Script V5a
rajivmordani
 
PDF
Introduction to Protractor
Jie-Wei Wu
 
PDF
Asynchronous programming done right - Node.js
Piotr Pelczar
 
PDF
The Beauty of Java Script
Michael Girouard
 
PDF
04 Advanced Javascript
crgwbr
 
DOC
code for quiz in my sql
JOYITAKUNDU1
 
PPTX
Call stack, event loop and async programming
Masters Academy
 
PDF
Jasmine BDD for Javascript
Luis Alfredo Porras Páez
 
PDF
WordPress Realtime - WordCamp São Paulo 2015
Fernando Daciuk
 
PDF
Sane Async Patterns
TrevorBurnham
 
PPTX
AngularJS Testing
Eyal Vardi
 
PPTX
ES6 Overview
Bruno Scopelliti
 
PDF
jQuery: Events, Animation, Ajax
Constantin Titarenko
 
KEY
Node.js - Best practices
Felix Geisendörfer
 
Stop Making Excuses and Start Testing Your JavaScript
Ryan Anklam
 
Introduccion a Jasmin
Rodrigo Quelca Sirpa
 
Angular promises and http
Alexe Bogdan
 
Bonnes pratiques de développement avec Node js
Francois Zaninotto
 
Expert JavaScript tricks of the masters
Ara Pehlivanian
 
How to test complex SaaS applications - The family july 2014
Guillaume POTIER
 
The Beauty Of Java Script V5a
rajivmordani
 
Introduction to Protractor
Jie-Wei Wu
 
Asynchronous programming done right - Node.js
Piotr Pelczar
 
The Beauty of Java Script
Michael Girouard
 
04 Advanced Javascript
crgwbr
 
code for quiz in my sql
JOYITAKUNDU1
 
Call stack, event loop and async programming
Masters Academy
 
Jasmine BDD for Javascript
Luis Alfredo Porras Páez
 
WordPress Realtime - WordCamp São Paulo 2015
Fernando Daciuk
 
Sane Async Patterns
TrevorBurnham
 
AngularJS Testing
Eyal Vardi
 
ES6 Overview
Bruno Scopelliti
 
jQuery: Events, Animation, Ajax
Constantin Titarenko
 
Node.js - Best practices
Felix Geisendörfer
 

More from Visual Engineering (20)

PDF
Workshop 27: Isomorphic web apps with ReactJS
Visual Engineering
 
PDF
Workshop iOS 4: Closures, generics & operators
Visual Engineering
 
PDF
Workshop iOS 3: Testing, protocolos y extensiones
Visual Engineering
 
PDF
Workshop iOS 2: Swift - Structures
Visual Engineering
 
PDF
Workhop iOS 1: Fundamentos de Swift
Visual Engineering
 
PDF
Workshop 26: React Native - The Native Side
Visual Engineering
 
PDF
Workshop 25: React Native - Components
Visual Engineering
 
PDF
Workshop 24: React Native Introduction
Visual Engineering
 
PDF
Workshop 23: ReactJS, React & Redux testing
Visual Engineering
 
PDF
Workshop 22: ReactJS Redux Advanced
Visual Engineering
 
PDF
Workshop 22: React-Redux Middleware
Visual Engineering
 
PDF
Workshop 21: React Router
Visual Engineering
 
PDF
Workshop 20: ReactJS Part II Flux Pattern & Redux
Visual Engineering
 
PDF
Workshop 19: ReactJS Introduction
Visual Engineering
 
PDF
Workshop 18: CSS Animations & cool effects
Visual Engineering
 
PDF
Workshop 17: EmberJS parte II
Visual Engineering
 
PDF
Workshop 16: EmberJS Parte I
Visual Engineering
 
PDF
Workshop 11: Trendy web designs & prototyping
Visual Engineering
 
PDF
Workshop 6: Designer tools
Visual Engineering
 
PDF
Workshop 4: NodeJS. Express Framework & MongoDB.
Visual Engineering
 
Workshop 27: Isomorphic web apps with ReactJS
Visual Engineering
 
Workshop iOS 4: Closures, generics & operators
Visual Engineering
 
Workshop iOS 3: Testing, protocolos y extensiones
Visual Engineering
 
Workshop iOS 2: Swift - Structures
Visual Engineering
 
Workhop iOS 1: Fundamentos de Swift
Visual Engineering
 
Workshop 26: React Native - The Native Side
Visual Engineering
 
Workshop 25: React Native - Components
Visual Engineering
 
Workshop 24: React Native Introduction
Visual Engineering
 
Workshop 23: ReactJS, React & Redux testing
Visual Engineering
 
Workshop 22: ReactJS Redux Advanced
Visual Engineering
 
Workshop 22: React-Redux Middleware
Visual Engineering
 
Workshop 21: React Router
Visual Engineering
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Visual Engineering
 
Workshop 19: ReactJS Introduction
Visual Engineering
 
Workshop 18: CSS Animations & cool effects
Visual Engineering
 
Workshop 17: EmberJS parte II
Visual Engineering
 
Workshop 16: EmberJS Parte I
Visual Engineering
 
Workshop 11: Trendy web designs & prototyping
Visual Engineering
 
Workshop 6: Designer tools
Visual Engineering
 
Workshop 4: NodeJS. Express Framework & MongoDB.
Visual Engineering
 

Recently uploaded (20)

PPTX
Services offered by Dynamic Solutions in Pakistan
DaniyaalAdeemShibli1
 
PDF
Solar Panel Installation Guide – Step By Step Process 2025.pdf
CRMLeaf
 
PDF
Teaching Reproducibility and Embracing Variability: From Floating-Point Exper...
University of Rennes, INSA Rennes, Inria/IRISA, CNRS
 
PPTX
AIRLINE PRICE API | FLIGHT API COST |
philipnathen82
 
PPTX
AI-Ready Handoff: Auto-Summaries & Draft Emails from MQL to Slack in One Flow
bbedford2
 
PDF
QAware_Mario-Leander_Reimer_Architecting and Building a K8s-based AI Platform...
QAware GmbH
 
PPTX
PFAS Reporting Requirements 2026 Are You Submission Ready Certivo.pptx
Certivo Inc
 
PPTX
ConcordeApp: Engineering Global Impact & Unlocking Billions in Event ROI with AI
chastechaste14
 
PDF
Build Multi-agent using Agent Development Kit
FadyIbrahim23
 
PDF
IEEE-CS Tech Predictions, SWEBOK and Quantum Software: Towards Q-SWEBOK
Hironori Washizaki
 
PPTX
Materi_Pemrograman_Komputer-Looping.pptx
RanuFajar1
 
PPTX
Why Use Open Source Reporting Tools for Business Intelligence.pptx
Varsha Nayak
 
PPTX
Explanation about Structures in C language.pptx
Veeral Rathod
 
PPTX
The-Dawn-of-AI-Reshaping-Our-World.pptxx
parthbhanushali307
 
PDF
Exploring AI Agents in Process Industries
amoreira6
 
PPTX
Web Testing.pptx528278vshbuqffqhhqiwnwuq
studylike474
 
PPTX
EU POPs Limits & Digital Product Passports Compliance Strategy 2025.pptx
Certivo Inc
 
PDF
Bandai Playdia The Book - David Glotz
BluePanther6
 
PDF
ShowUs: Pharo Stream Deck (ESUG 2025, Gdansk)
ESUG
 
PDF
Community & News Update Q2 Meet Up 2025
VictoriaMetrics
 
Services offered by Dynamic Solutions in Pakistan
DaniyaalAdeemShibli1
 
Solar Panel Installation Guide – Step By Step Process 2025.pdf
CRMLeaf
 
Teaching Reproducibility and Embracing Variability: From Floating-Point Exper...
University of Rennes, INSA Rennes, Inria/IRISA, CNRS
 
AIRLINE PRICE API | FLIGHT API COST |
philipnathen82
 
AI-Ready Handoff: Auto-Summaries & Draft Emails from MQL to Slack in One Flow
bbedford2
 
QAware_Mario-Leander_Reimer_Architecting and Building a K8s-based AI Platform...
QAware GmbH
 
PFAS Reporting Requirements 2026 Are You Submission Ready Certivo.pptx
Certivo Inc
 
ConcordeApp: Engineering Global Impact & Unlocking Billions in Event ROI with AI
chastechaste14
 
Build Multi-agent using Agent Development Kit
FadyIbrahim23
 
IEEE-CS Tech Predictions, SWEBOK and Quantum Software: Towards Q-SWEBOK
Hironori Washizaki
 
Materi_Pemrograman_Komputer-Looping.pptx
RanuFajar1
 
Why Use Open Source Reporting Tools for Business Intelligence.pptx
Varsha Nayak
 
Explanation about Structures in C language.pptx
Veeral Rathod
 
The-Dawn-of-AI-Reshaping-Our-World.pptxx
parthbhanushali307
 
Exploring AI Agents in Process Industries
amoreira6
 
Web Testing.pptx528278vshbuqffqhhqiwnwuq
studylike474
 
EU POPs Limits & Digital Product Passports Compliance Strategy 2025.pptx
Certivo Inc
 
Bandai Playdia The Book - David Glotz
BluePanther6
 
ShowUs: Pharo Stream Deck (ESUG 2025, Gdansk)
ESUG
 
Community & News Update Q2 Meet Up 2025
VictoriaMetrics
 

Workshop 5: JavaScript testing

  • 1. Front End Workshops VI.JavaScript testing. Client vs. Server testing. Test Driven Development Raúl Delgado Astudillo [email protected] Mario García Martín [email protected]
  • 2. JavaScript testing “Testing is an infinite process of comparing the invisible to the ambiguous in order to avoid the unthinkable happening to the anonymous.” — James Bach
  • 3. What is a test? Type some code Open and load the browser Prove functionality A test is (simply) the validation of an expectation. Manual testing... ...is NOT enough!
  • 4. Can we do better? Manual testing is... Time consuming Error prone Irreproducible (Nearly) Impossible if we want to test a wide set of browsers and platforms YES!! Automated testing
  • 5. Tests should be Fast to run Easy to understand Isolated Not reliant on an Internet connection
  • 6. Benefits and pitfalls of testing Regression testing Refactoring Cross-browser testing Good documentation Helps us write cleaner interfaces (testable code) Writing good tests can be challenging
  • 7. More information in... ● Test-Driven JavaScript Development, by Christian Johansen ● https://en.wikipedia.org/wiki/Software_testing
  • 8. Client testing “A passing test doesn't mean no problem. It means no problem observed. This time. With these inputs. So far. On my machine.” — Michael Bolton
  • 10. Jasmine — Scaffolding describe("A suite with setup and tear-down", function() { var foo; beforeAll(function() {}); afterAll(function() {}); beforeEach(function() { foo = 1; }); afterEach(function() { foo = 0; }); it("can contain specs with one or more expectations", function() { expect(foo).toBe(1); expect(true).toBe(true); }); });
  • 11. Matchers expect(3).toBe(3); // Compares with === expect({a: 3}).toEqual({a: 3}); // For comparison of objects expect('barely').toMatch(/bar/); // For regular expressions expect(null).toBeDefined(); // Compares against undefined expect(undefined).toBeUndefined(); // Compares against undefined expect(null).toBeNull(); // Compares against null expect('hello').toBeTruthy(); // For boolean casting testing expect('').toBeFalsy(); // For boolean casting testing expect(['bar', 'foo']).toContain('bar'); // For finding an item in an Array expect(2).toBeLessThan(3); // For mathematical comparisons expect(3).toBeGreaterThan(2); // For mathematical comparisons expect(3.14).toBeCloseTo(3.17, 1); // For precision math comparison // For testing if a function throws an exception expect(function() { throw new Error('Error!'); }).toThrow(); // Modifier 'not' expect(false).not.toBe(true);
  • 12. Spies describe("A suite", function() { var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; spyOn(foo, 'setBar'); foo.setBar(123); foo.setBar(456, 'another param'); }); it("that defines a spy out of the box", function() { expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called // tracks all the arguments of its calls expect(foo.setBar).toHaveBeenCalledWith(123); expect(foo.setBar).toHaveBeenCalledWith(456, 'another param'); expect(bar).toBeNull(); // stops all execution on a function }); });
  • 13. Spies — and.callthrough describe("A suite", function() { var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; spyOn(foo, 'setBar').and.callThrough(); foo.setBar(123); }); it("that defines a spy configured to call through", function() { expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called expect(bar).toEqual(123); // the spied function has been called }); });
  • 14. describe("A suite", function() { var foo, bar = null; beforeEach(function() { foo = { getBar: function() { return bar; } }; spyOn(foo, 'getBar').and.returnValue(745); }); it("that defines a spy configured to fake a return value", function() { expect(foo.getBar()).toBe(745); // when called returns the requested value expect(bar).toBeNull(); // should not affect the variable }); }); Spies — and.returnValue
  • 15. describe("A suite", function() { var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; spyOn(foo, 'setBar').and.callFake(function() { console.log('hello'); }); foo.setBar(); // logs hello in the console. }); it("that defines a spy configured with an alternate implementation", function() { expect(foo.setBar).toHaveBeenCalled(); // tracks that the spy was called expect(bar).toBeNull(); // should not affect the variable }); }); Spies — and.callFake
  • 16. Spies — createSpy describe("A suite", function() { var spy; beforeAll(function() { $(window).on('resize', function() { $(window).trigger('myEvent'); }); }); afterAll(function() { $(window).off('resize'); }); beforeEach(function() { spy = jasmine.createSpy(); }); it("that defines a spy created manually", function() { $(window).on('myEvent', spy); $(window).trigger('resize'); expect(spy).toHaveBeenCalled(); // tracks that the spy was called }); });
  • 17. Spies — Other tracking properties (I) describe("A spy", function() { var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; spyOn(foo, 'setBar'); foo.setBar(123); foo.setBar(456, 'baz'); }); it("has a rich set of tracking properties", function() { expect(foo.setBar.calls.count()).toEqual(2); // tracks the number of calls // tracks the args of each call expect(foo.setBar.calls.argsFor(0)).toEqual([123]); expect(foo.setBar.calls.argsFor(1)).toEqual([456, 'baz']); // has shortcuts to the first and most recent call expect(foo.setBar.calls.first().args).toEqual([123]); expect(foo.setBar.calls.mostRecent().args).toEqual([456, 'baz']); }); });
  • 18. Spies — Other tracking properties (II) describe("A spy", function() { var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; spyOn(foo, 'setBar'); foo.setBar(123); foo.setBar(456, 'baz'); }); it("has a rich set of tracking properties", function() { // tracks the context and return values expect(foo.setBar.calls.first().object).toEqual(foo); expect(foo.setBar.calls.first().returnValue).toBeUndefined(); // can be reset foo.setBar.calls.reset(); expect(foo.setBar.calls.count()).toBe(0); }); });
  • 19. Asynchronous support describe("Asynchronous specs", function() { var value; beforeEach(function(done) { setTimeout(function() { value = 0; done(); }, 100); }); it("should support async execution of preparation and expectations", function(done) { expect(value).toBe(0); done(); }); });
  • 20. Clock describe("Manually ticking the Jasmine Clock", function() { var timerCallback; beforeEach(function() { timerCallback = jasmine.createSpy(); jasmine.clock().install(); }); afterEach(function() { jasmine.clock().uninstall(); }); it("causes a timeout to be called synchronously", function() { setTimeout(timerCallback, 100); expect(timerCallback).not.toHaveBeenCalled(); jasmine.clock().tick(101); expect(timerCallback).toHaveBeenCalled(); }); });
  • 21. Clock — Mocking the date describe("Mocking the Date object", function() { beforeEach(function() { jasmine.clock().install(); }); afterEach(function() { jasmine.clock().uninstall(); }); it("mocks the Date object and sets it to a given time", function() { var baseTime = new Date(2013, 9, 23); jasmine.clock().mockDate(baseTime); jasmine.clock().tick(50); expect(new Date().getTime()).toEqual(baseTime.getTime() + 50); }); });
  • 22. Sinon — Spies and Stubs var spy = sinon.spy(); sinon.spy($, 'ajax'); $.ajax.restore(); sinon.stub($, 'ajax'); $.ajax.restore(); sinon.stub($, 'ajax', function(options) { console.log(options.url); }); $.ajax.restore();
  • 23. Sinon — Fake timer describe("Manually ticking the Clock", function() { var clock, timerCallback; beforeEach(function() { timerCallback = sinon.spy(); clock = sinon.useFakeTimers(); }); afterEach(function() { clock.restore(); }); it("causes a timeout to be called synchronously", function() { setTimeout(timerCallback, 100); expect(timerCallback.callCount).toBe(0); clock.tick(101); expect(timerCallback.callCount).toBe(1); expect(new Date().getTime()).toBe(101); }); });
  • 24. Sinon — Fake server describe("A suite with a sinon fakeServer", function() { var server; beforeEach(function() { server = sinon.fakeServer.create(); server.autoRespond = true; server.respondWith(function(xhr) { xhr.respond(200, {'Content-Type':'application/json'}, JSON.stringify({'msg': 'msg'})); }); server.xhr.useFilters = true; server.xhr.addFilter(function(method, url) { return !!url.match(/fixtures|css/); // If returns true the request will not be faked. }); }); afterEach(function() { server.restore(); }); });
  • 25. More information in... ● https://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#JavaScri pt ● http://stackoverflow.com/questions/300855/javascript-unit-test-tools- for-tdd ● http://jasmine.github.io/ ● http://sinonjs.org/
  • 37. Test Driven Development “The best TDD can do is assure that the code does what the programmer thinks it should do. That is pretty good by the way.” — James Grenning
  • 38. The cycle of TDD Write a test Run tests. Watch the new test fail Make the test pass Refactor to remove duplication
  • 39. Benefits of TDD Produces code that works Honors the Single Responsibility Principle Forces conscious development Productivity boost
  • 40. More information in... ● Test-Driven Development By Example, by Kent Beck.
  • 41. Jasmine Disabling specs xdescribe("A disabled suite", function() { it("where the specs will not be executed", function() { expect(2).toEqual(1); }); }); describe("A suite", function() { xit("with a disabled spec declared with 'xit'", function() { expect(true).toBe(false); }); it.only("with a spec that will be executed", function() { expect(1).toBe(1); }); it("with another spec that will not be executed", function() { expect(1).toBe(1); }); });
  • 42. Asynchronous support describe("long asynchronous specs", function() { beforeEach(function(done) { done(); }, 1000); afterEach(function(done) { done(); }, 1000); it("takes a long time", function(done) { setTimeout(done, 9000); }, 10000); });
  • 43. Asynchronous support. Jasmine 1.3 describe("Asynchronous specs", function() { var value, flag; it("should support async execution of test preparation and expectations", function() { flag = false; value = 0; setTimeout(function() { flag = true; }, 500); waitsFor(function() { value++; return flag; }, "The Value should be incremented", 750); runs(function() { expect(value).toBeGreaterThan(0); }); }); });
  • 44. jasmine.Clock v.1.3 it('description', function() { jasmine.Clock.useMock(); setTimeout(function() { console.log('print something'); }, 200); jasmine.Clock.tick(190); }); it('description', function() { jasmine.Clock.useMock(); jasmine.Clock.tick(190); });
  • 45. Karma npm install karma --save-dev npm install karma-jasmine karma-chrome-launcher karma-phantomjs-launcher --save-dev npm install karma-coverage --save-dev npm install -g karma-cli Installation Configuration karma init karma.conf.js npm install grunt-karma --save-dev grunt.loadNpmTasks('grunt-karma'); karma: { unit: { configFile: 'karma.conf.js' } } Grunt task
  • 46. Karma configuration The files array determines which files are included in the browser and which files are watched and served by Karma. Each pattern is either a simple string or an object with four properties: pattern String, no default value. The pattern to use for matching. This property is mandatory. watched Boolean (true). If autoWatch is true all files that have set watched to true will be watched for changes. included Boolean (true). Should the files be included in the browser using <script> tag? Use false if you want to load them manually, eg. using Require.js. served Boolean (true). Should the files be served by Karma's webserver?
  • 47. THANKS FOR YOUR ATTENTION Leave your questions on the comments section