Created
November 7, 2011 21:08
-
-
Save jmarnold/1346188 to your computer and use it in GitHub Desktop.
Backbone testing fun
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Logistics = (function () { | |
var self = { | |
windowService: { | |
refresh: function () { | |
window.location.reload(); | |
}, | |
navigateTo: function (url) { | |
window.location = url; | |
} | |
} | |
}; | |
return self; | |
} ()); | |
TimeService = (function() { | |
var service = { | |
currentTime: function() { | |
// TODO -- js datetime fun | |
return new Date(); | |
} | |
}; | |
return service; | |
}()); | |
TimeCellModel = Backbone.Model.extend({ | |
defaults: { | |
timeValue: '', | |
originalVal: '', | |
checkpoint: '', | |
isSelected: false, | |
displayClass: 'inactive' | |
}, | |
initialize: function() { | |
this.bind('change', function() { | |
if(!this.hasChanged('isSelected')) { | |
return; | |
} | |
var display = this.get('isSelected') ? 'active' : 'inactive'; | |
this.set({displayClass: display}); | |
}); | |
}, | |
appendTime: function(val) { | |
var timeValue = this.get('timeValue'); | |
if(timeValue.length == 2) { | |
timeValue += ':'; | |
} | |
timeValue += val; | |
if(!this.validateTime(timeValue)) { | |
return; | |
} | |
this.set({timeValue: timeValue}); | |
}, | |
validateTime: function(time) { | |
var n = time.indexOf(':') == -1 ? 4 : 5; | |
if(time.length < n) { | |
var x = n - time.length; | |
for(var i = 0; i < x; i++) { | |
if(time.length == 2) { | |
time += ':'; | |
} | |
time += '0'; | |
} | |
} | |
var isValid = Date.parse(time) != null; | |
return isValid; | |
}, | |
resetTime: function() { | |
var val = this.get('originalVal'); | |
this.set({timeValue: val}); | |
}, | |
addMinute: function() { | |
var date = Date.parse(this.get('timeValue')); | |
date.add({ minutes: 1}); | |
this.set({timeValue: date.toString('HH:mm')}); | |
}, | |
subtractMinute: function() { | |
var date = Date.parse(this.get('timeValue')); | |
date.add({ minutes: -1}); | |
this.set({timeValue: date.toString('HH:mm')}); | |
} | |
}); | |
TimeCellModelCollection = Backbone.Collection.extend({ | |
model: TimeCellModel, | |
initialize: function() { | |
this._index = -1; | |
this.selectedTimeCell = null; | |
}, | |
canSelectPrevious: function() { | |
var x = this._index - 1; | |
return x >= 0; | |
}, | |
canSelectNext: function() { | |
var x = this._index + 1; | |
return x <= (this.length - 1); | |
}, | |
selectTimeCell: function(timeCell) { | |
this.selectedTimeCell = timeCell; | |
for(var i = 0; i < this.length; i++) { | |
var x = this.at(i); | |
if(x.get('checkpoint') == timeCell.get('checkpoint')) { | |
this._index = i; | |
break; | |
} | |
} | |
this.trigger('timeCellChanged', timeCell); | |
}, | |
selectPreviousTimeCell: function() { | |
if(!this.canSelectPrevious()) { | |
return; | |
} | |
var index = this._index - 1; | |
var model = this.at(index); | |
this.selectTimeCell(model); | |
}, | |
selectNextTimeCell: function() { | |
if(!this.canSelectNext()) { | |
return; | |
} | |
var index = this._index + 1; | |
var model = this.at(index); | |
this.selectTimeCell(model); | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<section id="timestamp-right"> | |
<div id="timestamp-tool"> | |
<header> | |
<h1 id="time-display"> | |
<span data-bind="text timeValue"></span> | |
</h1> | |
<a href="javascript:void(0);" rel="goBack" class="left">Left arrow</a> | |
<a href="javascript:void(0);" rel="now" class="clock">Middle Clock</a> | |
<a href="javascript:void(0);" rel="goFoward" class="right">Right arrow</a> | |
</header> | |
<nav> | |
<a href="javascript:void(0);" class="number" data-number="7">7</a> | |
<a href="javascript:void(0);" class="number" data-number="8">8</a> | |
<a href="javascript:void(0);" class="number" data-number="9">9</a> | |
<br /> | |
<a href="javascript:void(0);" class="number" data-number="4">4</a> | |
<a href="javascript:void(0);" class="number" data-number="5">5</a> | |
<a href="javascript:void(0);" class="number" data-number="6">6</a> | |
<br /> | |
<a href="javascript:void(0);" class="number" data-number="1">1</a> | |
<a href="javascript:void(0);" class="number" data-number="2">2</a> | |
<a href="javascript:void(0);" class="number" data-number="3">3</a> | |
<br /> | |
<a href="javascript:void(0);" class="clear-btn">CLR</a> | |
<a href="javascript:void(0);" class="number" data-number="0">0</a> | |
<a href="javascript:void(0);" class="reset-btn">RST</a> | |
</nav> | |
</div> | |
</section> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |
<html> | |
<head> | |
<title>TimeEntry Sample</title> | |
<link rel="shortcut icon" type="image/png" href="jasmine_favicon.png"/> | |
<script src="../jquery-1.6.2.min.js"></script> | |
<script src="../jquery-ui-1.8.16.custom.min.js"></script> | |
<script src="../amplify.core.min.js"></script> | |
<script src="../underscore-min.js"></script> | |
<script src="../backbone-min.js"></script> | |
<script src="../config.js"></script> | |
<script src="../backbone.modelbinding.min.js"></script> | |
<script src="../date.js"></script> | |
<script src="../common.js"></script> | |
<script src="time-entry.js"></script> | |
<script type="text/javascript"> | |
$(document).ready(function() { | |
var setupPresenter = function() { | |
var model = new CheckpointModel({ | |
originalVal: '12:30' | |
}); | |
var view = new TimeEntryView({model: model}); | |
var presenter = new TimeEntryPresenter(view, model); | |
presenter.initialize(); | |
}; | |
$.ajax({ | |
async: false, | |
url: 'time-entry-fixture.html', | |
success: function(response) { | |
$('body').append(response); | |
setupPresenter(); | |
} | |
}); | |
}); | |
</script> | |
</head> | |
<body> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
describe('TimeCellModelTester', function () { | |
it('should_validate_times', function() { | |
var model = new TimeCellModel(); | |
expect(model.validateTime('77:77')).toEqual(false); | |
expect(model.validateTime('12:77')).toEqual(false); | |
expect(model.validateTime('12:30')).toEqual(true); | |
expect(model.validateTime('12:3')).toEqual(true); | |
expect(model.validateTime('12')).toEqual(true); | |
expect(model.validateTime('7')).toEqual(false); | |
expect(model.validateTime('07')).toEqual(true); | |
expect(model.validateTime('07:3')).toEqual(true); | |
}); | |
it('should_update_displayClass', function() { | |
var model = new TimeCellModel(); | |
model.set({isSelected: false}); // being explicit for readability | |
expect(model.get('displayClass')).toEqual('inactive'); | |
model.set({isSelected: true}); | |
expect(model.get('displayClass')).toEqual('active'); | |
}); | |
}); | |
describe('TimeEntryPresenterTester', function () { | |
var presenter; | |
var view; | |
var model; | |
var pressNumber; | |
beforeEach(function() { | |
loadFixtures('entry/time-entry-fixture.html'); | |
model = new TimeCellModel({ | |
originalVal: '12:30' | |
}); | |
view = new TimeEntryView({model: model}); | |
presenter = new TimeEntryPresenter(view, model); | |
pressNumber = function(x) { | |
$(view.el).find('a.number').each(function() { | |
if($(this).data('number') == x) { | |
$(this).click(); | |
} | |
}); | |
}; | |
}); | |
it('should_bind_model_on_initialize', function() { | |
view.bindTo = jasmine.createSpy('TimeEntryView.bindTo'); | |
presenter.initialize(); | |
expect(view.bindTo).toHaveBeenCalled(); | |
}); | |
it('should_set_time_when_numerical_buttons_are_clicked', function() { | |
presenter.initialize(); | |
view.trigger('number', 1); | |
view.trigger('number', 2); | |
view.trigger('number', 4); | |
view.trigger('number', 0); | |
expect(presenter.model.get('timeValue')).toEqual('12:40'); | |
}); | |
it('should_clear_time_when_button_is_pressed', function() { | |
presenter.initialize(); | |
view.trigger('number', 1); | |
view.trigger('number', 2); | |
view.trigger('clear'); | |
expect(model.get('timeValue')).toEqual(''); | |
}); | |
it('should_reset_time_to_original_value', function() { | |
presenter.initialize(); | |
view.trigger('number', 1); | |
view.trigger('number', 2); | |
view.trigger('reset'); | |
expect(model.get('timeValue')).toEqual('12:30'); | |
}); | |
it('should_set_time_to_current_time', function() { | |
presenter.initialize(); | |
spyOn(TimeService, 'currentTime').andCallFake(function() { | |
var date = new Date(); | |
date.setHours(15); | |
date.setMinutes(0); | |
return date; | |
}); | |
view.trigger('clock'); | |
expect(model.get('timeValue')).toEqual('15:00'); | |
}); | |
it('should_increase_time', function() { | |
presenter.initialize(); | |
spyOn(TimeService, 'currentTime').andCallFake(function() { | |
var date = new Date(); | |
date.setHours(15); | |
date.setMinutes(0); | |
return date; | |
}); | |
view.trigger('right'); | |
expect(model.get('timeValue')).toEqual('15:01'); | |
}); | |
it('should_decrease_time', function() { | |
presenter.initialize(); | |
spyOn(TimeService, 'currentTime').andCallFake(function() { | |
var date = new Date(); | |
date.setHours(15); | |
date.setMinutes(0); | |
return date; | |
}); | |
view.trigger('left'); | |
expect(model.get('timeValue')).toEqual('14:59'); | |
}); | |
it('should_render_updates_from_clicking_number_buttons', function() { | |
presenter.initialize(); | |
pressNumber('1'); | |
pressNumber('2'); | |
pressNumber('3'); | |
pressNumber('0'); | |
var time = '12:30'; | |
expect(model.get('timeValue')).toEqual(time); | |
expect($('#time-display > span:first').html()).toEqual(time); | |
}); | |
it('should_render_updates_from_clicking_clear_button', function() { | |
presenter.initialize(); | |
pressNumber('1'); | |
pressNumber('2'); | |
pressNumber('3'); | |
pressNumber('0'); | |
$(view.el).find('a.clear-btn').click(); | |
var time = ''; | |
expect(model.get('timeValue')).toEqual(time); | |
expect($('#time-display > span:first').html()).toEqual(time); | |
}); | |
it('should_render_updates_from_clicking_reset_button', function() { | |
presenter.initialize(); | |
pressNumber('1'); | |
pressNumber('2'); | |
pressNumber('4'); | |
pressNumber('5'); | |
$(view.el).find('a.reset-btn').click(); | |
var time = '12:30'; | |
expect(model.get('timeValue')).toEqual(time); | |
expect($('#time-display > span:first').html()).toEqual(time); | |
}); | |
it('should_render_updates_from_clicking_clock_button', function() { | |
presenter.initialize(); | |
spyOn(TimeService, 'currentTime').andCallFake(function() { | |
var date = new Date(); | |
date.setHours(15); | |
date.setMinutes(0); | |
return date; | |
}); | |
$(view.el).find('a.clock').click(); | |
var time = '15:00'; | |
expect(model.get('timeValue')).toEqual(time); | |
expect($('#time-display > span:first').html()).toEqual(time); | |
}); | |
it('should_render_updates_from_clicking_right_button', function() { | |
presenter.initialize(); | |
spyOn(TimeService, 'currentTime').andCallFake(function() { | |
var date = new Date(); | |
date.setHours(15); | |
date.setMinutes(0); | |
return date; | |
}); | |
$(view.el).find('a.clock').click(); | |
$(view.el).find('a.right').click(); | |
var time = '15:01'; | |
expect(model.get('timeValue')).toEqual(time); | |
expect($('#time-display > span:first').html()).toEqual(time); | |
}); | |
it('should_render_updates_from_clicking_left_button', function() { | |
presenter.initialize(); | |
spyOn(TimeService, 'currentTime').andCallFake(function() { | |
var date = new Date(); | |
date.setHours(15); | |
date.setMinutes(0); | |
return date; | |
}); | |
$(view.el).find('a.clock').click(); | |
$(view.el).find('a.left').click(); | |
var time = '14:59'; | |
expect(model.get('timeValue')).toEqual(time); | |
expect($('#time-display > span:first').html()).toEqual(time); | |
}); | |
it('should_not_allow_invalid_times', function() { | |
presenter.initialize(); | |
pressNumber('0'); | |
pressNumber('7'); | |
pressNumber('7'); | |
pressNumber('7'); | |
pressNumber('3'); | |
pressNumber('0'); | |
var time = '07:30'; | |
expect(model.get('timeValue')).toEqual(time); | |
expect($('#time-display > span:first').html()).toEqual(time); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
TimeEntryPresenter = function(view, model) { | |
this._view = view; | |
this.model = model; | |
this.initialize = function() { | |
this._view.bindTo(this.model); | |
var self = this; | |
this._view.bind('number', function(val) { | |
self.model.appendTime(val); | |
}); | |
this._view.bind('clear', function() { | |
self.model.set({timeValue: ''}); | |
}); | |
this._view.bind('reset', function() { | |
self.model.resetTime(); | |
}); | |
this._view.bind('clock', function() { | |
// TODO -- js datetime fun | |
var date = TimeService.currentTime(); | |
self.model.set({timeValue: date.toString('HH:mm')}); | |
}); | |
this._view.bind('right', function() { | |
var time = self.model.get('timeValue'); | |
if(time == '') { | |
self._view.trigger('clock'); | |
} | |
self.model.addMinute(); | |
}); | |
this._view.bind('left', function() { | |
var time = self.model.get('timeValue'); | |
if(time == '') { | |
self._view.trigger('clock'); | |
} | |
self.model.subtractMinute(); | |
}); | |
}; | |
}; | |
TimeEntryView = Backbone.View.extend({ | |
el: '#timestamp-tool', | |
bindTo: function(model) { | |
// find a better place to handle this? | |
var self = this;; | |
$(this.el).find('.number').click(function() { | |
var val = $(this).data('number'); | |
self.trigger('number', val); | |
}); | |
$(this.el).find('.clear-btn').click(function() { | |
self.trigger('clear'); | |
}); | |
$(this.el).find('.reset-btn').click(function() { | |
self.trigger('reset'); | |
}); | |
$(this.el).find('.clock').click(function() { | |
self.trigger('clock'); | |
}); | |
$(this.el).find('.right').click(function() { | |
self.trigger('right'); | |
}); | |
$(this.el).find('.left').click(function() { | |
self.trigger('left'); | |
}); | |
Backbone.ModelBinding.bind(this); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment