15
15
16
16
import lombok .experimental .UtilityClass ;
17
17
import org .openqa .selenium .By ;
18
+ import org .openqa .selenium .NoSuchElementException ;
18
19
import solutions .bellatrix .core .configuration .ConfigurationService ;
19
20
import solutions .bellatrix .core .utilities .InstanceFactory ;
20
21
import solutions .bellatrix .core .utilities .Ref ;
21
22
import solutions .bellatrix .core .utilities .Wait ;
22
23
import solutions .bellatrix .web .components .WebComponent ;
24
+ import solutions .bellatrix .web .components .contracts .Component ;
23
25
import solutions .bellatrix .web .configuration .WebSettings ;
24
26
import solutions .bellatrix .web .findstrategies .CssFindStrategy ;
25
27
import solutions .bellatrix .web .findstrategies .FindStrategy ;
@@ -43,7 +45,7 @@ public static String getShadowHtml(WebComponent shadowComponent, boolean isShado
43
45
}
44
46
45
47
public static <TComponent extends WebComponent , TFindStrategy extends FindStrategy > TComponent createFromShadowRoot (Class <TComponent > componentClass , ShadowRoot parentComponent , TFindStrategy findStrategy ) {
46
- return createAllFromShadowRoot (componentClass , parentComponent , findStrategy ). get ( 0 );
48
+ return retryFindingSingleComponent (() -> createAllFromShadowRoot (componentClass , parentComponent , findStrategy ), findStrategy );
47
49
}
48
50
49
51
public static <TComponent extends WebComponent , TFindStrategy extends FindStrategy > List <TComponent > createAllFromShadowRoot (Class <TComponent > componentClass , ShadowRoot parentComponent , TFindStrategy findStrategy ) {
@@ -69,7 +71,7 @@ public static <TComponent extends WebComponent, TFindStrategy extends FindStrate
69
71
}
70
72
71
73
public static <TComponent extends WebComponent , TFindStrategy extends FindStrategy > TComponent createInShadowContext (Class <TComponent > componentClass , WebComponent parentComponent , TFindStrategy findStrategy ) {
72
- return createAllInShadowContext (componentClass , parentComponent , findStrategy ). get ( 0 );
74
+ return retryFindingSingleComponent (() -> createAllInShadowContext (componentClass , parentComponent , findStrategy ), findStrategy );
73
75
}
74
76
75
77
public static <TComponent extends WebComponent , TFindStrategy extends FindStrategy > List <TComponent > createAllInShadowContext (Class <TComponent > componentClass , WebComponent parentComponent , TFindStrategy findStrategy ) {
@@ -103,7 +105,7 @@ private static String[] getAbsoluteCss(ShadowRoot shadowRoot, String locator) {
103
105
shadowRoot .findElement (), locator , null ).toArray (String []::new );
104
106
};
105
107
106
- return getCss (js , locator );
108
+ return getCss (js );
107
109
}
108
110
109
111
private static String [] getRelativeCss (ShadowRoot shadowRoot , String locator , String parentLocator ) {
@@ -113,30 +115,18 @@ private static String[] getRelativeCss(ShadowRoot shadowRoot, String locator, St
113
115
shadowRoot .findElement (), locator , parentLocator ).toArray (String []::new );
114
116
};
115
117
116
- return getCss (js , locator );
118
+ return getCss (js );
117
119
}
118
120
119
- private static String [] getCss (Callable <String []> callable , String locator ) {
120
- if (Wait .retry (() -> {
121
- String [] foundElements ;
122
- try {
123
- foundElements = callable .call ();
124
- } catch (Exception e ) {
125
- throw new RuntimeException (e );
126
- }
127
-
128
- if (foundElements == null || foundElements .length == 0 ) {
129
- throw new IllegalArgumentException ();
130
- }
131
- }, Duration .ofSeconds (ConfigurationService .get (WebSettings .class ).getTimeoutSettings ().getElementWaitTimeout ()), Duration .ofSeconds (1 ), false )) {
132
- try {
133
- return callable .call ();
134
- } catch (Exception e ) {
135
- throw new RuntimeException (e );
136
- }
137
- } else {
138
- throw new IllegalArgumentException ("No elements inside the shadow DOM were found with the locator: " + locator );
121
+ private static String [] getCss (Callable <String []> callable ) {
122
+ String [] foundElements ;
123
+ try {
124
+ foundElements = callable .call ();
125
+ } catch (Exception e ) {
126
+ throw new RuntimeException (e );
139
127
}
128
+
129
+ return foundElements ;
140
130
}
141
131
142
132
private static <TComponent extends WebComponent > TComponent buildMissingShadowRootsAndCreate (Class <TComponent > clazz , ShadowRoot parentComponent , Ref <String > fullCss ) {
@@ -206,7 +196,7 @@ private static String retraceParentShadowRoots(WebComponent component) {
206
196
}
207
197
208
198
StringBuilder finalCss = new StringBuilder ();
209
- while (!findStrategies .isEmpty ()) {
199
+ while (!findStrategies .isEmpty ()) {
210
200
finalCss .append (findStrategies .pop ());
211
201
}
212
202
@@ -254,6 +244,28 @@ private static String convertToCssOrXpath(FindStrategy findStrategy) {
254
244
return null ;
255
245
}
256
246
247
+ private static <TComponent extends WebComponent > TComponent retryFindingSingleComponent (Callable <List <TComponent >> callable , FindStrategy findStrategy ) {
248
+ if (Wait .retry (() -> {
249
+ List <TComponent > foundElements ;
250
+ try {
251
+ foundElements = callable .call ();
252
+ } catch (Exception e ) {
253
+ throw new RuntimeException (e );
254
+ }
255
+
256
+ if (foundElements .isEmpty ()) throw new IllegalArgumentException ();
257
+
258
+ }, Duration .ofSeconds (ConfigurationService .get (WebSettings .class ).getTimeoutSettings ().getElementWaitTimeout ()), Duration .ofSeconds (1 ), false )) {
259
+ try {
260
+ return callable .call ().get (0 );
261
+ } catch (Exception e ) {
262
+ throw new RuntimeException (e );
263
+ }
264
+ } else {
265
+ throw new NoSuchElementException ("No element inside the shadow DOM was found with the findStrategy: " + findStrategy .toString ());
266
+ }
267
+ }
268
+
257
269
private static final String javaScript = /* lang=js */ """
258
270
function (element, locator, relativeElementCss) {
259
271
const child_combinator = " > ";
@@ -338,11 +350,11 @@ function getAbsoluteCss(xpath) {
338
350
}
339
351
340
352
let startPoint = temporaryDiv;
341
-
353
+
342
354
if (relativeElementCss) {
343
355
startPoint = temporaryDiv.querySelector(relativeElementCss);
344
356
}
345
-
357
+
346
358
let elements;
347
359
if (locator.startsWith("/") || locator.startsWith("./") || locator.startsWith("(")) {
348
360
let result = document.evaluate(locator, startPoint, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
@@ -354,20 +366,20 @@ function getAbsoluteCss(xpath) {
354
366
} else {
355
367
elements = Array.from(startPoint.querySelectorAll(locator));
356
368
}
357
-
369
+
358
370
let finalLocators = [];
359
371
elements.forEach((el) => {
360
372
finalLocators.push(getAbsoluteCss(getAbsoluteXpath(el)));
361
373
});
362
-
374
+
363
375
return finalLocators;
364
376
}""" ;
365
377
366
378
private static final String getInnerHtmlScript = """
367
379
function (element, isShadowRoot) {
368
380
const child_combinator = " > ";
369
381
const node = "/";
370
-
382
+
371
383
function clone(element, tag) {
372
384
let cloneElement;
373
385
if (element instanceof ShadowRoot && !tag) {
@@ -381,20 +393,20 @@ function clone(element, tag) {
381
393
cloneElement.appendChild(element.firstChild.cloneNode());
382
394
}
383
395
}
384
-
396
+
385
397
if (element.shadowRoot) {
386
398
cloneElement.appendChild(clone(element.shadowRoot, "shadow-root"));
387
399
}
388
-
400
+
389
401
if (element.children) {
390
402
for (const child of element.children) {
391
403
cloneElement.appendChild(clone(child, undefined));
392
404
}
393
405
}
394
-
406
+
395
407
return cloneElement;
396
408
}
397
-
409
+
398
410
let temporaryDiv = document.createElement("temporary-div");
399
411
if (element.shadowRoot) {
400
412
temporaryDiv.appendChild(clone(element.shadowRoot, undefined));
@@ -404,7 +416,7 @@ function clone(element, tag) {
404
416
temporaryDiv.appendChild(clone(element, "redundant-el"));
405
417
temporaryDiv = temporaryDiv.querySelector("redundant-el");
406
418
}
407
-
419
+
408
420
return temporaryDiv.innerHTML;
409
421
}
410
422
""" ;
0 commit comments