Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / core / test / unit / spec / class / Class.js
diff --git a/src/core/test/unit/spec/class/Class.js b/src/core/test/unit/spec/class/Class.js
new file mode 100644 (file)
index 0000000..f355716
--- /dev/null
@@ -0,0 +1,466 @@
+describe("Ext.Class", function() {
+    var cls, emptyFn = function(){};
+    beforeEach(function() {
+        window.My = {
+            awesome: {
+                Class: function(){console.log(11)},
+                Class1: function(){console.log(12)},
+                Class2: function(){console.log(13)}
+            },
+            cool: {
+                AnotherClass: function(){console.log(21)},
+                AnotherClass1: function(){console.log(22)},
+                AnotherClass2: function(){console.log(23)}
+            }
+        };
+    });
+
+    afterEach(function() {
+        if (window.My) {
+            window.My = undefined;
+        }
+
+        try {
+            delete window.My;
+        } catch (e) {}
+    });
+
+    // START PREPROCESSORS =================================================================== /
+    describe("preprocessors", function() {
+
+        beforeEach(function() {
+            cls = function() {};
+            cls.prototype.config = {};
+            cls.ownMethod = function(name, fn) {
+                this.prototype[name] = fn;
+            };
+        });
+
+        describe("extend", function() {
+
+            it("should extend from Base if no 'extend' property found", function() {
+                var data = {};
+
+                Ext.Class.preprocessors.extend.fn(cls, data, emptyFn, emptyFn);
+
+                expect((new cls) instanceof Ext.Base).toBeTruthy();
+            });
+
+            it("should extend from given parent class", function() {
+                var data = {
+                    extend: My.awesome.Class
+                };
+
+                Ext.Class.preprocessors.extend.fn(cls, data, emptyFn, emptyFn);
+
+                expect((new cls) instanceof My.awesome.Class).toBeTruthy();
+            });
+
+            it("should have superclass reference", function() {
+                var data = {
+                    extend: My.awesome.Class
+                };
+
+                var parentPrototype = My.awesome.Class.prototype;
+
+                Ext.Class.preprocessors.extend.fn(cls, data, emptyFn, emptyFn);
+
+                expect(cls.superclass).toEqual(parentPrototype);
+                expect((new cls).superclass).toEqual(parentPrototype);
+            });
+        });
+
+        describe("config", function() {
+
+            it("should create getter if not exists", function() {
+                var data = {
+                    config: {
+                        someName: 'someValue'
+                    }
+                };
+
+                Ext.Class.preprocessors.config.fn(cls, data, emptyFn, emptyFn);
+
+                expect(data.getSomeName).toBeDefined();
+            });
+
+            it("should NOT create getter if already exists", function() {
+                var data = {
+                    config: {
+                        someName: 'someValue'
+                    }
+                };
+
+                var called = false;
+                cls.prototype.getSomeName = function() {
+                    called = true;
+                };
+
+                Ext.Class.preprocessors.config.fn(cls, data, emptyFn, emptyFn);
+
+                expect(data.getSomeName).not.toBeDefined();
+            });
+
+            it("should create setter if not exists", function() {
+                var data = {
+                    config: {
+                        someName: 'someValue'
+                    }
+                };
+
+                Ext.Class.preprocessors.config.fn(cls, data, emptyFn, emptyFn);
+
+                expect(data.setSomeName).toBeDefined();
+            });
+
+            it("should NOT create setter if already exists", function() {
+                var data = {
+                    config: {
+                        someName: 'someValue'
+                    }
+                };
+
+                var called = false;
+
+                cls.prototype.setSomeName = function() {
+                    called = true;
+                };
+
+                Ext.Class.preprocessors.config.fn(cls, data, emptyFn, emptyFn);
+
+                expect(data.setSomeName).not.toBeDefined();
+            });
+
+            it("should create apply if not exists", function() {
+                var data = {
+                    config: {
+                        someName: 'someValue'
+                    }
+                };
+
+                Ext.Class.preprocessors.config.fn(cls, data, emptyFn, emptyFn);
+
+                expect(data.applySomeName).toBeDefined();
+            });
+
+            it("should NOT create apply if already exists", function() {
+                var data = {
+                    config: {
+                        someName: 'someValue'
+                    }
+                };
+
+                var called = false;
+                cls.prototype.applySomeName = function() {
+                    called = true;
+                };
+
+                Ext.Class.preprocessors.config.fn(cls, data, emptyFn, emptyFn);
+
+                expect(data.applySomeName).not.toBeDefined();
+            });
+        });
+
+        describe("statics", function() {
+            it("should copy static properties to the class", function() {
+                var data = {
+                    statics: {
+                        someName: 'someValue',
+                        someMethod: Ext.emptyFn
+                    }
+                };
+
+                Ext.Class.preprocessors.statics.fn(cls, data, emptyFn, emptyFn);
+
+                var obj = new cls;
+
+                expect(obj.statics).not.toBeDefined();
+                expect(cls.someName).toBe('someValue');
+                expect(cls.someMethod).toBe(Ext.emptyFn);
+            });
+        });
+
+        describe("inheritableStatics", function() {
+
+            it("should store names of inheritable static properties", function() {
+                var data = {
+                    inheritableStatics: {
+                        someName: 'someValue',
+                        someMethod: Ext.emptyFn
+                    }
+                };
+
+                Ext.Class.preprocessors.inheritableStatics.fn(cls, data, emptyFn, emptyFn);
+
+                var obj = new cls;
+
+                expect(obj.inheritableStatics).not.toBeDefined();
+                expect(cls.someName).toBe('someValue');
+                expect(cls.prototype.$inheritableStatics).toEqual(['someName', 'someMethod']);
+                expect(cls.someMethod).toBe(Ext.emptyFn);
+            });
+
+            it("should inherit inheritable statics", function() {
+                var data = {
+                    inheritableStatics: {
+                        someName: 'someValue',
+                        someMethod: Ext.emptyFn
+                    }
+                }, cls2 = function(){};
+
+                Ext.Class.preprocessors.inheritableStatics.fn(cls, data, emptyFn, emptyFn);
+                Ext.Class.preprocessors.extend.fn(cls2, { extend: cls }, emptyFn, emptyFn);
+
+                expect(cls2.someName).toEqual('someValue');
+                expect(cls2.someMethod).toBe(Ext.emptyFn);
+            });
+
+            it("should NOT inherit inheritable statics if the class already has it", function() {
+                var data = {
+                    inheritableStatics: {
+                        someName: 'someValue',
+                        someMethod: Ext.emptyFn
+                    }
+                }, cls2 = function(){};
+
+                cls2.someName = 'someOtherValue';
+                cls2.someMethod = function(){};
+
+                Ext.Class.preprocessors.inheritableStatics.fn(cls, data, emptyFn, emptyFn);
+                Ext.Class.preprocessors.extend.fn(cls2, { extend: cls }, emptyFn, emptyFn);
+
+                expect(cls2.someName).toEqual('someOtherValue');
+                expect(cls2.someMethod).not.toBe(Ext.emptyFn);
+            });
+        });
+    });
+
+    // END PREPROCESSORS =================================================================== /
+
+    describe("Instantiation", function() {
+        var subClass, parentClass, mixinClass1, mixinClass2;
+
+        beforeEach(function() {
+            mixinClass1 = new Ext.Class({
+                config: {
+                    mixinConfig: 'mixinConfig'
+                },
+
+                constructor: function(config) {
+                    this.initConfig(config);
+
+                    this.mixinConstructor1Called = true;
+                },
+
+                mixinProperty1: 'mixinProperty1',
+
+                mixinMethod1: function() {
+                    this.mixinMethodCalled = true;
+                }
+            });
+
+            mixinClass2 = new Ext.Class({
+                constructor: function(config) {
+                    this.initConfig(config);
+
+                    this.mixinConstructor2Called = true;
+                },
+
+                mixinProperty2: 'mixinProperty2',
+
+                mixinMethod2: function() {
+                    this.mixinMethodCalled = true;
+                }
+            });
+
+            parentClass = new Ext.Class({
+                mixins: {
+                    mixin1: mixinClass1
+                },
+                config: {
+                    name: 'parentClass',
+                    isCool: false,
+                    members: {
+                        abe: 'Abraham Elias',
+                        ed: 'Ed Spencer'
+                    },
+                    hobbies: ['football', 'bowling']
+                },
+                constructor: function(config) {
+                    this.initConfig(config);
+
+                    this.parentConstructorCalled = true;
+
+                    this.mixins.mixin1.constructor.apply(this, arguments);
+                },
+
+                parentProperty: 'parentProperty',
+
+                parentMethod: function() {
+                    this.parentMethodCalled = true;
+                }
+            });
+
+            subClass = new Ext.Class({
+                extend: parentClass,
+                mixins: {
+                    mixin1: mixinClass1,
+                    mixin2: mixinClass2
+                },
+                config: {
+                    name: 'subClass',
+                    isCool: true,
+                    members: {
+                        jacky: 'Jacky Nguyen',
+                        tommy: 'Tommy Maintz'
+                    },
+                    hobbies: ['sleeping', 'eating', 'movies'],
+                    isSpecial: true
+                },
+                constructor: function(config) {
+                    this.initConfig(config);
+
+                    this.subConstrutorCalled = true;
+
+                    subClass.superclass.constructor.apply(this, arguments);
+
+                    this.mixins.mixin2.constructor.apply(this, arguments);
+                },
+                myOwnMethod: function() {
+                    this.myOwnMethodCalled = true;
+                }
+            });
+        });
+
+        describe("addStatics", function() {
+            it("single with name - value arguments", function() {
+                var called = false;
+
+                subClass.addStatics({
+                    staticMethod: function(){
+                        called = true;
+                    }
+                });
+
+                expect(subClass.staticMethod).toBeDefined();
+                subClass.staticMethod();
+
+                expect(called).toBeTruthy();
+            });
+
+            it("multiple with object map argument", function() {
+                subClass.addStatics({
+                    staticProperty: 'something',
+                    staticMethod: function(){}
+                });
+
+                expect(subClass.staticProperty).toEqual('something');
+                expect(subClass.staticMethod).toBeDefined();
+            });
+        });
+
+
+        describe("override", function() {
+            it("should override", function() {
+                subClass.override({
+                    myOwnMethod: function(){
+                        this.isOverridden = true;
+
+                        this.callOverridden(arguments);
+                    }
+                });
+
+                var obj = new subClass;
+                obj.myOwnMethod();
+
+                expect(obj.isOverridden).toBe(true);
+                expect(obj.myOwnMethodCalled).toBe(true);
+            });
+        });
+
+        describe("mixin", function() {
+            it("should have all properties of mixins", function() {
+                var obj = new subClass;
+                expect(obj.mixinProperty1).toEqual('mixinProperty1');
+                expect(obj.mixinProperty2).toEqual('mixinProperty2');
+                expect(obj.mixinMethod1).toBeDefined();
+                expect(obj.mixinMethod2).toBeDefined();
+                expect(obj.config.mixinConfig).toEqual('mixinConfig');
+            });
+        });
+
+        describe("config", function() {
+            it("should merge properly", function() {
+                var obj = new subClass;
+                expect(obj.config).toEqual({
+                    mixinConfig: 'mixinConfig',
+                    name: 'subClass',
+                    isCool: true,
+                    members: {
+                        abe: 'Abraham Elias',
+                        ed: 'Ed Spencer',
+                        jacky: 'Jacky Nguyen',
+                        tommy: 'Tommy Maintz'
+                    },
+                    hobbies: ['sleeping', 'eating', 'movies'],
+                    isSpecial: true
+                });
+            });
+
+            it("should apply default config", function() {
+                var obj = new subClass;
+                expect(obj.getName()).toEqual('subClass');
+                expect(obj.getIsCool()).toEqual(true);
+                expect(obj.getHobbies()).toEqual(['sleeping', 'eating', 'movies']);
+            });
+
+            it("should apply with supplied config", function() {
+                var obj = new subClass({
+                    name: 'newName',
+                    isCool: false,
+                    members: {
+                        aaron: 'Aaron Conran'
+                    }
+                });
+
+                expect(obj.getName()).toEqual('newName');
+                expect(obj.getIsCool()).toEqual(false);
+                expect(obj.getMembers().aaron).toEqual('Aaron Conran');
+            });
+
+            it("should not share the same config", function() {
+                var obj1 = new subClass({
+                    name: 'newName',
+                    isCool: false,
+                    members: {
+                        aaron: 'Aaron Conran'
+                    }
+                });
+
+                var obj2 = new subClass();
+
+                expect(obj2.getName()).not.toEqual('newName');
+            });
+        });
+
+        describe("overriden methods", function() {
+            it("should call self constructor", function() {
+                var obj = new subClass;
+                expect(obj.subConstrutorCalled).toBeTruthy();
+            });
+
+            it("should call parent constructor", function() {
+                var obj = new subClass;
+                expect(obj.parentConstructorCalled).toBeTruthy();
+            });
+
+            it("should call mixins constructors", function() {
+                var obj = new subClass;
+                expect(obj.mixinConstructor1Called).toBeTruthy();
+                expect(obj.mixinConstructor2Called).toBeTruthy();
+            });
+        });
+
+    });
+
+});