Skip to content

Commit c6c7a41

Browse files
committed
Fix Finder recursion when chained selectors are used and no root is set
Using chained selectors when looking for nodes from every window caused a StackOverflowException because the list of remaining root nodes was not updated properly. The list is used to determine whether the recursion should continue or not, so the method was calling itself until the StackOverflowException was thrown. Finder now holds a reference to the original root node of the lookup so the list of remaining root nodes actually updates. This commit also fixes an UnsupportedOperationException in Find All which occured when searching nodes from multiple windows. Exception happened because the find results were added to the map recursively, and some of the results were located in unmodifiable collections. Now a single Map gets passed as a parameter for the whole duration of the process, and all found nodes are added to this instance.
1 parent 0351f4b commit c6c7a41

File tree

2 files changed

+80
-16
lines changed

2 files changed

+80
-16
lines changed

src/main/java/javafxlibrary/utils/Finder.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.testfx.service.query.NodeQuery;
1111

1212
import java.util.Arrays;
13+
import java.util.HashSet;
1314
import java.util.Set;
1415

1516
import static javafxlibrary.utils.TestFxAdapter.robot;
@@ -19,6 +20,7 @@ public class Finder {
1920
public enum FindPrefix { ID, CSS, CLASS, TEXT, XPATH, PSEUDO }
2021
private String[] prefixes;
2122
protected Parent currentRoot;
23+
private Parent originalRoot;
2224
private Set<Parent> rootNodes;
2325
private String originalQuery;
2426

@@ -47,8 +49,10 @@ public Node find(String query, Parent root) {
4749
public Set<Node> findAll(String query) {
4850
if (containsPrefixes(query)) {
4951
originalQuery = query;
52+
originalRoot = this.currentRoot;
5053
rootNodes = robot.fromAll().queryAll();
51-
return newFindAll(parseWholeQuery(query));
54+
Set<Node> allNodes = new HashSet<>();
55+
return newFindAll(parseWholeQuery(query), allNodes);
5256
}
5357
return robot.lookup(query).queryAll();
5458
}
@@ -57,7 +61,8 @@ public Set<Node> findAll(String query, Parent root) {
5761
RobotLog.debug("Executing Finder.findAll using query: " + query + " and root: " + root);
5862
if (containsPrefixes(query)) {
5963
this.currentRoot = root;
60-
return newFindAll(parseWholeQuery(query));
64+
Set<Node> allNodes = new HashSet<>();
65+
return newFindAll(parseWholeQuery(query), allNodes);
6166
}
6267
return robot.from(root).lookup(query).queryAll();
6368
}
@@ -67,26 +72,30 @@ private Node newFind(String query) {
6772
Node result = executeLookup(query, prefix);
6873

6974
if (result == null && rootNodes != null && rootNodes.size() > 1) {
70-
RobotLog.debug("Could not find anything from " + currentRoot + ", moving to the next root node");
71-
rootNodes.remove(currentRoot);
72-
currentRoot = rootNodes.iterator().next();
75+
RobotLog.debug("Could not find anything from " + originalRoot + ", moving to the next root node");
76+
rootNodes.remove(originalRoot);
77+
originalRoot = rootNodes.iterator().next();
78+
currentRoot = originalRoot;
7379
result = newFind(parseWholeQuery(originalQuery));
7480
}
7581

7682
return result;
7783
}
7884

79-
private Set<Node> newFindAll(String query) {
85+
private Set<Node> newFindAll(String query, Set<Node> allNodes) {
8086
FindPrefix prefix = getPrefix(query);
8187
Set<Node> nodes = executeLookupAll(query, prefix);
88+
allNodes.addAll(nodes);
8289

8390
if (rootNodes != null && rootNodes.iterator().hasNext() && rootNodes.size() > 1) {
84-
RobotLog.debug("Finished lookup with root " + currentRoot + ", moving to the next root node");
85-
rootNodes.remove(currentRoot);
86-
currentRoot = rootNodes.iterator().next();
87-
nodes.addAll(newFindAll(parseWholeQuery(originalQuery)));
91+
RobotLog.debug("Finished lookup with root " + originalRoot + ", moving to the next root node");
92+
rootNodes.remove(originalRoot);
93+
originalRoot = rootNodes.iterator().next();
94+
currentRoot = originalRoot;
95+
RobotLog.debug("Starting another lookup using new root: " + currentRoot);
96+
newFindAll(parseWholeQuery(originalQuery), allNodes);
8897
}
89-
return nodes;
98+
return allNodes;
9099
}
91100

92101
private Node executeLookup(String query, FindPrefix prefix) {

src/test/robotframework/acceptance/FindTest.robot

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
*** Settings ***
22
Documentation Tests to test javafxlibrary.keywords.AdditionalKeywords.Find related keywords
33
Library JavaFXLibrary
4-
Suite Setup Setup all tests
54
Suite Teardown Teardown all tests
65
Force Tags set-find
76

87
*** Variables ***
9-
${TEST_APPLICATION} javafxlibrary.testapps.TestBoundsLocation
8+
${CURRENT_APPLICATION} NOT SET
9+
${BOUNDS_APP} javafxlibrary.testapps.TestBoundsLocation
10+
${WINDOW_APP} javafxlibrary.testapps.TestMultipleWindows
1011

1112
*** Test Cases ***
1213
Find With TestFX Query
1314
[Tags] smoke
15+
Set Test App ${BOUNDS_APP}
1416
${rectangle} Find \#green
1517
${text} Find .whiteText
1618
Should Contain ${rectangle} Rectangle[id=green, x=300.0, y=0.0, width=150.0, height=150.0, fill=0x00a000ff]
1719
Should Contain ${text} Text[text="75x75", x=0.0, y=0.0, alignment=CENTER, origin=BASELINE
1820

1921
Find With XPath
2022
[Tags] smoke
23+
Set Test App ${BOUNDS_APP}
2124
${rect_by_id} Find xpath=//Rectangle[@id="lime"]
2225
${rect_by_fill} Find xpath=//Rectangle[@fill="0xff1493ff"]
2326
${text} Find xpath=//Text[@text="75x75"]
@@ -27,50 +30,58 @@ Find With XPath
2730

2831
Find With Class
2932
[Tags] smoke
33+
Set Test App ${BOUNDS_APP}
3034
${rectangle} Find class=javafx.scene.shape.Rectangle
3135
${text} Find class=javafx.scene.text.Text
3236
Should Contain ${rectangle} Rectangle[id=red, x=0.0, y=0.0, width=300.0, height=300.0, fill=0xff0000ff]
3337
Should Contain ${text} Text[text="300x300", x=0.0, y=0.0, alignment=CENTER, origin=BASELINE
3438

3539
Find With CSS Query
3640
[Tags] smoke
41+
Set Test App ${BOUNDS_APP}
3742
${rectangle} Find css=\#violet
3843
${text} Find css=VBox HBox StackPane Text.whiteText
3944
Should Contain ${rectangle} Rectangle[id=violet, x=525.0, y=0.0, width=75.0, height=75.0, fill=0x9400d3ff]
4045
Should Contain ${text} Text[text="75x75", x=0.0, y=0.0, alignment=CENTER, origin=BASELINE
4146

4247
Find With ID
4348
[Tags] smoke
49+
Set Test App ${BOUNDS_APP}
4450
${rectangle} Find id=darkblue
4551
Should Contain ${rectangle} Rectangle[id=darkblue, x=300.0, y=150.0, width=300.0, height=150.0, fill=0x00008bff]
4652

4753
Find With Chained Selectors
4854
[Tags] smoke
55+
Set Test App ${BOUNDS_APP}
4956
${lime} Find css=VBox HBox Pane id=lime
5057
${blue} Find css=VBox HBox Pane xpath=//Rectangle[@width="600.0"]
5158
Should Contain ${lime} Rectangle[id=lime, x=500.0, y=200.0, width=75.0, height=75.0, fill=0x00ff00ff]
5259
Should Contain ${blue} Rectangle[id=blue, x=0.0, y=0.0, width=600.0, height=300.0, fill=0x00bfffff]
5360

5461
Find With Root
5562
[Tags] smoke
63+
Set Test App ${BOUNDS_APP}
5664
${root} Find css=Pane
5765
${rectangle} Find id=lime true ${root}
5866
Should Contain ${rectangle} Rectangle[id=lime, x=500.0, y=200.0, width=75.0, height=75.0, fill=0x00ff00ff]
5967

6068
Find All With TestFX Query
6169
[Tags] smoke
70+
Set Test App ${BOUNDS_APP}
6271
@{nodes} Find All .whiteText
6372
Length Should Be ${nodes} 3
6473

6574
Find All With XPath
6675
[Tags] smoke
76+
Set Test App ${BOUNDS_APP}
6777
@{all_rectangles} Find All xpath=//Rectangle
6878
@{text_nodes} Find All xpath=//Text[@text="75x75"]
6979
Length Should Be ${all_rectangles} 9
7080
Length Should Be ${text_nodes} 6
7181

7282
Find All With CSS query
7383
[Tags] smoke
84+
Set Test App ${BOUNDS_APP}
7485
@{nodes1} Find All css=VBox HBox > StackPane Rectangle
7586
@{nodes2} Find All css=Pane Rectangle
7687
@{nodes3} Find All css=Pane > Rectangle
@@ -80,13 +91,15 @@ Find All With CSS query
8091

8192
Find All With Chained Selectors
8293
[Tags] smoke
94+
Set Test App ${BOUNDS_APP}
8395
@{nodes1} Find All css=VBox HBox xpath=//Rectangle
8496
@{nodes2} Find All css=VBox HBox xpath=//Rectangle[@width="75.0"]
8597
Length Should Be ${nodes1} 6
8698
Length Should Be ${nodes2} 4
8799

88100
Find All With Root
89101
[Tags] smoke
102+
Set Test App ${BOUNDS_APP}
90103
${xroot} Find css=VBox HBox VBox HBox
91104
${croot} Find css=Pane
92105
@{xpath} Find All xpath=//Rectangle[@width="75.0"] false ${xroot}
@@ -96,6 +109,7 @@ Find All With Root
96109

97110
Find Nth Node With XPath
98111
[Tags] smoke
112+
Set Test App ${BOUNDS_APP}
99113
${node1} Find xpath=/VBox/HBox/VBox/HBox/VBox/HBox/StackPane
100114
${node2} Find xpath=/VBox/HBox/VBox/HBox/VBox/HBox/StackPane[2]
101115
${child1} Find css=Rectangle true ${node1}
@@ -105,6 +119,7 @@ Find Nth Node With XPath
105119

106120
Find With Pseudo Class
107121
[Tags] smoke
122+
Set Test App ${BOUNDS_APP}
108123
${root} Find css=VBox HBox VBox HBox StackPane
109124
${target} Find xpath=//Text[@text="150x150"]
110125
Move To ${target}
@@ -113,6 +128,7 @@ Find With Pseudo Class
113128

114129
Find All With Pseudo Class
115130
[Tags] smoke
131+
Set Test App ${BOUNDS_APP}
116132
${node} Find xpath=//Text[@text="300x300"]
117133
Move To ${node}
118134
@{hovered} Find All pseudo=hover
@@ -124,48 +140,87 @@ Find All With Pseudo Class
124140

125141
Nothing Is Found
126142
[Tags] smoke negative
143+
Set Test App ${BOUNDS_APP}
127144
${node} Find css=NoSuchSelector
128145
Should Be Empty ${node}
129146

130147
Nothing Is Found When failIfNotFound Is True
131148
[Tags] smoke negative
149+
Set Test App ${BOUNDS_APP}
132150
${msg} Run Keyword And Expect Error * Find css=NoSuchSelector true
133151
Should Be Equal ${msg} Unable to find anything with query: "css=NoSuchSelector"
134152

135153
Nothing Is Found With Find All
136154
[Tags] smoke negative
155+
Set Test App ${BOUNDS_APP}
137156
${nodes} Find All css=NoSuchSelector
138157
Should Be Empty ${nodes}
139158

140159
Nothing Is Found With Find All When failIfNotFound Is True
141160
[Tags] smoke negative
161+
Set Test App ${BOUNDS_APP}
142162
${msg} Run Keyword And Expect Error * Find All css=NoSuchSelector true
143163
Should Be Equal ${msg} Unable to find anything with query: "css=NoSuchSelector"
144164

145165
Previous Query Returns Nothing In Chained Selector
146166
[Tags] smoke negative
167+
Set Test App ${BOUNDS_APP}
147168
${node} Find css=VBox css=ZBox Pane id=lime
148169
Should Be Empty ${node}
149170

150171
Previous Query Returns Nothing In Chained Selector With Find All
151172
[Tags] smoke negative
173+
Set Test App ${BOUNDS_APP}
152174
${nodes} Find All css=VBox css=ZBox Pane id=lime
153175
Should Be Empty ${nodes}
154176

155177
Previous Query Returns Nothing In Chained Selector When failIfNotFound Is True
156178
[Tags] smoke negative
179+
Set Test App ${BOUNDS_APP}
157180
${msg} Run Keyword And Expect Error * Find css=VBox css=ZBox Pane id=lime true
158181
Should Be Equal ${msg} Unable to find anything with query: "css=VBox css=ZBox Pane id=lime"
159182

160183
Previous Query Returns Nothing In Chained Selector With Find All When failIfNotFound Is True
161184
[Tags] smoke negative
185+
Set Test App ${BOUNDS_APP}
162186
${msg} Run Keyword And Expect Error * Find All css=VBox css=ZBox Pane id=lime true
163187
Should Be Equal ${msg} Unable to find anything with query: "css=VBox css=ZBox Pane id=lime"
164188

189+
Find From Another Window
190+
[Tags] smoke
191+
Set Test App ${WINDOW_APP}
192+
${node} Find id=thirdWindowLabel
193+
Should End With ${node} Label[id=thirdWindowLabel, styleClass=label]'Third window'
194+
195+
Find From Another Window Using Chained Selector
196+
[Tags] smoke
197+
Set Test App ${WINDOW_APP}
198+
${node} Find css=HBox id=thirdWindowLabel
199+
Should End With ${node} Label[id=thirdWindowLabel, styleClass=label]'Third window'
200+
201+
Find All From Multiple Windows
202+
[Tags] smoke
203+
Set Test App ${WINDOW_APP}
204+
${nodes} Find All css=.label
205+
Length Should Be ${nodes} 3
206+
207+
Find All From Multiple Windows Using Chained Selector
208+
[Tags] smoke
209+
Set Test App ${WINDOW_APP}
210+
${nodes} Find All css=HBox css=.label
211+
Length Should Be ${nodes} 3
212+
165213
*** Keywords ***
166-
Setup all tests
167-
Launch Javafx Application ${TEST_APPLICATION}
168-
Set Screenshot Directory ${OUTPUT_DIR}${/}report-images
214+
Set Test App
215+
[Arguments] ${APPLICATION}
216+
Run Keyword Unless '${CURRENT_APPLICATION}' == '${APPLICATION}' Change Current Application ${APPLICATION}
217+
218+
Change Current Application
219+
[Arguments] ${APPLICATION}
220+
Run Keyword Unless '${CURRENT_APPLICATION}' == 'NOT SET' Close Javafx Application
221+
Set Suite Variable ${CURRENT_APPLICATION} ${APPLICATION}
222+
Launch Javafx Application ${APPLICATION}
223+
Set Screenshot Directory ${OUTPUT_DIR}${/}report-images
169224

170225
Teardown all tests
171226
Close Javafx Application

0 commit comments

Comments
 (0)