UNPKG

extjs-gpl

Version:

GPL licensed version of Sencha Ext JS

705 lines (577 loc) 23.9 kB
describe("Ext.Base", function() { var cls; afterEach(function() { cls = null; }); describe("deprecated", function() { afterEach(function() { delete Ext.versions.foo; delete Ext.compatVersions.foo; }); function declareClass (compatVersion) { Ext.setCompatVersion('foo', compatVersion); cls = Ext.define(null, { foo: function () { return 'a'; }, deprecated: { name: 'foo', 5: { methods: { bar: 'foo', foo: function () { return this.callParent() + 'd'; } } }, 5.1: { methods: { foo: { fn: function () { return this.callParent() + 'c'; } } } }, '5.2': { methods: { foo: { message: 'Foo is bad', fn: function () { return this.callParent() + 'b'; } } } } } }); } describe('no backward compatibility', function () { beforeEach(function () { declareClass('5.2'); }); it("should not activate methods when compatVersion equals curVersion", function() { var obj = new cls(); var s = obj.foo(); expect(s).toBe('a'); }); it("should install error shim from old block", function() { var obj = new cls(); var s = 'No exception'; // Silence console error spyOn(Ext, 'log'); try { obj.bar(); } catch (e) { s = e.message; } expect(s).toBe('"#bar" is deprecated. Please use "foo" instead.'); }); }); describe('one increment of backward compatibility', function () { beforeEach(function () { declareClass('5.1'); }); it("should activate just one block", function() { var obj = new cls(); var s = obj.foo(); expect(s).toBe('ab'); }); it("should install error shim from old block", function() { var obj = new cls(); var s = 'No exception'; // Silence console error spyOn(Ext, 'log'); try { obj.bar(); } catch (e) { s = e.message; } expect(s).toBe('"#bar" is deprecated. Please use "foo" instead.'); }); }); describe('two increments of backward compatibility', function () { beforeEach(function () { declareClass('5'); }); it("should activate just two blocks", function() { var obj = new cls(); var s = obj.foo(); expect(s).toBe('abc'); }); it("should install error shim from old block", function() { var obj = new cls(); var s = 'No exception'; // Silence console error spyOn(Ext, 'log'); try { obj.bar(); } catch (e) { s = e.message; } expect(s).toBe('"#bar" is deprecated. Please use "foo" instead.'); }); }); describe('full backward compatibility', function () { beforeEach(function () { declareClass('4.2'); }); it("should activate all three blocks", function() { var obj = new cls(); var s = obj.foo(); expect(s).toBe('abcd'); }); it("should install alias", function() { var obj = new cls(); var s = obj.bar(); expect(s).toBe('abcd'); }); }); }); describe("compatibility", function() { var Cls, fn, overrideFn; beforeEach(function() { fn = function() {}; overrideFn = function() {}; Cls = Ext.define(null, { someFn: fn }); }); afterEach(function() { overrideFn = fn = Cls = null; }); describe("null/undefined", function() { it("should not apply the override if the compat value is null", function() { Ext.define(null, { override: Cls, compatibility: null, someFn: overrideFn }); expect(Cls.prototype.someFn).toBe(fn); }); it("should not apply the override if the compat value is undefined", function() { Ext.define(null, { override: Cls, compatibility: null, someFn: overrideFn }); expect(Cls.prototype.someFn).toBe(fn); }); }); describe("boolean", function() { it("should not apply the override if the compat value is false", function() { Ext.define(null, { override: Cls, compatibility: false, someFn: overrideFn }); expect(Cls.prototype.someFn).toBe(fn); }); it("should apply the override if the compat value is true", function() { Ext.define(null, { override: Cls, compatibility: true, someFn: overrideFn }); expect(Cls.prototype.someFn).toBe(overrideFn); }); }); describe("numeric", function() { it("should not apply the override if the compat value is 0", function() { Ext.define(null, { override: Cls, compatibility: 0, someFn: overrideFn }); expect(Cls.prototype.someFn).toBe(fn); }); it("should apply the override if the compat value is non zero", function() { Ext.define(null, { override: Cls, compatibility: 9, someFn: overrideFn }); expect(Cls.prototype.someFn).toBe(overrideFn); }); }); // We don't want exhaustive testing of all version combinations here since // that would basically just be testing checkVersion, we just want to see if // the basics get passed along describe("other values", function() { var oldVersions; beforeEach(function () { oldVersions = Ext.versions; Ext.versions = { ext: new Ext.Version('4.2.2.900') }; }); afterEach(function () { Ext.versions = oldVersions; oldVersions = null; }); describe("version string", function() { it("should not apply the override if the version string does not match", function() { Ext.define(null, { override: Cls, compatibility: '4.2.1', someFn: overrideFn }); expect(Cls.prototype.someFn).toBe(fn); }); it("should apply the override if the version string matches", function() { Ext.define(null, { override: Cls, compatibility: '4.2.2.900', someFn: overrideFn }); expect(Cls.prototype.someFn).toBe(overrideFn); }); }); describe("array of version strings", function() { it("should not apply the override if the versions don't match", function() { Ext.define(null, { override: Cls, compatibility: ['4.2.1', '5.1.0-5.1.3'], someFn: overrideFn }); expect(Cls.prototype.someFn).toBe(fn); }); it("should apply the override if the versions match", function() { Ext.define(null, { override: Cls, compatibility: ['4.1.0-4.1.3', '4.2.0-4.2.4'], someFn: overrideFn }); expect(Cls.prototype.someFn).toBe(overrideFn); }); }); }); }); describe("borrow", function() { beforeEach(function() { Ext.define("spec.Foo", { a: function() { return 'foo a'; }, b: function() { return 'foo b'; }, c: function() { return 'foo c'; } }); Ext.define("spec.Bar", { a: function() { return 'bar a'; } }); }); afterEach(function() { Ext.undefine('spec.Foo'); Ext.undefine('spec.Bar'); }); it("should borrow methods", function() { spec.Bar.borrow(spec.Foo, ['b', 'c']); var bar = new spec.Bar(); expect(bar.a()).toEqual('bar a'); expect(bar.b()).toEqual('foo b'); expect(bar.c()).toEqual('foo c'); }); }); describe("createAlias", function() { var o; function makeCls(fn, name) { var o = {}; o[name || 'oldFn'] = fn; cls = Ext.define(null, o); } afterEach(function() { o = null; }); it("should create a method on the prototype", function() { makeCls(function(){}); cls.createAlias('newFn', 'oldFn'); expect(Ext.isFunction(cls.prototype.newFn)).toBe(true); }); it("should call through to the old method with the passed arguments", function() { var a, b; makeCls(function(arg1, arg2) { a = arg1; b = arg2; }); cls.createAlias('newFn', 'oldFn'); o = new cls(); o.newFn('Val', 17); expect(a).toBe('Val'); expect(b).toBe(17); }); it("should dynamically resolve the old method at runtime", function() { var values = []; makeCls(function() { values.push(1); }); cls.createAlias('newFn', 'oldFn'); o = new cls(); o.newFn(); cls.override({ oldFn: function() { values.push(2); } }); o.newFn(); o.oldFn = function() { values.push(3); }; o.newFn(); expect(values).toEqual([1, 2, 3]); }); }); describe("override", function() { describe("mixins", function() { var aFn, bFn; beforeEach(function() { aFn = function() {}; bFn = function() {}; Ext.define('spec.Mix1', { extend: 'Ext.Mixin', mixinConfig: { id: 'mix1' }, a: aFn }); Ext.define('spec.Mix2', { extend: 'Ext.Mixin', mixinConfig: { id: 'mix2' }, b: bFn }); }); afterEach(function() { aFn = bFn = null; Ext.undefine('spec.Mix1'); Ext.undefine('spec.Mix2'); Ext.undefine('spec.MyBase'); }); it("should add mixins on a class without mixins", function() { cls = Ext.define('spec.MyBase', { }); Ext.define(null, { override: 'spec.MyBase', mixins : ['spec.Mix1'] }); expect(cls.prototype.a).toBe(aFn); expect(cls.prototype.mixins.mix1).toBe(spec.Mix1.prototype); }); it("should add mixins on a class with existing mixins", function() { cls = Ext.define('spec.MyBase', { mixins: ['spec.Mix1'] }); Ext.define(null, { override: 'spec.MyBase', mixins : ['spec.Mix2'] }); expect(cls.prototype.a).toBe(aFn); expect(cls.prototype.mixins.mix1).toBe(spec.Mix1.prototype); expect(cls.prototype.b).toBe(bFn); expect(cls.prototype.mixins.mix2).toBe(spec.Mix2.prototype); }); it("should add mixins when the type differs", function() { cls = Ext.define('spec.MyBase', { mixins: { mixFoo: 'spec.Mix1' } }); Ext.define(null, { override: 'spec.MyBase', mixins : ['spec.Mix2'] }); expect(cls.prototype.a).toBe(aFn); expect(cls.prototype.mixins.mixFoo).toBe(spec.Mix1.prototype); expect(cls.prototype.b).toBe(bFn); expect(cls.prototype.mixins.mix2).toBe(spec.Mix2.prototype); }); }); }); describe("destruction", function() { var Class, instance, linked; beforeEach(function() { Class = Ext.define(null, { constructor: function(config) { Ext.apply(this, config); } }); }); afterEach(function() { // Should be already destroyed in the tests! Class = instance = linked = null; }); describe("basics", function() { beforeEach(function() { instance = new Class(); instance.destroy(); }); it("should set destroyed flag", function() { expect(instance.destroyed).toBe(true); }); it("should set isDestroyed flag", function() { expect(instance.isDestroyed).toBe(true); }); it("should replace destroy method with emptyFn", function() { expect(instance.destroy).toBe(Ext.emptyFn); }); }); describe("linking", function() { describe("instances", function() { beforeEach(function() { linked = new Class(); instance = new Class(); instance.link('foo', linked); instance.destroy(); }); it("should destroy linked instance", function() { expect(linked.destroyed).toBe(true); }); it("should null linked reference on the instance", function() { expect(instance.foo).toBe(null); }); it("should null $links map", function() { expect(instance.$links).toBe(null); }); }); describe("DOM nodes", function() { beforeEach(function() { linked = document.createElement('div'); document.body.appendChild(linked); instance = new Class(); instance.link('frobbe', linked); instance.destroy(); }); it("should detach the linked DOM node", function() { expect(linked.parentElement).toBe(null); }); it("should null linked reference on the instance", function() { expect(instance.frobbe).toBe(null); }); it("should null $links map", function() { expect(instance.$links).toBe(null); }); }); }); describe("cleanup", function() { var oldFlag; beforeEach(function() { oldFlag = Ext.Base.prototype.clearPropertiesOnDestroy; Ext.Base.prototype.clearPropertiesOnDestroy = true; Class.prototype.$noClearOnDestroy = { bar: true }; Class.prototype.qux = {}; Class.prototype.mymse = function() {}; }); afterEach(function() { Ext.Base.prototype.clearPropertiesOnDestroy = oldFlag; }); describe("reaping", function() { beforeEach(function() { instance = new Class({ foo: 'baroo', bar: {}, blerg: function() {}, // NOT emptyFn throbbe: Ext.emptyFn, frob: Ext.privateFn, fred: Ext.identityFn, zumbo: {}, gurgle: [], zingbong: document.createElement('div') }); instance.destroy(); }); it("should null own object references", function() { expect(instance.zumbo).toBe(null); }); it("should null own array references", function() { expect(instance.gurgle).toBe(null); }); it("should null own DOM node references", function() { expect(instance.zingbong).toBe(null); }); it("should null own closure references", function() { expect(instance.blerg).toBe(null); }); it("should not null primitive values", function() { expect(instance.foo).toBe('baroo'); }); it("should not null own emptyFn references", function() { expect(instance.throbbe).toBe(Ext.emptyFn); }); it("should not null own privateFn references", function() { expect(instance.frob).toBe(Ext.privateFn); }); it("should not null own identityFn references", function() { expect(instance.fred).toBe(Ext.identityFn); }); it("should not null inherited object references", function() { expect(typeof instance.qux).toBe('object'); }); it("should not null inherited function references", function() { expect(typeof instance.mymse).toBe('function'); }); it("should not null whitelisted own properties", function() { expect(typeof instance.bar).toBe('object'); }); it("should not null properties when the mood is not right", function() { instance = new Class({ foo: {}, clearPropertiesOnDestroy: false }); instance.destroy(); expect(typeof instance.foo).toBe('object'); }); }); if (Object.setPrototypeOf) { describe("nuking", function() { it("should not nuke the instance by default", function() { instance = new Class(); instance.destroy(); expect(Object.getPrototypeOf(instance)).not.toBe(null); }); it("should set prototype to null when flag is set", function() { instance = new Class({ clearPrototypeOnDestroy: true }); instance.destroy(); expect(Object.getPrototypeOf(instance)).toBe(null); }); }); } describe("asynchronoucitiness", function() { var oldDelay; beforeEach(function() { Class.prototype.clearPropertiesOnDestroy = 'async'; // Jasmine may kick in to introduce an async gap in processing oldDelay = Ext.Reaper.delay; Ext.Reaper.delay = Number.MAX_SAFE_INTEGER; // Can't spy on the instance because destructor would null the spy! spyOn(Class.prototype, '$reap').andCallThrough(); instance = new Class({ foo: {} }); instance.destroy(); }); afterEach(function() { Ext.Reaper.delay = oldDelay; }); it("should add instance to Reaper's pile of corpses", function() { expect(Ext.Array.indexOf(Ext.Reaper.queue, instance)).not.toBe(-1); }); it("should raise the timer", function() { expect(Ext.Reaper.timer).not.toBe(null); }); it("should reap all dead bodies on tick", function() { Ext.Reaper.tick(); expect(instance.foo).toBe(null); expect(Ext.Reaper.queue.length).toBe(0); }); }); }); }); });