Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / core / test / unit / spec / class / ClassManager.js
1 describe("Ext.ClassManager", function() {
2     var manager = Ext.ClassManager,
3         cls, emptyFn = function(){};
4
5
6
7     beforeEach(function() {
8         manager.enableNamespaceParseCache = false;
9         window.My = {
10             awesome: {
11                 Class: function(){console.log(11);},
12                 Class1: function(){console.log(12);},
13                 Class2: function(){console.log(13);}
14             },
15             cool: {
16                 AnotherClass: function(){console.log(21);},
17                 AnotherClass1: function(){console.log(22);},
18                 AnotherClass2: function(){console.log(23);}
19             }
20         };
21     });
22
23     afterEach(function() {
24         if (window.Something) {
25             window.Something = undefined;
26         }
27
28         if (window.My) {
29             window.My = undefined;
30         }
31
32         if (window.I) {
33             window.I = undefined;
34         }
35
36         if (window.Test) {
37             window.Test = undefined;
38         }
39
40         try {
41             delete window.Something;
42             delete window.My;
43             delete window.I;
44             delete window.Test;
45         } catch (e) {}
46         manager.enableNamespaceParseCache = true;
47     });
48
49     describe("parseNamespace", function() {
50         it("should return the broken-down namespace", function() {
51             var parts = manager.parseNamespace('Some.strange.alien.Namespace');
52
53             expect(parts).toEqual([Ext.global, 'Some', 'strange', 'alien', 'Namespace']);
54         });
55
56         it("should return the broken-down namespace with object rewrites", function() {
57             var parts = manager.parseNamespace('Ext.some.Namespace');
58
59             expect(parts).toEqual([Ext, 'some', 'Namespace']);
60         });
61     });
62
63     describe("exist", function() {
64         it("should return whether a single class exists", function() {
65             expect(manager.isCreated('My.notexisting.Class')).toBe(false);
66             expect(manager.isCreated('My.awesome.Class')).toBe(true);
67         });
68     });
69
70     describe("loader preprocessor", function() {
71         beforeEach(function() {
72             cls = function(){};
73         });
74
75         it("should load and replace string class names with objects", function() {
76             var data = {
77                     extend: 'My.awesome.Class',
78                     mixins: {
79                         name1: My.cool.AnotherClass,
80                         name2: 'My.cool.AnotherClass1'
81                     }
82                 },
83                 expected = {
84                     extend: My.awesome.Class,
85                     mixins: {
86                         name1: My.cool.AnotherClass,
87                         name2: My.cool.AnotherClass1
88                     }
89                 },
90                 classNames;
91
92
93             spyOn(Ext.Loader, 'require').andCallFake(function(classes, fn) {
94                 classNames = classes;
95                 fn();
96             });
97
98             Ext.Class.getPreprocessor('loader').fn(cls, data, emptyFn, emptyFn);
99
100             expect(Ext.Loader.require).toHaveBeenCalled();
101             expect(classNames).toEqual(['My.awesome.Class', 'My.cool.AnotherClass1']);
102             expect(data).toEqual(expected);
103         });
104     });
105
106     describe("create", function() {
107         var subClass, parentClass, mixinClass1, mixinClass2, subSubClass;
108
109         beforeEach(function() {
110             mixinClass1 = manager.create('I.am.the.MixinClass1', {
111                 config: {
112                     mixinConfig: 'mixinConfig'
113                 },
114
115                 constructor: function() {
116                     this.mixinConstructor1Called = true;
117                 },
118
119                 mixinProperty1: 'mixinProperty1',
120
121                 mixinMethod1: function() {
122                     this.mixinMethodCalled = true;
123                 }
124             });
125
126             mixinClass2 = manager.create('I.am.the.MixinClass2', {
127                 constructor: function() {
128                     this.mixinConstructor2Called = true;
129                 },
130
131                 mixinProperty2: 'mixinProperty2',
132
133                 mixinMethod2: function() {
134                     this.mixinMethodCalled = true;
135                 }
136             });
137
138             parentClass = manager.create('I.am.the.ParentClass', {
139                 alias: ['parentclass', 'superclass'],
140
141                 mixins: {
142                     mixin1: 'I.am.the.MixinClass1'
143                 },
144
145                 config: {
146                     name: 'parentClass',
147                     isCool: false,
148                     members: {
149                         abe: 'Abraham Elias',
150                         ed: 'Ed Spencer'
151                     },
152                     hobbies: ['football', 'bowling']
153                 },
154
155                 onClassExtended: function(subClass, data) {
156                     subClass.onClassExtendedCalled = true;
157                 },
158
159                 constructor: function(config) {
160                     this.initConfig(config);
161
162                     this.parentConstructorCalled = true;
163
164                     this.mixins.mixin1.constructor.apply(this, arguments);
165                 },
166
167                 parentProperty: 'parentProperty',
168
169                 parentMethod: function() {
170                     this.parentMethodCalled = true;
171                 }
172             });
173
174             subClass = manager.create('I.am.the.SubClass', {
175                 alias: 'subclass',
176
177                 extend: 'I.am.the.ParentClass',
178
179                 mixins: {
180                     mixin1: 'I.am.the.MixinClass1',
181                     mixin2: 'I.am.the.MixinClass2'
182                 },
183                 config: {
184                     name: 'subClass',
185                     isCool: true,
186                     members: {
187                         jacky: 'Jacky Nguyen',
188                         tommy: 'Tommy Maintz'
189                     },
190                     hobbies: ['sleeping', 'eating', 'movies'],
191                     isSpecial: true
192                 },
193                 constructor: function() {
194                     this.subConstrutorCalled = true;
195
196                     this.superclass.constructor.apply(this, arguments);
197
198                     this.mixins.mixin2.constructor.apply(this, arguments);
199                 },
200                 myOwnMethod: function() {
201                     this.myOwnMethodCalled = true;
202                 }
203             });
204         });
205
206         it("should create the namespace", function() {
207             expect(I).toBeDefined();
208             expect(I.am).toBeDefined();
209             expect(I.am.the).toBeDefined();
210             expect(I.am.the.SubClass).toBeDefined();
211         });
212
213         it("should get className", function() {
214             expect(Ext.getClassName(subClass)).toEqual('I.am.the.SubClass');
215         });
216
217         describe("addStatics", function() {
218             it("single with name - value arguments", function() {
219                 var called = false;
220
221                 subClass.addStatics({
222                     staticMethod: function(){
223                         called = true;
224                     }
225                 });
226
227                 expect(subClass.staticMethod).toBeDefined();
228                 subClass.staticMethod();
229
230                 expect(called).toBeTruthy();
231             });
232
233             it("multiple with object map argument", function() {
234                 subClass.addStatics({
235                     staticProperty: 'something',
236                     staticMethod: function(){}
237                 });
238
239                 expect(subClass.staticProperty).toEqual('something');
240                 expect(subClass.staticMethod).toBeDefined();
241             });
242         });
243
244         describe("mixin", function() {
245             it("should have all properties of mixins", function() {
246                 var obj = new subClass();
247                 expect(obj.mixinProperty1).toEqual('mixinProperty1');
248                 expect(obj.mixinProperty2).toEqual('mixinProperty2');
249                 expect(obj.mixinMethod1).toBeDefined();
250                 expect(obj.mixinMethod2).toBeDefined();
251                 expect(obj.config.mixinConfig).toEqual('mixinConfig');
252             });
253         });
254
255         describe("config", function() {
256             it("should merge properly", function() {
257                 var obj = new subClass();
258
259                 expect(obj.config).toEqual({
260                     mixinConfig: 'mixinConfig',
261                     name: 'subClass',
262                     isCool: true,
263                     members: {
264                         abe: 'Abraham Elias',
265                         ed: 'Ed Spencer',
266                         jacky: 'Jacky Nguyen',
267                         tommy: 'Tommy Maintz'
268                     },
269                     hobbies: ['sleeping', 'eating', 'movies'],
270                     isSpecial: true
271                 });
272             });
273
274             it("should apply default config", function() {
275                 var obj = new subClass();
276
277                 expect(obj.getName()).toEqual('subClass');
278                 expect(obj.getIsCool()).toEqual(true);
279                 expect(obj.getHobbies()).toEqual(['sleeping', 'eating', 'movies']);
280             });
281
282             it("should apply with supplied config", function() {
283                 var obj = new subClass({
284                     name: 'newName',
285                     isCool: false,
286                     members: {
287                         aaron: 'Aaron Conran'
288                     }
289                 });
290
291                 expect(obj.getName()).toEqual('newName');
292                 expect(obj.getIsCool()).toEqual(false);
293                 expect(obj.getMembers().aaron).toEqual('Aaron Conran');
294             });
295         });
296
297         describe("overriden methods", function() {
298             it("should call self constructor", function() {
299                 var obj = new subClass();
300                 expect(obj.subConstrutorCalled).toBeTruthy();
301             });
302
303             it("should call parent constructor", function() {
304                 var obj = new subClass();
305                 expect(obj.parentConstructorCalled).toBeTruthy();
306             });
307
308             it("should call mixins constructors", function() {
309                 var obj = new subClass();
310                 expect(obj.mixinConstructor1Called).toBeTruthy();
311                 expect(obj.mixinConstructor2Called).toBeTruthy();
312             });
313         });
314
315         describe("alias", function() {
316             it("should store alias", function() {
317                 expect(manager.getByAlias('subclass')).toBe(subClass);
318             });
319
320             it("should store multiple aliases", function() {
321                 expect(manager.getByAlias('parentclass')).toBe(parentClass);
322                 expect(manager.getByAlias('superclass')).toBe(parentClass);
323             });
324         });
325
326         describe("onClassExtended", function() {
327             it("should store an internal reference", function() {
328                 expect(parentClass.prototype.$onExtended).toBeDefined();
329                 expect(subClass.prototype.$onExtended).toBeDefined();
330             });
331
332             it("should invoke the internal reference", function() {
333                 expect(subClass.onClassExtendedCalled).toBe(true);
334             });
335         });
336     });
337
338     describe("instantiate", function() {
339         beforeEach(function() {
340             manager.create('Test.stuff.Person', {
341                 alias: 'person',
342
343                 constructor: function(name, age, sex) {
344                     this.name = name;
345                     this.age = age;
346                     this.sex = sex;
347                 },
348
349                 eat: function(food) {
350                     this.eatenFood = food;
351                 }
352             });
353
354             manager.create('Test.stuff.Developer', {
355                 alias: 'developer',
356
357                 extend: 'Test.stuff.Person',
358
359                 constructor: function(isGeek, name, age, sex) {
360                     this.isGeek = isGeek;
361
362                     return this.superclass.constructor.apply(this, arguments);
363                 },
364
365                 code: function(language) {
366                     this.languageCoded = language;
367                     this.eat('bugs');
368                 }
369             });
370         });
371
372
373         it("should create the instance by full class name", function() {
374             var me = manager.instantiate('Test.stuff.Person', 'Jacky', 24, 'male');
375             expect(me instanceof Test.stuff.Person).toBe(true);
376         });
377
378         it("should create the instance by alias", function() {
379             var me = manager.instantiateByAlias('person', 'Jacky', 24, 'male');
380             expect(me instanceof Test.stuff.Person).toBe(true);
381         });
382
383         it("should pass all arguments to the constructor", function() {
384             var me = manager.instantiateByAlias('person', 'Jacky', 24, 'male');
385             expect(me.name).toBe('Jacky');
386             expect(me.age).toBe(24);
387             expect(me.sex).toBe('male');
388         });
389
390         it("should have all methods in prototype", function() {
391             var me = manager.instantiateByAlias('person', 'Jacky', 24, 'male');
392             me.eat('rice');
393
394             expect(me.eatenFood).toBe('rice');
395         });
396
397         it("should works with inheritance", function() {
398             var me = manager.instantiateByAlias('developer', true, 'Jacky', 24, 'male');
399             me.code('javascript');
400
401             expect(me.languageCoded).toBe('javascript');
402             expect(me.eatenFood).toBe('bugs');
403         });
404     });
405
406     describe("post-processors", function() {
407
408         xdescribe("uses", function() {
409             //expect(Something.Cool).toBeDefined();
410             //expect(Something.Cool instanceof test).toBeTruthy();
411         });
412
413         describe("singleton", function() {
414             it("should create the instance namespace and return the class", function() {
415                 var test = Ext.define('Something.Cool', {
416                     singleton: true,
417                     someMethod: function() {
418                         this.someMethodCalled = true;
419                     },
420                     someProperty: 'something'
421                 });
422
423                 expect(Something.Cool).toBeDefined();
424                 expect(Something.Cool instanceof test).toBeTruthy();
425             });
426         });
427
428         describe("alias xtype", function() {
429             it("should set xtype as a static class property", function() {
430                 var test = Ext.define('Something.Cool', {
431                     alias: 'widget.cool'
432                 });
433
434                 expect(Something.Cool.xtype).toEqual('cool');
435             });
436         });
437
438         describe("alternate", function() {
439             it("should create the alternate", function() {
440                 Ext.define('Something.Cool', {
441                     alternateClassName: 'Something.CoolAsWell',
442
443                     someMethod: function() {
444                         this.someMethodCalled = true;
445                     },
446
447                     someProperty: 'something'
448                 });
449
450                 expect(Something.CoolAsWell).toBeDefined();
451                 expect(Something.CoolAsWell).toBe(Something.Cool);
452             });
453
454             it("should create the alternate", function() {
455                 Ext.define('Something.Cool', {
456                     alternateClassName: ['Something.CoolAsWell', 'Something.AlsoCool']
457                 });
458
459                 expect(Something.CoolAsWell).toBe(Something.Cool);
460                 expect(Something.AlsoCool).toBe(Something.Cool);
461             });
462         });
463     });
464 });