UNPKG

siesta-lite

Version:

Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers

367 lines (291 loc) 14.3 kB
/* Siesta 5.6.1 Copyright(c) 2009-2022 Bryntum AB https://bryntum.com/contact https://bryntum.com/products/siesta/license */ /** * @class Siesta.Test.ExtJS @extends Siesta.Test.Browser @mixin Siesta.Test.ExtJSCore @mixin Siesta.Test.ExtJS.Ajax @mixin Siesta.Test.ExtJS.Observable @mixin Siesta.Test.ExtJS.FormField @mixin Siesta.Test.ExtJS.Component @mixin Siesta.Test.ExtJS.Element @mixin Siesta.Test.ExtJS.Store @mixin Siesta.Test.ExtJS.DataView @mixin Siesta.Test.ExtJS.Grid A base class for testing browser and ExtJS applications. It inherit from {@link Siesta.Test.Browser} and adds various ExtJS specific assertions. This file is a reference only, for a getting start guide and manual, please refer to <a href="#!/guide/getting_started_browser">Siesta getting started in browser environment</a> guide. */ Class('Siesta.Test.ExtJS', { isa : Siesta.Test.Browser, does : [ Siesta.Test.ExtJSCore, Siesta.Test.ExtJS.Component, Siesta.Test.ExtJS.Element, Siesta.Test.ExtJS.FormField, Siesta.Test.ExtJS.Observable, Siesta.Test.ExtJS.Store, Siesta.Test.ExtJS.Grid, Siesta.Test.ExtJS.DataView, Siesta.Test.ExtJS.Ajax ], has : { globalExtOverrides : null, extPathRegex1 : /(.*ext(?:js)?(?:-\d\.\d+\.\d+)?.*?)\/(?:build\/)?ext(?:-all)?(?:-debug|-dev)?\.js/, extPathRegex2 : /(.*ext(?:js)?-\d\.\d+(?:\.\d+)?.*?)\/ext-all(?:-debug|-dev)?\.js/, extPathRegex3 : /(.*ext(?:js)?\/gpl\/\d\.\d+(?:\.\d+)?.*?)\/ext-all(?:-debug|-dev)?\.js/ }, methods : { getExtBundlePath : function() { var path var testDescriptor = this.project.getScriptDescriptor(this.url) var me = this while (testDescriptor && !path) { if (testDescriptor.preload) { Joose.A.each(testDescriptor.preload, function (url) { if (url.match && (url.match(me.extPathRegex1) || url.match(me.extPathRegex2) || me.extPathRegex3.exec(url))) { path = url; return false; } }); } testDescriptor = testDescriptor.parent; } return path; }, getExtBundleFolder : function() { var folder; var testDescriptor = this.project.getScriptDescriptor(this.url) var me = this while (testDescriptor && !folder) { if (testDescriptor.preload) { Joose.A.each(testDescriptor.preload, function (url) { var match = me.extPathRegex1.exec(url) || me.extPathRegex2.exec(url) || me.extPathRegex3.exec(url); if (match) folder = match[1]; return false }); } testDescriptor = testDescriptor.parent; } return folder; }, getNumberOfGlobalExtOverrides : function (callback) { var globalExtOverrides = this.globalExtOverrides; if (globalExtOverrides != null) callback && callback.call(this, globalExtOverrides.length, globalExtOverrides) else { var me = this; var Ext = this.getExt(); var extjsBundleURL = me.getExtBundlePath() if (!extjsBundleURL) { me.fail(Siesta.Resource('Siesta.Test.ExtJS', 'bundleUrlNotFound')); callback && callback.call(me, null, null) return; } // For IE this.expectGlobal('0'); var frame = Ext.core.DomHelper.append(Ext.getBody(), { tag : "iframe", style : 'width:1024px;height:768px;position:absolute;left:-10000px;top:-10000px', src : 'about:blank' }, false); var freshWin = frame.contentWindow; freshWin.document.open(); freshWin.document.write( '<!DOCTYPE html>' + '<html>' + '<head>' + '<script type="text/javascript" src="' + extjsBundleURL + '"></script>' + '</head>' + '<body></body>' + '</html>' ); freshWin.document.close(); var resolveObject = function (hostObj, nameSpace) { var parts = nameSpace.split('.'); var p = hostObj for (var i = 0; i < parts.length; i++) { p = p[ parts[ i ] ]; }; return p; } var ignoreRegexp = [ /Ext\.data\.Store\.ImplicitModel|collectorThreadId|Ext\.dom\.GarbageCollector\.lastTime/, /Ext.globalEvents.cur/i, /Ext\.dd\.(DragDropManager|DragDropMgr|DDM)\.(currentPoint|offsetX|offsetY)/ ] var ignore = function (name) { for (var i = 0; i < ignoreRegexp.length; i++) if (ignoreRegexp[ i ].test(name)) return true return false } var getObjectDifferences = function (cleanObj, dirtyObj, ns) { var diff = [] for (var p in dirtyObj) { try { if (dirtyObj.hasOwnProperty(p)) { var dirtyValue = dirtyObj[ p ] var cleanValue = cleanObj[ p ] // Check if the object exists on the clean window and also do a string comparison // in case a builtin method has been overridden if ( (!cleanObj.hasOwnProperty(p) && typeof cleanValue == 'undefined' ) || ( String(cleanValue) != String(dirtyValue) && (typeof dirtyValue == 'function' || Ext.isPrimitive(dirtyValue)) ) ) { if (!ignore(ns + '.' + p)) diff.push(ns + '.' + p) } } } catch (e) { // Just continue } } return diff; } me.waitFor( function () { return freshWin.Ext && freshWin.Ext.isReady; }, function () { var dirtyWin = me.global, overrides = []; // Check for native class augmentations Ext.iterate(Ext.ClassManager.classes, function (item) { if (!item.match(/^Ext\./)) return; var freshItem = resolveObject(freshWin, item); var dirtyItem = resolveObject(dirtyWin, item); if (freshItem && typeof dirtyItem !== 'undefined') { var staticDiff = getObjectDifferences(freshItem, dirtyItem, item); overrides.push.apply(overrides, staticDiff); // Prototype properties if (dirtyItem.prototype) { var prototypeDiff = getObjectDifferences(freshItem.prototype, dirtyItem.prototype, item + '.prototype'); overrides.push.apply(overrides, prototypeDiff); } } }); me.globalExtOverrides = overrides Ext.destroy(frame); callback && callback.call(me, overrides.length, overrides) } ) // eof waitFor } }, /** * This assertion passes if no global Ext JS overrides exist. It creates a fresh iframe window where a new, fresh copy * of Ext JS w/o any overrides is loaded and then a comparison is made against the copy of Ext JS loaded in the test. * * A global ExtJS override is some change, made in the core class, for example like this: * Ext.data.Store.override({ removeAll : function () { // my fix ... } }) * While such overrides are often seems as the only possible solution (usually for some bug in Ext) they should be * avoided as much as possible, because it a very bad practice. For example, in the previous case, a better approach * would be to create a new subclass of the Ext.data.Store with the desired changed. * * See also {@link #assertMaxNumberOfGlobalExtOverrides} assertion. * * @param {String} [description] The description for the assertion */ assertNoGlobalExtOverrides : function (description, cb) { this.getNumberOfGlobalExtOverrides(function (length, overrides) { var R = Siesta.Resource('Siesta.Test.ExtJS'); if (length == null) { this.fail(R.get('assertNoGlobalExtOverridesInvalid')) } else { if (length) { this.fail(description, { assertionName : 'assertNoGlobalExtOverrides', descTpl : R.get('assertNoGlobalExtOverridesPassTpl'), got : length, gotDesc : R.get('assertNoGlobalExtOverridesGotDesc'), annotation : R.get('foundOverridesFor') + ': `' + overrides.join('`, `') + '`' }) } else { this.pass(description, { descTpl : R.get('assertNoGlobalExtOverridesPassTpl') }) } // For testing only cb && cb.call(this); } }) }, /** * This assertion passes if the number of global overrides does not exceed the given number. * * For example, you can add this assertion in your existing codebase (assuming you have 3 overrides your application * cannot function without): * * t.assertMaxNumberOfGlobalExtOverrides(3, "Ideally should be none of these") * * and catch all the cases when someone adds a new global override. * * @param {Number} maxNumber The maximum number of Ext JS overrides allowed * @param {String} [description] The description for the assertion */ assertMaxNumberOfGlobalExtOverrides : function (maxNumber, description, cb) { var R = Siesta.Resource('Siesta.Test.ExtJS'); this.getNumberOfGlobalExtOverrides(function (length, overrides) { if (length == null) { this.fail(R.get("extOverridesInvalid")); } else { if (length > maxNumber) { this.fail(description, { assertionName : 'assertNoGlobalExtOverrides', descTpl : R.get('foundLessOrEqualThan') + ' ' + maxNumber + ' ' + R.get('globalOverrides'), got : length, gotDesc : R.get('nbrOverridesFound'), annotation : R.get('foundOverridesFor') + ': `' + overrides.join('`, `') + '`' }) } else { this.pass(description, { descTpl : R.get('foundLessOrEqualThan') + ' ' + maxNumber + ' ' + R.get('globalOverrides'), annotation : R.get('nbrOverridesFound') + ': ' + length }) } // For testing only cb && cb.call(this) } }) }, /** * A helper method returning the total number of Ext JS container layouts that have been performed since the beginning of the page lifecycle. * @return {Int} The number of layouts */ getTotalLayoutCounter : function () { var count = 0 this.Ext().each(this.cq('container'), function(c) { count += c.layoutCounter }); return count; }, /** * This assertion passes if no Ext JS layout cycles are performed as a result of running the passed function. This * function will query all containers on the page and measure the number of layouts performed before and after the function call. * * @param {Function} fn The function to call * @param {Object} scope The 'thisObject' to use for the function call * @param {String} [description] The description for the assertion */ assertNoLayoutTriggered : function(fn, scope, description) { var countBefore = this.getTotalLayoutCounter(); fn.call(scope || this); this.is(this.getTotalLayoutCounter(), countBefore, description); }, areAnimationsRunning : function() { var Ext = this.Ext(); return Ext && Ext.fx && Ext.fx.Manager && Ext.fx.Manager.items && Ext.fx.Manager.items.getCount() > 0; } } })