Skip to content

Instantly share code, notes, and snippets.

@jmarnold
Created November 7, 2011 21:08
Show Gist options
  • Save jmarnold/1346188 to your computer and use it in GitHub Desktop.
Save jmarnold/1346188 to your computer and use it in GitHub Desktop.
Backbone testing fun
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);
}
});
<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>
<!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>
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);
});
});
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