Black box
Performance
Load testing
Usability testing
End-to-end
White box
Functional
Compatibility
Stress testing
Recovery
Unit testing
Integration
Security testing
Regression
Acceptance
Unit tests
Integration tests
Acceptance tests
UI tests
Common place to test
Mostly logic
Easier to automate
Routing
Database interactions
Knowing what to test
Route
Middleware
Business objects
Middleware
Business objects
Route
Test only app functionality
Server testing is straightforward
Don't forget to refactor
User interaction
Framework "Magic"
Appearance
User interface
Data for user interface
Source of data
User interface
Data for user interface
Source of data
Client testing needs change of perspective
Fake out all levels below the current one
Don’t Forget to Refactor
describe( 'Notes:', function() {
var Notes = window.modules.Notes;
it( 'should Notes module to be defined:', function() {
expect( Notes ).toBeDefined();
} );
} );
( function( window ) {
function Notes() {}
window.modules = window.modules || {};
window.modules.Notes = Notes;
} )( window );
describe( 'Notes:', function() {
var Notes = window.modules.Notes;
it( 'should Notes module to be defined:', function() {
expect( Notes ).toBeDefined();
} );
describe( 'initialization=>', function() {
beforeEach( function() {
env.stub( Notes.prototype, 'bindEvents' );
this.sut = new Notes();
} );
it( 'should bind events:', function() {
expect( this.sut.bindEvents ).toHaveBeenCalled();
} );
} );
} );
( function( window, $ ) {
function Notes() {
this.init();
}
$.extend( Notes.prototype, {
init: function() {
this.bindEvents();
},
bindEvents: function() {}
} );
window.modules = window.modules || {};
window.modules.Notes = Notes;
} )( window, jQuery );
describe( 'initialization=>', function() {
beforeEach( function() {
this.fakeDeferred = new $.Deferred();
env.stub( Notes.prototype, 'getNotes' );
env.stub( Notes.prototype, 'bindEvents' );
Object.defineProperty( window, 'authReady', {
value: this.fakeDeferred
} );
this.sut = new Notes();
} );
describe( 'user is NOT signed in=>', function() {
beforeEach( function() {
this.fakeDeferred.resolve( { user: { isLoggedIn: false } } );
} );
it( 'should NOT bind events:', function() {
expect( this.sut.bindEvents ).not.toHaveBeenCalled();
} );
it( 'should NOT get notes:', function() {
expect( this.sut.getNotes ).not.toHaveBeenCalled();
} );
} );
describe( 'user is signed in=>', function() {
beforeEach( function() {
this.fakeDeferred.resolve( { user: { isLoggedIn: true } } );
} );
it( 'should bind events:', function() {
expect( this.sut.bindEvents ).toHaveBeenCalled();
} );
it( 'should NOT get notes:', function() {
expect( this.sut.getNotes ).toHaveBeenCalled();
} );
} );
} );
( function( window, $ ) {
function Notes() {
this.init();
}
$.extend( Notes.prototype, {
init: function() {
window.authReady.then( function( auth ) {
if ( !auth.user.isLoggedIn ) {
return;
}
this.getNotes();
this.bindEvents();
}.bind( this ) );
},
bindEvents: function() {},
getNotes: function() {}
} );
window.modules = window.modules || {};
window.modules.Notes = Notes;
} )( window, jQuery );
describe( 'binding events=>', function() {
beforeEach( function() {
env.stub( Notes.prototype, 'init' );
this.sut = new Notes();
this.sut.$form = {
on: env.stub()
};
} );
it( 'should bind submit handler on save button:', function() {
this.sut.bindEvents();
expect( this.sut.$form.on ).toHaveBeenCalledWith( 'submit', this.sut.onSubmit );
} );
} );
( function( window, $ ) {
function Notes() {
this.$form = $( '.js-RC-notes' )
this.init();
}
$.extend( Notes.prototype, {
init: function() {
window.authReady.then( function( auth ) {
if ( !auth.user.isLoggedIn ) {
return;
}
this.getNotes();
this.bindEvents();
}.bind( this ) );
},
bindEvents: function() {
this.$form.on( 'submit', $.proxy( this.onSubmit, this ) );
},
getNotes: function() {},
onSubmit: function( event ) {}
} );
window.modules = window.modules || {};
window.modules.Notes = Notes;
} )( window, jQuery );
describe( 'getting notes=>', function() {
beforeEach( function() {
this.fakeParams = {
'race_id': '123',
'horse_id': [ 12, 23 ],
'race_type_code': 'F'
};
this.fakeConfig = {
type: 'GET',
url: '/racecards/ugc',
data: this.fakeParams
};
this.fakeDeferred = new $.Deferred();
env.stub( Notes.prototype, 'init' );
env.stub( Notes.prototype, 'processParams' ).returns( this.fakeParams );
env.stub( $, 'ajax' ).withArgs( this.fakeConfig ).returns( this.fakeDeferred );
this.sut = new Notes();
} );
describe( 'request is successful=>', function() {
beforeEach( function() {
this.fakeSuccessData = {
success: true,
error: 'error message',
data: { 123: {
comment: 'comment',
rating: 'rating',
odds: 'odds',
selection: true
} }
};
env.stub( Notes.prototype, 'getSuccess' );
} );
it( 'should render notes:', function() {
this.sut.getNotes();
this.fakeDeferred.resolve( this.fakeSuccessData );
expect( this.sut.getSuccess ).toHaveBeenCalledWith( this.fakeParams, this.fakeSuccessData );
} );
} );
describe( 'request is failed=>', function() {
beforeEach( function() {
this.fakeErrorData = {
message: 'error message'
};
env.stub( Notes.prototype, 'getError' );
} );
it( 'should handle error:', function() {
this.sut.getNotes();
this.fakeDeferred.reject( this.fakeErrorData );
expect( this.sut.getError ).toHaveBeenCalledWith( this.fakeErrorData );
} );
} );
} );
( function( window, $ ) {
function Notes() {
this.$form = $( '.js-RC-notes' )
this.init();
}
$.extend( Notes.prototype, {
init: function() {
window.authReady.then( function( auth ) {
if ( !auth.user.isLoggedIn ) {
return;
}
this.getNotes();
this.bindEvents();
}.bind( this ) );
},
bindEvents: function() {
this.$form.on( 'submit', $.proxy( this.onSubmit, this ) );
},
getNotes: function() {
var requestParams = this.processParams();
$.ajax( {
type: 'GET',
url: '/racecards/ugc',
data: requestParams
} )
.done( $.proxy( this.getSuccess, this, requestParams ) )
.fail( $.proxy( this.getError, this ) );
},
onSubmit: function( event ) {},
processParams: function() {},
getSuccess: function( requestParams, response ) {},
getError: function( error ) {}
} );
window.modules = window.modules || {};
window.modules.Notes = Notes;
} )( window, jQuery );