From dea4952595b118d4fbfeaad2ed0f5560dcb0da48 Mon Sep 17 00:00:00 2001 From: emaphp Date: Mon, 16 Mar 2015 01:00:31 -0300 Subject: [PATCH] added: model.destroy test --- Gruntfile.js | 5 + README.md | 10 +- bower.json | 2 +- dist/backbone.async.js | 4 +- dist/backbone.async.min.js | 2 +- package.json | 2 +- test/specs/model.js | 312 ++++++++++++++++++++++++++++++++++++- 7 files changed, 326 insertions(+), 11 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 4207422..a252a89 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -66,7 +66,12 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-jshint'); + //copies required libraries for testing grunt.registerTask('vendor', ['copy:jquery', 'copy:underscore', 'copy:backbone', 'copy:mocha', 'copy:chai', 'copy:promise']); + + //applies jshint to project files grunt.registerTask('test', ['jshint']); + + //minifies library grunt.registerTask('release', ['jshint', 'uglify:dist']); }; \ No newline at end of file diff --git a/README.md b/README.md index 89fc591..1cb4c29 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ var Contact = Backbone.Async.Contact.extend({ var contact = new Contact({id: 1}); //setup event listener -var object = { +var obj = { beforeFetch: function(data) { console.log('Contact is being fetched...'); }, @@ -163,9 +163,9 @@ var object = { } }; -_.extend(object, Backbone.Events); -object.listenTo(contact, 'before:fetch', object.beforeFetch); -object.listenTo(contact, 'before:save', object.beforeSave); +_.extend(obj, Backbone.Events); +obj.listenTo(contact, 'before:fetch', obj.beforeFetch); +obj.listenTo(contact, 'before:save', obj.beforeSave); //fetch contact contact.fetch() @@ -192,7 +192,7 @@ The *before:fetch* and *before:destroy* event handlers will receive an object co * model: The model instance. * options: The options provided. -The *before:save* event handler also includes an additional property named *attrs* with the attributes being saved. All *after:event* handlers receive the exact same object provided to the fulfilled and rejection callbacks plus a *success* argument. +The *before:save* event handler argument also includes an additional property named *attrs* with the attributes being saved. All *after:[event]* handlers receive the exact same object provided to the fulfilled and rejection callbacks plus a *success* argument.
###License diff --git a/bower.json b/bower.json index cfcf801..55895b0 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "backbone.async", - "version": "0.3.0", + "version": "1.0.0", "homepage": "https://github.com/emaphp/backbone.async", "authors": [ "Emmanuel Antico " diff --git a/dist/backbone.async.js b/dist/backbone.async.js index 61e885b..3e04311 100644 --- a/dist/backbone.async.js +++ b/dist/backbone.async.js @@ -1,5 +1,5 @@ /* - * Backbone.Async v0.3.0 + * Backbone.Async v1.0.0 * Copyright 2015 Emmanuel Antico * This library is distributed under the terms of the MIT license. */ @@ -94,7 +94,7 @@ }; var Async = Backbone.Async = Backbone.Async || {}; - Async.VERSION = '0.3.0'; + Async.VERSION = '1.0.0'; Async.Model = Backbone.Model.extend( buildPrototype(Backbone.Model, ['fetch', 'save', 'destroy']) diff --git a/dist/backbone.async.min.js b/dist/backbone.async.min.js index a8ce790..0f7d7f2 100644 --- a/dist/backbone.async.min.js +++ b/dist/backbone.async.min.js @@ -1 +1 @@ -!function(a,b){"function"==typeof define&&define.amd?define(["backbone","underscore"],function(c,d){return b(a,c,d)}):"undefined"!=typeof exports?module.exports=b(a,require("backbone"),require("underscore")):b(a,a.Backbone,a._)}(this,function(a,b,c){var d=function(a,b,c){return function(d,e,f){a&&a.apply(d,arguments);var g={response:e,options:f};g[c.collection?"collection":"model"]=d,b(g),"undefined"!=typeof f.silent&&f.silent||d.trigger("after:"+c.method,g,c.success)}},e=function(a,b,d,e){var f,g;return"save"===a?null===b||"object"==typeof b?(f=b,g=d):b&&((f={})[b]=d,g=e):g=b,g=g?c.extend({},g):{},{attrs:f,options:g}},f=function(a){return function(f,g){return f[g]=function(f,h,i){var j=this,k=e(g,f,h,i),l=k.options,m=k.attrs,n=l.success,o=l.error,p={method:g,collection:a===b.Collection.prototype};return new Promise(function(b,e){l.success=d(n,b,c.extend({success:!0},p)),l.error=d(o,e,c.extend({success:!1},p)),p.collection?("undefined"!=typeof l.silent&&l.silent||j.trigger("before:"+g,{collection:j,options:l}),a[g].call(j,l)):("undefined"!=typeof l.silent&&l.silent||j.trigger("before:"+g,"save"===g?{model:j,options:l,attrs:m}:{model:j,options:l}),a[g].apply(j,"save"===g?[m,l]:[l]))})},f}},g=function(a,b){return b.reduce(f(a.prototype),{})},h=b.Async=b.Async||{};return h.VERSION="0.3.0",h.Model=b.Model.extend(g(b.Model,["fetch","save","destroy"])),h.Collection=b.Collection.extend(g(b.Collection,["fetch"])),h}); \ No newline at end of file +!function(a,b){"function"==typeof define&&define.amd?define(["backbone","underscore"],function(c,d){return b(a,c,d)}):"undefined"!=typeof exports?module.exports=b(a,require("backbone"),require("underscore")):b(a,a.Backbone,a._)}(this,function(a,b,c){var d=function(a,b,c){return function(d,e,f){a&&a.apply(d,arguments);var g={response:e,options:f};g[c.collection?"collection":"model"]=d,b(g),"undefined"!=typeof f.silent&&f.silent||d.trigger("after:"+c.method,g,c.success)}},e=function(a,b,d,e){var f,g;return"save"===a?null===b||"object"==typeof b?(f=b,g=d):b&&((f={})[b]=d,g=e):g=b,g=g?c.extend({},g):{},{attrs:f,options:g}},f=function(a){return function(f,g){return f[g]=function(f,h,i){var j=this,k=e(g,f,h,i),l=k.options,m=k.attrs,n=l.success,o=l.error,p={method:g,collection:a===b.Collection.prototype};return new Promise(function(b,e){l.success=d(n,b,c.extend({success:!0},p)),l.error=d(o,e,c.extend({success:!1},p)),p.collection?("undefined"!=typeof l.silent&&l.silent||j.trigger("before:"+g,{collection:j,options:l}),a[g].call(j,l)):("undefined"!=typeof l.silent&&l.silent||j.trigger("before:"+g,"save"===g?{model:j,options:l,attrs:m}:{model:j,options:l}),a[g].apply(j,"save"===g?[m,l]:[l]))})},f}},g=function(a,b){return b.reduce(f(a.prototype),{})},h=b.Async=b.Async||{};return h.VERSION="1.0.0",h.Model=b.Model.extend(g(b.Model,["fetch","save","destroy"])),h.Collection=b.Collection.extend(g(b.Collection,["fetch"])),h}); \ No newline at end of file diff --git a/package.json b/package.json index dcd953f..e71229f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "backbone.async", - "version": "0.3.0", + "version": "1.0.0", "description": "Backbone Models meet Promises", "author": "Emmanuel Antico ", "license": "MIT", diff --git a/test/specs/model.js b/test/specs/model.js index 2e9cc52..c50c765 100644 --- a/test/specs/model.js +++ b/test/specs/model.js @@ -379,7 +379,7 @@ describe("ASync.Model tests", function() { done(); }) - .catch(function(err){done(err)}); + .catch(function(err){done(err);}); server.respond(); }); @@ -702,10 +702,320 @@ describe("ASync.Model tests", function() { }); describe('Delete tests', function() { + it('must call then', function(done) { + server.respondWith( + 'DELETE', + '/contacts/1', + [ + 204, + null, + '' + ] + ); + + var contact = new FIXTURES.Contact({id: 1}); + + contact.destroy({test: true, silent:false}) + .then(function(data) { + expect(data).to.be.a('object'); + expect(data).to.have.property('model'); + expect(data).to.have.property('response'); + expect(data).to.have.property('options'); + expect(data.model).to.be.deep.equal(contact); + + var attrs = data.model.attributes; + expect(attrs).to.have.property('id'); + + var response = data.response; + expect(response).to.be.undefined; + + expect(data.options).to.be.a('object'); + expect(data.options).to.have.property('test'); + expect(data.options).to.have.property('silent'); + + expect(data.options.test).to.be.true; + expect(data.options.silent).to.be.false; + + done(); + }) + .catch(function(err) { done(err); }); + server.respond(); + }); + + it('must call callbacks in order', function(done) { + server.respondWith( + 'DELETE', + '/contacts/2', + [ + 204, + null, + '' + ] + ); + + var contact = new FIXTURES.Contact({id: 2}); + var callback1 = sinon.spy(); + var callback2 = sinon.spy(); + + contact.destroy() + .then(callback1) + .then(callback2) + .then(function(data) { + expect(callback1.called).to.be.true; + expect(callback1.calledOnce).to.be.true; + expect(callback2.called).to.be.true; + expect(callback2.calledOnce).to.be.true; + expect(callback1.calledBefore(callback2)).to.be.true; + done(); + }) + .catch(function(err) { done(err); }); + + server.respond(); + }); + + it('must call event handlers', function(done) { + server.respondWith( + 'DELETE', + '/contacts/3', + [ + 204, + null, + '' + ] + ); + + var obj = _.extend({}, Backbone.Events); + var beforeCallback = sinon.spy(); + var afterCallback = sinon.spy(); + var contact = new FIXTURES.Contact({id: 3}); + obj.listenTo(contact, 'before:destroy', beforeCallback); + obj.listenTo(contact, 'after:destroy', afterCallback); + + contact.destroy({test: true, silent:false}) + .then(function(data) { + expect(beforeCallback.called).to.be.true; + expect(afterCallback.called).to.be.true; + expect(beforeCallback.calledBefore(afterCallback)).to.be.true; + + var dataArg = beforeCallback.args[0][0]; + expect(dataArg).to.be.a('object'); + expect(dataArg).to.have.property('model'); + expect(dataArg).to.have.property('options'); + expect(dataArg.model).to.be.deep.equal(contact); + expect(dataArg.options).to.have.property('test'); + expect(dataArg.options).to.have.property('silent'); + expect(dataArg.options.test).to.be.true; + expect(dataArg.options.silent).to.be.false; + + dataArg = afterCallback.args[0][0]; + expect(dataArg).to.be.a('object'); + expect(dataArg).to.have.property('model'); + expect(dataArg).to.have.property('options'); + expect(dataArg).to.have.property('response'); + expect(dataArg.model).to.be.deep.equal(contact); + expect(dataArg.response).to.be.undefined; + expect(dataArg.options).to.have.property('test'); + expect(dataArg.options).to.have.property('silent'); + expect(dataArg.options.test).to.be.true; + expect(dataArg.options.silent).to.be.false; + + var success = afterCallback.args[0][1]; + expect(success).to.be.true; + + done(); + }) + .catch(function(err) { done(err); }); + + server.respond(); + }); + + it('must not call event handlers', function(done) { + server.respondWith( + 'DELETE', + '/contacts/4', + [ + 204, + null, + '' + ] + ); + var obj = _.extend({}, Backbone.Events); + var beforeCallback = sinon.spy(); + var afterCallback = sinon.spy(); + var contact = new FIXTURES.Contact({id: 4}); + obj.listenTo(contact, 'before:destroy', beforeCallback); + obj.listenTo(contact, 'after:destroy', afterCallback); + + contact.destroy({test: false, silent: true}) + .then(function() { + expect(beforeCallback.called).to.be.false; + expect(afterCallback.called).to.be.false; + done(); + }) + .catch(function(err) { done(err); }); + + server.respond(); + }); + + it('must throw error', function(done) { + server.respondWith( + 'DELETE', + '/contacts/5', + [ + 204, + null, + '' + ] + ); + + var contact = new FIXTURES.Contact({id: 5}); + + contact.destroy() + .then(function(data) { + throw new Error(); + }) + .catch(function(err) { + expect(_.isError(err)).to.be.true; + done(); + }); + + server.respond(); + }); }); describe('Delete fail tests', function() { + it('must call catch', function(done) { + server.respondWith( + 'DELETE', + '/notes/1', + [ + 500, + null, + '' + ] + ); + + var note = new FIXTURES.Note({id: 1}); + + note.destroy({test: true, silent: false}) + .then(function() { + }) + .catch(function(data) { + expect(data).to.be.a('object'); + + expect(data).to.have.property('model'); + expect(data).to.have.property('response'); + expect(data).to.have.property('options'); + + expect(data.model).to.be.deep.equal(note); + expect(data.response).to.be.a('object'); + expect(data.response).to.have.property('status'); + expect(data.response).to.have.property('statusText'); + expect(data.response.status).to.equal(500); + expect(data.response.statusText).to.equal('Internal Server Error'); + var options = data.options; + expect(options).to.have.property('test'); + expect(options).to.have.property('silent'); + expect(options.test).to.be.true; + expect(options.silent).to.be.false; + done(); + }); + + server.respond(); + }); + + it('must call event handlers', function(done) { + server.respondWith( + 'DELETE', + '/notes/2', + [ + 500, + null, + '' + ] + ); + + var obj = _.extend({}, Backbone.Events); + var beforeCallback = sinon.spy(); + var afterCallback = sinon.spy(); + var note = new FIXTURES.Note({id: 2}); + obj.listenTo(note, 'before:destroy', beforeCallback); + obj.listenTo(note, 'after:destroy', afterCallback); + + note.destroy({test: true, silent:false}) + .then(function(data) { + }) + .catch(function(data) { + expect(beforeCallback.called).to.be.true; + expect(afterCallback.called).to.be.true; + expect(beforeCallback.calledBefore(afterCallback)).to.be.true; + + var dataArg = beforeCallback.args[0][0]; + expect(dataArg).to.be.a('object'); + expect(dataArg).to.have.property('model'); + expect(dataArg).to.have.property('options'); + expect(dataArg.model).to.be.deep.equal(note); + expect(dataArg.options).to.have.property('test'); + expect(dataArg.options).to.have.property('silent'); + expect(dataArg.options.test).to.be.true; + expect(dataArg.options.silent).to.be.false; + + dataArg = afterCallback.args[0][0]; + expect(dataArg).to.be.a('object'); + expect(dataArg).to.have.property('model'); + expect(dataArg).to.have.property('options'); + expect(dataArg).to.have.property('response'); + expect(dataArg.model).to.be.deep.equal(note); + expect(data.response).to.be.a('object'); + expect(data.response).to.have.property('status'); + expect(data.response).to.have.property('statusText'); + expect(data.response.status).to.equal(500); + expect(data.response.statusText).to.equal('Internal Server Error'); + + expect(dataArg.options).to.have.property('test'); + expect(dataArg.options).to.have.property('silent'); + expect(dataArg.options.test).to.be.true; + expect(dataArg.options.silent).to.be.false; + + var success = afterCallback.args[0][1]; + expect(success).to.be.false; + + done(); + }); + + server.respond(); + }); + + it('must not call event handlers', function(done) { + server.respondWith( + 'DELETE', + '/notes/3', + [ + 500, + null, + '' + ] + ); + + var obj = _.extend({}, Backbone.Events); + var beforeCallback = sinon.spy(); + var afterCallback = sinon.spy(); + var note = new FIXTURES.Note({id: 3}); + obj.listenTo(note, 'before:save', beforeCallback); + obj.listenTo(note, 'after:save', afterCallback); + + note.destroy({test: false, silent:true}) + .then(function(data) { + }) + .catch(function(data) { + expect(beforeCallback.called).to.be.false; + expect(afterCallback.called).to.be.false; + done(); + }); + + server.respond(); + }); }); }); \ No newline at end of file