Slides from my Lonestar Ruby Conf 2011 presentation.
*** Video of presentation: http://confreaks.com/videos/2531-lsrc2011-testing-javascript-with-jasmine ***
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
8. "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
13. 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(){ ... }; }); });
14. 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(); });
15. 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'! });
20. 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); });
Tim Tyrrell, from Chicago, moved to Austin a year and a half ago. I work as a Rails Developer at PeopleAdmin in Austin, TX. We have a SaaS talent management application with about 700 customers in the higher education, government, and non-profit sectors. Post jobs, apply to jobs, hiring workflows, etc.
I appreciate you attending my session. I know that you have a choice today on which session to attend, so I plan to make a good use of your time. In accordance, I want to set your expectations by displaying my agenda. It is pretty slide heavy talk with lots of different code examples, but we will blow through them, so don't let that scare you. I know that I am what is standing between you and chicken fried chicken, so I will tread lightly here. This is an intro to testing with jasmine. Cover a lot of stuff briefly. So if you have ever worked with Jasmine, you may want to bail right now.
- A lot of us use Ruby through Rails or Sinatra, so we have views, and these views use javascript. - I know that it is a gap in most applications. I think that is is something that might be scary but I want to show you that we can fill this gap and it is not very difficult. Although, it will take a mindset change.
- it is code! - it can be very complex! -There was a time where it was though of as a toy language, but that misconception has obviously been blown away. -What is the problem? I think it's viewed like the wild wild west. You write a bunch of procedural script inside the views and any thought of testing code like that is impossible. Procedural non-modular code, is horribly difficult to test. so right off the bat, you need to treat your javascript code with respect and care that you may backend code. Other perceived problems? Testing javascript is hard to get setup. - Why now? With javascript being more of an important piece of our software, with all this focus shifting to javascript, we need to do it right. Unit testing is the right way to do it.
- I know people say testing slows you down, but the reality is, a deployment that fails is going to slow you down. Refactoring some code and breaking half your application is going to slow you down. - yes, there are such things as spikes and prototypes where testing doesn't make sense. - what Obie said - testing is not easy. A know a number of folks in this room that have been doing it for 5+ years, and they are still learning new things and changing their opinions on the best way to do things.
Don't be this guy. You don't have to test-drive it, but you need to test it. The like unit testing because I don't want to get paged in the middle of the night.
- Created by Pivitol Labs - there are other JS testing frameworks: QUnit is the most obvious one, which is used by the jQuery project. QUnit is more of a standard assertion framework where as Jasmine has the BDD style-syntax
- super easy to get going and is super easy to use with Rails - Familiar RSpec Syntax (context switching is a killer) - It has a RubyGem for Ruby, Rails, or even Node.js. Also, you can use it without Ruby. - Easy to plug into a CI server, headless or not - Does not require the DOM - It does not depend on any other javascript frameworks - big community around it. Lot's of plugins and it is being pushed
- This is for testing javascript in isolation. "Unit testing" - More like Test::Unit or RSpec, JUnit, NUnit, etc. - Not Cucumber, Capybara, etc.
Differences? - With Rspec I could remove the double-quotes from "Calculate" and it will new that object up for us as the subject. - Rspec uses blocks and Jasmine uses anonymous functions - RSpec allows you to switch out the word describe for context and also there is some other syntactical magic you can us, Jasmine is straight forward.
Differences? - this is the setup/teardown events - you can declare @calc in the before block in RSpec and it will be available in other blocks. Not so with Jasmine.
- RSpec has different methods that define expectations, but Jasmine only has "expect" which is passed an argument and then chained with matchers. - To test negation you just chain on a "not" - Noel and the one assertion per "it"
spec_helper.rb
#spec helper.js
- A "onSpy" call will remove the specified function from the object and replace it with a spy. This spy will absorb all calls to that method and you can optionally chain a return method on to it.
- Test-Driven Development Write a failing test, make it pass, then make it better. Write a test before you write the code to make it pass. I will cover this quickly, it is something we have all heard a million times(I hope!).
- Attention span- Keeps me focused on one thing at a time. If I have a failing test, I know exactly what I am working on and will not bounce off onto a tangent or down a rabbit hole. - Helps you design your API, because you are utilizing it for your tests - Helps me sleep at night. I can deploy and not be scared to death that something will break. - Keeps me moving fast. Make a change, run the tests, move on. Don't need to open the browser and click. - Give me confidence in major refactorings. (Same as above)
- TDD manner!!!
- open the html in a browser
- gem 'jasmine' if bundler
- create a folder
- check out the default specs and functions - explain conventions. *Spec.js
- fire up the web server
- obviously used with Continuous Integration server. Selenium is run, browser opens closes, etc. - run it in the background while you work
Jasmine has a number of libraries, one of them deals with jQuery a set of custom matchers for jQuery framework an API for handling HTML fixtures in your specs
dom matchers, not object matchers
- find grained control of your text - if you are going to refactor your code or add more features, you don't want to break anything. You need to pin down you existing functionality to keep yourself moving fast.
Added a couple libraries and also a fixture directory.
- no ruby required here
- set the HTML or load a fixture from spec/javascripts - clears it after each run
- using a jQuery selecting in the expect matcher
- pinning down functionality
Also you can rake jasmine:ci Dr. Phil next.
Alright, that was the normal Jasmine way to get things set it. It is easy. But, it can be a little easier. There is a better way.
Best of breed. Templates, no generators, and coffeescript support. Defaults with Selenium, but you can rock it with Capybara, whatever - not a stand alone, you need ruby (obviously)
- folder conventions
- CoffeeScript next - recap
install node.js install npm install coffeescript
- no different than the other evergreen usage of calculator_spec.js
side by side.
- this is how I felt after I did that. so what did I do? 1. installed the evergreen gem 2. mimicked a folder structure 3. added a file of a coffee extension
capybara-webkit depends on a WebKit implementation from Qt, a cross-platform development toolkit. jasmine-headless-webkit uses the QtWebKit widget to run your specs without needing to render a pixel. It's nearly as fast as running in a JavaScript engine like Node.js, and, since it's a real browser environment, all the modules you would normally use, like jQuery and Backbone, work without any modifications.
- guard-jasmine-headless-webkit
- big problems - you get to work with me
THANKS FOR LISTENING! It is easy to setup and use, and it will help you sleep better at night. Grow a neck beard.