/components/backbone-relational/test/tests.js
JavaScript | 1762 lines | 1340 code | 353 blank | 69 comment | 22 complexity | 18066a3bec51f8efed44fd14e289da04 MD5 | raw file
- /* vim: set tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab: */
- // documentation on writing tests here: http://docs.jquery.com/QUnit
- // example tests: https://github.com/jquery/qunit/blob/master/test/same.js
- // more examples: https://github.com/jquery/jquery/tree/master/test/unit
- // jQueryUI examples: https://github.com/jquery/jquery-ui/tree/master/tests/unit
- //sessionStorage.clear();
- if ( !window.console ) {
- var names = [ 'log', 'debug', 'info', 'warn', 'error', 'assert', 'dir', 'dirxml',
- 'group', 'groupEnd', 'time', 'timeEnd', 'count', 'trace', 'profile', 'profileEnd' ];
- window.console = {};
- for ( var i = 0; i < names.length; ++i )
- window.console[ names[i] ] = function() {};
- }
- $(document).ready(function() {
- $.ajax = function( obj ) {
- window.requests.push( obj );
- return obj;
- };
-
- Backbone.Model.prototype.url = function() {
- // Use the 'resource_uri' if possible
- var url = this.get( 'resource_uri' );
-
- // Try to have the collection construct a url
- if ( !url && this.collection ) {
- url = this.collection.url && _.isFunction( this.collection.url ) ? this.collection.url() : this.collection.url;
- }
-
- // Fallback to 'urlRoot'
- if ( !url && this.urlRoot ) {
- url = this.urlRoot + this.id;
- }
-
- if ( !url ) {
- throw new Error( 'Url could not be determined!' );
- }
-
- return url;
- };
- /**
- * 'Zoo'
- */
- window.Zoo = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasMany,
- key: 'animals',
- relatedModel: 'Animal',
- includeInJSON: [ 'id', 'species' ],
- collectionType: 'AnimalCollection',
- collectionOptions: function( instance ) { return { 'url': 'zoo/' + instance.cid + '/animal/' } },
- reverseRelation: {
- key: 'livesIn',
- includeInJSON: 'id'
- }
- },
- { // A simple HasMany without recursive relation
- type: Backbone.HasMany,
- key: 'visitors',
- relatedModel: 'Visitor'
- }
- ],
- toString: function() {
- return 'Zoo (' + this.id + ')';
- }
- });
- window.Animal = Backbone.RelationalModel.extend({
- urlRoot: '/animal/',
-
- // For validation testing. Wikipedia says elephants are reported up to 12.000 kg. Any more, we must've weighted wrong ;).
- validate: function( attrs ) {
- if ( attrs.species === 'elephant' && attrs.weight && attrs.weight > 12000 ) {
- return "Too heavy.";
- }
- },
- toString: function() {
- return 'Animal (' + this.id + ')';
- }
- });
- window.AnimalCollection = Backbone.Collection.extend({
- model: Animal,
-
- initialize: function( models, options ) {
- options || (options = {});
- this.url = options.url;
- }
- });
- window.Visitor = Backbone.RelationalModel.extend();
- /**
- * House/Person/Job/Company
- */
- window.House = Backbone.RelationalModel.extend({
- relations: [{
- type: Backbone.HasMany,
- key: 'occupants',
- relatedModel: 'Person',
- reverseRelation: {
- key: 'livesIn',
- includeInJSON: false
- }
- }],
- toString: function() {
- return 'House (' + this.id + ')';
- }
- });
- window.User = Backbone.RelationalModel.extend({
- urlRoot: '/user/',
- toString: function() {
- return 'User (' + this.id + ')';
- }
- });
- window.Person = Backbone.RelationalModel.extend({
- relations: [
- {
- // Create a cozy, recursive, one-to-one relationship
- type: Backbone.HasOne,
- key: 'likesALot',
- relatedModel: 'Person',
- reverseRelation: {
- type: Backbone.HasOne,
- key: 'likedALotBy'
- }
- },
- {
- type: Backbone.HasOne,
- key: 'user',
- keyDestination: 'user_id',
- relatedModel: 'User',
- includeInJSON: Backbone.Model.prototype.idAttribute,
- reverseRelation: {
- type: Backbone.HasOne,
- includeInJSON: 'name',
- key: 'person'
- }
- },
- {
- type: 'HasMany',
- key: 'jobs',
- relatedModel: 'Job',
- reverseRelation: {
- key: 'person'
- }
- }
- ],
- toString: function() {
- return 'Person (' + this.id + ')';
- }
- });
- window.PersonCollection = Backbone.Collection.extend({
- model: Person
- });
- window.Password = Backbone.RelationalModel.extend({
- relations: [{
- type: Backbone.HasOne,
- key: 'user',
- relatedModel: 'User',
- reverseRelation: {
- type: Backbone.HasOne,
- key: 'password'
- }
- }]
- });
-
- // A link table between 'Person' and 'Company', to achieve many-to-many relations
- window.Job = Backbone.RelationalModel.extend({
- defaults: {
- 'startDate': null,
- 'endDate': null
- },
- toString: function() {
- return 'Job (' + this.id + ')';
- }
- });
- window.Company = Backbone.RelationalModel.extend({
- relations: [{
- type: 'HasMany',
- key: 'employees',
- relatedModel: 'Job',
- reverseRelation: {
- key: 'company'
- }
- },
- {
- type: 'HasOne',
- key: 'ceo',
- relatedModel: 'Person',
- reverseRelation: {
- key: 'runs'
- }
- }
- ],
- toString: function() {
- return 'Company (' + this.id + ')';
- }
- });
- window.CompanyCollection = Backbone.Collection.extend({
- model: Company
- });
- window.Node = Backbone.RelationalModel.extend({
- urlRoot: '/node/',
- relations: [{
- type: Backbone.HasOne,
- key: 'parent',
- relatedModel: 'Node',
- reverseRelation: {
- key: 'children'
- }
- }
- ],
- toString: function() {
- return 'Node (' + this.id + ')';
- }
- });
- window.NodeList = Backbone.Collection.extend({
- model: Node
- });
- window.Customer = Backbone.RelationalModel.extend({
- urlRoot: '/customer/',
- toString: function() {
- return 'Customer (' + this.id + ')';
- }
- });
- window.Address = Backbone.RelationalModel.extend({
- urlRoot: '/address/',
- toString: function() {
- return 'Address (' + this.id + ')';
- }
- });
- window.Shop = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasMany,
- key: 'customers',
- relatedModel: 'Customer',
- autoFetch: true
- },
- {
- type: Backbone.HasOne,
- key: 'address',
- relatedModel: 'Address',
- autoFetch: {
- success: function(model, response){
- response.successOK = true;
- },
- error: function(model, response){
- response.errorOK = true;
- }
- }
- }
- ],
- toString: function() {
- return 'Shop (' + this.id + ')';
- }
- });
- window.Agent = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasMany,
- key: 'customers',
- relatedModel: 'Customer'
- },
- {
- type: Backbone.HasOne,
- key: 'address',
- relatedModel: 'Address',
- autoFetch: false
- }
- ],
- toString: function() {
- return 'Agent (' + this.id + ')';
- }
- });
- /**
- * Reset variables that are persistent across tests, specifically `window.requests` and the state of
- * `Backbone.Relational.store`.
- */
- function reset() {
- // Reset last ajax requests
- window.requests = [];
- // save _reverseRelations, otherwise we'll get a lot of warnings about existing relations
- var oldReverseRelations = Backbone.Relational.store._reverseRelations;
- Backbone.Relational.store = new Backbone.Store();
- Backbone.Relational.store._reverseRelations = oldReverseRelations;
- Backbone.Relational.eventQueue = new Backbone.BlockingQueue();
- }
- /**
- * Initialize a few models that are used in a large number of tests
- */
- function initObjects() {
- reset();
- window.person1 = new Person({
- id: 'person-1',
- name: 'boy',
- likesALot: 'person-2',
- resource_uri: 'person-1',
- user: { id: 'user-1', login: 'dude', email: 'me@gmail.com', resource_uri: 'user-1' }
- });
- window.person2 = new Person({
- id: 'person-2',
- name: 'girl',
- likesALot: 'person-1',
- resource_uri: 'person-2'
- });
- window.person3 = new Person({
- id: 'person-3',
- resource_uri: 'person-3'
- });
- window.oldCompany = new Company({
- id: 'company-1',
- name: 'Big Corp.',
- ceo: {
- name: 'Big Boy'
- },
- employees: [ { person: 'person-3' } ], // uses the 'Job' link table to achieve many-to-many. No 'id' specified!
- resource_uri: 'company-1'
- });
- window.newCompany = new Company({
- id: 'company-2',
- name: 'New Corp.',
- employees: [ { person: 'person-2' } ],
- resource_uri: 'company-2'
- });
- window.ourHouse = new House({
- id: 'house-1',
- location: 'in the middle of the street',
- occupants: ['person-2'],
- resource_uri: 'house-1'
- });
- window.theirHouse = new House({
- id: 'house-2',
- location: 'outside of town',
- occupants: [],
- resource_uri: 'house-2'
- });
- }
-
-
- module( "Backbone.Semaphore", { setup: reset } );
-
-
- test( "Unbounded", function() {
- expect( 10 );
-
- var semaphore = _.extend( {}, Backbone.Semaphore );
- ok( !semaphore.isLocked(), 'Semaphore is not locked initially' );
- semaphore.acquire();
- ok( semaphore.isLocked(), 'Semaphore is locked after acquire' );
- semaphore.acquire();
- equal( semaphore._permitsUsed, 2 ,'_permitsUsed should be incremented 2 times' );
-
- semaphore.setAvailablePermits( 4 );
- equal( semaphore._permitsAvailable, 4 ,'_permitsAvailable should be 4' );
-
- semaphore.acquire();
- semaphore.acquire();
- equal( semaphore._permitsUsed, 4 ,'_permitsUsed should be incremented 4 times' );
-
- try {
- semaphore.acquire();
- }
- catch( ex ) {
- ok( true, 'Error thrown when attempting to acquire too often' );
- }
-
- semaphore.release();
- equal( semaphore._permitsUsed, 3 ,'_permitsUsed should be decremented to 3' );
-
- semaphore.release();
- semaphore.release();
- semaphore.release();
- equal( semaphore._permitsUsed, 0 ,'_permitsUsed should be decremented to 0' );
- ok( !semaphore.isLocked(), 'Semaphore is not locked when all permits are released' );
-
- try {
- semaphore.release();
- }
- catch( ex ) {
- ok( true, 'Error thrown when attempting to release too often' );
- }
- });
-
-
- module( "Backbone.BlockingQueue", { setup: reset } );
-
-
- test( "Block", function() {
- var queue = new Backbone.BlockingQueue();
- var count = 0;
- var increment = function() { count++; };
- var decrement = function() { count--; };
-
- queue.add( increment );
- ok( count === 1, 'Increment executed right away' );
-
- queue.add( decrement );
- ok( count === 0, 'Decrement executed right away' );
-
- queue.block();
- queue.add( increment );
-
- ok( queue.isLocked(), 'Queue is blocked' );
- equal( count, 0, 'Increment did not execute right away' );
-
- queue.block();
- queue.block();
-
- equal( queue._permitsUsed, 3 ,'_permitsUsed should be incremented to 3' );
-
- queue.unblock();
- queue.unblock();
- queue.unblock();
-
- equal( count, 1, 'Increment executed' );
- });
-
-
- module( "Backbone.Store", { setup: initObjects } );
-
-
- test( "Initialized", function() {
- // `initObjects` instantiates models of the following types: `Person`, `Job`, `Company`, `User`, `House` and `Password`
- equal( Backbone.Relational.store._collections.length, 6, "Store contains 6 collections" );
- });
-
- test( "getObjectByName", function() {
- equal( Backbone.Relational.store.getObjectByName( 'Backbone.RelationalModel' ), Backbone.RelationalModel );
- });
-
- test( "Add and remove from store", function() {
- var coll = Backbone.Relational.store.getCollection( person1 );
- var length = coll.length;
-
- var person = new Person({
- id: 'person-10',
- name: 'Remi',
- resource_uri: 'person-10'
- });
-
- ok( coll.length === length + 1, "Collection size increased by 1" );
-
- var request = person.destroy();
- // Trigger the 'success' callback to fire the 'destroy' event
- request.success();
-
- ok( coll.length === length, "Collection size decreased by 1" );
- });
- test( "addModelScope", function() {
- var models = {};
- Backbone.Relational.store.addModelScope( models );
- models.Book = Backbone.RelationalModel.extend({
- relations: [{
- type: Backbone.HasMany,
- key: 'pages',
- relatedModel: 'Page',
- createModels: false,
- reverseRelation: {
- key: 'book'
- }
- }]
- });
- models.Page = Backbone.RelationalModel.extend();
- var book = new models.Book();
- var page = new models.Page({ book: book });
- ok( book.relations.length === 1 );
- ok( book.get( 'pages' ).length === 1 );
- });
- test( "addModelScope with submodels and namespaces", function() {
- var ns = {};
- ns.People = {};
- Backbone.Relational.store.addModelScope( ns );
- ns.People.Person = Backbone.RelationalModel.extend({
- subModelTypes: {
- 'Student': 'People.Student'
- },
- iam: function() { return "I am an abstract person"; }
- });
- ns.People.Student = ns.People.Person.extend({
- iam: function() { return "I am a student"; }
- });
- ns.People.PersonCollection = Backbone.Collection.extend({
- model: ns.People.Person
- });
- var people = new ns.People.PersonCollection([{name: "Bob", type: "Student"}]);
- ok( people.at(0).iam() == "I am a student" );
- });
-
- test( "Models are created from objects, can then be found, destroyed, cannot be found anymore", function() {
- var houseId = 'house-10';
- var personId = 'person-10';
-
- var anotherHouse = new House({
- id: houseId,
- location: 'no country for old men',
- resource_uri: houseId,
- occupants: [{
- id: personId,
- name: 'Remi',
- resource_uri: personId
- }]
- });
-
- ok( anotherHouse.get('occupants') instanceof Backbone.Collection, "Occupants is a Collection" );
- ok( anotherHouse.get('occupants').get( personId ) instanceof Person, "Occupants contains the Person with id='" + personId + "'" );
-
- var person = Backbone.Relational.store.find( Person, personId );
-
- ok( person, "Person with id=" + personId + " is found in the store" );
-
- var request = person.destroy();
- // Trigger the 'success' callback to fire the 'destroy' event
- request.success();
-
- person = Backbone.Relational.store.find( Person, personId );
-
- ok( !person, personId + " is not found in the store anymore" );
- ok( !anotherHouse.get('occupants').get( personId ), "Occupants no longer contains the Person with id='" + personId + "'" );
-
- request = anotherHouse.destroy();
- // Trigger the 'success' callback to fire the 'destroy' event
- request.success();
-
- var house = Backbone.Relational.store.find( House, houseId );
-
- ok( !house, houseId + " is not found in the store anymore" );
- });
-
-
- test( "Model.collection is the first collection a Model is added to by an end-user (not it's Backbone.Store collection!)", function() {
- var person = new Person( { name: 'New guy' } );
- var personColl = new PersonCollection();
- personColl.add( person );
- ok( person.collection === personColl );
- });
-
- test( "All models can be found after adding them to a Collection via 'Collection.reset'", function() {
- var nodes = [
- { id: 1, parent: null },
- { id: 2, parent: 1 },
- { id: 3, parent: 4 },
- { id: 4, parent: 1 }
- ];
-
- var nodeList = new NodeList();
- nodeList.reset( nodes );
-
- var storeColl = Backbone.Relational.store.getCollection( Node );
- equal( storeColl.length, 4, "Every Node is in Backbone.Relational.store" );
- ok( Backbone.Relational.store.find( Node, 1 ) instanceof Node, "Node 1 can be found" );
- ok( Backbone.Relational.store.find( Node, 2 ) instanceof Node, "Node 2 can be found" );
- ok( Backbone.Relational.store.find( Node, 3 ) instanceof Node, "Node 3 can be found" );
- ok( Backbone.Relational.store.find( Node, 4 ) instanceof Node, "Node 4 can be found" );
- });
-
- test( "Inheritance creates and uses a separate collection", function() {
- var whale = new Animal( { id: 1, species: 'whale' } );
- ok( Backbone.Relational.store.find( Animal, 1 ) === whale );
-
- var numCollections = Backbone.Relational.store._collections.length;
-
- var Mammal = Animal.extend({
- urlRoot: '/mammal/'
- });
-
- var lion = new Mammal( { id: 1, species: 'lion' } );
- var donkey = new Mammal( { id: 2, species: 'donkey' } );
-
- equal( Backbone.Relational.store._collections.length, numCollections + 1 );
- ok( Backbone.Relational.store.find( Animal, 1 ) === whale );
- ok( Backbone.Relational.store.find( Mammal, 1 ) === lion );
- ok( Backbone.Relational.store.find( Mammal, 2 ) === donkey );
-
- var Primate = Mammal.extend({
- urlRoot: '/primate/'
- });
-
- var gorilla = new Primate( { id: 1, species: 'gorilla' } );
-
- equal( Backbone.Relational.store._collections.length, numCollections + 2 );
- ok( Backbone.Relational.store.find( Primate, 1 ) === gorilla );
- });
-
- test( "Inheritance with `subModelTypes` uses the same collection as the model's super", function() {
- var Mammal = Animal.extend({
- subModelTypes: {
- 'primate': 'Primate',
- 'carnivore': 'Carnivore'
- }
- });
- window.Primate = Mammal.extend();
- window.Carnivore = Mammal.extend();
- var lion = new Carnivore( { id: 1, species: 'lion' } );
- var wolf = new Carnivore( { id: 2, species: 'wolf' } );
- var numCollections = Backbone.Relational.store._collections.length;
- var whale = new Mammal( { id: 3, species: 'whale' } );
- equal( Backbone.Relational.store._collections.length, numCollections, "`_collections` should have remained the same" );
- ok( Backbone.Relational.store.find( Mammal, 1 ) === lion );
- ok( Backbone.Relational.store.find( Mammal, 2 ) === wolf );
- ok( Backbone.Relational.store.find( Mammal, 3 ) === whale );
- ok( Backbone.Relational.store.find( Carnivore, 1 ) === lion );
- ok( Backbone.Relational.store.find( Carnivore, 2 ) === wolf );
- ok( Backbone.Relational.store.find( Carnivore, 3 ) !== whale );
- var gorilla = new Primate( { id: 4, species: 'gorilla' } );
- equal( Backbone.Relational.store._collections.length, numCollections, "`_collections` should have remained the same" );
- ok( Backbone.Relational.store.find( Animal, 4 ) !== gorilla );
- ok( Backbone.Relational.store.find( Mammal, 4 ) === gorilla );
- ok( Backbone.Relational.store.find( Primate, 4 ) === gorilla );
- delete window.Primate;
- delete window.Carnivore;
- });
-
-
- module( "Backbone.RelationalModel", { setup: initObjects } );
-
-
- test( "Return values: set returns the Model", function() {
- var personId = 'person-10';
- var person = new Person({
- id: personId,
- name: 'Remi',
- resource_uri: personId
- });
-
- var result = person.set( { 'name': 'Hector' } );
- ok( result === person, "Set returns the model" );
- });
-
- test( "getRelations", function() {
- equal( person1.getRelations().length, 6 );
- });
-
- test( "getRelation", function() {
- var rel = person1.getRelation( 'user' );
- equal( rel.key, 'user' );
- });
-
- test( "fetchRelated on a HasOne relation", function() {
- var errorCount = 0;
- var person = new Person({
- id: 'person-10',
- resource_uri: 'person-10',
- user: 'user-10'
- });
-
- var requests = person.fetchRelated( 'user', { error: function() {
- errorCount++;
- }
- });
-
- ok( _.isArray( requests ) );
- equal( requests.length, 1, "A request has been made" );
- ok( person.get( 'user' ) instanceof User );
-
- // Triggering the 'error' callback should destroy the model
- requests[ 0 ].error();
- // Trigger the 'success' callback to fire the 'destroy' event
- window.requests[ window.requests.length - 1 ].success();
- equal( person.get( 'user' ), null, "User has been destroyed & removed" );
- equal( errorCount, 1, "The error callback executed successfully" );
-
- var person2 = new Person({
- id: 'person-11',
- resource_uri: 'person-11'
- });
-
- requests = person2.fetchRelated( 'user' );
- equal( requests.length, 0, "No request was made" );
- });
-
- test( "fetchRelated on a HasMany relation", function() {
- var errorCount = 0;
- var zoo = new Zoo({
- animals: [ 'lion-1', 'zebra-1' ]
- });
-
- //
- // Case 1: separate requests for each model
- //
- var requests = zoo.fetchRelated( 'animals', { error: function() { errorCount++; } } );
- ok( _.isArray( requests ) );
- equal( requests.length, 2, "Two requests have been made (a separate one for each animal)" );
- equal( zoo.get( 'animals' ).length, 2, "Two animals in the zoo" );
-
- // Triggering the 'error' callback for either request should destroy the model
- requests[ 0 ].error();
- // Trigger the 'success' callback to fire the 'destroy' event
- window.requests[ window.requests.length - 1 ].success();
-
- equal( zoo.get( 'animals' ).length, 1, "One animal left in the zoo" );
- equal( errorCount, 1, "The error callback executed successfully" );
-
- //
- // Case 2: one request per fetch (generated by the collection)
- //
- // Give 'zoo' a custom url function that builds a url to fetch a set of models from their ids
- errorCount = 0;
- zoo.get( 'animals' ).url = function( models ) {
- return '/animal/' + ( models ? 'set/' + _.pluck( models, 'id' ).join(';') + '/' : '' );
- };
-
- // Set two new animals to be fetched; both should be fetched in a single request
- zoo.set( { animals: [ 'lion-2', 'zebra-2' ] } );
-
- equal( zoo.get( 'animals' ).length, 0 );
-
- requests = zoo.fetchRelated( 'animals', { error: function() { errorCount++; } } );
-
- ok( _.isArray( requests ) );
- equal( requests.length, 1 );
- ok( requests[ 0 ].url === '/animal/set/lion-2;zebra-2/' );
- equal( zoo.get('animals').length, 2 );
-
- // Triggering the 'error' callback (some error occured during fetching) should trigger the 'destroy' event
- // on both fetched models, but should NOT actually make 'delete' requests to the server!
- var numRequests = window.requests.length;
- requests[ 0 ].error();
- ok( window.requests.length === numRequests, "An error occured when fetching, but no DELETE requests are made to the server while handling local cleanup." );
-
- equal( zoo.get( 'animals' ).length, 0, "Both animals are destroyed" );
- equal( errorCount, 2, "The error callback executed successfully for both models" );
-
- // Re-fetch them
- requests = zoo.fetchRelated( 'animals' );
-
- equal( requests.length, 1 );
- equal( zoo.get( 'animals' ).length, 2 );
-
- // No more animals to fetch!
- requests = zoo.fetchRelated( 'animals' );
-
- ok( _.isArray( requests ) );
- equal( requests.length, 0 );
- equal( zoo.get( 'animals' ).length, 2 );
- });
- test( "autoFetch a HasMany relation", function() {
- var shopOne = new Shop({
- id: 'shop-1',
- customers: ['customer-1', 'customer-2']
- });
- equal( requests.length, 2, "Two requests to fetch the users has been made" );
- requests.length = 0;
- var shopTwo = new Shop({
- id: 'shop-2',
- customers: ['customer-1', 'customer-3']
- });
- equal( requests.length, 1, "A request to fetch a user has been made" ); //as customer-1 has already been fetched
- });
- test( "autoFetch on a HasOne relation (with callbacks)", function() {
- var shopThree = new Shop({
- id: 'shop-3',
- address: 'address-3'
- });
- equal( requests.length, 1, "A request to fetch the address has been made" );
-
- var res = { successOK: false, errorOK: false };
-
- requests[0].success( res );
- equal( res.successOK, true, "The success() callback has been called" );
- requests.length = 0;
- var shopFour = new Shop({
- id: 'shop-4',
- address: 'address-4'
- });
- equal( requests.length, 1, "A request to fetch the address has been made" );
- requests[0].error( res );
- equal( res.errorOK, true, "The error() callback has been called" );
- });
- test( "autoFetch false by default", function() {
- var agentOne = new Agent({
- id: 'agent-1',
- customers: ['customer-4', 'customer-5']
- });
- equal( requests.length, 0, "No requests to fetch the customers has been made as autoFetch was not defined" );
- var agentOne = new Agent({
- id: 'agent-2',
- address: 'address-5'
- });
- equal( requests.length, 0, "No requests to fetch the customers has been made as autoFetch was set to false" );
- });
- test( "clone", function() {
- var user = person1.get( 'user' );
- // HasOne relations should stay with the original model
- var newPerson = person1.clone();
- ok( newPerson.get( 'user' ) === null );
- ok( person1.get( 'user' ) === user );
- });
-
- test( "toJSON", function() {
- var node = new Node({ id: '1', parent: '3', name: 'First node' });
- new Node({ id: '2', parent: '1', name: 'Second node' });
- new Node({ id: '3', parent: '2', name: 'Third node' });
-
- var json = node.toJSON();
- ok( json.children.length === 1 );
- });
- test( "constructor.findOrCreate", function() {
- var personColl = Backbone.Relational.store.getCollection( person1 ),
- origPersonCollSize = personColl.length;
- // Just find an existing model
- var person = Person.findOrCreate( person1.id );
- ok( person === person1 );
- ok( origPersonCollSize === personColl.length, "Existing person was found (none created)" );
- // Update an existing model
- person = Person.findOrCreate( { id: person1.id, name: 'dude' } );
- equal( person.get( 'name' ), 'dude' );
- equal( person1.get( 'name' ), 'dude' );
- ok( origPersonCollSize === personColl.length, "Existing person was updated (none created)" );
- // Look for a non-existent person; 'options.create' is false
- person = Person.findOrCreate( { id: 5001 }, { create: false } );
- ok( !person );
- ok( origPersonCollSize === personColl.length, "No person was found (none created)" );
- // Create a new model
- person = Person.findOrCreate( { id: 5001 } );
- ok( person instanceof Person );
- ok( origPersonCollSize + 1 === personColl.length, "No person was found (1 created)" );
- // Find when options.update is false
- person = Person.findOrCreate( { id: person1.id, name: 'phil' }, { update: false } );
- equal( person.get( 'name' ), 'dude' );
- equal( person1.get( 'name' ), 'dude' );
- });
- test( "change events in relation can use changedAttributes properly", function() {
- var scope = {};
- Backbone.Relational.store.addModelScope( scope );
- scope.PetAnimal = Backbone.RelationalModel.extend({
- subModelTypes: {
- 'cat': 'Cat',
- 'dog': 'Dog'
- }
- });
- scope.Dog = scope.PetAnimal.extend();
- scope.Cat = scope.PetAnimal.extend();
- scope.PetOwner = Backbone.RelationalModel.extend({
- relations: [{
- type: Backbone.HasMany,
- key: 'pets',
- relatedModel: scope.PetAnimal,
- reverseRelation: {
- key: 'owner'
- }
- }]
- });
- var owner = new scope.PetOwner( { id: 'owner-2354' } );
- var animal = new scope.Dog( { type: 'dog', id: '238902', color: 'blue' } );
- equal( animal.get('color'), 'blue', 'animal starts out blue' );
- var changes = 0, changedAttrs;
- animal.on('change', function(model, options) {
- changes++;
- changedAttrs = model.changedAttributes();
- });
- animal.set( { color: 'green' } );
- equal( changes, 1, 'change event gets called after animal.set' );
- equal( changedAttrs.color, 'green', '... with correct properties in "changedAttributes"' );
- owner.set(owner.parse({
- id: 'owner-2354',
- pets: [ { id: '238902', type: 'dog', color: 'red' } ]
- }));
- equal( animal.get('color'), 'red', 'color gets updated properly' );
- equal( changes, 2, 'change event gets called after owner.set' );
- equal( changedAttrs.color, 'red', '... with correct properties in "changedAttributes"' );
- });
-
- module( "Backbone.RelationalModel inheritance (`subModelTypes`)", { setup: reset } );
- test( "Object building based on type, when using explicit collections" , function() {
- var scope = {};
- Backbone.Relational.store.addModelScope( scope );
- scope.Mammal = Animal.extend({
- subModelTypes: {
- 'primate': 'Primate',
- 'carnivore': 'Carnivore'
- }
- });
- scope.Primate = scope.Mammal.extend();
- scope.Carnivore = scope.Mammal.extend();
- var MammalCollection = AnimalCollection.extend({
- model: scope.Mammal
- });
- var mammals = new MammalCollection( [
- { id: 5, species: 'chimp', type: 'primate' },
- { id: 6, species: 'panther', type: 'carnivore' }
- ]);
- ok( mammals.at( 0 ) instanceof scope.Primate );
- ok( mammals.at( 1 ) instanceof scope.Carnivore );
- });
- test( "Object building based on type, when used in relations" , function() {
- var scope = {};
- Backbone.Relational.store.addModelScope( scope );
- var PetAnimal = scope.PetAnimal = Backbone.RelationalModel.extend({
- subModelTypes: {
- 'cat': 'Cat',
- 'dog': 'Dog'
- }
- });
- var Dog = scope.Dog = PetAnimal.extend();
- var Cat = scope.Cat = PetAnimal.extend();
- var PetPerson = scope.PetPerson = Backbone.RelationalModel.extend({
- relations: [{
- type: Backbone.HasMany,
- key: 'pets',
- relatedModel: PetAnimal,
- reverseRelation: {
- key: 'owner'
- }
- }]
- });
- var petPerson = new scope.PetPerson({
- pets: [
- {
- type: 'dog',
- name: 'Spot'
- },
- {
- type: 'cat',
- name: 'Whiskers'
- }
- ]
- });
- ok( petPerson.get( 'pets' ).at( 0 ) instanceof Dog );
- ok( petPerson.get( 'pets' ).at( 1 ) instanceof Cat );
- petPerson.get( 'pets' ).add({
- type: 'dog',
- name: 'Spot II'
- });
-
- ok( petPerson.get( 'pets' ).at( 2 ) instanceof Dog );
- });
-
- test( "Automatic sharing of 'superModel' relations" , function() {
- var scope = {};
- Backbone.Relational.store.addModelScope( scope );
- scope.PetPerson = Backbone.RelationalModel.extend({});
- scope.PetAnimal = Backbone.RelationalModel.extend({
- subModelTypes: {
- 'dog': 'Dog'
- },
- relations: [{
- type: Backbone.HasOne,
- key: 'owner',
- relatedModel: scope.PetPerson,
- reverseRelation: {
- type: Backbone.HasMany,
- key: 'pets'
- }
- }]
- });
- scope.Flea = Backbone.RelationalModel.extend({});
- scope.Dog = scope.PetAnimal.extend({
- relations: [{
- type: Backbone.HasMany,
- key: 'fleas',
- relatedModel: scope.Flea,
- reverseRelation: {
- key: 'host'
- }
- }]
- });
-
- var dog = new scope.Dog({
- name: 'Spot'
- });
-
- var person = new scope.PetPerson({
- pets: [ dog ]
- });
- equal( dog.get( 'owner' ), person, "Dog has a working owner relation." );
- var flea = new scope.Flea({
- host: dog
- });
-
- equal( dog.get( 'fleas' ).at( 0 ), flea, "Dog has a working fleas relation." );
- });
-
- test( "toJSON includes the type", function() {
- var scope = {};
- Backbone.Relational.store.addModelScope( scope );
- scope.PetAnimal = Backbone.RelationalModel.extend({
- subModelTypes: {
- 'dog': 'Dog'
- }
- });
- scope.Dog = scope.PetAnimal.extend();
-
- var dog = new scope.Dog({
- name: 'Spot'
- });
-
- var json = dog.toJSON();
-
- equal( json.type, 'dog', "The value of 'type' is the pet animal's type." );
- });
-
-
- module( "Backbone.Relation options", { setup: initObjects } );
-
-
- test( "'includeInJSON' (Person to JSON)", function() {
- var json = person1.toJSON();
- equal( json.user_id, 'user-1', "The value of 'user_id' is the user's id (not an object, since 'includeInJSON' is set to the idAttribute)" );
- ok ( json.likesALot instanceof Object, "The value of 'likesALot' is an object ('includeInJSON' is 'true')" );
- equal( json.likesALot.likesALot, 'person-1', "Person is serialized only once" );
-
- json = person1.get( 'user' ).toJSON();
- equal( json.person, 'boy', "The value of 'person' is the person's name ('includeInJSON is set to 'name')" );
-
- json = person2.toJSON();
- ok( person2.get('livesIn') instanceof House, "'person2' has a 'livesIn' relation" );
- equal( json.livesIn, undefined , "The value of 'livesIn' is not serialized ('includeInJSON is 'false')" );
-
- json = person3.toJSON();
- ok( json.user_id === null, "The value of 'user_id' is null");
- ok( json.likesALot === null, "The value of 'likesALot' is null");
- });
- test( "'includeInJSON' (Zoo to JSON)", function() {
- var zoo = new Zoo({
- name: 'Artis',
- animals: [
- new Animal( { id: 1, species: 'bear', name: 'Baloo' } ),
- new Animal( { id: 2, species: 'tiger', name: 'Shere Khan' } )
- ]
- });
- var json = zoo.toJSON();
- equal( json.animals.length, 2 );
- var bear = json.animals[ 0 ];
- equal( bear.species, 'bear', "animal's species has been included in the JSON" );
- equal( bear.name, undefined, "animal's name has not been included in the JSON" );
- });
-
- test( "'createModels' is false", function() {
- var NewUser = Backbone.RelationalModel.extend({});
- var NewPerson = Backbone.RelationalModel.extend({
- relations: [{
- type: Backbone.HasOne,
- key: 'user',
- relatedModel: NewUser,
- createModels: false
- }]
- });
-
- var person = new NewPerson({
- id: 'newperson-1',
- resource_uri: 'newperson-1',
- user: { id: 'newuser-1', resource_uri: 'newuser-1' }
- });
-
- ok( person.get( 'user' ) == null );
-
- var user = new NewUser( { id: 'newuser-1', name: 'SuperUser' } );
-
- ok( person.get( 'user' ) === user );
- // Old data gets overwritten by the explicitly created user, since a model was never created from the old data
- ok( person.get( 'user' ).get( 'resource_uri' ) == null );
- });
- test( "Relations load from both `keySource` and `key`", function() {
- var Property = Backbone.RelationalModel.extend({
- idAttribute: 'property_id'
- });
- var View = Backbone.RelationalModel.extend({
- idAttribute: 'id',
- relations: [{
- type: Backbone.HasMany,
- key: 'properties',
- keySource: 'property_ids',
- relatedModel: Property,
- reverseRelation: {
- key: 'view',
- keySource: 'view_id'
- }
- }]
- });
- var property1 = new Property({
- property_id: 1,
- key: 'width',
- value: 500,
- view_id: 5
- });
- var view = new View({
- id: 5,
- property_ids: [ 2 ]
- });
- var property2 = new Property({
- property_id: 2,
- key: 'height',
- value: 400
- });
- // The values from view.property_ids should be loaded into view.properties
- ok( view.get( 'properties' ) && view.get( 'properties' ).length === 2, "'view' has two 'properties'" );
- ok( typeof view.get( 'property_ids' ) === 'undefined', "'view' does not have 'property_ids'" );
- view.set( 'properties', [ property1, property2 ] );
- ok( view.get( 'properties' ) && view.get( 'properties' ).length === 2, "'view' has two 'properties'" );
- view.set( 'property_ids', [ 1, 2 ] );
- ok( view.get( 'properties' ) && view.get( 'properties' ).length === 2, "'view' has two 'properties'" );
- });
- test( "'keyDestination' saves to 'key'", function() {
- var Property = Backbone.RelationalModel.extend({
- idAttribute: 'property_id'
- });
- var View = Backbone.RelationalModel.extend({
- idAttribute: 'id',
- relations: [{
- type: Backbone.HasMany,
- key: 'properties',
- keyDestination: 'properties_attributes',
- relatedModel: Property,
- reverseRelation: {
- key: 'view',
- keyDestination: 'view_attributes',
- includeInJSON: true
- }
- }]
- });
- var property1 = new Property({
- property_id: 1,
- key: 'width',
- value: 500,
- view: 5
- });
- var view = new View({
- id: 5,
- properties: [ 2 ]
- });
- var property2 = new Property({
- property_id: 2,
- key: 'height',
- value: 400
- });
- var viewJSON = view.toJSON();
- ok( viewJSON.properties_attributes && viewJSON.properties_attributes.length === 2, "'viewJSON' has two 'properties_attributes'" );
- ok( typeof viewJSON.properties === 'undefined', "'viewJSON' does not have 'properties'" );
- });
-
- test( "'collectionOptions' sets the options on the created HasMany Collections", function() {
- var zoo = new Zoo();
- ok( zoo.get("animals").url === "zoo/" + zoo.cid + "/animal/");
- });
-
-
- module( "Backbone.Relation preconditions", { setup: reset } );
-
-
- test( "'type', 'key', 'relatedModel' are required properties", function() {
- var Properties = Backbone.RelationalModel.extend({});
- var View = Backbone.RelationalModel.extend({
- relations: [
- {
- key: 'listProperties',
- relatedModel: Properties
- }
- ]
- });
-
- var view = new View();
- ok( view._relations.length === 0 );
-
- View = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasOne,
- relatedModel: Properties
- }
- ]
- });
-
- view = new View();
- ok( view._relations.length === 0 );
-
- View = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasOne,
- key: 'listProperties'
- }
- ]
- });
-
- view = new View();
- ok( view._relations.length === 0 );
- });
-
- test( "'type' can be a string or an object reference", function() {
- var Properties = Backbone.RelationalModel.extend({});
- var View = Backbone.RelationalModel.extend({
- relations: [
- {
- type: 'Backbone.HasOne',
- key: 'listProperties',
- relatedModel: Properties
- }
- ]
- });
-
- var view = new View();
- ok( view._relations.length === 1 );
-
- View = Backbone.RelationalModel.extend({
- relations: [
- {
- type: 'HasOne',
- key: 'listProperties',
- relatedModel: Properties
- }
- ]
- });
-
- view = new View();
- ok( view._relations.length === 1 );
-
- View = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasOne,
- key: 'listProperties',
- relatedModel: Properties
- }
- ]
- });
-
- view = new View();
- ok( view._relations.length === 1 );
- });
-
- test( "'key' can be a string or an object reference", function() {
- var Properties = Backbone.RelationalModel.extend({});
- var View = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasOne,
- key: 'listProperties',
- relatedModel: Properties
- }
- ]
- });
-
- var view = new View();
- ok( view._relations.length === 1 );
-
- View = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasOne,
- key: 'listProperties',
- relatedModel: Properties
- }
- ]
- });
-
- view = new View();
- ok( view._relations.length === 1 );
- });
-
- test( "HasMany with a reverseRelation HasMany is not allowed", function() {
- var User = Backbone.RelationalModel.extend({});
- var Password = Backbone.RelationalModel.extend({
- relations: [{
- type: 'HasMany',
- key: 'users',
- relatedModel: User,
- reverseRelation: {
- type: 'HasMany',
- key: 'passwords'
- }
- }]
- });
-
- var password = new Password({
- plaintext: 'qwerty',
- users: [ 'person-1', 'person-2', 'person-3' ]
- });
-
- ok( password._relations.length === 0, "No _relations created on Password" );
- });
-
- test( "Duplicate relations not allowed (two simple relations)", function() {
- var Properties = Backbone.RelationalModel.extend({});
- var View = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasOne,
- key: 'properties',
- relatedModel: Properties
- },
- {
- type: Backbone.HasOne,
- key: 'properties',
- relatedModel: Properties
- }
- ]
- });
-
- var view = new View();
- view.set( { properties: new Properties() } );
- ok( view._relations.length === 1 );
- });
-
- test( "Duplicate relations not allowed (one relation with a reverse relation, one without)", function() {
- var Properties = Backbone.RelationalModel.extend({});
- var View = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasOne,
- key: 'properties',
- relatedModel: Properties,
- reverseRelation: {
- type: Backbone.HasOne,
- key: 'view'
- }
- },
- {
- type: Backbone.HasOne,
- key: 'properties',
- relatedModel: Properties
- }
- ]
- });
-
- var view = new View();
- view.set( { properties: new Properties() } );
- ok( view._relations.length === 1 );
- });
-
- test( "Duplicate relations not allowed (two relations with reverse relations)", function() {
- var Properties = Backbone.RelationalModel.extend({});
- var View = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasOne,
- key: 'properties',
- relatedModel: Properties,
- reverseRelation: {
- type: Backbone.HasOne,
- key: 'view'
- }
- },
- {
- type: Backbone.HasOne,
- key: 'properties',
- relatedModel: Properties,
- reverseRelation: {
- type: Backbone.HasOne,
- key: 'view'
- }
- }
- ]
- });
-
- var view = new View();
- view.set( { properties: new Properties() } );
- ok( view._relations.length === 1 );
- });
-
- test( "Duplicate relations not allowed (different relations, reverse relations)", function() {
- var Properties = Backbone.RelationalModel.extend({});
- var View = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasOne,
- key: 'listProperties',
- relatedModel: Properties,
- reverseRelation: {
- type: Backbone.HasOne,
- key: 'view'
- }
- },
- {
- type: Backbone.HasOne,
- key: 'windowProperties',
- relatedModel: Properties,
- reverseRelation: {
- type: Backbone.HasOne,
- key: 'view'
- }
- }
- ]
- });
-
- var view = new View();
- var prop1 = new Properties( { name: 'a' } );
- var prop2 = new Properties( { name: 'b' } );
-
- view.set( { listProperties: prop1, windowProperties: prop2 } );
-
- ok( view._relations.length === 2 );
- ok( prop1._relations.length === 2 );
- ok( view.get( 'listProperties' ).get( 'name' ) === 'a' );
- ok( view.get( 'windowProperties' ).get( 'name' ) === 'b' );
- });
-
-
- module( "Backbone.Relation general", { setup: reset } );
-
-
- test( "Only valid models (no validation failure) should be added to a relation", function() {
- var zoo = new Zoo();
-
- zoo.bind( 'add:animals', function( animal ) {
- ok( animal instanceof Animal );
- });
-
- var smallElephant = new Animal( { name: 'Jumbo', species: 'elephant', weight: 2000, livesIn: zoo } );
- equal( zoo.get( 'animals' ).length, 1, "Just 1 elephant in the zoo" );
-
- // should fail validation, so it shouldn't be added
- zoo.get( 'animals' ).add( { name: 'Big guy', species: 'elephant', weight: 13000 }, { validate: true } );
- equal( zoo.get( 'animals' ).length, 1, "Still just 1 elephant in the zoo" );
- });
- test( "collections can also be passed as attributes on creation", function() {
- var animals = new AnimalCollection([
- { id: 1, species: 'Lion' },
- { id: 2 ,species: 'Zebra' }
- ]);
- var zoo = new Zoo( { animals: animals } );
- equal( zoo.get( 'animals' ), animals, "The 'animals' collection has been set as the zoo's animals" );
- equal( zoo.get( 'animals' ).length, 2, "Two animals in 'zoo'" );
- zoo.destroy();
- var newZoo = new Zoo( { animals: animals.models } );
- ok( newZoo.get( 'animals' ).length === 2, "Two animals in the 'newZoo'" );
- });
- test( "models can also be passed as attributes on creation", function() {
- var artis = new Zoo( { name: 'Artis' } );
- var animal = new Animal( { species: 'Hippo', livesIn: artis });
- equal( artis.get( 'animals' ).at( 0 ), animal, "Artis has a Hippo" );
- equal( animal.get( 'livesIn' ), artis, "The Hippo is in Artis" );
- });
- test( "id checking handles for `undefined`, `null`, `0` ids properly", function() {
- var parent = new Node();
- var child = new Node( { parent: parent } );
- equal( child.get( 'parent' ), parent );
- parent.destroy();
- equal( child.get( 'parent' ), null );
- // It used to be the case that `randomOtherNode` became `child`s parent here, since both the `parent.id`
- // (which is stored as the relation's `keyContents`) and `randomOtherNode.id` were undefined.
- var randomOtherNode = new Node();
- equal( child.get( 'parent' ), null );
- // Create a child with parent id=0, then create the parent
- child = new Node( { parent: 0 } );
- equal( child.get( 'parent' ), null );
- parent = new Node( { id: 0 } );
- equal( child.get( 'parent' ), parent );
- child.destroy();
- parent.destroy();
- // The other way around; create the parent with id=0, then the child
- parent = new Node( { id: 0 } );
- equal( parent.get( 'children' ).length, 0 );
- child = new Node( { parent: 0 } );
- equal( child.get( 'parent' ), parent );
- });
- test("Repeated model initialization and a collection should not break existing models", function () {
- var dataCompanyA = {
- id: 'company-a',
- name: 'Big Corp.',
- employees: [ { id: 'job-a' }, { id: 'job-b' } ]
- };
- var dataCompanyB = {
- id: 'company-b',
- name: 'Small Corp.',
- employees: []
- };
- var companyA = new Company( dataCompanyA );
- // Attempting to instantiate another model with the same data will throw an error
- raises( function() { new Company( dataCompanyA ); }, "Can only instantiate one model for a given `id` (per model type)" );
- // init-ed a lead and its nested contacts are a collection
- ok( companyA.get('employees') instanceof Backbone.Collection, "Company's employees should be a collection" );
- equal(companyA.get('employees').length, 2, 'with elements');
- var companyCollection = new CompanyCollection( [ dataCompanyA, dataCompanyB ] );
- // After loading a collection with models of the same type
- // the existing company should still have correct collections
- ok( companyCollection.get( dataCompanyA.id ) === companyA );
- ok( companyA.get('employees') instanceof Backbone.Collection, "Company's employees should still be a collection" );
- equal( companyA.get('employees').length, 2, 'with elements' );
- });
- test("If keySource is used don't remove a model that is present in the key attribute", function() {
- var ForumPost = Backbone.RelationalModel.extend({
- // Normally would set something here, not needed for test
- });
- var ForumPostCollection = Backbone.Collection.extend({
- model: ForumPost
- });
- var Forum = Backbone.RelationalModel.extend({
- relations: [{
- type: Backbone.HasMany,
- key: 'posts',
- relatedModel: ForumPost,
- collectionType: ForumPostCollection,
- reverseRelation: {
- key: 'forum',
- keySource: 'forum_id'
- }
- }]
- });
- var TestPost = new ForumPost({
- id: 1,
- title: "Hello World",
- forum: {id: 1, title: "Cupcakes"}
- });
- var TestForum = Forum.findOrCreate(1);
- notEqual( TestPost.get('forum'), null, "The post's forum is not null" );
- equal( TestPost.get('forum').get('title'), "Cupcakes", "The post's forum title is Cupcakes" );
- equal( TestForum.get('title'), "Cupcakes", "A forum of id 1 has the title cupcakes" );
- });
- // GH-187
- test( "Can pass related model in constructor", function() {
- var A = Backbone.RelationalModel.extend();
- var B = Backbone.RelationalModel.extend({
- relations: [{
- type: Backbone.HasOne,
- key: 'a',
- keySource: 'a_id',
- relatedModel: A
- }]
- });
- var a1 = new A({ id: 'a1' });
- var b1 = new B();
- b1.set( 'a', a1 );
- ok( b1.get( 'a' ) instanceof A );
- ok( b1.get( 'a' ).id == 'a1' );
- var a2 = new A({ id: 'a2' });
- var b2 = new B({ a: a2 });
- ok( b2.get( 'a' ) instanceof A );
- ok( b2.get( 'a' ).id == 'a2' );
- });
- module( "Backbone.HasOne", { setup: initObjects } );
-
-
- test( "HasOne relations on Person are set up properly", function() {
- ok( person1.get('likesALot') === person2 );
- equal( person1.get('user').id, 'user-1', "The id of 'person1's user is 'user-1'" );
- ok( person2.get('likesALot') === person1 );
- });
-
- test( "Reverse HasOne relations on Person are set up properly", function() {
- ok( person1.get( 'likedALotBy' ) === person2 );
- ok( person1.get( 'user' ).get( 'person' ) === person1, "The person belonging to 'person1's user is 'person1'" );
- ok( person2.get( 'likedALotBy' ) === person1 );
- });
-
- test( "'set' triggers 'change' and 'update', on a HasOne relation, for a Model with multiple relations", function() {
- expect( 9 );
- // triggers initialization of the reverse relation from User to Password
- var password = new Password( { plaintext: 'asdf' } );
-
- person1.bind( 'change', function( model, options ) {
- ok( model.get( 'user' ) instanceof User, "In 'change', model.user is an instance of User" );
- equal( model.previous( 'user' ).get( 'login' ), oldLogin, "previousAttributes is available on 'change'" );
- });
-
- person1.bind( 'change:user', function( model, options ) {
- ok( model.get( 'user' ) instanceof User, "In 'change:user', model.user is an instance of User" );
- equal( model.previous( 'user' ).get( 'login' ), oldLogin, "previousAttributes is available on 'change'" );
- });
-
- person1.bind( 'update:user', function( model, attr, options ) {
- ok( model.get( 'user' ) instanceof User, "In 'update:user', model.user is an instance of User" );
- ok( attr.get( 'person' ) === person1, "The user's 'person' is 'person1'" );
- ok( attr.get( 'password' ) instanceof Password, "The user's password attribute is a model of type Password");
- equal( attr.get( 'password' ).get( 'plaintext' ), 'qwerty', "The user's password is ''qwerty'" );
- });
-
- var user = { login: 'me@hotmail.com', password: { plaintext: 'qwerty' } };
- var oldLogin = person1.get( 'user' ).get( 'login' );
- // Triggers assertions for 'change' and 'change:user'
- person1.set( { user: user } );
-
- user = person1.get( 'user' ).bind( 'update:password', function( model, attr, options ) {
- equal( attr.get( 'plaintext' ), 'asdf', "The user's password is ''qwerty'" );
- });
-
- // Triggers assertions for 'update:user'
- user.set( { password: password } );
- });
- test( "'set' doesn't triggers 'change' and 'update:' when passed `silent: true`", function() {
- expect( 2 );
- person1.bind( 'change', function( model, options ) {
- ok( false, "'change' should not get triggered" );
- });
- person1.bind( 'update:user', function( model, attr, options ) {
- ok( false, "'update:user' should not get triggered" );
- });
- person1.bind( 'change:user', function( model, attr, options ) {
- ok( false, "'change:user' should not get triggered" );
- });
- ok( person1.get( 'user' ) instanceof User, "person1 has a 'user'" );
- var user = new User({ login: 'me@hotmail.com', password: { plaintext: