SlideShare a Scribd company logo
1 of 38
Download to read offline
Testing JavaScript
          LIKE A BOSS
                       Jo Cranford
                       @jocranford




Thursday, 19 July 12
Y U NO JAVASCRIPT
                            TESTS?



Thursday, 19 July 12
BDD With Jasmine Is
                         Awesome Sauce

         describe("Score Calculation Behaviour", function() {

             it("should score 0 when no pins are knocked down", function() {

                       var game = new BowlingGame(10);
                       game.roll(0);

                       expect(game.score()).toBe(0);

             });

   });




Thursday, 19 July 12
Is JavaScript Ever Really
                   That Simple?



Thursday, 19 July 12
What About ...

    •   Asynchronous goodness

    •   Interacting with teh DOMz

    •   Evil Legacy Code

    •   Continuous Integration

    •   Clean readable tests that reflect your domain


Thursday, 19 July 12
Approaches To Testing
                        Asynchronous Code




Thursday, 19 July 12
Let’s Load Some JSON

                       [
                           {
                                "firstName": "Jo",
                                "lastName": "Cranford",
                                "company": "Atlassian"
                           },
                           {
                                "firstName": "Rachel",
                                "lastName": "Laycock",
                                "company": "ThoughtWorks"
                           }
                 ]




Thursday, 19 July 12
The JavaScript Code

                       var Presentation = function() {
                         this.presenters = [];
                 };

                 Presentation.prototype.loadPresenters = function() {
                     var presenters = this.presenters;

                        $.getJSON("people.json", function(data) {
                            $.each(data, function(idx, person) {
                                presenters.push(person);
                            });
                        });
                 };




Thursday, 19 July 12
Easy, Right?

           describe("How not to test an asynchronous function", function
           () {

               it("should load the presenters", function () {

                       var presentation = new Presentation();
                       presentation.loadPresenters();

                       expect(presentation.presenters.length).toBe(2);

               });
    });




Thursday, 19 July 12
Well ... Not So Much.




Thursday, 19 July 12
But This Might Work ...

           describe("Still not ideal though", function () {

              it("should load the presenters", function () {

                       spyOn($, "getJSON").andCallFake(function (url, callback) {
                           callback([{},{}]);
                       })

                       var presentation = new Presentation();
                       presentation.loadPresenters();

                       expect(presentation.presenters.length).toBe(2);

              });
     });



Thursday, 19 July 12
A Little Detour ...




Thursday, 19 July 12
Spy On An Existing Method

           it("can spy on an existing method", function() {

               var fakeElement = $("<div style='display:none'></div>");
               spyOn(fakeElement, 'show');

               var toggleable = new Toggleable(fakeElement);

               toggleable.toggle();

               expect(fakeElement.show).toHaveBeenCalled();

     });




Thursday, 19 July 12
Spy On An Existing Method

           it("can create a method for you", function() {

               var fakeElement = {};
               fakeElement.css = function() {};
               fakeElement.show = jasmine.createSpy("Show spy");

               var toggleable = new Toggleable(fakeElement);

               toggleable.toggle();

               expect(fakeElement.show).toHaveBeenCalled();

     });




Thursday, 19 July 12
Wait, There’s More ...


    •   expect(spy).not.toHaveBeenCalled()

    •   createSpy().andReturn(something)

    •   createSpy().andCallFake(function() {})

    •   createSpy().andCallThrough()



Thursday, 19 July 12
Spy On The Details

    •   expect(spy).toHaveBeenCalled()

    •   expect(spy.callCount).toBe(x)

    •   expect(spy).toHaveBeenCalledWith()

         •   Tip: use jasmine.any(Function/Object) for parameters
             you don’t care about


Thursday, 19 July 12
... And We’re Back.


                       Sooooo ... spies are great and all,
                       but what if your callback function
                            takes a while to run?




Thursday, 19 July 12
Don’t Do This At Home.

           Presentation.prototype.loadPresentersMoreSlowly = function() {

               var preso = this;

               $.getJSON("people.json", function(data) {
                   setTimeout(function() {
                       $.each(data, function(idx, person) {
                           preso.presenters.push(person);
                       });
                   }, 2000);
               });

     };



Thursday, 19 July 12
Don’t Do This, Either.
           it("should have loaded after three seconds, right?", function()
           {

               spyOn($, "getJSON").andCallFake(function(url, callback)   {
                   callback([{}, {}]);
               })

               var presentation = new Presentation();
               presentation.loadPresentersMoreSlowly();

               setTimeout(function() {
                   expect(presentation.presenters.length).toBe(2);
               }, 3000);

     });




Thursday, 19 July 12
But What If I Just ...

           Presentation.prototype.loadPresentersMoreSlowly = function() {

               var preso = this;

               $.getJSON("people.json", function(data) {
                   setTimeout(function() {
                       $.each(data, function(idx, person) {
                           preso.presenters.push(person);
                       });
                       preso.presentersHaveLoaded = true;
                   }, 2000);
               });

     };



Thursday, 19 July 12
Now Wait, Wait ... RUN!
                 it("should load the presenters", function() {

                       spyOn($, "getJSON").andCallFake(function(url, callback) {
                           callback([{}, {}]);
                       })

                       var presentation = new Presentation();
                       presentation.loadPresentersMoreSlowly();

                       waitsFor(function() {
                           return presentation.presentersHaveLoaded;
                       }, "presenters have loaded");

                       runs(function() {
                           expect(presentation.presenters.length).toBe(2);
                       });

           });

Thursday, 19 July 12
Testing Interaction With The
                    DOM

    •   Do you REALLY need to?

    •   Tests will have a high maintenance cost

    •   Instead separate logic from view and test logic

    •   Use templates for the view



Thursday, 19 July 12
Testing Interaction With The
                  DOM
            it("should display the score", function() {

                setFixtures("<div id='score'></div>");

                var bowlingGameView = new BowlingGameView();
                bowlingGameView.showScore(100);

                expect($("#score").text()).toBe("Your current score is 100");

      });




                       https://github.com/velesin/jasmine-jquery
Thursday, 19 July 12
Legacy (untested)
                        JavaScript Code
    •   Long methods

    •   Violation of Single Responsibility Principle

    •   Side effects

    •   Lack of dependency injection

    •   Lots of new X()

    •   Unclear intentions

Thursday, 19 July 12
Testing Interaction

          it("should call the method on the dependency", function() {

                       var dependency = {};
                       dependency.method = jasmine.createSpy();

                       var myObject = new Something(dependency);
                       myObject.doSomething();

                       expect(dependency.method).toHaveBeenCalled();
          });




Thursday, 19 July 12
If Dependencies Aren’t
                             Injected ...

          var LegacySomething = function() {

                       this.doSomething = function() {
                           var dependency = new Dependency();
                           dependency.method();
                       };

          };




Thursday, 19 July 12
Create Stubs

          it("is a pain but not impossible", function() {

                       Dependency = function() {};
                       Dependency.prototype.method = jasmine.createSpy()

                       var myObject = new LegacySomething();
                       myObject.doSomething();

                       expect(Dependency.prototype.method).toHaveBeenCalled();
          });




Thursday, 19 July 12
Continuous Integration


    •   Ruby Gem

    •   Maven

    •   Node.js

    •   Rhino (Java)



Thursday, 19 July 12
Ruby Gem
                        require 'jasmine'
                        load 'jasmine/tasks/jasmine.rake'




                              > rake jasmine:ci




                       https://github.com/pivotal/jasmine-gem
Thursday, 19 July 12
Maven


                               > mvn clean test




               http://searls.github.com/jasmine-maven-plugin/
Thursday, 19 July 12
Node.js


                             > jasmine-node specs/




                       https://github.com/mhevery/jasmine-node
Thursday, 19 July 12
Rhino

    •   Download:

         •   Rhino (js.jar) from Mozilla

         •   env.rhino.js from www.envjs.com

         •   Jasmine console reporter from Larry Myers Jasmine
             Reporters project (github)



                 http://www.build-doctor.com/2010/12/08/javascript-bdd-jasmine/
Thursday, 19 July 12
Rhino
                 load('env.rhino.1.2.js');

           Envjs.scriptTypes['text/javascript'] = true;

           var specFile;

           for (i = 0; i < arguments.length; i++) {
               specFile = arguments[i];

                       console.log("Loading: " + specFile);

                       window.location = specFile
           }



          > java -jar js.jar -opt -1 env.bootstrap.js ../SpecRunner.html



Thursday, 19 July 12
Extending Jasmine With
                    Custom Matchers
               it("should match the latitude and longitude", function() {

                   var pointOnMap = { latitude: "51.23", longitude: "-10.14" };

                   expect(pointOnMap.latitude).toBe("51.23");
                   expect(pointOnMap.longitude).toBe("-10.14");

         });

         it("should match the latitude and longitude", function() {

                   var pointOnMap = { latitude: "51.23", longitude: "-10.14" };

                   expect(pointOnMap).toHaveLatitude("51.23");
                   expect(pointOnMap).toHaveLongitude("-10.14");

         });


Thursday, 19 July 12
Extending Jasmine With
                    Custom Matchers

         it("should match the latitude and longitude", function() {

             var pointOnMap = { latitude: "51.23", longitude: "-10.14" };

             expect(pointOnMap).toHaveLatLongCoordinates("51.23", "-10.14");

   });




Thursday, 19 July 12
Extending Jasmine With
                    Custom Matchers

   beforeEach(function() {
       this.addMatchers({
           toHaveLatitude: function(lat) {
               return this.actual.latitude === lat;
           },
           toHaveLongitude: function(lat) {
               return this.actual.latitude === lat;
           },
           toHaveLatLongCoordinates: function(lat, lng) {
               return (this.actual.latitude === lat &&
                  this.actual.longitude === lng);
           }
       });
   });


Thursday, 19 July 12
Custom Failure Messages


          toHaveLatitude: function(lat) {
              this.message = function() {
                  return "Expected Latitude " + this.actual.latitude
                    + " to be " + lat;
              };
              return this.actual.latitude === lat;
          }




Thursday, 19 July 12
Thursday, 19 July 12

More Related Content

What's hot

Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friendThe Software House
 
NetBeans Plugin Development: JRebel Experience Report
NetBeans Plugin Development: JRebel Experience ReportNetBeans Plugin Development: JRebel Experience Report
NetBeans Plugin Development: JRebel Experience ReportAnton Arhipov
 
Google Guava - Core libraries for Java & Android
Google Guava - Core libraries for Java & AndroidGoogle Guava - Core libraries for Java & Android
Google Guava - Core libraries for Java & AndroidJordi Gerona
 
CodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodecamp Romania
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserHoward Lewis Ship
 
jQuery Data Manipulate API - A source code dissecting journey
jQuery Data Manipulate API - A source code dissecting journeyjQuery Data Manipulate API - A source code dissecting journey
jQuery Data Manipulate API - A source code dissecting journeyHuiyi Yan
 
OSDC.fr 2012 :: Cascalog : progammation logique pour Hadoop
OSDC.fr 2012 :: Cascalog : progammation logique pour HadoopOSDC.fr 2012 :: Cascalog : progammation logique pour Hadoop
OSDC.fr 2012 :: Cascalog : progammation logique pour HadoopPublicis Sapient Engineering
 
Clean code with google guava jee conf
Clean code with google guava jee confClean code with google guava jee conf
Clean code with google guava jee confIgor Anishchenko
 
Arquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackArquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackNelson Glauber Leal
 
History of jQuery
History of jQueryHistory of jQuery
History of jQueryjeresig
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KThomas Fuchs
 
JavaScript & HTML5 - Brave New World
JavaScript & HTML5 - Brave New WorldJavaScript & HTML5 - Brave New World
JavaScript & HTML5 - Brave New WorldRobert Nyman
 
Object oriented javascript
Object oriented javascriptObject oriented javascript
Object oriented javascriptShah Jalal
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScriptMichael Girouard
 
Google guava overview
Google guava overviewGoogle guava overview
Google guava overviewSteve Min
 

What's hot (20)

Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friend
 
NetBeans Plugin Development: JRebel Experience Report
NetBeans Plugin Development: JRebel Experience ReportNetBeans Plugin Development: JRebel Experience Report
NetBeans Plugin Development: JRebel Experience Report
 
Google Guava - Core libraries for Java & Android
Google Guava - Core libraries for Java & AndroidGoogle Guava - Core libraries for Java & Android
Google Guava - Core libraries for Java & Android
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
 
CodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical Groovy
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The Browser
 
jQuery Data Manipulate API - A source code dissecting journey
jQuery Data Manipulate API - A source code dissecting journeyjQuery Data Manipulate API - A source code dissecting journey
jQuery Data Manipulate API - A source code dissecting journey
 
OSDC.fr 2012 :: Cascalog : progammation logique pour Hadoop
OSDC.fr 2012 :: Cascalog : progammation logique pour HadoopOSDC.fr 2012 :: Cascalog : progammation logique pour Hadoop
OSDC.fr 2012 :: Cascalog : progammation logique pour Hadoop
 
Clean code with google guava jee conf
Clean code with google guava jee confClean code with google guava jee conf
Clean code with google guava jee conf
 
Arquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackArquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com Jetpack
 
History of jQuery
History of jQueryHistory of jQuery
History of jQuery
 
Google guava
Google guavaGoogle guava
Google guava
 
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2KZepto.js, a jQuery-compatible mobile JavaScript framework in 2K
Zepto.js, a jQuery-compatible mobile JavaScript framework in 2K
 
JavaScript & HTML5 - Brave New World
JavaScript & HTML5 - Brave New WorldJavaScript & HTML5 - Brave New World
JavaScript & HTML5 - Brave New World
 
BVJS
BVJSBVJS
BVJS
 
Easy Button
Easy ButtonEasy Button
Easy Button
 
Google Guava
Google GuavaGoogle Guava
Google Guava
 
Object oriented javascript
Object oriented javascriptObject oriented javascript
Object oriented javascript
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScript
 
Google guava overview
Google guava overviewGoogle guava overview
Google guava overview
 

Similar to Testing javascriptwithjasmine sydjs

Understanding JavaScript
Understanding JavaScriptUnderstanding JavaScript
Understanding JavaScriptnodejsbcn
 
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 JavaScriptGuy Royse
 
Integrate Spring MVC with RequireJS & Backbone.js & Spring Data JPA
Integrate Spring MVC with RequireJS & Backbone.js & Spring Data JPAIntegrate Spring MVC with RequireJS & Backbone.js & Spring Data JPA
Integrate Spring MVC with RequireJS & Backbone.js & Spring Data JPACheng Ta Yeh
 
Declarative web data visualization using ClojureScript
Declarative web data visualization using ClojureScriptDeclarative web data visualization using ClojureScript
Declarative web data visualization using ClojureScriptOSCON Byrum
 
The next step, part 2
The next step, part 2The next step, part 2
The next step, part 2Pat Cavit
 
mDevCamp - The Best from Google IO
mDevCamp - The Best from Google IOmDevCamp - The Best from Google IO
mDevCamp - The Best from Google IOondraz
 
Organizing Code with JavascriptMVC
Organizing Code with JavascriptMVCOrganizing Code with JavascriptMVC
Organizing Code with JavascriptMVCThomas Reynolds
 
SfCon: Test Driven Development
SfCon: Test Driven DevelopmentSfCon: Test Driven Development
SfCon: Test Driven DevelopmentAugusto Pascutti
 
Get started with YUI
Get started with YUIGet started with YUI
Get started with YUIAdam Lu
 
06 jQuery #burningkeyboards
06 jQuery  #burningkeyboards06 jQuery  #burningkeyboards
06 jQuery #burningkeyboardsDenis Ristic
 
Student management system
Student management systemStudent management system
Student management systemgeetika goyal
 
DOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQueryDOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQueryRemy Sharp
 
Jasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishyJasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishyIgor Napierala
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testingVisual Engineering
 
Ian 20150116 java script oop
Ian 20150116 java script oopIan 20150116 java script oop
Ian 20150116 java script oopLearningTech
 

Similar to Testing javascriptwithjasmine sydjs (20)

Understanding JavaScript
Understanding JavaScriptUnderstanding JavaScript
Understanding JavaScript
 
Js in the open
Js in the openJs in the open
Js in the open
 
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
 
Integrate Spring MVC with RequireJS & Backbone.js & Spring Data JPA
Integrate Spring MVC with RequireJS & Backbone.js & Spring Data JPAIntegrate Spring MVC with RequireJS & Backbone.js & Spring Data JPA
Integrate Spring MVC with RequireJS & Backbone.js & Spring Data JPA
 
Declarative web data visualization using ClojureScript
Declarative web data visualization using ClojureScriptDeclarative web data visualization using ClojureScript
Declarative web data visualization using ClojureScript
 
The next step, part 2
The next step, part 2The next step, part 2
The next step, part 2
 
mDevCamp - The Best from Google IO
mDevCamp - The Best from Google IOmDevCamp - The Best from Google IO
mDevCamp - The Best from Google IO
 
Sane Async Patterns
Sane Async PatternsSane Async Patterns
Sane Async Patterns
 
Organizing Code with JavascriptMVC
Organizing Code with JavascriptMVCOrganizing Code with JavascriptMVC
Organizing Code with JavascriptMVC
 
SfCon: Test Driven Development
SfCon: Test Driven DevelopmentSfCon: Test Driven Development
SfCon: Test Driven Development
 
Introduction to jQuery
Introduction to jQueryIntroduction to jQuery
Introduction to jQuery
 
Get started with YUI
Get started with YUIGet started with YUI
Get started with YUI
 
Introduccion a Jasmin
Introduccion a JasminIntroduccion a Jasmin
Introduccion a Jasmin
 
06 jQuery #burningkeyboards
06 jQuery  #burningkeyboards06 jQuery  #burningkeyboards
06 jQuery #burningkeyboards
 
Student management system
Student management systemStudent management system
Student management system
 
DOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQueryDOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQuery
 
662305 11
662305 11662305 11
662305 11
 
Jasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishyJasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishy
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testing
 
Ian 20150116 java script oop
Ian 20150116 java script oopIan 20150116 java script oop
Ian 20150116 java script oop
 

Recently uploaded

Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
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 DiscoveryTrustArc
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
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.pdfhans926745
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
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 WorkerThousandEyes
 
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 2024The Digital Insurer
 
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 Scriptwesley chun
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
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.pdfUK Journal
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
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...apidays
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 

Recently uploaded (20)

Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
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
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
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
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
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
 
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
 
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
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
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
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
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...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 

Testing javascriptwithjasmine sydjs

  • 1. Testing JavaScript LIKE A BOSS Jo Cranford @jocranford Thursday, 19 July 12
  • 2. Y U NO JAVASCRIPT TESTS? Thursday, 19 July 12
  • 3. BDD With Jasmine Is Awesome Sauce describe("Score Calculation Behaviour", function() { it("should score 0 when no pins are knocked down", function() { var game = new BowlingGame(10); game.roll(0); expect(game.score()).toBe(0); }); }); Thursday, 19 July 12
  • 4. Is JavaScript Ever Really That Simple? Thursday, 19 July 12
  • 5. What About ... • Asynchronous goodness • Interacting with teh DOMz • Evil Legacy Code • Continuous Integration • Clean readable tests that reflect your domain Thursday, 19 July 12
  • 6. Approaches To Testing Asynchronous Code Thursday, 19 July 12
  • 7. Let’s Load Some JSON [ { "firstName": "Jo", "lastName": "Cranford", "company": "Atlassian" }, { "firstName": "Rachel", "lastName": "Laycock", "company": "ThoughtWorks" } ] Thursday, 19 July 12
  • 8. The JavaScript Code var Presentation = function() { this.presenters = []; }; Presentation.prototype.loadPresenters = function() { var presenters = this.presenters; $.getJSON("people.json", function(data) { $.each(data, function(idx, person) { presenters.push(person); }); }); }; Thursday, 19 July 12
  • 9. Easy, Right? describe("How not to test an asynchronous function", function () { it("should load the presenters", function () { var presentation = new Presentation(); presentation.loadPresenters(); expect(presentation.presenters.length).toBe(2); }); }); Thursday, 19 July 12
  • 10. Well ... Not So Much. Thursday, 19 July 12
  • 11. But This Might Work ... describe("Still not ideal though", function () { it("should load the presenters", function () { spyOn($, "getJSON").andCallFake(function (url, callback) { callback([{},{}]); }) var presentation = new Presentation(); presentation.loadPresenters(); expect(presentation.presenters.length).toBe(2); }); }); Thursday, 19 July 12
  • 12. A Little Detour ... Thursday, 19 July 12
  • 13. Spy On An Existing Method it("can spy on an existing method", function() { var fakeElement = $("<div style='display:none'></div>"); spyOn(fakeElement, 'show'); var toggleable = new Toggleable(fakeElement); toggleable.toggle(); expect(fakeElement.show).toHaveBeenCalled(); }); Thursday, 19 July 12
  • 14. Spy On An Existing Method it("can create a method for you", function() { var fakeElement = {}; fakeElement.css = function() {}; fakeElement.show = jasmine.createSpy("Show spy"); var toggleable = new Toggleable(fakeElement); toggleable.toggle(); expect(fakeElement.show).toHaveBeenCalled(); }); Thursday, 19 July 12
  • 15. Wait, There’s More ... • expect(spy).not.toHaveBeenCalled() • createSpy().andReturn(something) • createSpy().andCallFake(function() {}) • createSpy().andCallThrough() Thursday, 19 July 12
  • 16. Spy On The Details • expect(spy).toHaveBeenCalled() • expect(spy.callCount).toBe(x) • expect(spy).toHaveBeenCalledWith() • Tip: use jasmine.any(Function/Object) for parameters you don’t care about Thursday, 19 July 12
  • 17. ... And We’re Back. Sooooo ... spies are great and all, but what if your callback function takes a while to run? Thursday, 19 July 12
  • 18. Don’t Do This At Home. Presentation.prototype.loadPresentersMoreSlowly = function() { var preso = this; $.getJSON("people.json", function(data) { setTimeout(function() { $.each(data, function(idx, person) { preso.presenters.push(person); }); }, 2000); }); }; Thursday, 19 July 12
  • 19. Don’t Do This, Either. it("should have loaded after three seconds, right?", function() { spyOn($, "getJSON").andCallFake(function(url, callback) { callback([{}, {}]); }) var presentation = new Presentation(); presentation.loadPresentersMoreSlowly(); setTimeout(function() { expect(presentation.presenters.length).toBe(2); }, 3000); }); Thursday, 19 July 12
  • 20. But What If I Just ... Presentation.prototype.loadPresentersMoreSlowly = function() { var preso = this; $.getJSON("people.json", function(data) { setTimeout(function() { $.each(data, function(idx, person) { preso.presenters.push(person); }); preso.presentersHaveLoaded = true; }, 2000); }); }; Thursday, 19 July 12
  • 21. Now Wait, Wait ... RUN! it("should load the presenters", function() { spyOn($, "getJSON").andCallFake(function(url, callback) { callback([{}, {}]); }) var presentation = new Presentation(); presentation.loadPresentersMoreSlowly(); waitsFor(function() { return presentation.presentersHaveLoaded; }, "presenters have loaded"); runs(function() { expect(presentation.presenters.length).toBe(2); }); }); Thursday, 19 July 12
  • 22. Testing Interaction With The DOM • Do you REALLY need to? • Tests will have a high maintenance cost • Instead separate logic from view and test logic • Use templates for the view Thursday, 19 July 12
  • 23. Testing Interaction With The DOM it("should display the score", function() { setFixtures("<div id='score'></div>"); var bowlingGameView = new BowlingGameView(); bowlingGameView.showScore(100); expect($("#score").text()).toBe("Your current score is 100"); }); https://github.com/velesin/jasmine-jquery Thursday, 19 July 12
  • 24. Legacy (untested) JavaScript Code • Long methods • Violation of Single Responsibility Principle • Side effects • Lack of dependency injection • Lots of new X() • Unclear intentions Thursday, 19 July 12
  • 25. Testing Interaction it("should call the method on the dependency", function() { var dependency = {}; dependency.method = jasmine.createSpy(); var myObject = new Something(dependency); myObject.doSomething(); expect(dependency.method).toHaveBeenCalled(); }); Thursday, 19 July 12
  • 26. If Dependencies Aren’t Injected ... var LegacySomething = function() { this.doSomething = function() { var dependency = new Dependency(); dependency.method(); }; }; Thursday, 19 July 12
  • 27. Create Stubs it("is a pain but not impossible", function() { Dependency = function() {}; Dependency.prototype.method = jasmine.createSpy() var myObject = new LegacySomething(); myObject.doSomething(); expect(Dependency.prototype.method).toHaveBeenCalled(); }); Thursday, 19 July 12
  • 28. Continuous Integration • Ruby Gem • Maven • Node.js • Rhino (Java) Thursday, 19 July 12
  • 29. Ruby Gem require 'jasmine' load 'jasmine/tasks/jasmine.rake' > rake jasmine:ci https://github.com/pivotal/jasmine-gem Thursday, 19 July 12
  • 30. Maven > mvn clean test http://searls.github.com/jasmine-maven-plugin/ Thursday, 19 July 12
  • 31. Node.js > jasmine-node specs/ https://github.com/mhevery/jasmine-node Thursday, 19 July 12
  • 32. Rhino • Download: • Rhino (js.jar) from Mozilla • env.rhino.js from www.envjs.com • Jasmine console reporter from Larry Myers Jasmine Reporters project (github) http://www.build-doctor.com/2010/12/08/javascript-bdd-jasmine/ Thursday, 19 July 12
  • 33. Rhino load('env.rhino.1.2.js'); Envjs.scriptTypes['text/javascript'] = true; var specFile; for (i = 0; i < arguments.length; i++) { specFile = arguments[i]; console.log("Loading: " + specFile); window.location = specFile } > java -jar js.jar -opt -1 env.bootstrap.js ../SpecRunner.html Thursday, 19 July 12
  • 34. Extending Jasmine With Custom Matchers it("should match the latitude and longitude", function() { var pointOnMap = { latitude: "51.23", longitude: "-10.14" }; expect(pointOnMap.latitude).toBe("51.23"); expect(pointOnMap.longitude).toBe("-10.14"); }); it("should match the latitude and longitude", function() { var pointOnMap = { latitude: "51.23", longitude: "-10.14" }; expect(pointOnMap).toHaveLatitude("51.23"); expect(pointOnMap).toHaveLongitude("-10.14"); }); Thursday, 19 July 12
  • 35. Extending Jasmine With Custom Matchers it("should match the latitude and longitude", function() { var pointOnMap = { latitude: "51.23", longitude: "-10.14" }; expect(pointOnMap).toHaveLatLongCoordinates("51.23", "-10.14"); }); Thursday, 19 July 12
  • 36. Extending Jasmine With Custom Matchers beforeEach(function() { this.addMatchers({ toHaveLatitude: function(lat) { return this.actual.latitude === lat; }, toHaveLongitude: function(lat) { return this.actual.latitude === lat; }, toHaveLatLongCoordinates: function(lat, lng) { return (this.actual.latitude === lat && this.actual.longitude === lng); } }); }); Thursday, 19 July 12
  • 37. Custom Failure Messages toHaveLatitude: function(lat) { this.message = function() { return "Expected Latitude " + this.actual.latitude + " to be " + lat; }; return this.actual.latitude === lat; } Thursday, 19 July 12