SlideShare uma empresa Scribd logo
1 de 23
Baixar para ler offline
ADVANCED JASMINE
FRONT-END JAVASCRIPT UNIT TESTING
/Lars Thorup, ZeaLake @larsthorup
WHO IS LARS THORUP
Software developer/architect
C++, C# and JavaScript
Test Driven Development
Coach: Teaching agile and automated testing
Advisor: Assesses software projects and companies
Founder and CEO of ZeaLake
AGENDA
Unit tests gives quality feedback
Make them fast
Make them precise
Run thousands of unit tests in seconds
We will look at
Mocking techniques
Front-end specific testing patterns
Assuming knowledge about JavaScript and unit testing
JASMINE BASICS
describe('Calculator', function () {
var calc;
beforeEach(function () {
calc = new Calculator();
});
it('should multiply', function () {
expect(calc.multiply(6, 7)).toBe(42);
});
});
MOCKING, SPYING AND STUBBING
HOW TO TEST IN ISOLATION?
We want to test code in isolation
here the code is the 'keypress' event handler
and isolation means not invoking the getMatch() method
'keypress': function (element, event) {
var pattern = this.element.val();
pattern += String.fromCharCode(event.charCode);
var match = this.getMatch(pattern);
if (match) {
event.preventDefault();
this.element.val(match);
}
}
MOCKING METHODS
We can mock the getMatch() method
decide how the mock should behave
verify that the mocked method was called correctly
spyOn(autoComplete, 'getMatch').andReturn('monique');
$('#name').trigger($.Event('keypress', {charCode: 109}));
expect(autoComplete.getMatch).toHaveBeenCalledWith('m');
expect($('#name')).toHaveValue('monique');
MOCKING GLOBAL FUNCTIONS
Global functions are properties of the window object
openPopup: function (url) {
var popup = window.open(url, '_blank', 'resizable');
popup.focus();
}
var popup;
spyOn(window, 'open').andCallFake(function () {
popup = {
focus: jasmine.createSpy()
};
return popup;
});
autoComplete.openPopup('zealake.com');
expect(window.open).toHaveBeenCalledWith('zealake.com', '_blank', 'resizable');
expect(popup.focus).toHaveBeenCalledWith();
MOCKING CONSTRUCTORS
Constructors are functions
with thisbeing the object to construct
this.input = new window.AutoComplete(inputElement, {
listUrl: this.options.listUrl
});
this.input.focus();
spyOn(window, 'AutoComplete').andCallFake(function () {
this.focus = jasmine.createSpy();
});
expect(window.AutoComplete.callCount).toBe(1);
var args = window.AutoComplete.mostRecentCall.args;
expect(args[0]).toBe('#name');
expect(args[1]).toEqual({listUrl: '/someUrl'});
var object = window.AutoComplete.mostRecentCall.object;
expect(object.focus).toHaveBeenCalledWith();
HOW TO AVOID WAITING?
We want the tests to be fast
So don't use Jasmine waitsFor()
But we often need to wait
For animations to complete
For AJAX responses to return
delayHide: function () {
var self = this;
setTimeout(function () {
self.element.hide();
}, this.options.hideDelay);
}
MOCKING TIMERS
Use Jasmine's mock clock
Control the clock explicitly
Now the test completes in milliseconds
without waiting
jasmine.Clock.useMock();
autoComplete.delayHide();
expect($('#name')).toBeVisible();
jasmine.Clock.tick(500);
expect($('#name')).not.toBeVisible();
MOCKING TIME
new Date()tends to return different values over time
Actually, that's the whole point :)
But how do we test code that does that?
We cannot expecton a value that changes on every run
We can mock the Date()constructor!
var then = new Date();
jasmine.Clock.tick(42000);
var now = new Date();
expect(now.getTime() - then.getTime()).toBe(42000);
MOCKING DATE() WITH JASMINE
Keep Date() and setTimeout() in sync
jasmine.GlobalDate = window.Date;
var MockDate = function () {
var now = jasmine.Clock.defaultFakeTimer.nowMillis;
return new jasmine.GlobalDate(now);
};
MockDate.prototype = jasmine.GlobalDate.prototype;
window.Date = MockDate;
jasmine.getEnv().currentSpec.after(function () {
window.Date = jasmine.GlobalDate;
});
MOCKING AJAX REQUESTS
To test in isolation
To vastly speed up the tests
Many options
can.fixture
Mockjax
Sinon
can.fixture('/getNames', function (original, respondWith) {
respondWith({list: ['rachel', 'lakshmi']});
});
autoComplete = new AutoComplete('#name', {
listUrl: '/getNames'
});
jasmine.Clock.tick(can.fixture.delay);
respondWith(500); // Internal server error
DOM FIXTURES
Supply the markup required by the code
Automatically cleanup markup after every test
Various solutions
Built into QUnit as #qunit-fixture
Use jasmine-jquery
var fixtures = jasmine.getFixtures();
fixtures.set(fixtures.sandbox());
$('<input id="name">').appendTo('#sandbox');
autoComplete = new AutoComplete('#name');
SPYING ON EVENTS
How do we test that an event was triggered?
Or prevented from bubbling?
Use jasmine-jquery!
'keypress': function (element, event) {
var pattern = this.element.val() +
String.fromCharCode(event.charCode);
var match = this.getMatch(pattern);
if(match) {
event.preventDefault();
this.element.val(match);
}
}
keypressEvent = spyOnEvent('#name', 'keypress');
$('#name').trigger($.Event('keypress', {charCode: 109}));
expect(keypressEvent).toHaveBeenPrevented();
SIMULATING CSS TRANSITIONS
JASMINE MATCHERS
EXPRESSIVE MATCHERS
Make your tests more readable
Use jasmine-jquery for jQuery-specific matchers
Instead of:
Prefer:
expect($('#name').is(':visible')).toBeFalsy();
expect($('#name')).not.toBeVisible();
ROLL YOUR OWN MATCHERS
Make your tests even more readable
Like this can.js specific matcher:
Defined like this:
github.com/pivotal/jasmine/wiki/Matchers
expect($('#name')).toHaveControlOfType(AutoComplete);
jasmine.getEnv().currentSpec.addMatchers({
toHaveControlOfType: function (expected) {
var actual = this.actual.controls(expected);
return actual.length > 0;
}
});
STRUCTURE OF TEST CODE
Reuse common setup code
By nesting Jasmine's describe()functions
describe('delayHide', function () {
beforeEach(function () {
autoComplete.delayHide();
});
it('should initially stay visible', function () {
expect($('#name')).toBeVisible();
});
describe('after a delay', function () {
beforeEach(function () {
jasmine.Clock.tick(500);
});
it('should be invisible', function () {
expect($('#name')).not.toBeVisible();
});
});
});
BROWSER-SPECIFIC TESTS
Some code is browser specific
maybe using a browser specific API
and might only be testable in that browser
Tests can be conditioned
Or iterated...
can.each([
{
response: {list: ['rachel', 'lakshmi']},
expected: ['rachel', 'lakshmi']
},
{
response: 500,
expected: []
}
], function (scenario) {
describe('when ' + JSON.stringify(scenario.response), function () {
it('should ' + JSON.stringify(scenario.expected), function () {
});
});
});
RESOURCES
github.com/larsthorup/jasmine-demo-advanced
@larsthorup
pivotal.github.io/jasmine
github.com/velesin/jasmine-jquery
canjs.com
github.com/hakimel/reveal.js

Mais conteúdo relacionado

Mais procurados

Applet skelton58
Applet skelton58Applet skelton58
Applet skelton58
myrajendra
 
Rediscovering Spring with Spring Boot(1)
Rediscovering Spring with Spring Boot(1)Rediscovering Spring with Spring Boot(1)
Rediscovering Spring with Spring Boot(1)
Gunith Devasurendra
 

Mais procurados (20)

Applet skelton58
Applet skelton58Applet skelton58
Applet skelton58
 
Unit testing
Unit testingUnit testing
Unit testing
 
Core java
Core java Core java
Core java
 
C++ concept of Polymorphism
C++ concept of  PolymorphismC++ concept of  Polymorphism
C++ concept of Polymorphism
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Spock Framework
Spock FrameworkSpock Framework
Spock Framework
 
Rediscovering Spring with Spring Boot(1)
Rediscovering Spring with Spring Boot(1)Rediscovering Spring with Spring Boot(1)
Rediscovering Spring with Spring Boot(1)
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 
SOLID : les principes à l’origine du succès de Symfony et de vos applications
SOLID : les principes à l’origine du succès de Symfony et de vos applicationsSOLID : les principes à l’origine du succès de Symfony et de vos applications
SOLID : les principes à l’origine du succès de Symfony et de vos applications
 
Implementing a JavaScript Engine
Implementing a JavaScript EngineImplementing a JavaScript Engine
Implementing a JavaScript Engine
 
Test Data Builder Pattern
Test Data Builder PatternTest Data Builder Pattern
Test Data Builder Pattern
 
Array within a class
Array within a classArray within a class
Array within a class
 
Java script
Java scriptJava script
Java script
 
Java Tut1
Java Tut1Java Tut1
Java Tut1
 
WinAppDriver Development
WinAppDriver DevelopmentWinAppDriver Development
WinAppDriver Development
 
Core Java Tutorials by Mahika Tutorials
Core Java Tutorials by Mahika TutorialsCore Java Tutorials by Mahika Tutorials
Core Java Tutorials by Mahika Tutorials
 
Spring framework core
Spring framework coreSpring framework core
Spring framework core
 
Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新
Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新
Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新
 
Unit testing with JUnit
Unit testing with JUnitUnit testing with JUnit
Unit testing with JUnit
 
Top 10 reasons to migrate to Gradle
Top 10 reasons to migrate to GradleTop 10 reasons to migrate to Gradle
Top 10 reasons to migrate to Gradle
 

Semelhante a Advanced Jasmine - Front-End JavaScript Unit Testing

Unit testing JavaScript using Mocha and Node
Unit testing JavaScript using Mocha and NodeUnit testing JavaScript using Mocha and Node
Unit testing JavaScript using Mocha and Node
Josh Mock
 
In search of JavaScript code quality: unit testing
In search of JavaScript code quality: unit testingIn search of JavaScript code quality: unit testing
In search of JavaScript code quality: unit testing
Anna Khabibullina
 
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScriptThe Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
Hazelcast
 
An Introduction to AngularJs Unittesting
An Introduction to AngularJs UnittestingAn Introduction to AngularJs Unittesting
An Introduction to AngularJs Unittesting
Inthra onsap
 
JavaScript Proven Practises
JavaScript Proven PractisesJavaScript Proven Practises
JavaScript Proven Practises
Robert MacLean
 

Semelhante a Advanced Jasmine - Front-End JavaScript Unit Testing (20)

Jason code testing framework
Jason code testing frameworkJason code testing framework
Jason code testing framework
 
Unit testing JavaScript using Mocha and Node
Unit testing JavaScript using Mocha and NodeUnit testing JavaScript using Mocha and Node
Unit testing JavaScript using Mocha and Node
 
Unit testing with mocha
Unit testing with mochaUnit testing with mocha
Unit testing with mocha
 
Js fwdays unit tesing javascript(by Anna Khabibullina)
Js fwdays unit tesing javascript(by Anna Khabibullina)Js fwdays unit tesing javascript(by Anna Khabibullina)
Js fwdays unit tesing javascript(by Anna Khabibullina)
 
JS Frameworks Day April,26 of 2014
JS Frameworks Day April,26 of 2014JS Frameworks Day April,26 of 2014
JS Frameworks Day April,26 of 2014
 
In search of JavaScript code quality: unit testing
In search of JavaScript code quality: unit testingIn search of JavaScript code quality: unit testing
In search of JavaScript code quality: unit testing
 
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScriptThe Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
 
Testing JavaScript with Jasmine in Rails Applications
Testing JavaScript with Jasmine in Rails Applications Testing JavaScript with Jasmine in Rails Applications
Testing JavaScript with Jasmine in Rails Applications
 
Quick tour to front end unit testing using jasmine
Quick tour to front end unit testing using jasmineQuick tour to front end unit testing using jasmine
Quick tour to front end unit testing using jasmine
 
An Introduction to AngularJs Unittesting
An Introduction to AngularJs UnittestingAn Introduction to AngularJs Unittesting
An Introduction to AngularJs Unittesting
 
Testing JavaScript Applications
Testing JavaScript ApplicationsTesting JavaScript Applications
Testing JavaScript Applications
 
Testing Web Applications
Testing Web ApplicationsTesting Web Applications
Testing Web Applications
 
Agile Android
Agile AndroidAgile Android
Agile Android
 
JavaScript Proven Practises
JavaScript Proven PractisesJavaScript Proven Practises
JavaScript Proven Practises
 
Advanced Javascript Unit Testing
Advanced Javascript Unit TestingAdvanced Javascript Unit Testing
Advanced Javascript Unit Testing
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
 
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptjQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
 
JavaFX Overview
JavaFX OverviewJavaFX Overview
JavaFX Overview
 
JavaFX Pitfalls
JavaFX PitfallsJavaFX Pitfalls
JavaFX Pitfalls
 
Cappuccino @ JSConf 2009
Cappuccino @ JSConf 2009Cappuccino @ JSConf 2009
Cappuccino @ JSConf 2009
 

Mais de Lars Thorup

Javascript unit testing with QUnit and Sinon
Javascript unit testing with QUnit and SinonJavascript unit testing with QUnit and Sinon
Javascript unit testing with QUnit and Sinon
Lars Thorup
 

Mais de Lars Thorup (18)

100 tests per second - 40 releases per week
100 tests per second - 40 releases per week100 tests per second - 40 releases per week
100 tests per second - 40 releases per week
 
SQL or NoSQL - how to choose
SQL or NoSQL - how to chooseSQL or NoSQL - how to choose
SQL or NoSQL - how to choose
 
Super fast end-to-end-tests
Super fast end-to-end-testsSuper fast end-to-end-tests
Super fast end-to-end-tests
 
Extreme Programming - to the next-level
Extreme Programming - to the next-levelExtreme Programming - to the next-level
Extreme Programming - to the next-level
 
Unit testing legacy code
Unit testing legacy codeUnit testing legacy code
Unit testing legacy code
 
Advanced QUnit - Front-End JavaScript Unit Testing
Advanced QUnit - Front-End JavaScript Unit TestingAdvanced QUnit - Front-End JavaScript Unit Testing
Advanced QUnit - Front-End JavaScript Unit Testing
 
Put "fast" back in "fast feedback"
Put "fast" back in "fast feedback"Put "fast" back in "fast feedback"
Put "fast" back in "fast feedback"
 
Database Schema Evolution
Database Schema EvolutionDatabase Schema Evolution
Database Schema Evolution
 
Javascript unit testing with QUnit and Sinon
Javascript unit testing with QUnit and SinonJavascript unit testing with QUnit and Sinon
Javascript unit testing with QUnit and Sinon
 
Continuous Integration for front-end JavaScript
Continuous Integration for front-end JavaScriptContinuous Integration for front-end JavaScript
Continuous Integration for front-end JavaScript
 
Automated Performance Testing
Automated Performance TestingAutomated Performance Testing
Automated Performance Testing
 
Test and Behaviour Driven Development (TDD/BDD)
Test and Behaviour Driven Development (TDD/BDD)Test and Behaviour Driven Development (TDD/BDD)
Test and Behaviour Driven Development (TDD/BDD)
 
Agile Contracts
Agile ContractsAgile Contracts
Agile Contracts
 
High Performance Software Engineering Teams
High Performance Software Engineering TeamsHigh Performance Software Engineering Teams
High Performance Software Engineering Teams
 
Elephant Carpaccio
Elephant CarpaccioElephant Carpaccio
Elephant Carpaccio
 
Automated Testing for Embedded Software in C or C++
Automated Testing for Embedded Software in C or C++Automated Testing for Embedded Software in C or C++
Automated Testing for Embedded Software in C or C++
 
Unit Testing in JavaScript with MVC and QUnit
Unit Testing in JavaScript with MVC and QUnitUnit Testing in JavaScript with MVC and QUnit
Unit Testing in JavaScript with MVC and QUnit
 
Introduction to Automated Testing
Introduction to Automated TestingIntroduction to Automated Testing
Introduction to Automated Testing
 

Último

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Último (20)

GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 

Advanced Jasmine - Front-End JavaScript Unit Testing

  • 1. ADVANCED JASMINE FRONT-END JAVASCRIPT UNIT TESTING /Lars Thorup, ZeaLake @larsthorup
  • 2. WHO IS LARS THORUP Software developer/architect C++, C# and JavaScript Test Driven Development Coach: Teaching agile and automated testing Advisor: Assesses software projects and companies Founder and CEO of ZeaLake
  • 3. AGENDA Unit tests gives quality feedback Make them fast Make them precise Run thousands of unit tests in seconds We will look at Mocking techniques Front-end specific testing patterns Assuming knowledge about JavaScript and unit testing
  • 4. JASMINE BASICS describe('Calculator', function () { var calc; beforeEach(function () { calc = new Calculator(); }); it('should multiply', function () { expect(calc.multiply(6, 7)).toBe(42); }); });
  • 6. HOW TO TEST IN ISOLATION? We want to test code in isolation here the code is the 'keypress' event handler and isolation means not invoking the getMatch() method 'keypress': function (element, event) { var pattern = this.element.val(); pattern += String.fromCharCode(event.charCode); var match = this.getMatch(pattern); if (match) { event.preventDefault(); this.element.val(match); } }
  • 7. MOCKING METHODS We can mock the getMatch() method decide how the mock should behave verify that the mocked method was called correctly spyOn(autoComplete, 'getMatch').andReturn('monique'); $('#name').trigger($.Event('keypress', {charCode: 109})); expect(autoComplete.getMatch).toHaveBeenCalledWith('m'); expect($('#name')).toHaveValue('monique');
  • 8. MOCKING GLOBAL FUNCTIONS Global functions are properties of the window object openPopup: function (url) { var popup = window.open(url, '_blank', 'resizable'); popup.focus(); } var popup; spyOn(window, 'open').andCallFake(function () { popup = { focus: jasmine.createSpy() }; return popup; }); autoComplete.openPopup('zealake.com'); expect(window.open).toHaveBeenCalledWith('zealake.com', '_blank', 'resizable'); expect(popup.focus).toHaveBeenCalledWith();
  • 9. MOCKING CONSTRUCTORS Constructors are functions with thisbeing the object to construct this.input = new window.AutoComplete(inputElement, { listUrl: this.options.listUrl }); this.input.focus(); spyOn(window, 'AutoComplete').andCallFake(function () { this.focus = jasmine.createSpy(); }); expect(window.AutoComplete.callCount).toBe(1); var args = window.AutoComplete.mostRecentCall.args; expect(args[0]).toBe('#name'); expect(args[1]).toEqual({listUrl: '/someUrl'}); var object = window.AutoComplete.mostRecentCall.object; expect(object.focus).toHaveBeenCalledWith();
  • 10. HOW TO AVOID WAITING? We want the tests to be fast So don't use Jasmine waitsFor() But we often need to wait For animations to complete For AJAX responses to return delayHide: function () { var self = this; setTimeout(function () { self.element.hide(); }, this.options.hideDelay); }
  • 11. MOCKING TIMERS Use Jasmine's mock clock Control the clock explicitly Now the test completes in milliseconds without waiting jasmine.Clock.useMock(); autoComplete.delayHide(); expect($('#name')).toBeVisible(); jasmine.Clock.tick(500); expect($('#name')).not.toBeVisible();
  • 12. MOCKING TIME new Date()tends to return different values over time Actually, that's the whole point :) But how do we test code that does that? We cannot expecton a value that changes on every run We can mock the Date()constructor! var then = new Date(); jasmine.Clock.tick(42000); var now = new Date(); expect(now.getTime() - then.getTime()).toBe(42000);
  • 13. MOCKING DATE() WITH JASMINE Keep Date() and setTimeout() in sync jasmine.GlobalDate = window.Date; var MockDate = function () { var now = jasmine.Clock.defaultFakeTimer.nowMillis; return new jasmine.GlobalDate(now); }; MockDate.prototype = jasmine.GlobalDate.prototype; window.Date = MockDate; jasmine.getEnv().currentSpec.after(function () { window.Date = jasmine.GlobalDate; });
  • 14. MOCKING AJAX REQUESTS To test in isolation To vastly speed up the tests Many options can.fixture Mockjax Sinon can.fixture('/getNames', function (original, respondWith) { respondWith({list: ['rachel', 'lakshmi']}); }); autoComplete = new AutoComplete('#name', { listUrl: '/getNames' }); jasmine.Clock.tick(can.fixture.delay); respondWith(500); // Internal server error
  • 15. DOM FIXTURES Supply the markup required by the code Automatically cleanup markup after every test Various solutions Built into QUnit as #qunit-fixture Use jasmine-jquery var fixtures = jasmine.getFixtures(); fixtures.set(fixtures.sandbox()); $('<input id="name">').appendTo('#sandbox'); autoComplete = new AutoComplete('#name');
  • 16. SPYING ON EVENTS How do we test that an event was triggered? Or prevented from bubbling? Use jasmine-jquery! 'keypress': function (element, event) { var pattern = this.element.val() + String.fromCharCode(event.charCode); var match = this.getMatch(pattern); if(match) { event.preventDefault(); this.element.val(match); } } keypressEvent = spyOnEvent('#name', 'keypress'); $('#name').trigger($.Event('keypress', {charCode: 109})); expect(keypressEvent).toHaveBeenPrevented();
  • 19. EXPRESSIVE MATCHERS Make your tests more readable Use jasmine-jquery for jQuery-specific matchers Instead of: Prefer: expect($('#name').is(':visible')).toBeFalsy(); expect($('#name')).not.toBeVisible();
  • 20. ROLL YOUR OWN MATCHERS Make your tests even more readable Like this can.js specific matcher: Defined like this: github.com/pivotal/jasmine/wiki/Matchers expect($('#name')).toHaveControlOfType(AutoComplete); jasmine.getEnv().currentSpec.addMatchers({ toHaveControlOfType: function (expected) { var actual = this.actual.controls(expected); return actual.length > 0; } });
  • 21. STRUCTURE OF TEST CODE Reuse common setup code By nesting Jasmine's describe()functions describe('delayHide', function () { beforeEach(function () { autoComplete.delayHide(); }); it('should initially stay visible', function () { expect($('#name')).toBeVisible(); }); describe('after a delay', function () { beforeEach(function () { jasmine.Clock.tick(500); }); it('should be invisible', function () { expect($('#name')).not.toBeVisible(); }); }); });
  • 22. BROWSER-SPECIFIC TESTS Some code is browser specific maybe using a browser specific API and might only be testable in that browser Tests can be conditioned Or iterated... can.each([ { response: {list: ['rachel', 'lakshmi']}, expected: ['rachel', 'lakshmi'] }, { response: 500, expected: [] } ], function (scenario) { describe('when ' + JSON.stringify(scenario.response), function () { it('should ' + JSON.stringify(scenario.expected), function () { }); }); });