1515
1616import lombok .experimental .UtilityClass ;
1717import org .openqa .selenium .By ;
18+ import org .openqa .selenium .NoSuchElementException ;
1819import solutions .bellatrix .core .configuration .ConfigurationService ;
1920import solutions .bellatrix .core .utilities .InstanceFactory ;
2021import solutions .bellatrix .core .utilities .Ref ;
2122import solutions .bellatrix .core .utilities .Wait ;
2223import solutions .bellatrix .web .components .WebComponent ;
24+ import solutions .bellatrix .web .components .contracts .Component ;
2325import solutions .bellatrix .web .configuration .WebSettings ;
2426import solutions .bellatrix .web .findstrategies .CssFindStrategy ;
2527import solutions .bellatrix .web .findstrategies .FindStrategy ;
@@ -43,7 +45,7 @@ public static String getShadowHtml(WebComponent shadowComponent, boolean isShado
4345 }
4446
4547 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 );
4749 }
4850
4951 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
6971 }
7072
7173 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 );
7375 }
7476
7577 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) {
103105 shadowRoot .findElement (), locator , null ).toArray (String []::new );
104106 };
105107
106- return getCss (js , locator );
108+ return getCss (js );
107109 }
108110
109111 private static String [] getRelativeCss (ShadowRoot shadowRoot , String locator , String parentLocator ) {
@@ -113,30 +115,18 @@ private static String[] getRelativeCss(ShadowRoot shadowRoot, String locator, St
113115 shadowRoot .findElement (), locator , parentLocator ).toArray (String []::new );
114116 };
115117
116- return getCss (js , locator );
118+ return getCss (js );
117119 }
118120
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 );
139127 }
128+
129+ return foundElements ;
140130 }
141131
142132 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) {
206196 }
207197
208198 StringBuilder finalCss = new StringBuilder ();
209- while (!findStrategies .isEmpty ()) {
199+ while (!findStrategies .isEmpty ()) {
210200 finalCss .append (findStrategies .pop ());
211201 }
212202
@@ -254,6 +244,28 @@ private static String convertToCssOrXpath(FindStrategy findStrategy) {
254244 return null ;
255245 }
256246
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+
257269 private static final String javaScript = /* lang=js */ """
258270 function (element, locator, relativeElementCss) {
259271 const child_combinator = " > ";
@@ -338,11 +350,11 @@ function getAbsoluteCss(xpath) {
338350 }
339351
340352 let startPoint = temporaryDiv;
341-
353+
342354 if (relativeElementCss) {
343355 startPoint = temporaryDiv.querySelector(relativeElementCss);
344356 }
345-
357+
346358 let elements;
347359 if (locator.startsWith("/") || locator.startsWith("./") || locator.startsWith("(")) {
348360 let result = document.evaluate(locator, startPoint, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
@@ -354,20 +366,20 @@ function getAbsoluteCss(xpath) {
354366 } else {
355367 elements = Array.from(startPoint.querySelectorAll(locator));
356368 }
357-
369+
358370 let finalLocators = [];
359371 elements.forEach((el) => {
360372 finalLocators.push(getAbsoluteCss(getAbsoluteXpath(el)));
361373 });
362-
374+
363375 return finalLocators;
364376 }""" ;
365377
366378 private static final String getInnerHtmlScript = """
367379 function (element, isShadowRoot) {
368380 const child_combinator = " > ";
369381 const node = "/";
370-
382+
371383 function clone(element, tag) {
372384 let cloneElement;
373385 if (element instanceof ShadowRoot && !tag) {
@@ -381,20 +393,20 @@ function clone(element, tag) {
381393 cloneElement.appendChild(element.firstChild.cloneNode());
382394 }
383395 }
384-
396+
385397 if (element.shadowRoot) {
386398 cloneElement.appendChild(clone(element.shadowRoot, "shadow-root"));
387399 }
388-
400+
389401 if (element.children) {
390402 for (const child of element.children) {
391403 cloneElement.appendChild(clone(child, undefined));
392404 }
393405 }
394-
406+
395407 return cloneElement;
396408 }
397-
409+
398410 let temporaryDiv = document.createElement("temporary-div");
399411 if (element.shadowRoot) {
400412 temporaryDiv.appendChild(clone(element.shadowRoot, undefined));
@@ -404,7 +416,7 @@ function clone(element, tag) {
404416 temporaryDiv.appendChild(clone(element, "redundant-el"));
405417 temporaryDiv = temporaryDiv.querySelector("redundant-el");
406418 }
407-
419+
408420 return temporaryDiv.innerHTML;
409421 }
410422 """ ;
0 commit comments