//describe your code describe ( 'presentation.js' , function(){ //what it should do it ( 'should be informative', function(){ //expect something expect( presentation.inform() ).toBeTruthy(); )}; } );
Note how describe + it
reads like a sentence.
 
TDD & BDD go together like coffee shops and hipsters.
The key concept is to write your unit test before you write a line of implementation code.
Writing code this way helps you:
A true TDD purist will tell you to follow the following path to testing enlightenment:
Lets take a look at a simple FizzBuzz example to so you what this looks like.
What is FizzBuzz?
Spec
expect( kata.fizzBuzz( 3 ) ) .toEqual( 'Fizz' );
fizzBuzz.js
var fizzBuzz : function( test ){ //nothing is here yet }
The simplest implementation.
Spec
expect(kata.fizzBuzz(3)).toEqual('Fizz');
fizzBuzz.js
var fizzBuzz : function( test ){ return "Fizz"; }
Spec
expect(kata.fizzBuzz(3)).toEqual('Fizz'); expect(kata.fizzBuzz(0)).toEqual( '' );
fizzBuzz.js
var fizzBuzz : function( test ){ return "Fizz"; }
Spec
expect(kata.fizzBuzz(3)).toEqual('Fizz'); expect(kata.fizzBuzz(0)).toEqual( '' );
fizzBuzz.js
var fizzBuzz : function( test ){ if ( test % 3 === 0 ){ return 'Fizz'; } return ''; }
Nobody actually has time for this, but its a noble goal to shoot for!
$(document).ready(function(){ var div1 = $('div.one'), itemCount = getItemCount( 'li.item' ); div1.on('click',function(){ ... }); function getItemCount( selector ){ return $( selector ).length; } });
$(document).ready()
closure.
var app = { init : function(){ div1.on( 'click', this.handleDivClick ); this.itemCount = this.getItemCount( 'li.item' ); }, getItemCount : function( selector ){ return $( selector ).length; }, handleDivClick : function( e ){ //this in here will still be div1 } };
Now we can test our code to make sure:
Rebecca Murphey has an excellent presentation on "Writing Testable JavaScript" here: http://www.youtube.com/watch?v=OzjogCFO4Zo
js |--tests | |--fixtures | |--spec SpecRunner.html
<!-- include source files here... --> <script type="text/javascript" src="src/Player.js"></script> <script type="text/javascript" src="src/Song.js"></script> <!-- include spec files here... --> <script type="text/javascript" src="spec/SpecHelper.js"></script> <script type="text/javascript" src="spec/PlayerSpec.js"></script>
To show all tests click on the "5 Specs" text.
This is helpful when you have a lot of tests and you want to only run the "Describe" that has a failing test.
describe('fizzbuzz'){ it( 'should return fizz when the number is divisible by 3', function(){ expect( kata.fizzBuzz(3) ).toEqual('Fizz'); //matcher expect( kata.fizzBuzz(0) ).toEqual( '' ); }); });
beforeEach( function (){ //run before each "it" }); afterEach( function (){ //run after each "it" });
toBe( 'expected' ) //exact compare (===)
toEqual( 'expected' ) //more general compare, can compare objects
toBeUndefined( ) //checks for undefined
toBeDefined( ) //checks if var is not undefined
toMatch( /regex/ ) //matches against regex
toBeNull( /regex/ ) //checks if a var is null
toBeTruthy( ) //checks if var is truthy
toBeFalsy( ) //checks if var is falsy
toBeLessThan( number ) //checks if value is less than number
toBeGreaterThan( number ) //checks if value is greater than number
toContain( item ) //look for item in array
expect( function(){ fn(); }).toThrow( e ) //fn() should throw an error
Any matcher can be "reversed" by including the not keyword.
expect( 5 ).not.toEqual( 3 );
Jasmine jQuery is a set of matchers and functions that help you test DOM elements.
toBe( $('jQuerySelector') ) //compares results of one selector to another
toBeChecked( ) //radios and checkboxes
toBeHidden( ) //display:none, hidden form elements, with & height = 0
toBeVisible( ) //checks for element to consume space on the document
toBeSelected( ) //only for elements with selected attribute
toHaveCss( 'css' ) //pass in css like calling the jQuery css() fn
toHaveAttr( 'attrName', 'attrValue' ) //checks for attribute on element
toConatin( $('jQuerySelector') ) //checks if selector is in children
toHaveValue( value ) //checks if element has the value attribute equal to the value passed in
toHaveText( 'text' ) //checks if element has text
toHaveId( 'id' ) //checks if element has id
toHaveHtml( 'html' ) //checks if element has html
toHandle( 'eventname' ) //checks if element listens for event
toBeFocused( ) //checks if element has focus
Jasmine jQuery assumes that they are in the path:
spec/javascripts/fixtures
This path can be overridden by adding the following code to the SpecRunner.html file:
(function(){ //this loads fixtures from a fixtures folder //relative to where SpecRunner.html lives jasmine.getFixtures() .fixturesPath = 'fixtures/'; var jasmineEnv = jasmine.getEnv(); jasmineEnv.updateInterval = 1000;
beforeEach( function(){ //fixture will be reset before each test loadFixtures( 'appFixture.html'); } );
What if you have code like this?
hide : function(){ $('.hidden').slideDown(5000); }
Jasmine provides us with runs and waits functions for this:
runs( function(){ myObject.hide() }); //technically doesn't have to be in runs, but it better describe the intent waits( 5100 ); runs( function(){ expect( $('.hidden') ).not.toBeVisible(); });
When you have runs / waits functions Jasmine runs the first function, waits the duration of the waits function call, then calls the next runs function.
Good for jQuery animations, setTimeouts, setIntervals, or any other asynchronous and timed code.
Spies are utilities provided by jasmine to make sure a callback function has been called.
The following code is a good canidate for a spy:
hide : function(){ var $ele = $('.hideMe'), self = this; $ele.fadeOut( function(){ self.showOtherDiv }); }
To use it we tell Jasmine to spyOn something. By default they are similar to mocks in other unit testing frameworks.
it('must call the success callback', function(){ //overwrites showOtherDiv with the spy spyOn( myObj, 'showOtherDiv' ); expect( myObj.showOtherDiv ) .toHaveBeenCalled(); } );
expect( myObj.showOtherDiv ).toHaveBeenCalled(); //validates that the method was called
expect( myObj.showOtherDiv ) .toHaveBeenCalledWith( args ); //validates that the method was called with specific arguments
myObj.showOtherDiv.calls.length //number of times called
expect( myObj.showOtherDiv.calls.length ) .toEqual(2)
myObj.showOtherDiv.calls //array of calls
myObj.showOtherDiv.calls[0].args //array of args
myObj.showOtherDiv.mostRecentCall //get last call, has same metadata as other calls
Spies can be extended to make your tests more powerful.
spyOn( myObj, 'populateData' ) .andCallThrough(); //will create the spy but also call the original function
spyOn( myObj, 'populateData' ) .andReturn( 'foobar' ); //simlar to a stub in other unit testing frameworks
/
#