0

I have the following lines in the page object class (to deal with Shadow DOM):

11        headerContent(wait:true) { $("content-header") }
12        shadowRoot0(wait:true) { js.exec("return arguments[0].shadowRoot", headerContent) }

However, when run it in the GebSpock tests, it persistently fails with below exception:

|                      Caused by: java.lang.IllegalArgumentException: The last argument to the js function must be string-like
|                       at geb.js.JavascriptInterface.exec(JavascriptInterface.groovy:53)
|                       at test.ui.modules.RightHandHeader._clinit__closure1$_closure3(RightHandHeader.groovy:12)
...

Above code lines are translated from below codes using JavascriptExecutor with WebElement which just work well when executing:

    WebElement shadowDomHost = driver.findElement(By.cssSelector("content-header"))
    WebElement root0 = (WebElement) ((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot", shadowDomHost)

There must be something wrong when calling js.exec in GebSpock.

Anyone has any idea about this issue ? What's the correct syntax passing parameters to js.exec() ?

PS:

    def exec(Object[] args) {
        if (args.size() == 0) {
            throw new IllegalArgumentException("there must be a least one argument")
        }

        def script
        def jsArgs
        if (args.size() == 1) {
            script = args[0]
            jsArgs = []
        } else {
            script = args.last()
            jsArgs = args[0..(args.size() - 2)]
        }

        if (!(script instanceof CharSequence)) {
            throw new IllegalArgumentException("The last argument to the js function must be string-like")
        }

        execjs(script.toString(), *jsArgs)
    }
  • In Geb, the line 11 is having the Navigator object type. I tried to pass the "headerContent.firstElement()" to the js.exec(). However, still saw the same exception. Tried also converting it to the string type, but it complained about characters '-&gt' in the parameters, etc. Not sure if Geb supports the shadow DOM elements? – Guoping Oct 06 '21 at 14:20

1 Answers1

0

I believe you've swapped the order of the arguments in the js.exec() call. Based on the Book of Geb:

The js object also has an exec() method that can be used to run snippets of JavaScript. It is identical to the JavascriptExecutor.executeScript() method, except that it takes its arguments in the other order…

Example: assert js.exec(1, 2, "return arguments[0] + arguments[1];") == 3

This should mean that this should fix your issue:

shadowRoot0 (wait:true) { 
    js.exec(headerContent.singleElement(), "return arguments[0].shadowRoot")
}
aspok
  • 285
  • 3
  • 10
  • Hi, aspok, thank you very much for your help ! Yes it works now when pass the parameters in other order. The js.exec() returns the shadowRoot0 correctly. However, the returned shadowRoot0 becomes the RemoteWebElement type. In the page object class, the line 'sMenu(wait:true) { shadowRoot0.find("saturn-menu") }' stops working (caused by: groovy.lang.MissingMethodException: No signature of method: org.openqa.selenium.remote.RemoteWebElement.find() ). Is there a way to cast it to Navigator type and continue to use the same search Geb syntax in the page object ? – Guoping Oct 07 '21 at 12:15
  • You can create a `Navigator` from a `WebElement` by passing it to the `$()` method available in `content` blocks. So in your case that would be `$(js.exec(headerContent.singleElement(), "return arguments[0].shadowRoot"))` – erdi Oct 11 '21 at 20:27
  • @Guoping, I suggest you accept the correct answer here in order to close the question. It is still listed as open. It is alkso a matter of courtesy. Please click the grey checkmark, making it green. Thank you. – kriegaex Oct 17 '21 at 08:22