UNPKG

extjs-gpl

Version:

GPL licensed version of Sencha Ext JS

411 lines (361 loc) 12.7 kB
// HasMany is not a real class, but is an alternate way of declaring ManyToOne // The purpose of these tests is to check that they set everything up correctly, // functionality tested in ManyToOne. describe("Ext.data.schema.HasMany", function() { var Thread, Post, Vote; function defineThread(options) { var cfg = { extend: 'Ext.data.Model', fields: ['id', 'title'] }; if (options) { cfg = Ext.apply(cfg, options); } Thread = Ext.define('spec.Thread', cfg); } function definePost(options) { var cfg = { extend: 'Ext.data.Model', fields: ['id', 'title'] }; if (options) { cfg = Ext.apply(cfg, options); } Post = Ext.define('spec.Post', cfg); } function defineVote(options) { var cfg = { extend: 'Ext.data.Model', fields: ['id', 'title'] }; if (options) { cfg = Ext.apply(cfg, options); } Vote = Ext.define('spec.Vote', cfg); } beforeEach(function() { MockAjaxManager.addMethods(); Ext.data.Model.schema.setNamespace('spec'); }); afterEach(function() { if (Post) { Ext.undefine('spec.Post'); Post = null; } if (Vote) { Ext.undefine('spec.Vote'); } if (Thread) { Ext.undefine('spec.Thread'); Thread = null; } Ext.data.Model.schema.clear(true); MockAjaxManager.removeMethods(); }); function expectFn(name, o) { o = o || Thread; expect(Ext.isFunction(o.prototype[name])).toBe(true); } function expectNotFn(name, o) { o = o || Thread; expect(Ext.isFunction(o.prototype[name])).toBe(false); } describe("declarations", function() { describe("Configuration of model only", function() { it("should accept a string", function() { definePost(); defineThread({ hasMany: 'Post' }); expectFn('posts'); expectFn('getThread', Post); expectFn('setThread', Post); }); it("should accept an array of strings", function() { definePost(); defineVote(); defineThread({ hasMany: ['Post', 'Vote'] }); expectFn('posts'); expectFn('votes'); expectFn('getThread', Post); expectFn('setThread', Post); expectFn('getThread', Vote); expectFn('setThread', Vote); }); it("should accept an object", function() { definePost(); defineThread({ hasMany: { type: 'Post' } }); expectFn('posts'); expectFn('getThread', Post); expectFn('setThread', Post); }); it("should accept an array of objects", function() { definePost(); defineVote(); defineThread({ hasMany: [{ type: 'Post' }, { type: 'Vote' }] }); expectFn('posts'); expectFn('votes'); expectFn('getThread', Post); expectFn('setThread', Post); expectFn('getThread', Vote); expectFn('setThread', Vote); }); }); describe("extra configurations", function() { describe("role", function() { it("should add the specified role", function() { definePost(); defineThread({ hasMany: { type: 'Post', role: 'comments' } }); expectFn('comments'); expectNotFn('posts'); expectFn('getThread', Post); expectFn('setThread', Post); }); }); describe("getterName", function() { it("should allow a custom getterName", function() { definePost(); defineThread({ hasMany: { type: 'Post', getterName: 'comments' } }); expectFn('comments'); expectNotFn('posts'); expectFn('getThread', Post); expectFn('setThread', Post); }); }); describe("inverse", function() { it("should be able to declare inverse configs", function() { definePost(); defineThread({ hasMany: { type: 'Post', inverse: { role: 'discussion' } } }); expectFn('discussionPosts'); expectNotFn('posts'); expectFn('getDiscussion', Post); expectFn('setDiscussion', Post); }); }); describe("child", function() { it("should be able to set child", function() { definePost(); defineThread({ hasMany: { child: 'Post' } }); expectFn('posts'); expectFn('getThread', Post); expectFn('setThread', Post); }); }); }); describe("timing", function() { describe("when the many class already exists", function() { it("should setup methods on both classes", function() { definePost(); defineThread({ hasMany: 'Post' }); expectFn('posts'); expectFn('getThread', Post); expectFn('setThread', Post); }); }); describe("when the many class does not exist", function() { it("should setup methods on both classes when the many arrives", function() { defineThread({ hasMany: 'Post' }); expectNotFn('posts'); definePost(); expectFn('posts'); expectFn('getThread', Post); expectFn('setThread', Post); }); }); }); }); describe("instance related configs", function() { describe("storeConfig", function() { it("should apply a storeConfig", function() { definePost(); defineThread({ hasMany: { type: 'Post', storeConfig: { autoSync: true } } }); var thread = new Thread(); expect(thread.posts().getAutoSync()).toBe(true); }); }); describe("associationKey", function() { it("should apply the associationKey for loading nested data", function() { definePost(); defineThread({ hasMany: { type: 'Post', associationKey: 'comments' } }); var thread = Thread.load(1); Ext.Ajax.mockCompleteWithData({ id: 1, posts: [{ id: 101 }, { id: 102 }] }); // Key is comments, should be nothing expect(thread.posts().getCount()).toBe(0); thread = Thread.load(2); Ext.Ajax.mockCompleteWithData({ id: 2, comments: [{ id: 201 }, { id: 202 }] }); expect(thread.posts().getCount()).toBe(2); }); }); describe("child", function() { it("should drop the many records when the owner is dropped", function() { definePost(); defineThread({ hasMany: { child: 'Post' } }); var thread = new Thread({id: 1}), post = new Post({id: 101}); thread.posts().add(post); thread.drop(); expect(post.dropped).toBe(true); }); }); }); describe("legacy functionality", function() { describe("foreignKey", function() { it("should recognize a default foreignKey as entity_id", function() { definePost({ fields: ['id', 'name', 'thread_id'] }); defineThread({ hasMany: 'Post' }); var thread = new Thread({id: 1}), post = new Post({id: 101}); thread.posts().add(post); expect(post.get('thread_id')).toBe(1); }); it("should recognize a custom foreignKey as entity_id", function() { definePost({ fields: ['id', 'name', 'customField'] }); defineThread({ hasMany: { type: 'Post', foreignKey: 'customField' } }); var thread = new Thread({id: 1}), post = new Post({id: 101}); thread.posts().add(post); expect(post.get('customField')).toBe(1); }); }); it("should use the name parameter as the role", function() { definePost(); defineThread({ hasMany: { model: 'Post', name: 'comments' } }); expectFn('comments'); expectFn('getThread', Post); expectFn('setThread', Post); }); it("should use the associatedName parameter as the role", function() { definePost(); defineThread({ hasMany: { model: 'Post', associatedName: 'comments' } }); expectFn('comments'); }); it("should accept a storeConfig when given a name", function() { definePost(); defineThread({ hasMany: { model: 'Post', name: 'comments', storeConfig: { trackRemoved: false } } }); var thread = new Thread(); expect(thread.comments().getTrackRemoved()).toBe(false); }); it("should accept a storeConfig when given an associationKey", function() { definePost(); defineThread({ hasMany: { model: 'Post', associationKey: 'someValue', storeConfig: { trackRemoved: false } } }); var thread = new Thread(); expect(thread.posts().getTrackRemoved()).toBe(false); }); it("should respect a role config when using model", function() { definePost(); defineThread({ hasMany: { model: 'Post', role: 'comments' } }); expectFn('comments'); expectFn('getThread', Post); expectFn('setThread', Post); }); }); });