Syrius Node Pruning
Introduction
As you know, Oryon interacts with Syrius by referencing components using XPath selectors on a component tree.
In a nutshell, this tree corresponds to the hierarchical structure of the visual elements shown to the user. The structure is provided by the Syrius server, and rendered by the Syrius application.
However, it has been observed that there are nodes which are present in the tree, but not actually rendered. Such nodes cannot be interacted with, and cause the tree (and therefore the XPaths) to be more complicated than they need to be. We call such nodes dysfunctional.
Starting with Oryon 2.6.2, we have added a feature to effectively hide such dysfunctional nodes from the component tree, resulting in a simpler structure and more predictable XPaths.
We recommend to make use of this functionality, however please carefully read the following notes to understand the impact.
Detailed problem description
In Syrius, every action you perform triggers a call to the backend server, which sends updates to the client component tree state. These updates could change existing nodes (e.g. change the text of a field), remove nodes, or add new nodes.
Unfortunately, it has been observed that certain operations (in particular operations which change tables or lists) seem to send new nodes to be added, while not sending the commands to remove obsolete nodes.
This leads to unnecessarily complicated component hierarchies, where certain nodes remain present in
the component tree, but are not attached to any interactable UI object. For instance, consider the (simplified) situation where
a component identified by the XPath //DataList/TextField
exists, and upon clicking a button, is replaced by another one.
However, if the update sent from the server to the client does not send the full chain of required commands,
this might lead to the following situation:
- The user still only sees one
TextField
in the UI. It would be expected that the original XPath continues to work. - Under the hood however, there are now two
TextField
nodes: //DataList/TextField[1]
exists in the component tree, but is not attached to any UI object. This node is dysfunctional.//DataList/TextField[2]
exists and is functional. However, because of the additional presence of the dysfunctional node, its XPath has changed.
Note that this is just one example (albeit one with the particularly annoying effect of having to adjust the XPaths when interacting with the “same” node, from a user perspective). There are more instances of dysfunctional nodes, the exact reasons why Syrius creates some of these are unknown.
Here is a comparison of the state of a freshly launched Syrius client, right after login. Enabling pruning has removed over 300 nodes.
Compatibility with existing scripts, transitioning
Depending on how you defined your XPath expressions in your scripts, you may need to adjust the paths after enabling pruning. However, it is unfortunately impossible to tell beforehand which path expressions might require adjustment. It can only be found out by enabling the functionality and manually performing the required changes, if there are any.
The proposed transitioning strategy is as follows:
- Enable pruning on a script-by-script basis.
- Once all scripts are adapted, enable it globally.
The alternative possibility is to first enable pruning globally, and then fix potential failing scripts.
Controlling pruning at runtime
Here is a sample code snippet that shows the two methods to control pruning at runtime:
// ...
// save current pruning state (boolean value)
def pruning = gui.getRemoveDysfunctionalNodes()
// enable pruning
gui.setRemoveDysfunctionalNodes(true)
gui.clickMenuItem("//MenuItem[@text='Alle Sessions schliessen']")
// ...
// restore state
gui.setRemoveDysfunctionalNodes(pruning)
This is one possibility to ensure that a particular script/keyword enables pruning while it is running, without affecting other keywords.
Another approach (during the transition period) is to initially modify every keyword to start with
gui.setRemoveDysfunctionalNodes(false)
In this case, you will not need to take care of restoring state, as each keyword sets its own required state.
Afterwards, you can gradually enable pruning individually per keyword.
Global pruning configuration
For downward compatibility reasons, pruning is not enabled by default.
However, there is a launch parameter that can be specified to control the initial setting.
This parameter can be used from batch (or command) files when launching Syrius/Oryon locally,
as well as in the startCommand parameter of the OryonDriver
used in Step.
Here is an example (split into several lines for readability):
java.exe
-javaagent:oryon-2.6.2/agent/oryon-agent.jar=license:oryon.license,module:SyriusFX
-Doryon.removeDysfunctionalNodes=true
-cp jps-client-boot-9.9.2.jar
-Xmx2048M
jps.network.client.Client --server-url http://syrius.example.com
Note the second line: the -Doryon.removeDysfunctionalNodes=true
enables pruning on start.
In other words, it behaves as if the equivalent of gui.setRemoveDysfunctionalNodes(true)
had been called,
right after starting up Syrius/Oryon.
Possible parameter settings
-Doryon.removeDysfunctionalNodes=false
- no initial pruning, may be overridden at runtime. This is also the default behavior if the option is not specified.-Doryon.removeDysfunctionalNodes=true
- pruning enabled initially, may be overridden at runtime.-Doryon.removeDysfunctionalNodes=FALSE
- pruning disabled, may NOT be overridden at runtime.-Doryon.removeDysfunctionalNodes=TRUE
- pruning enabled, may NOT be overridden at runtime.