siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
577 lines (482 loc) • 24.6 kB
JavaScript
/*
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')
})
}
}
});