Version 8.0.1 |
resolvers
moduleThis extension API lets you install hooks that can modify the way QF-Test recognizes and records components and items. This is a very powerful feature that gives you fine-grained control over the QF-Test component management.
Video: 'Resolvers in QF-Test'.
Note When registering resolvers it is important to specify the correct 'GUI engine' attribute in the 'SUT script'. If the wrong engine is specified, the resolver simply will not work. If no engine is specified the resolver applies to all engines which can cause confusion and break replay in engines for which the resolver was not intended.
We will start with a short description of how QF-Test does component recognition to give you an idea where resolvers come into play. It consists roughly of four steps:
QF-Test uses resolvers for steps 2 and 3. Via the API you can overwrite resolver methods and thus manipulate component recognition.
A resolver is the only way to influence component recognition during recording. During replay you also have other options (e.g. a script or a regular expression in the details of the 'Component' node) to get at component data.
Web
For web applications QF-Test offers a specialized interface providing most of the
functionality of the resolvers described below, which is a lot easier to handle.
See Improving component recognition with a CustomWebResolver
. The 'Install CustomWebResolver' node
has been optimized for web elements thus providing a better
performance than resolvers of this section. The use of below resolvers
for web components should be limited to very special cases.
A list of available resolvers
:
NameResolver
subsection 53.1.7GenericClassNameResolver
subsection 53.1.8ClassNameResolver
subsection 53.1.9FeatureResolver
subsection 53.1.10ExtraFeatureResolver
subsection 53.1.11ItemNameResolver
subsection 53.1.12ItemValueResolver
subsection 53.1.13TreeTableResolver
subsection 53.1.14InterestingParentResolver
subsection 53.1.15TooltipResolver
subsection 53.1.16IdResolver
subsection 53.1.17EnabledResolver
subsection 53.1.18VisibilityResolver
subsection 53.1.19MainTextResolver
subsection 53.1.20WholeTextResolver
subsection 53.1.21BusyPaneResolver
subsection 53.1.22GlassPaneResolver
subsection 53.1.23TreeIndentationResolver
subsection 53.1.24EventSynchronizer
subsection 53.1.25BusyApplicationDetector
subsection 53.1.26ExtraFeatureMatcher
subsection 53.1.27.1The following two steps are required to implement a resolver:
In most cases the interface consists of only one method. A typical example would be (Jython-Skript):
| ||||
Example 53.1: Simple NameResolver (Jython) for MenuItems |
The first three lines are the method of the resolver interface. The name of the
method defines the resolver type. Each resolver type manipulates a certain value in the
'Component' node data. In our case the method is getName
thus
defining a name resolver. The fourth line calls the function addResolver
of the resolvers
module and registers the resolver.
Most resolver methods only have two parameters: the first is the component for which component recognition is done at that moment. The second is the value or object to be handled by the method. With a name resolver it is the name determined by the QF-Test standard name resolver. With a feature resolver the feature determined by QF-Test and so on. You will find a detailed description of the resolvers interfaces in chapters subsection 53.1.7 to subsection 53.1.26.
Each resolver needs to be given a name at registration time. The name has to be
unique. It will be used when the resolver needs to be updated or
uninstalled explicitly via resolvers.removeResolver("resolver name")
(see subsection 53.1.4). The names of all registered
resolvers can be listed via the function resolvers.listNames()
(see subsection 53.1.5).
After changing the contents of a resolver script it needs to be executed again in order to register the updated resolver. As long as the name of the resolver remains unchanged there is no need to first deregister the old version first.
All resolver types can be registered either for single components, specific classes or Generic classes. Resolvers registered for a single component are only called when exactly that component is being handled. Resolvers registered for a certain class are called for all components of this type and derived classes.
A resolver may be registered for one or several components and/or classes.
If no parameter is specified the resolver will be called for components of
all classes. For example, a NameResolver
or a FeatureResolver
registered globally will be
called for each and every name or feature. This is similar to but more efficient than
registering them on the java.lang.Object
class in the case of Java applications.
You may set up resolvers for various tasks and register them at run time. In order to install a resolver permanently, put the 'SUT script' node for the resolver directly after the 'Wait for client to connect' node in the start sequence of the SUT.
If multiple resolvers are registered globally or registered on the same object or class, the resolver added last will be called first. The first resolver returning a non-null value determines the outcome.
Since a resolver will be called for each instance of the component, respectively class, displayed
in the GUI you should implement time-saving algorithms for the resolvers.
For example, in a Jython script the execution of string[0:3] == "abc"
is faster than
string.startswith("abc")
.
All exceptions thrown inside a name resolver will be caught and handled by the
ResolverRegistry
. However, instead of dumping a stack trace, the registry
will only print a short message like "Exception inside NameResolver" because some resolvers
may be called very often, and a buggy resolver printing a stack trace for every error
would flood the net and the client terminal. Therefore name resolvers should include
their own error handling. This can still generate a lot of output in some cases, but
the output will be more useful than a Java stack trace.
The resolvers
module is always automatically available in all
'SUT script' nodes.
Most examples in the manual are implemented as Jython scripts. In subsection 53.1.7 you will find examples for Groovy 'SUT script' nodes.
addResolver
The generic function addResolver
has a central role in the
resolvers
module. Given the name of the defined method and its parameters
it identifies the respective object and its specific function for registering the
resolver.
| |||||||||||||||||||||||||||||||
History
Resolvers have quite a history in QF-Test. Up to QF-Test version 4.1 you had to call
a function specific to each resolver interface in order to register a certain resolver
type. You may continue to use those functions. However, they are no longer described in
the manual. The flexible addResolver
function replaces the following
functions, among others, of the resolvers
module:
addNameResolver2(String name, Method method, Object target=None, ...)
addClassNameResolver(String name, Method method, Object target=None, ...)
addGenericClassNameResolver(String name, Method method, Object target=None, ...)
addFeatureResolver2(String name, Method method, Object target=None, ...)
addExtraFeatureResolver(String name, Method method, Object target=None, ...)
addItemNameResolver2(String name, Method method, Object target=None, ...)
addItemValueResolver2(String name, Method method, Object target=None, ...)
addTreeTableResolver(String name, Method getTable, Method getColumn=None, Object target=None)
addTooltipResolver(String name, Method method, Object target=None, ...)
addIdResolver(String name, Method method, Object target=None,...)
removeResolver
The function removeResolver
may be used to deregister resolvers installed
via the resolvers
module.
Often, resolvers are registered directly after the start of the application and remain active during the full time of test execution. In some cases, however, resolvers are required only for handling a certain component and then need be to removed, either due to performance issues or because the effect of the resolver is not desirable for other components.
There are two functions for deregistration. The first, removeResolver
deregisters a single resolver, the second, removeAll
, removes all resolvers
registered by the user.
| |||||||||||||||||||
The example first removes a resolver registered under the name "menuItems", then
deregister all resolvers registered via the resolvers
module.
| ||||
Example 53.2: SUT script deregistering a resolver |
listNames
Return a list of resolver names registered via the resolvers
module.
| |||||||||
The example checks whether a certain resolver has been registered. If not, an error message is written to the run log.
| ||||
Example 53.3: Groovy SUT script searching for a certain resolver registered via the resolvers module |
Accessing 'Best label'
When you want to access the Best label
from within a resolver, you can use the method
rc.engine.helper.getBestLabel()
.
| |||||||||||||||
The example shows a name resolver transferring the best label to the 'Name' attribute.
| ||||
Example 53.4: NameResolver using the best label |
NameResolver
Interface
The NameResolver
works on the 'Name' attribute value of a
'Component' node.
After QF-Test determined the name of a GUI element the registered NameResolvers
get a chance to override or suppress this name. The first resolver that returns a non-null
value determines the outcome. If no resolvers are registered or all of them return null
the original name is used.
A NameResolver
can change (or provide) the name of a GUI element as set
with setName()
for AWT/Swing, setId()
or the fx:id
attribute for JavaFX,
setData(name, ...)
for SWT or via the 'ID' attribute of a DOM node for web
applications. It can be very useful when setting names in the source code is
not an option, like for third-party code or when child components of complex
components are not readily accessible. For example, QF-Test provides a name
resolver for the Java Swing JFileChooser
dialog, which you can read more about in the
Tutorial chapter 'The Standard Library'.
In some cases it may be desirable to suppress an element's name, for example for names which are not unique or which - even worse - vary depending on the situation. To do so, getName should return the empty string.
Technologies: AWT/Swing, JavaFX, SWT, Windows, Android, iOS. For web
applications please use 'Install CustomWebResolver' node as described in Improving component recognition with a CustomWebResolver
.
It was optimized for web elements and is more performant. Just in case the functionality
provided there is insufficient make use of the NameResolver
.
A NameResolver
needs to implement the following method:
| |||||||||||||||||
The first example is a NameResolver
returning the text of the menu item
as name for components of the generic class MenuItems
for which the QF-Test standard resolver could not determine a name.
| ||||
Example 53.5: Jython name resolver for MenuItems |
Give it a try. Copy the example above into a 'SUT script' node and execute
it. If your application is based on SWT instead of Swing, replace
getLabel()
with getText()
. Then
record some menu actions into a new, empty test suite. You'll find that all recorded
menu item components without name will now have names set according to their
labels. If setName
is not used in your application and the labels of menu
items are more or less static while the structure of the items often changes, this
can be a very useful feature.
The second example is a name resolver assigning a defined name ('Serial number') to a component which would otherwise have a partially dynamic name (e.g. 'Serial no: 100347'). It is registered for a specific Java Swing class.
| ||||
Example 53.6: Jython NameResolver for a specific class |
The following Groovy example returns the text of the menu item as the name for a component the QF-Test standard resolver did not find a name for.
| ||||
Example 53.7: Groovy resolver for MenuItems |
A resolver can be registered for multiple component classes at once:
| ||||
Example 53.8: Register a Resolver for multiple classes |
GenericClassNameResolver
Interface
A GenericClassNameResolver
can assign generic classes (chapter 60) to
arbitrary components. It can be used to make recorded components more readable and to register additional resolvers for the newly created classes.
Technologies: all
Web You should only use this resolver with a web application if the 'Install CustomWebResolver' node is insufficient.
After QF-Test determined the generic class name of a GUI element the registered
GenericClassNameResolvers
get a chance to override this generic class name.
The first resolver that returns a non-null value determines the outcome. If no
resolvers are registered or all of them return null the original
generic class name is used.
For performance reasons classes are cached so the resolver will only be called once at the most for each element. If you change your resolver you need to re-load or to close and re-open the area which shows the component.
Web If a generic class name was already assigned to an element via a 'CustomWebResolver', no GenericClassNameResolvers will be called for that element.
A GenericClassNameResolver
needs to implement the following method:
| |||||||||||||||||
ClassNameResolver
Interface
The ClassNameResolver
can control the class QF-Test records for a component. It can be used to make
recorded components more readable and to register additional resolvers for
the newly created classes. However, we generally recommend the use of
Generic classes instead. To register generic classes you should
use the GenericClassNameResolver
(subsection 53.1.8).
Technologies: all
Web You should only use this resolver with a web application if the 'Install CustomWebResolver' node is insufficient.
A ClassNameResolver
needs to implement the following method:
| |||||||||||||||||
After QF-Test determined the class name of a GUI element the registered
ClassNameResolvers
get a chance to override this class name.
The first resolver that returns a non-null value determines the outcome. If no
resolvers are registered or all of them return null the original
class name is used. The resolver is free to return any arbitrary
class name. Those names will be treated as normal classes in
QF-Test internal methods.
For performance reasons classes are cached so the resolver will only be called once at the most for each element. If you change your resolver you need to re-load or to close and re-open the area which shows the component.
FeatureResolver
Interface
A FeatureResolver
can provide a feature for a GUI element.
After QF-Test determined the feature of a GUI element the registered
FeatureResolvers
get a chance to override or suppress this feature. The
first resolver that returns a non-null value determines the outcome. If no resolvers
are registered or all of them return null the original feature is used.
To suppress an element's feature getFeature
should return the empty string.
Technologies: AWT/Swing, JavaFX, SWT, Windows, Android, iOS. For web applications
please use the 'Install CustomWebResolver' node as described in Improving component recognition with a CustomWebResolver
.
It was optimized for web elements and is more performant. Just in case the functionality
provided there is insufficient make use of the FeatureResolver
.
A FeatureResolver
needs to implement the following method:
| |||||||||||||||||
The following example implements a feature resolver returning the title of the panel border as feature for Java/Swing panels.
| ||||
Example 53.9: A FeatureResoler for Java/Swing Panels |
ExtraFeatureResolver
Interface
An ExtraFeatureResolver
can add, change or delete an 'Extra feature' in the
'Extra features' table for a GUI element. For this purpose the interface provides a number of
methods.
Instances of the class de.qfs.apps.qftest.shared.data.ExtraFeature
represent one 'Extra feature' for a GUI element, comprising its name and value along
with information about whether the feature is expected to match, whether it is a
regular expression and whether the match should be negated. For possible states the
class defines the constants STATE_IGNORE, STATE_SHOULD_MATCH and STATE_MUST_MATCH.
After QF-Test determined the 'Extra features' for a GUI element, the registered
ExtraFeatureResolvers
get a chance to override these features. In
contrast to other resolvers, QF-Test does not stop when the first resolver returns a
non-null value. Instead it passes its result as input to the next resolver which makes
it possible to register several ExtraFeatureResolvers
that handle
different 'Extra features'. If no resolvers are registered or all of them return null,
QF-Test will proceed to use the original set.
Of course, in order to be able to implement the getExtraFeatures
method properly, you
need to know the details for the API of the classes involved, namely
ExtraFeature
and ExtraFeatureSet
described below
- after the examples.
Technologies: AWT/Swing, JavaFX, SWT, Windows, Android, iOS. For web applications
please use the 'Install CustomWebResolver' described in Improving component recognition with a CustomWebResolver
.
It was optimized for web elements and is more performant. Only if the functionality
provided there is insufficient should you use the ExtraFeatureResolver
.
To ensure consistency when capturing and replaying qfs:label*
'Extra feature' variants as well as mapping them to and from SmartID, some
constraints should be maintained. They do not apply to the legacy
qfs:label
'Extra features', which stands on its own.
When handling qfs:label*
variants in an
ExtraFeatureResolver
you
have to make sure that the whole set of the variants remains
consistent. This means
qfs:label*
variant with "Should match",
the rest should be "Ignore".
qfs:labelBest
should either be the "Should match" variant or
it should have the same value as the "Should match" variant.
QF-Test itself maintains those constraints when determining associated labels.
To make it easier for ExtraFeatureResolvers
to do so as well, the
ExtraFeatureSet
class manages those constraints when called from an
ExtraFeatureResolver
:
qfs:labelBest
is changed and it has the state "Ignore",
the value of the "Should match" variant is automatically changed as well.
qfs:labelBest
is automatically changed as well.
qfs:label*
variant is set to "Should match" all others are
changed to ignore and qfs:labelBest
is updated accordingly.
Note
If there are qfs:label*
variants with the status "Must match" or
with a regular expression constraint handling is immediately deactivated.
A ExtraFeatureResolver
needs to implement the following method:
| |||||||||||||||||
The first example implements an ExtraFeatureResolver
adding
the title of a Java/Swing dialog as an 'Extra feature' with the status "must match"
(STATE_MUST_MATCH). This comes in handy when component recognition depends
on the correct title of the dialog.
| ||||
Example 53.10:
ExtraFeatureResolver adding an 'Extra feature' for Java/Swing dialogs
|
The following example shows how to change an existing 'Extra feature'.
The example handles qfs:labelBest
, which triggers special treatment
of the qfs:label*
variants as described above: if they
adhere to the constraints, QF-Test will update the respective
qfs:label*
variants so that the whole set will remain consistent.
| ||||
Example 53.11:
ExtraFeatureResolver changing an existing 'Extra feature'
|
The next example shows how to change the state of
the qfs:label*
variant with the state 'should match'
to 'ignore':
| ||||
Example 53.12:
An ExtraFeatureResolver (Groovy) changing the state of the 'Extra feature'
|
Thanks to the constraints described above, a simple ExtraFeatureResolver
that was formerly written as
| ||||
Example 53.13:
ExtraFeatureResolver changing an existing 'Extra feature'
|
can simply be updated to example ExtraFeatureResolver
changing an existing 'Extra feature'
above.
In the following you will find the description of the APIs of the classes
ExtraFeature
and ExtraFeatureSet
.
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The class de.qfs.apps.qftest.shared.data.ExtraFeatureSet
collects
ExtraFeatures
into set:
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ItemNameResolver
Interface
An ItemNameResolver
can change (or provide) the textual representation
of the index for addressing a sub-item of a complex component.
After QF-Test determined the name for an item's index the registered
ItemNameResolvers
get a chance to override. The
first resolver that returns a non-null value determines the outcome. If no resolvers
are registered or all of them return null the original name is used.
Technologies: AWT/Swing, JavaFX, SWT, Windows, Android, iOS.
For web applications please use the 'Install CustomWebResolver' node
described in Improving component recognition with a CustomWebResolver
.
It was optimized for web elements and is more performant. Only if the functionality
provided there is insufficient should you use the ItemNameResolver
.
An ItemNameResolver
needs to implement the following method:
| |||||||||||||||||||
The example implements an ItemNameResolver
making the ID of a
JTable
available as index:
| ||||
Example 53.14: An ItemNameResolver for JTableHeader |
ItemValueResolver
Interface
The ItemValueResolver
is used to improve the textual check of elements.
An ItemValueResolver
can change (or provide) the textual representation
of the value a sub-item of a complex component as used by a 'Check text' node
or retrieved via a 'Fetch text' node.
After QF-Test determined the value for an item's index the registered
ItemValueResolvers
get a chance to override. The
first resolver that returns a non-null value determines the outcome. If no resolvers
are registered or all of them return null the original value is used.
Technologies: AWT/Swing, JavaFX, SWT, Windows, Android, iOS. For web applications please use
the 'Install CustomWebResolver' as described in Improving component recognition with a CustomWebResolver
.
It was optimized for web elements and is more performant. Just in case the functionality
provided there is insufficient use the ItemValueResolver
.
An ItemValueResolver
needs to implement the following method:
| |||||||||||||||||||
TreeTableResolver
Interface
A TreeTableResolver
helps QF-Test recognize TreeTable components. A
TreeTable is a mixture between a table and a tree. It is not a standard Swing
component, but most TreeTables are implemented alike using a tree as the
renderer component for one column of the table. Once QF-Test recognizes a TreeTable as
such, it treats the row indexes of all table cells as tree indexes, which is a lot
more useful in that context than standard table row indexes. In addition, geometry
information for cells in the tree column is based on tree nodes instead of table
cells.
Technologies: AWT/Swing
Note The interface is only relevant for AWT/Swing. For SWT and JavaFX multi-column trees
are support by QF-Test automatically. For web frameworks the TreeTable is defined by the
(custom) web resolver (see Improving component recognition with a CustomWebResolver
).
A TreeTableResolver
needs to implement to following two methods:
| |||||||||||||||||||||||||||
Most TreeTableResolvers
are trivial to implement. The following Jython
example works well for the org.openide.explorer.view.TreeTable
component
used in the popular netBeans IDE, provided that the resolver is registered for the
TreeTable class:
| ||||
Example 53.15: TreeTableResolver for netBeans IDE |
The following example shows a typical TreeTableResolver
.
| ||||
Example 53.16: TreeTableResolver for Swing TreeTable with optional
getColumn method |
As practically all TreeTables implement the tree in the first column of the table the
getColumn
method is optional. When none is passed QF-Test automatically
creates a default implementation for the first column:
| ||||
Example 53.17: Simplified TreeTableResolver |
If no dedicated getTree
method is available, the cell renderer of the column
containing the tree (typically 0) might work, as it is typically derived from JTree
.
| ||||
Example 53.18: Simplified TreeTableResolver using the method getCellRenderer |
InterestingParentResolver
Interface
An InterestingParentResolver
influences which components will be
treated as interesting or ignorable by QF-Test recording. This, in turn, determines
whether a 'Component' node will be created for a component.
Technologies: AWT/Swing, JavaFX, SWT, Windows, Android, iOS. For web applications
please use the 'Install CustomWebResolver' node as described in Improving component recognition with a CustomWebResolver
.
It was optimized for web elements and is more performant. Just in case the functionality
provided there is insufficient make use of the InterestingParentResolver
.
An InterestingParentResolver
needs to implement the following method:
| |||||||||||||||||
TooltipResolver
Interface
A TooltipResolver
can provide a tooltip for a component. A tooltip is one
of the texts considered for the 'qfs:label' 'Extra feature'.
Technologies: AWT/Swing, JavaFX, SWT. For web applications
please use the 'Install CustomWebResolver' node as described in Improving component recognition with a CustomWebResolver
.
It was optimized for web elements and is more performant. Just in case the functionality
provided there is insufficient make use of the TooltipResolver
.
A TooltipResolver
needs to implement the following method:
| |||||||||||||||||
IdResolver
interface
An IdResolver
allows modifying or even removing the 'ID' attribute of a DomNode.
When QF-Test registers the DOM nodes of a web page it also caches the "id" attribute of
those nodes. Depending on the option Use ID attribute as name the value of
the "id" attribute will even be taken as name for the component. As many web pages or component libraries
generate such IDs automatically it's a very common requirement to modify that ID in order to get
stable and reliable component recognition.
There are three possibilities to deal with such automatically generated IDs:
autoIdPatterns
. This parameter allows to specify
dedicated values to ignore like
myAutoId
or even regular expressions like auto.*
, which ignores any ID beginning
with auto
.
customIdAttributes
. It allows to specify
custom attributes which will be used for determining the 'ID'.
IdResolver
.
The options mentioned above can also be combined and don't exclude each other.
In case you decide to implement a custom algorithm you should always use an IdResolver
.
You should take care that the 'ID' attribute of a node can show up in multiple places.
The most notably place is the
attribute 'Name' of the node (depending on the option Use ID attribute as name), its 'Feature' and its
'Extra feature'. Because of that many locations you should prefer implementing
an IdResolver
over implementing individual
Name-
, Feature-
and ExtraFeatureResolvers
.
More importantly, changing a node's 'ID' attribute can have a major impact on whether
the attribute is unique and QF-Test's mechanism for using an ID as a 'Name' takes
uniqueness into account, so an IdResolver
is allowed to return non-unique
IDs whereas a NameResolver2
is not.
Technologies: Web
The
de.qfs.apps.qftest.extensions.IdResolver
interface consists of a single method:
| |||||||||||||||||
EnabledResolver
Interface
An EnabledResolver
provides information about when to consider a component
active or inactive. AWT/Swing Components have a respective attribute. Web and JavaFX,
however, have special stylesheet classes that need to be evaluated via the
EnabledResolver
.
Technologies: JavaFX, Web, Windows, Android, iOS
An EnabledResolver
needs to implement the following method:
| |||||||||||||||||
The example determines the enabled state of a web node via the css class
v-disabled
.
| ||||
Example 53.19: An EnabledResolver |
VisibilityResolver
Interface
A VisibilityResolver
influences whether to consider a web element to be visible.
Technologies: Web, Windows, Android, iOS
A VisibilityResolver
needs to implement the following method:
| |||||||||||||||||
The resolver in the example below returns false for the visibility state of the web element in case it is opaque.
| ||||
Example 53.20: A VisibilityResolver |
MainTextResolver
Interface
A MainTextResolver
determines the primary line of text of a component, which then may be
used for the 'Feature', the qfs:label*
variants etc.
Technologies: AWT/Swing, JavaFX, SWT, Web, Windows, Android, iOS
A MainTextResolver
needs to implement the following method:
| |||||||||||||||||
The resolver in the example removes the string TO-DO
from
the 'main' text of all components.
| ||||
Example 53.21: A MainTextResolver |
WholeTextResolver
Interface
A WholeTextResolver
determines the 'whole' text of a component,
i.e. what should be used for checks, etc.
Technologies: AWT/Swing, JavaFX, SWT, Web, Windows, Android, iOS
A WholeTextResolver
needs to implement the following method:
| |||||||||||||||||
The resolver in the example removes the string TO-DO
from the
texts used for example for checks of TextFields and TextAreas.
| ||||
Example 53.22: A WholeTextResolver |
BusyPaneResolver
Interfaces
At text execution, QF-Test waits for BusyPanes covering other components to disappear before resuming
in a determined state. A BusyPaneResolver
influences whether to consider
a component as being covered.
Technologies: AWT/Swing, JavaFX
A BusyPaneResolver
needs to implement the following method:
| |||||||||||||||
The resolver in the example below deactivates recognition of BusyPanes for components of the type "my.special.Component".
| ||||
Example 53.23: A BusyPaneResolver |
GlassPaneResolver
Interfaces
When components (e.g. transparent ones) hide others components you can use a
GlassPaneResolver
to inform QF-Test of this relationship and thus redirect
events to the correct component.
Technology: AWT/Swing
A GlassPaneResolver
needs to implement the following method:
| |||||||||||||||||
The resolver in the example below deactivates passing on events through GlassPanes.
| ||||
Example 53.24: A GlassPaneResolver |
TreeIndentationResolver
Interface
A TreeIndentationResolver
is used to
determine the indentation of a tree node in a tree or tree table.
Use this resolver if QF-Test can not automatically determine the right indentation of nodes
in a Tree or TreeTable component
and the abilities of the parameter "treeIndentationMode"
of the CustomWebResolver category treeResolver
are not sufficient.
Note that the return value of the resolver is treated like a pixel amount. This means that to distinguish different tree levels, the indentation value must differ by at least 2 by default.
Technologies: Web
A TreeIndentationResolver
has to implement the following method:
| |||||||||||||||||
The following Groovy example tries to determine the indentation of all TreeNodes
through the HTML attribute aria-level
.
| ||||
Example 53.25: A TreeIndentationResolver |
EventSynchronizer
Interface
After replaying an event to the SUT QF-Test waits for synchronization with the respective
Event Dispatch Thread. Via an EventSynchronizer
you can tell QF-Test when the
SUT is ready to accept the next event. It ought to be used when the SUT has a non-standard
event synchronization.
Technologies: AWT/Swing, JavaFX, SWT, Web
An EventSynchronizer
needs to implement the following method:
| |||||||||||||
The resolver in the following example stops execution on the Dispatch Thread until the next full second.
| ||||
Example 53.26: An EventSynchronizer |
BusyApplicationDetector
Interface
Using a BusyApplicationDetector
can tell QF-Test when to consider an
application to be currently 'busy' and not in grade of accepting events.
Technologies: AWT/Swing, JavaFX, SWT, Web
A BusyApplicationDetector
needs to implement the following method:
| |||||||||||
The resolver in the example uses a SUT specific method to tell QF-Test it is 'busy':
| ||||
Example 53.27: A BusyApplicationDetector |
Matcher
The difference between a matcher
and a resolver
is that
matchers
are relevant for replay only. They have no effect on recordings.
However, they are registered via the resolvers
module as well.
A matcher
can become useful when you are working with generic components or
for keyword driven testing, if you do not record components.
ExtraFeatureMatcher
Interface
An ExtraFeatureMatcher
influences whether to consider an 'Extra feature'
QF-Test registered for the component as 'suitable'.
Technologies: AWT/Swing, JavaFX, SWT, Web
An ExtraFeatureMatcher
needs to implement the following method:
| |||||||||||||||||||||||
The matcher in the example below checks the value of the 'Extra feature' my:label
against the my-label
attribute of the web element.
| ||||
Example 53.28: An ExtraFeatureMatcher |
The resolver method call can be limited to a specific feature name by means of the
special resolvers method addSpecificExtraFeatureMatcher
:
| ||||
Example 53.29: Using addSpecificExtraFeatureMatcher |
As an alternative to directly implementing a resolver in an SUT-script, it is possible to provide them as Java classes inside a JAR file in the plugin folder. In doing so, it is helpful to implement the aforementioned resolver interfaces (Basically, QF-Test is able to detect resolvers by their implemented method names).
To implement the interfaces provided by QF-Test, the file qfsut.jar
has to be added to the
development classpath. Most of the interfaces reside in the de.qfs.apps.qftest.extensions
package, and the names of the interfaces which have two method parameters are suffixed with a "2".
All Interfaces named Item...
reside in the package de.qfs.apps.qftest.extensions.items
.
When calling resolvers.addResolver(...)
in an SUT script, provide an instance of
the implemented resolver class as argument.
Last update: 9/10/2024 Copyright © 1999-2024 Quality First Software GmbH |