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