Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Testing Javascript with Jasmine

Testing Javascript with Jasmine

A talk I gave a an AustinJS meeting and also Lone Star Ruby Conf 2011 *** Video here: http://confreaks.com/videos/2531-lsrc2011-testing-javascript-with-jasmine ***

Tim Tyrrell

May 16, 2012
Tweet

More Decks by Tim Tyrrell

Other Decks in Programming

Transcript

  1. Agenda - Briefly cover why you should unit test -

    Discuss what Jasmine is and isn't - Show syntax with comparisons to RSpec - Jasmine with: - Vanilla JavaScript - Jasmine with jQuery - Jasmine with Ruby (not Rails) - Jasmine with Rails - Evergreen - capybara-webkit - Where does CoffeeScript, node.js, etc. fit in? - Other helpful libraries/Wrap-up
  2. "There is only one way to go truly fast. Do

    the best job you can. Anything else is slower." @unclebobmartin http://twitter.com/#!/unclebobmartin/status/39438225869254656
  3. RSpec vs. Jasmine: Structure #RSpec describe "Calculate" do describe "#add"

    do it "should return the sum" do ... end end end //Jasmine describe "Calculate", function(){ describe "#Add", function(){ it "should return the sum", function(){ ... }; }); });
  4. RSpec vs. Jasmine: Before/After #RSpec before(:each) do @calc = Calculator.new

    end after(:each) do @calc.reset end //Jasmine var calc; beforeEach(function() { calc = new Calculator(); }); afterEach(function() { calc.reset(); });
  5. RSpec vs. Jasmine: Expectations # RSpec it "should return the

    sum" do calc = Calculator.new calc.add(1,1).should == 2 calc.add(1,2).should_not == 2 #Use one expectation per 'it'! end // Jasmine it("should return the sum", function() { var calc = new Calculator(); expect(calc.Add(1,1)).toEqual(2); expect(calc.Add(1,2)).not.toEqual(2); //Use one expectation per 'it'! });
  6. Custom Matchers #RSpec Spec::Matchers.define :be_greater_than_zero do match do |actual| actual

    > 0 end end Spec::Matchers.define :be_zero_when_subtracting do match do |actual, number| (actual - number) == 0 end end
  7. Custom Matchers // Jasmine beforeEach(function() { this.addMatchers({ toBeGreaterThanZero: function() {

    return this.actual > 0; } }), this.addMatchers({ toBeZeroWhenSubtracting: function(number) { return (this.actual - number) === 0 } }) });
  8. Custom Matchers describe('Custom Matchers', function () { it('should be greater

    than 0', function () { expect(1).toBeGreaterThanZero(); }); it('should equal zero when subtracting two numbers', function() { expect(5).toBeZeroWhenSubtracting(5); }); });
  9. RSpec vs. Jasmine: Stubbing # RSpec it "should add the

    numbers" do calc = Calculator.new calc.stub!(:add).and_return(3) calc.add(1,1).should == 3 end // Jasmine it("should add the numbers", function() { var calc = new Calculator(); spyOn(calc, 'add').andReturn(3); expect(calc.Add(1,1)).toEqual(3); });
  10. describe("Calculator", function() { var calc; beforeEach(function(){ calc = new Calculator();

    }); it("should return the sum", function() { expect(calc.Add(1,1)).toEqual(2); }); }); Spec for Calculator:
  11. * toBe(jQuerySelector) * toBeChecked() * toBeEmpty() * toBeHidden() * toBeSelected()

    * toBeVisible() * toContain(jQuerySelector) * toExist() * toHaveAttr(attributeName, attributeValue) * toHaveBeenTriggeredOn(selector) * toHaveClass(className) * toHaveData(key, value) * toHaveHtml(string) * toHaveId(id) * toHaveText(string) * toHaveValue(value) * toBeDisabled() jasmine-jquery Matchers
  12. Lettering.js results <h1 class="fancy_title"> <span class="char1">S</span> <span class="char2">o</span> <span class="char3">m</span>

    <span class="char4">e</span> <span class="char5"></span> <span class="char6">T</span> <span class="char7">i</span> <span class="char8">t</span> <span class="char9">l</span> <span class="char10">e</span> </h1>
  13. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head>

    <title>Jasmine Test Runner</title> <link rel="stylesheet" type="text/css" href="lib/jasmine-1.0.2/jasmine.css"> <script type="text/javascript" src="lib/jasmine-1.0.2/jasmine.js"></script> <script type="text/javascript" src="lib/jasmine-1.0.2/jasmine-html.js"></script> <script type="text/javascript" src="lib/jquery-1.6.1.min.js"></script> <script type="text/javascript" src="lib/jasmine-jquery-1.2.0.js"></script> <script type="text/javascript" src="lib/jquery.lettering-0.6.1.min.js"></script> <script type="text/javascript" src="spec/LetteringSpec.js"></script> </head> <body> <script type="text/javascript"> jasmine.getEnv().addReporter(new jasmine.TrivialReporter()); jasmine.getEnv().execute(); </script> </body> </html>
  14. describe("Lettering", function(){ beforeEach(function(){ //loadFixtures('myfixture.html'); setFixtures('<h1 class="fancy_title">Some Title</h1>'); $('.fancy_title').lettering(); }); it("should

    be visible", function() { expect($('.fancy_title')).toBeVisible(); }); it("should have 10 spans", function(){ expect($('.fancy_title > span').length).toEqual(10); }); });
  15. describe("Lettering", function(){ beforeEach(function(){ //loadFixtures('myfixture.html'); setFixtures('<h1 class="fancy_title">Some Title</h1>'); $('.fancy_title').lettering(); }); it("should

    be visible", function() { expect($('.fancy_title')).toBeVisible(); }); it("should have 10 spans", function(){ expect($('.fancy_title > span').length).toEqual(10); }); it("should contain 'S' as the text of the first span", function(){ expect($('.fancy_title > span:first').text()).toEqual('S'); }); });
  16. describe("Lettering", function(){ beforeEach(function(){ //loadFixtures('myfixture.html'); setFixtures('<h1 class="fancy_title">Some Title</h1>'); $('.fancy_title').lettering(); }); it("should

    be visible", function() { expect($('.fancy_title')).toBeVisible(); }); it("should have 10 spans", function(){ expect($('.fancy_title > span').length).toEqual(10); }); it("should contain 'S' as the text of the first span", function(){ expect($('.fancy_title > span:first').text()).toEqual('S'); }); it("should have a class of 'char1' on the first span", function(){ expect($('.fancy_title > span:first')).toHaveClass('char1'); }); });
  17. Jasmine with Rails gem "jasmine" $ bundle install $ jasmine

    init (optional) $ rake jasmine or $ rake jasmine:ci http://localhost:8888
  18. Installing CoffeeScript brew install node.js (then add to PATH, NODE_PATH)

    curl http://npmjs.org/install.sh | sh npm install -g coffee-script
  19. require('/calculator.js') describe 'Calculator', -> beforeEach -> @calc = new Calculator

    it 'should return the sum', -> expect(@calc.Add(1,1)).toEqual(2)
  20. require('/calculator.js') describe 'Calculator', -> beforeEach -> @calc = new Calculator

    it 'should return the sum', -> expect(@calc.Add(1,1)).toEqual(2)
  21. require('/calculator.js') describe 'Calculator', -> beforeEach -> @calc = new Calculator

    it 'should return the sum', -> expect(@calc.Add(1,1)).toEqual(2)
  22. Headless Browser Install - Download and install Qt 4.7+ binary

    package - gem install capybara-webkit -v=1.0.0.beta4 - create "config/evergreen.rb"
  23. Configure Evergreen require 'capybara-webkit' Evergreen.configure do |config| #config.driver = :selenium

    config.driver = :webkit config.public_dir = 'public' config.spec_dir = 'spec/javascripts' end
  24. Using a Headless Browser #selenium Finished in 3.92 seconds 2

    examples, 0 failures #webkit Finished in 1.05 seconds 2 examples, 0 failures
  25. Rosie "Rosie is a factory for building JavaScript objects, mostly

    useful for setting up test data. It is inspired by factory_girl." https://github.com/bkeepers/rosie
  26. Summer Breeze "Summer Breeze is a tool for generating fixture

    DOM output for Jasmine JavaScript tests directly from your Rails Views with a simple DSL for specifying fixtures" https://github.com/noelrappin/summer_breeze
  27. Wrap Up 1. Unit testing is important 2. Javascript can

    and should be unit tested 3. Jasmine is easy to setup and use
  28. Thank You! @timtyrrell Questions? Did I miss any cool plugins?

    http://bit.ly/jasmine-lsrc http://spkr8.com/t/7818