siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
226 lines (172 loc) • 8.75 kB
JavaScript
/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
/**
@class Siesta.Recorder.TargetExtractor.ExtJS
To resolve a component, this is done in the following prio list
1. Custom (non-auto-gen Id, client provided)
2. Custom field property (see componentIdentifier). User provides button with "foo : 'savebutton'", possibly add CSS selector
3. Custom xtype, user provides subclassed button for example, possibly combined with CSS selector (composite query)
3. For components, add some intelligence, user generated CSS properties win over Ext CSS properties
3a. Buttons could look for iconCls, text etc
3b. Menuitems same thing
3c. Grids and lists provide nth-child to know which position in the list
3d. Find extra non Ext classes (they start with "x-"), which of course have been put there by client
4. CSS selector (class names, nodeName DIV etc)
5. Coordinates
The type of target, possible options:
- 'cq' component query
- 'csq' composite query
*/
Class('Siesta.Recorder.TargetExtractor.ExtJS', {
isa : Siesta.Recorder.TargetExtractor,
does : [
Ariadne.ExtJSDomQueryFinder.Role.ExtJSHelper
],
has : {
// An accessor method to get the relevant Ext JS object for the target (which could reside inside an iframe)
Ext : null,
// do not calculate only-dom query for performance reasons
skipDomQuery : false,
uniqueComponentProperty : null
},
methods : {
initialize : function () {
this.SUPER()
this.ariadneDomFinder = new Ariadne.ExtJSDomQueryFinder({
uniqueDomNodeProperty : this.uniqueDomNodeProperty,
shouldIgnoreDomElementId : this.shouldIgnoreDomElementId
})
var properties = this.uniqueComponentProperty
if (properties)
properties = properties instanceof Array ? properties : [ properties ]
this.ariadneCQFinder = new Ariadne.ExtJSComponentQueryFinder({
uniqueComponentProperty : properties
})
if (this.swallowExceptions) {
this.findComponentQueryFor = this.safeBind(this.findComponentQueryFor)
this.findCompositeQueryFor = this.safeBind(this.findCompositeQueryFor)
}
},
setExt : function (node) {
var doc = node.ownerDocument;
this.Ext = (doc.defaultView || doc.parentWindow).Ext;
this.ariadneCQFinder.setExt(this.Ext)
},
getTargets : function (event, saveOffset, targetOverride, onlyXY) {
if (onlyXY) return this.SUPER(event, saveOffset, targetOverride, onlyXY);
var target = targetOverride || event.target;
var component;
this.setExt(target);
var hasCQ = this.Ext && this.Ext.ComponentQuery && (this.Ext.versions && !this.Ext.versions.touch);
if (hasCQ) {
component = this.getComponentOfDomElement(target);
}
var compEl = component && (component.el || component.element)
compEl = compEl && compEl.dom
// 1. Ext might not exist in the page,
// 2. Ext JS < 4 has no support for ComponentQuery
// 3. We don't support recording Touch applications
// 4. If the page has been translated by Google translate toolbar, then google will create copies
// of many component's elements with the same ids, which messes up everything
// so in this case, wrong component of the element can be found
// we add additional check, that target is inside of the component el,
// otherwise we skip all the component/composite queries
if (!hasCQ || (compEl && !compEl.contains(target))) return this.SUPER(event, saveOffset, targetOverride);
var result = []
var hasCoordinates = event.x != null && event.y != null
// also try to find component/composite queries for the target
if (component) {
var componentQuery = this.findComponentQueryFor(component)
if (componentQuery) {
result.unshift({
type : 'cq',
target : componentQuery,
offset : hasCoordinates && (saveOffset || !this.isElementReachableAtCenter(compEl, false)) ?
this.findOffset(event.x, event.y, compEl)
:
null
})
// if `target` and `compEl` are the same - it means CQ is enough, no need to identify node any "deeper"
if (compEl != target) {
var compositeQuery = this.findCompositeQueryFor(target, componentQuery, component)
if (compositeQuery)
result.unshift({
type : 'csq',
target : compositeQuery,
offset : hasCoordinates && (saveOffset || !this.isElementReachableAtCenter(target, false)) ?
this.findOffset(event.x, event.y, target)
:
null
})
}
}
}
// only get XY from SUPER method if `skipDomQuery` is enablled _and_ we already have cq/csq target
return result.concat(this.SUPER(event, saveOffset, targetOverride, this.skipDomQuery && result.length))
},
findCompositeQueryFor : function (node, componentQuery, component) {
if (!componentQuery) {
var component = this.getComponentOfDomElement(node)
if (!component) return null
componentQuery = this.findComponentQueryFor(component)
if (!componentQuery) return null
}
var compEl = component.el || component.element
var root = compEl.dom
if (node == root || !root.contains(node)) return null
var compositeDomQuery = this.findDomQueryFor(node, root)
return compositeDomQuery ? componentQuery + ' => ' + compositeDomQuery : null
},
findComponentQueryFor : function (comp, root) {
return this.ariadneCQFinder.findQuery(comp, root)
}
// something old, not used remove after some time
// // Component Query with extensions - ".someMethod()" at the end
// doNonStandardComponentQuery : function (query, lookUpUntil) {
// var Ext = this.Ext
// var match = /(.+?)\.(\w+)\(\)/g.exec(query)
//
// var trimmedQuery = ((match && match[ 1 ]) || query).trim();
// var methodName = match && match[ 2 ]
//
// // Discard any hidden components, special treatment of Ext Widgets that don't yet implement isVisible.
// // https://www.sencha.com/forum/showthread.php?308370-CQ-crashes-if-widgets-are-used&p=1126410#post1126410
// var matchedComponents = Ext.ComponentQuery.query(trimmedQuery + ':not([isVisible])').concat(
// Ext.ComponentQuery.query(trimmedQuery + '[isVisible]{isVisible()}')
// )
//
// if (methodName)
// for (var i = 0; i < matchedComponents.length; i++)
// if (Object.prototype.toString.call(matchedComponents[ i ][ methodName ]) == '[object Function]')
// matchedComponents[ i ] = matchedComponents[ i ][ methodName ]()
//
// return matchedComponents
// },
//
//
// resolveTarget : function (target) {
// if (target.type == 'cq') {
// var component = this.doNonStandardComponentQuery(target.target)[ 0 ]
// var el = component && (component.el || component.element)
//
// return el && el.dom
// }
//
// if (target.type == 'csq') {
// var parts = target.target.split('=>')
//
// var compEl = this.resolveTarget({ type : 'cq', target : parts[ 0 ] })
//
// var el = compEl && Sizzle.Sizzle(parts[ 1 ], compEl)[ 0 ]
//
// return el
// }
//
// return this.SUPERARG(arguments)
// }
}
});