module('Backbone.Mutators'); test("can get 'normal' value", function () { expect(2); var Model = Backbone.Model.extend({ mutators: { fullname: function () { return this.firstname + ' ' + this.lastname; } } }); var model = new Model(); model.set('firstname', 'Sebastian'); model.set('lastname', 'Golasch'); equal(model.get('firstname'), 'Sebastian', 'Can get unmutated firstname'); equal(model.get('lastname'), 'Golasch', 'Can get unmutated lastname'); }); test("can get 'mutated' value (newly created)", function () { expect(3); var Model = Backbone.Model.extend({ mutators: { fullname: function () { return this.get('firstname') + ' ' + this.get('lastname'); } } }); var model = new Model(); model.set('firstname', 'Sebastian'); model.set('lastname', 'Golasch'); equal(model.get('firstname'), 'Sebastian', 'Can get unmutated firstname'); equal(model.get('lastname'), 'Golasch', 'Can get unmutated lastname'); equal(model.get('fullname'), 'Sebastian Golasch', 'Can get mutated fullname'); }); test("can get 'mutated' value (overridden)", function () { expect(5); var Model = Backbone.Model.extend({ mutators: { status: function (key, value, options, set) { if(key){ set('status', value); } return { status: this.attributes.status, overallStatus: this.get('overallStatus'), underestimatedNonOverallStatus: this.get('underestimatedNonOverallStatus') }; } } }); var model = new Model(); model.set('overallStatus', 1); model.set('underestimatedNonOverallStatus', 3); model.set('status', 2); equal(model.get('overallStatus'), 1, 'Can get unmutated overallStatus'); equal(model.get('underestimatedNonOverallStatus'), 3, 'Can get unmutated underestimatedNonOverallStatus'); equal(model.get('status').status, 2, 'Can get mutated status'); equal(model.get('status').overallStatus, 1, 'Can get mutated status'); equal(model.get('status').underestimatedNonOverallStatus, 3, 'Can get mutated status'); }); test("can get 'normal' value - object context", function () { expect(2); var Model = Backbone.Model.extend({ mutators: { fullanme: { get: function () { return this.get('firstname') + ' ' + this.get('lastname'); } } } }); var model = new Model(); model.set('firstname', 'Sebastian'); model.set('lastname', 'Golasch'); equal(model.get('firstname'), 'Sebastian', 'Can get unmutated firstname'); equal(model.get('lastname'), 'Golasch', 'Can get unmutated lastname'); }); test("can get 'mutated' value (newly created) - object context", function () { expect(3); var Model = Backbone.Model.extend({ mutators: { fullname: { get: function () { return this.get('firstname') + ' ' + this.get('lastname'); } } } }); var model = new Model(); model.set('firstname', 'Sebastian'); model.set('lastname', 'Golasch'); equal(model.get('firstname'), 'Sebastian', 'Can get unmutated firstname'); equal(model.get('lastname'), 'Golasch', 'Can get unmutated lastname'); equal(model.get('fullname'), 'Sebastian Golasch', 'Can get mutated fullname'); }); test("can get 'mutated' value (overridden) - object context", function () { expect(5); var Model = Backbone.Model.extend({ mutators: { status: { get: function () { return { status: this.attributes.status, overallStatus: this.get('overallStatus'), underestimatedNonOverallStatus: this.get('underestimatedNonOverallStatus') }; } } } }); var model = new Model(); model.set('overallStatus', 1); model.set('underestimatedNonOverallStatus', 3); model.set('status', 2); equal(model.get('overallStatus'), 1, 'Can get unmutated overallStatus'); equal(model.get('underestimatedNonOverallStatus'), 3, 'Can get unmutated underestimatedNonOverallStatus'); equal(model.get('status').status, 2, 'Can get mutated status'); equal(model.get('status').overallStatus, 1, 'Can get mutated status'); equal(model.get('status').underestimatedNonOverallStatus, 3, 'Can get mutated status'); }); test("can set 'normal' value (key <-> value)", function () { expect(1); var Model = Backbone.Model.extend({ mutators: { status: { set: function () { return { status: this.attributes.status, overallStatus: this.get('overallStatus'), underestimatedNonOverallStatus: this.get('underestimatedNonOverallStatus') }; } } } }); var model = new Model(); model.set('overallStatus', 1); equal(model.get('overallStatus'), 1, 'Can get unmutated overallStatus'); }); test("can set 'mutated' value (key <-> value)", function () { expect(2); var Model = Backbone.Model.extend({ mutators: { status: { set: function (key, value, options) { this.set('pState', value.pState, options); this.set('aState', value.aState, options); } } } }); var model = new Model(); model.set('status', {pState: 1, aState: 2}); equal(model.get('pState'), 1, 'Can get mutated pState'); equal(model.get('aState'), 2, 'Can get mutated aState'); }); test("can set 'normal' value (object)", function () { expect(1); var Model = Backbone.Model.extend({ mutators: { status: { set: function () { return { status: this.attributes.status, overallStatus: this.get('overallStatus'), underestimatedNonOverallStatus: this.get('underestimatedNonOverallStatus') }; } } } }); var model = new Model(); model.set({overallStatus: 1}); equal(model.get('overallStatus'), 1, 'Can get unmutated overallStatus'); }); test("can set attribute objects", function () { expect(3); var Model = Backbone.Model.extend({ mutators: { fullname: { set: function (key, value, options) { var names = value.split(' '); this.set('firstname', names[0], options); this.set('lastname', names[1], options); } } } }); var model = new Model(); model.set({ fullname: 'Sebastian Golasch', admin: true }); equal(model.get('firstname'), 'Sebastian', 'Can get the firstname'); equal(model.get('lastname'), 'Golasch', 'Can get the lastname'); equal(model.get('admin'), true, 'Can get the admin status'); }); test("can set newly created 'mutated' value (object)", function () { expect(2); var Model = Backbone.Model.extend({ mutators: { status: { set: function (key, value, options) { this.set('pState', value.pState, options); this.set('aState', value.aState, options); } } } }); var model = new Model(); model.set({status: {pState: 1, aState: 2, dState: 3}}); equal(model.get('pState'), 1, 'Can get mutated pState'); equal(model.get('aState'), 2, 'Can get mutated aState'); }); test("can set 'mutated' value (object)", function () { expect(4); var Model = Backbone.Model.extend({ mutators: { status: { set: function (key, value, options, set) { if(_.isString(value)){ set(key, value); } else { this.set('pState', value.pState, options); this.set('aState', value.aState, options); if (value.pState === 1) { set(key, 'supercool', options); } } } } }, defaults: { status: 'awkward' } }); var model = new Model(); equal(model.get('status'), 'awkward', 'Can get unmodified value'); model.set({status: {pState: 1, aState: 2, dState: 3}}); equal(model.get('status'), 'supercool', 'Can get mutated status value'); equal(model.get('pState'), 1, 'Can get mutated pState'); equal(model.get('aState'), 2, 'Can get mutated aState'); }); test("can set 'mutated' value and fire event", function () { expect(3); var Model = Backbone.Model.extend({ mutators: { status: { set: function (key, value, options, set) { set(key, value.toLowerCase(), options); } } }, defaults: { status: 'awkward' } }); var model = new Model(); model.bind('mutators:set:status', function () { ok(true, 'Callback called'); }); equal(model.get('status'), 'awkward', 'Can get unmodified value'); model.set({status: 'SUPERCOOL'}); equal(model.get('status'), 'supercool', 'Can get mutated status value'); }); test("can set 'mutated' value and fire event", function () { expect(2); var Model = Backbone.Model.extend({ mutators: { status: { set: function (key, value, options, set) { set(key, value.toLowerCase(), options); } } }, defaults: { status: 'awkward' } }); var model = new Model(); model.bind('mutators:set:status', function () { ok(true, 'Callback called (And this shouldn´t happen)'); }); equal(model.get('status'), 'awkward', 'Can get unmodified value'); model.set('status', 'SUPERCOOL', {silent: true}); equal(model.get('status'), 'supercool', 'Can get mutated status value'); }); test("can set 'mutated' value and fire event", function () { expect(4); var Model = Backbone.Model.extend({ mutators: { status: { set: function (key, value, options, set) { set(key, value.toLowerCase(), options); } } }, defaults: { status: 'awkward' } }); var model = new Model(); model.bind('mutators:set:status', function () { ok(true, 'Callback called (And this shouldn´t happen)'); }); model.bind('change:status', function () { ok(true, 'Callback called (And this should happen)'); }); equal(model.get('status'), 'awkward', 'Can get unmodified value'); model.set('status', 'SUPERCOOL', {mutators: {silent: true}}); equal(model.get('status'), 'supercool', 'Can get mutated status value'); }); test("can serialize an unmutated model", function () { expect(2); var Model = Backbone.Model.extend({ defaults: { a: 'a', b: 'b' } }); equal((new Model()).toJSON().a, 'a', 'can serialize unmutated model'); equal((new Model()).toJSON().b, 'b', 'can serialize unmutated model'); }); test("can serialize mutated model", function () { expect(3); var Model = Backbone.Model.extend({ defaults: { a: 'a', b: 'b' }, mutators: { state: function () { return this.get('a') + ', ' + this.get('b'); } } }); equal((new Model()).toJSON().a, 'a', 'can serialize mutated model'); equal((new Model()).get('state'), 'a, b', 'can serialize mutated model'); equal((new Model()).toJSON().state, 'a, b', 'can serialize mutated model'); }); test("can serialize mutated model with only a setter", function () { expect(2); var Model = Backbone.Model.extend({ mutators: { status: { set: function (key, value, options, set) { set(key, value.toLowerCase(), options); } } }, defaults: { status: 'awkward' } }); var model = new Model(); equal(model.toJSON().status, 'awkward', 'can serialize mutated model'); model.set('status', 'SUPERCOOL', {mutators: {silent: true}}); equal(model.toJSON().status, 'supercool', 'can serialize mutated model'); }); test("can escape mutated properties", function () { expect(2); var Model = Backbone.Model.extend({ defaults: { a: 'a', b: 'b' }, mutators: { b: function () { return 'c'; } } }); var model = new Model(); equal(model.get('b'), 'c'); model.set('b', 'foobar'); equal(model.get('b'), 'c'); }); test("can get/set using single method", 6, function(){ var Model = Backbone.Model.extend({ mutators:{ state:function(key, value){ if(key){ this.set("a", value); equal(arguments.length, 4); return null; //prevents ret from returning } return this.get("a"); } } }); var model = new Model(); var value = "happy"; model.set('state', value); equal(model.get('state'), value); var new_state = "excited", new_level = 10; //set multiple model.set({ level:new_level, state:new_state }); equal(model.get('state'), new_state); equal(model.get('level'), new_level); }); test("can omit transient variables from JSON when saving", 4, function() { var Model = Backbone.Model.extend({ defaults:{ firstName:"Iain", middleInit:"M", lastName:"Banks" }, mutators:{ fullName:{ get: function() { var fullName = this.get("firstName"); fullName += " " + this.get("middleInit"); fullName += ". " + this.get("lastName"); return fullName; }, transient: true } } }); var model = new Model(); // First make sure we didn't break the accessor (or the normal model property // access) equal(model.get("fullName"), "Iain M. Banks"); equal(model.get("firstName"), "Iain"); // Ensure that a normal toJSON call (like you'd use with a template) includes // the computed value var modelToJSON = model.toJSON(); equal(modelToJSON.fullName, "Iain M. Banks"); // Backbone always sets 'emulateHTTP' to true or (usually) false when syncing, // so we use the existence of that property as a proxy for "yes I'm syncing" var modelToJSONSync = model.toJSON({emulateHTTP:false}); equal(typeof modelToJSONSync.fullName, "undefined"); });