UNPKG

siesta-lite

Version:

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

577 lines (482 loc) 24.6 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.Component This is a mixin, with helper methods for testing functionality relating to Ext.Component. This mixin is being consumed by {@link Siesta.Test.ExtJS}. */ Role('Siesta.Test.ExtJS.Component', { requires: ['waitFor'], methods: { componentIsHidden : function (comp) { var el = this.compToEl(comp); if (!el) return true return (comp.isHidden && comp.isHidden() || comp.isVisible && !comp.isVisible()) || !this.isElementVisible(el); }, /** * Waits until the main element of the passed component is the 'top' element in the DOM. The callback will receive the passed component instance. * * @param {Ext.Component/String} component An Ext.Component instance or a ComponentQuery string. In the latter case, * this method will also wait until the component query find some component (meaning the component does not have to * be already created when waiting starts) * @param {Function} callback The callback to call after the component becomes visible * @param {Object} scope The scope for the callback * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value. */ waitForComponentVisible: function (component, callback, scope, timeout) { var R = Siesta.Resource('Siesta.Test.ExtJS.Component'); var me = this; if (this.typeOf(component) != 'String' && !this.isExtJSComponentQueryTarget(component)) { throw R.get('badInputText') + ': ' + component; } return this.waitFor({ method : function () { var comp = me.normalizeComponent(component, true) if (!comp) return false var el = me.compToEl(comp); return el && me.elementIsTop(el, true) && comp; }, callback : callback, scope : scope, timeout : timeout, assertionName : 'waitForComponentVisible', description : ' ' + R.get('component') + ' "' + (me.typeOf(component) == 'String' ? component : component.id) + '" ' + R.get('toBeVisible') }); }, /** * Waits until the main element of the passed component is not visible. The callback will receive the passed component instance. * * @param {Ext.Component/String} component An Ext.Component instance or a ComponentQuery string. In the latter case, * this method will also wait until the component query find some component (meaning the component does not have to * be already created when waiting starts) * @param {Function} callback The callback to call after the component becomes not visible * @param {Object} scope The scope for the callback * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value. */ waitForComponentNotVisible: function (component, callback, scope, timeout) { var R = Siesta.Resource('Siesta.Test.ExtJS.Component'); var me = this; if (this.typeOf(component) != 'String' && !this.isExtJSComponentQueryTarget(component)) { throw R.get('badInputText') + ': ' + component; } return this.waitFor({ method : function () { var comp = me.normalizeComponent(component, true) if (!comp) return false return me.componentIsHidden(comp) && comp }, callback : callback, scope : scope, timeout : timeout, assertionName : 'waitForComponentNotVisible', description : ' ' + R.get('component') + ' "' + (me.typeOf(component) == 'String' ? component : component.id) + '" ' + R.get('toNotBeVisible') }); }, /** * Waits until Ext.ComponentQuery detects some results from the passed query parameter. The callback will receive the result of the query. * * The "root" argument of this method can be omitted. * * @param {String} selector The component query phrase * @param {Ext.Container} root The container to start a component query from. Optional * @param {Function} callback The callback to call after the xtype has been found * @param {Object} scope The scope for the callback * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value. */ waitForComponentQuery: function (selector, root, callback, scope, timeout) { // no `root` supplied if (this.typeOf(root) == 'Function') { timeout = scope scope = callback callback = root root = this.getExt() && this.getExt().ComponentQuery } return this.waitFor({ method : function () { var result = (root && root.query(selector) || this.getExt() && this.getExt().ComponentQuery.query(selector)); return result && result.length > 0 ? result : false; }, callback : callback, scope : scope, timeout : timeout, assertionName : 'waitForComponentQuery', description : ' ' + Siesta.Resource('Siesta.Test.ExtJS.Component', 'componentQuery') + ' "' + selector + '"' }); }, /** * Waits until {@link Siesta.Test.ExtJSCore#compositeQuery} detects some results from the passed query parameter. The callback will receive the result of the query. * * The "root" argument of this method can be omitted. * * @param {String} query The composite query phrase * @param {Ext.Container} root The container to start a component query from. Optional * @param {Function} callback The callback * @param {Object} scope The scope for the callback * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value. */ waitForCompositeQuery: function (query, root, callback, scope, timeout) { // no `root` supplied if (this.typeOf(root) == 'Function') { timeout = scope scope = callback callback = root root = this.getExt().ComponentQuery } var me = this; return me.waitFor({ method : function () { var result = me.compositeQuery(query, root, true); return result.length > 0 ? result : false; }, callback : callback, scope : scope, timeout : timeout, assertionName : 'waitForCompositeQuery', description : ' ' + Siesta.Resource('Siesta.Test.ExtJS.Component', 'compositeQuery') + ' "' + query + '"' }); }, /** * Waits until {@link Siesta.Test.ExtJSCore#compositeQuery} does not detects any results from the passed query parameter. * * The "root" argument of this method can be omitted. * * @param {String} query The composite query phrase * @param {Ext.Container} root The container to start a component query from. Optional * @param {Function} callback The callback * @param {Object} scope The scope for the callback * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value. */ waitForCompositeQueryNotFound: function (query, root, callback, scope, timeout) { // no `root` supplied if (this.typeOf(root) == 'Function') { timeout = scope scope = callback callback = root root = this.getExt().ComponentQuery } var me = this; return me.waitFor({ method : function () { var result = me.compositeQuery(query, root, true); return result.length > 0 ? false : true; }, callback : callback, scope : scope, timeout : timeout, assertionName : 'waitForCompositeQueryNotFound', description : ' ' + Siesta.Resource('Siesta.Test.ExtJS.Component', 'compositeQuery') + ' "' + query + '" ' + Siesta.Resource('Siesta.Test.ExtJS.Component', 'toReturnEmptyArray') }); }, /** * Shorthand alias for {@link #waitForComponentQuery} * * @param {String} query The component query phrase * @param {Ext.Container} root The container to start a component query from * @param {Function} callback The callback to call after the xtype has been found * @param {Object} scope The scope for the callback * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value. */ waitForCQ: function () { return this.waitForComponentQuery.apply(this, arguments); }, /** * Alias for {@link #waitForComponentQueryNotFound} * * @param {String} query * @param {Function} callback * @param {Object} scope * @param {Number} timeout */ waitForCQNotFound: function () { return this.waitForComponentQueryNotFound.apply(this, arguments); }, /** * Waits until Ext.ComponentQuery from the passed query parameter is no longer found, and then calls the callback supplied. * * The "root" argument of this method can be omitted. * * @param {String} query The component query selector * @param {Ext.Container} root The container to start a component query from. Optional * @param {Function} callback The callback to call after the xtype has been found * @param {Object} scope The scope for the callback * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value. */ waitForComponentQueryNotFound: function (query, root, callback, scope, timeout) { var R = Siesta.Resource('Siesta.Test.ExtJS.Component'); // no `root` supplied if (this.typeOf(root) == 'Function') { timeout = scope scope = callback callback = root root = this.getExt().ComponentQuery } return this.waitFor({ method : function () { var result = root.query(query); return result.length === 0 && result; }, callback : callback, scope : scope, timeout : timeout, assertionName : 'waitForComponentQueryNotFound', description : R.get('componentQuery') + ': ' + query + ' ' + R.get('toReturnEmpty') }); }, /** * Alias for {@link #waitForComponentQueryVisible} * * @param {String} query * @param {Function} callback * @param {Object} scope * @param {Number} timeout */ waitForCQVisible: function () { return this.waitForComponentQueryVisible.apply(this, arguments); }, /** * Alias for {@link #waitForComponentQueryNotVisible} * * @param {String} query * @param {Function} callback * @param {Object} scope * @param {Number} timeout */ waitForCQNotVisible: function () { return this.waitForComponentQueryNotVisible.apply(this, arguments); }, /** * Waits until all results of the `Ext.ComponentQuery` are detected and visible. * * The "root" argument of this method can be omitted. * * @param {String} query The component query selector * @param {Ext.Container} root The container to start a component query from. Optional * @param {Function} callback The callback to call after the waiting has been completed * @param {Object} scope The scope for the callback * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value. */ waitForComponentQueryVisible: function (query, root, callback, scope, timeout) { var me = this, R = Siesta.Resource('Siesta.Test.ExtJS.Component'), Ext = me.getExt(); // no `root` supplied if (this.typeOf(root) == 'Function') { timeout = scope scope = callback callback = root root = Ext.ComponentQuery } var firstNonVisibleId var resultsLen return this.waitFor({ method : function () { firstNonVisibleId = null var result = root.query(query), allVisible = true resultsLen = result.length if (resultsLen > 0) { Joose.A.each(result, function (c) { if (!c.rendered || !me.isElementVisible(c)) { allVisible = false firstNonVisibleId = c.id return false } }) return allVisible && result } else { return false } }, callback : callback, scope : scope, timeout : timeout, assertionName : 'waitForComponentQueryVisible', description : ' ' + R.get('componentQuery') + ': ' + query + ' to return a non-empty set of visible components', annotation : function () { // empty resultset if (resultsLen === 0) return "No matching components" // success - return nothing to not pollute the output with extra details if (resultsLen > 0 && firstNonVisibleId == null) return "" // non-empty resultset with some components hidden if (resultsLen > 0 && firstNonVisibleId != null) return "The matching component [id=" + firstNonVisibleId + "] is not visible" } }) }, /** * Waits until the result of the `Ext.ComponentQuery` is either empty, or the found component(s) is hidden. * * The "root" argument of this method can be omitted. * * @param {String} query The component query selector * @param {Ext.Container} root The container to start a component query from. Optional * @param {Function} callback The callback to call after the xtype has been found * @param {Object} scope The scope for the callback * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value. */ waitForComponentQueryNotVisible: function (query, root, callback, scope, timeout) { var me = this, R = Siesta.Resource('Siesta.Test.ExtJS.Component'), Ext = me.getExt(); // no `root` supplied if (this.typeOf(root) == 'Function') { timeout = scope scope = callback callback = root root = Ext.ComponentQuery } var firstVisibleId var resultsLen return this.waitFor({ method : function () { firstVisibleId = null var result = root.query(query), allHidden = true; resultsLen = result.length if (resultsLen > 0) { Joose.A.each(result, function (comp) { if (!me.componentIsHidden(comp)) { firstVisibleId = comp.id allHidden = false; return false; } }); return allHidden && result; } else { return true; } }, callback : callback, scope : scope, timeout : timeout, assertionName : 'waitForComponentQueryVisible', description : ' ' + R.get('componentQuery') + ': ' + query + ' ' + R.get('toReturnHiddenCmp'), annotation : function () { // success - return nothing to not pollute the output with extra details if (resultsLen === 0 || firstVisibleId == null) return "" // non-empty resultset with some components visible if (firstVisibleId != null) return "The matching component [id=" + firstVisibleId + "] is visible" } }); }, /** * Waits until the a component with the specified xtype can be detected by a simple ComponentQuery. * * The "root" argument of this method can be omitted. * * @param {String} xtype The component xtype to look for. * @param {Ext.Container} root The container to start a component query from. Optional * @param {Function} callback The callback to call after the xtype has been found * @param {Object} scope The scope for the callback * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value. */ waitForXType: function (xtype, root, callback, scope, timeout) { return this.waitForComponentQuery(xtype, root, callback, scope, timeout); }, /** * Waits until the a component with the specified xtype can be detected by a simple ComponentQuery. * * @param {String} component The class name to wait for. * @param {Boolean} rendered true to also wait for the component to be rendered * @param {Function} callback The callback to call after the component has been found * @param {Object} scope The scope for the callback * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value. */ waitForComponent: function (component, rendered, callback, scope, timeout) { var Ext = this.getExt(); var xtype if (Ext.isString(component)) { xtype = Ext.ClassManager.get(component).xtype; } else { xtype = component.xtype; } if (rendered) { xtype = xtype + '[rendered]'; } return this.waitForXType(xtype, callback, scope, timeout); }, /** * This assertion passes when the passed width and height matches the result of component.getSize() * * @param {Ext.Component/String} component An Ext.Component instance or a ComponentQuery * @param {Int} width * @param {Int} height * @param {String} [description] The description of the assertion */ hasSize: function (component, width, height, description) { component = this.normalizeComponent(component); this.isDeeply(component.getSize(), { width: width, height: height }, description); }, /** * This assertion passes when the passed x and y matches the result of component.getPosition() * * @param {Ext.Component/String} component An Ext.Component instance or a ComponentQuery * @param {Int} x * @param {Int} y * @param {String} [description] The description of the assertion */ hasPosition: function (component, x, y, description) { component = this.normalizeComponent(component); this.isDeeply(component.getPosition(), [x, y], description); }, /** * This assertion accepts variable number of Ext.Component instances (can be also provided as component query string). * Then it calls their "destroy" method and verifies that: * - there were no exceptions during destroy * - that each component was actually destoyed (since destroy can be canceled in the "beforedestroy" event listener) * * @param {Ext.Component/Array[Ext.Component]/String} components A single instance of Ext.Component, an array of such or a string with component query * @param {String} [description] The description of the assertion */ destroysOk : function (components, description) { var Ext = this.Ext(); var R = Siesta.Resource('Siesta.Test.ExtJS.Component'); if (this.typeOf(components) != 'Array') { if (this.typeOf(components) == 'String') components = this.Ext().ComponentQuery.query(components); else components = [ components ] } if (!components.length) { this.fail(description, { assertionName : 'destroysOk', annotation : R.get('invalidDestroysOkInput') }) return } var currentComp var e = this.getExceptionCatcher()(function () { Joose.A.each(components, function (component) { currentComp = component component.destroy() }) }) if (e !== undefined) { this.fail(description, { assertionName : 'destroysOk', got : e, gotDesc : R.get('exception'), annotation : R.get('exceptionAnnotation') + ' ' + currentComp.id }) return } var me = this var allDestroyed = Joose.A.each(components, function (component) { // ExtJS ST if (!(component.isDestroyed || component.destroy == Ext.emptyFn)) { me.fail(description, { assertionName : 'destroysOk', annotation : R.get('Component') + ' [' + component.id + '] ' + R.get('destroyFailed') }) return false } }) if (allDestroyed === false) return this.pass(description, { descTpl : R.get('destroyPassed') }) } } });