forked from boranton/testcafe-workshop
407 lines
10 KiB
JavaScript
Executable File
407 lines
10 KiB
JavaScript
Executable File
/*global app, jasmine, describe, it, beforeEach, expect */
|
|
|
|
describe('controller', function () {
|
|
'use strict';
|
|
|
|
var subject, model, view;
|
|
|
|
var setUpModel = function (todos) {
|
|
model.read.and.callFake(function (query, callback) {
|
|
callback = callback || query;
|
|
callback(todos);
|
|
});
|
|
|
|
model.getCount.and.callFake(function (callback) {
|
|
|
|
var todoCounts = {
|
|
active: todos.filter(function (todo) {
|
|
return !todo.completed;
|
|
}).length,
|
|
completed: todos.filter(function (todo) {
|
|
return !!todo.completed;
|
|
}).length,
|
|
total: todos.length
|
|
};
|
|
|
|
callback(todoCounts);
|
|
});
|
|
|
|
model.remove.and.callFake(function (id, callback) {
|
|
callback();
|
|
});
|
|
|
|
model.create.and.callFake(function (title, callback) {
|
|
callback();
|
|
});
|
|
|
|
model.update.and.callFake(function (id, updateData, callback) {
|
|
callback();
|
|
});
|
|
};
|
|
|
|
var createViewStub = function () {
|
|
var eventRegistry = {};
|
|
return {
|
|
render: jasmine.createSpy('render'),
|
|
bind: function (event, handler) {
|
|
eventRegistry[event] = handler;
|
|
},
|
|
trigger: function (event, parameter) {
|
|
eventRegistry[event](parameter);
|
|
}
|
|
};
|
|
};
|
|
|
|
beforeEach(function () {
|
|
model = jasmine.createSpyObj('model', ['read', 'getCount', 'remove', 'create', 'update']);
|
|
view = createViewStub();
|
|
subject = new app.Controller(model, view);
|
|
});
|
|
|
|
it('should show entries on start-up', function () {
|
|
setUpModel([]);
|
|
|
|
subject.setView('');
|
|
|
|
expect(view.render).toHaveBeenCalledWith('showEntries', []);
|
|
});
|
|
|
|
describe('routing', function () {
|
|
|
|
it('should show all entries without a route', function () {
|
|
var todo = {title: 'my todo'};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
|
|
expect(view.render).toHaveBeenCalledWith('showEntries', [todo]);
|
|
});
|
|
|
|
it('should show all entries without "all" route', function () {
|
|
var todo = {title: 'my todo'};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('#/');
|
|
|
|
expect(view.render).toHaveBeenCalledWith('showEntries', [todo]);
|
|
});
|
|
|
|
it('should show active entries', function () {
|
|
var todo = {title: 'my todo', completed: false};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('#/active');
|
|
|
|
expect(model.read).toHaveBeenCalledWith({completed: false}, jasmine.any(Function));
|
|
expect(view.render).toHaveBeenCalledWith('showEntries', [todo]);
|
|
});
|
|
|
|
it('should show completed entries', function () {
|
|
var todo = {title: 'my todo', completed: true};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('#/completed');
|
|
|
|
expect(model.read).toHaveBeenCalledWith({completed: true}, jasmine.any(Function));
|
|
expect(view.render).toHaveBeenCalledWith('showEntries', [todo]);
|
|
});
|
|
});
|
|
|
|
it('should show the content block when todos exists', function () {
|
|
setUpModel([{title: 'my todo', completed: true}]);
|
|
|
|
subject.setView('');
|
|
|
|
expect(view.render).toHaveBeenCalledWith('contentBlockVisibility', {
|
|
visible: true
|
|
});
|
|
});
|
|
|
|
it('should hide the content block when no todos exists', function () {
|
|
setUpModel([]);
|
|
|
|
subject.setView('');
|
|
|
|
expect(view.render).toHaveBeenCalledWith('contentBlockVisibility', {
|
|
visible: false
|
|
});
|
|
});
|
|
|
|
it('should check the toggle all button, if all todos are completed', function () {
|
|
setUpModel([{title: 'my todo', completed: true}]);
|
|
|
|
subject.setView('');
|
|
|
|
expect(view.render).toHaveBeenCalledWith('toggleAll', {
|
|
checked: true
|
|
});
|
|
});
|
|
|
|
it('should set the "clear completed" button', function () {
|
|
var todo = {id: 42, title: 'my todo', completed: true};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
|
|
expect(view.render).toHaveBeenCalledWith('clearCompletedButton', {
|
|
completed: 1,
|
|
visible: true
|
|
});
|
|
});
|
|
|
|
it('should highlight "All" filter by default', function () {
|
|
setUpModel([]);
|
|
|
|
subject.setView('');
|
|
|
|
expect(view.render).toHaveBeenCalledWith('setFilter', '');
|
|
});
|
|
|
|
it('should highlight "Active" filter when switching to active view', function () {
|
|
setUpModel([]);
|
|
|
|
subject.setView('#/active');
|
|
|
|
expect(view.render).toHaveBeenCalledWith('setFilter', 'active');
|
|
});
|
|
|
|
describe('toggle all', function () {
|
|
it('should toggle all todos to completed', function () {
|
|
var todos = [{
|
|
id: 42,
|
|
title: 'my todo',
|
|
completed: false
|
|
}, {
|
|
id: 21,
|
|
title: 'another todo',
|
|
completed: false
|
|
}];
|
|
|
|
setUpModel(todos);
|
|
subject.setView('');
|
|
|
|
view.trigger('toggleAll', {completed: true});
|
|
|
|
expect(model.update).toHaveBeenCalledWith(42, {completed: true}, jasmine.any(Function));
|
|
expect(model.update).toHaveBeenCalledWith(21, {completed: true}, jasmine.any(Function));
|
|
});
|
|
|
|
it('should update the view', function () {
|
|
var todos = [{
|
|
id: 42,
|
|
title: 'my todo',
|
|
completed: true
|
|
}];
|
|
|
|
setUpModel(todos);
|
|
subject.setView('');
|
|
|
|
view.trigger('toggleAll', {completed: false});
|
|
|
|
expect(view.render).toHaveBeenCalledWith('elementComplete', {id : 42, completed : false});
|
|
});
|
|
});
|
|
|
|
describe('new todo', function () {
|
|
it('should add a new todo to the model', function () {
|
|
setUpModel([]);
|
|
|
|
subject.setView('');
|
|
|
|
view.trigger('newTodo', 'a new todo');
|
|
|
|
expect(model.create).toHaveBeenCalledWith('a new todo', jasmine.any(Function));
|
|
});
|
|
|
|
it('should add a new todo to the view', function () {
|
|
setUpModel([]);
|
|
|
|
subject.setView('');
|
|
|
|
view.render.calls.reset();
|
|
model.read.calls.reset();
|
|
model.read.and.callFake(function (callback) {
|
|
callback([{
|
|
title: 'a new todo',
|
|
completed: false
|
|
}]);
|
|
});
|
|
|
|
view.trigger('newTodo', 'a new todo');
|
|
|
|
expect(model.read).toHaveBeenCalled();
|
|
|
|
expect(view.render).toHaveBeenCalledWith('showEntries', [{
|
|
title: 'a new todo',
|
|
completed: false
|
|
}]);
|
|
});
|
|
|
|
it('should clear the input field when a new todo is added', function () {
|
|
setUpModel([]);
|
|
|
|
subject.setView('');
|
|
|
|
view.trigger('newTodo', 'a new todo');
|
|
|
|
expect(view.render).toHaveBeenCalledWith('clearNewTodo');
|
|
});
|
|
});
|
|
|
|
describe('element removal', function () {
|
|
it('should remove an entry from the model', function () {
|
|
var todo = {id: 42, title: 'my todo', completed: true};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
view.trigger('itemRemove', {id: 42});
|
|
|
|
expect(model.remove).toHaveBeenCalledWith(42, jasmine.any(Function));
|
|
});
|
|
|
|
it('should remove an entry from the view', function () {
|
|
var todo = {id: 42, title: 'my todo', completed: true};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
view.trigger('itemRemove', {id: 42});
|
|
|
|
expect(view.render).toHaveBeenCalledWith('removeItem', 42);
|
|
});
|
|
|
|
it('should update the element count', function () {
|
|
var todo = {id: 42, title: 'my todo', completed: true};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
view.trigger('itemRemove', {id: 42});
|
|
|
|
expect(view.render).toHaveBeenCalledWith('updateElementCount', 0);
|
|
});
|
|
});
|
|
|
|
describe('remove completed', function () {
|
|
it('should remove a completed entry from the model', function () {
|
|
var todo = {id: 42, title: 'my todo', completed: true};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
view.trigger('removeCompleted');
|
|
|
|
expect(model.read).toHaveBeenCalledWith({completed: true}, jasmine.any(Function));
|
|
expect(model.remove).toHaveBeenCalledWith(42, jasmine.any(Function));
|
|
});
|
|
|
|
it('should remove a completed entry from the view', function () {
|
|
var todo = {id: 42, title: 'my todo', completed: true};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
view.trigger('removeCompleted');
|
|
|
|
expect(view.render).toHaveBeenCalledWith('removeItem', 42);
|
|
});
|
|
});
|
|
|
|
describe('element complete toggle', function () {
|
|
it('should update the model', function () {
|
|
var todo = {id: 21, title: 'my todo', completed: false};
|
|
setUpModel([todo]);
|
|
subject.setView('');
|
|
|
|
view.trigger('itemToggle', {id: 21, completed: true});
|
|
|
|
expect(model.update).toHaveBeenCalledWith(21, {completed: true}, jasmine.any(Function));
|
|
});
|
|
|
|
it('should update the view', function () {
|
|
var todo = {id: 42, title: 'my todo', completed: true};
|
|
setUpModel([todo]);
|
|
subject.setView('');
|
|
|
|
view.trigger('itemToggle', {id: 42, completed: false});
|
|
|
|
expect(view.render).toHaveBeenCalledWith('elementComplete', {id: 42, completed: false});
|
|
});
|
|
});
|
|
|
|
describe('edit item', function () {
|
|
it('should switch to edit mode', function () {
|
|
var todo = {id: 21, title: 'my todo', completed: false};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
|
|
view.trigger('itemEdit', {id: 21});
|
|
|
|
expect(view.render).toHaveBeenCalledWith('editItem', {id: 21, title: 'my todo'});
|
|
});
|
|
|
|
it('should leave edit mode on done', function () {
|
|
var todo = {id: 21, title: 'my todo', completed: false};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
|
|
view.trigger('itemEditDone', {id: 21, title: 'new title'});
|
|
|
|
expect(view.render).toHaveBeenCalledWith('editItemDone', {id: 21, title: 'new title'});
|
|
});
|
|
|
|
it('should persist the changes on done', function () {
|
|
var todo = {id: 21, title: 'my todo', completed: false};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
|
|
view.trigger('itemEditDone', {id: 21, title: 'new title'});
|
|
|
|
expect(model.update).toHaveBeenCalledWith(21, {title: 'new title'}, jasmine.any(Function));
|
|
});
|
|
|
|
it('should remove the element from the model when persisting an empty title', function () {
|
|
var todo = {id: 21, title: 'my todo', completed: false};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
|
|
view.trigger('itemEditDone', {id: 21, title: ''});
|
|
|
|
expect(model.remove).toHaveBeenCalledWith(21, jasmine.any(Function));
|
|
});
|
|
|
|
it('should remove the element from the view when persisting an empty title', function () {
|
|
var todo = {id: 21, title: 'my todo', completed: false};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
|
|
view.trigger('itemEditDone', {id: 21, title: ''});
|
|
|
|
expect(view.render).toHaveBeenCalledWith('removeItem', 21);
|
|
});
|
|
|
|
it('should leave edit mode on cancel', function () {
|
|
var todo = {id: 21, title: 'my todo', completed: false};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
|
|
view.trigger('itemEditCancel', {id: 21});
|
|
|
|
expect(view.render).toHaveBeenCalledWith('editItemDone', {id: 21, title: 'my todo'});
|
|
});
|
|
|
|
it('should not persist the changes on cancel', function () {
|
|
var todo = {id: 21, title: 'my todo', completed: false};
|
|
setUpModel([todo]);
|
|
|
|
subject.setView('');
|
|
|
|
view.trigger('itemEditCancel', {id: 21});
|
|
|
|
expect(model.update).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|