Handling nested iframes with Geb

564 views
Skip to first unread message

Jeff

unread,
Mar 15, 2018, 11:56:45 AM3/15/18
to Geb User Mailing List
I'm new to Geb, and trying to use it to automate interactions on a site that makes heavy use of nested iframes.  

This is an example of the basic structure (leaving out some of the basic markup not relevant to my question):

<iframe id="firstFrame">
<iframe id="secondFrame">
<iframe id="thirdFrame">
<form id="login_form">
      <input id="email" type="text">
      <input id="password" type="password">
      <input class="action" value="Log in" id="login_button" type="submit">
</form>
</iframe>
</iframe>
</iframe>


My goal is to interact with elements in the "login_form" within the thirdFrame.

I've tried a couple of different approaches using "withFrame()", along these lines:

withFrame($("#firstFrame")) {
            withFrame($("#secondFrame"))
                    {
                        withFrame($("#thirdFrame")) {
                            assert { $("#email").displayed }
                        }
                    }
        }


...but that's not working.  Since I'm also new to Groovy, this may just be a lack of understanding of basic code syntax.

Can anyone suggest the correct syntax for interacting with nested iframes in Geb?




Marcin Erdmann

unread,
Mar 15, 2018, 2:18:18 PM3/15/18
to Geb User Mailing List
Hi Jeff,

You will need to be more specific than "that's not working". Can you please share the error you're getting? The code that you pasted looks to me like it should work.

Marcin

--
You received this message because you are subscribed to the Google Groups "Geb User Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to geb-user+unsubscribe@googlegroups.com.
To post to this group, send email to geb-...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/geb-user/88a389b1-b6c9-4d72-8140-4efc00e7e5c2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jeff

unread,
Mar 15, 2018, 3:33:34 PM3/15/18
to Geb User Mailing List
Aaagh, can't believe I forget to include the error!  The exception I'm getting is shown below.  

But thanks Marcin for confirming that my code syntax looks good.  The rendered page I'm working with actually has 21 iframes, so I'll dig more into the hierarchy of the nested frames to make sure I've got that part correct.

The exception is:

org.openqa.selenium.NoSuchFrameException: No elements for given content: []
Build info: version: '3.11.0', revision: 'e59cfb3', time: '2018-03-11T20:26:55.152Z'
System info: host: 'MacBook-Pro-2.local', ip: '2601:602:9701:1a30:4d40:10a1:f9ec:5ada', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.13.3', java.version: '1.8.0_131'
Driver info: driver.version: unknown

at geb.frame.DefaultFrameSupport.executeWithFrame(DefaultFrameSupport.groovy:79)
at geb.frame.DefaultFrameSupport.withFrame(DefaultFrameSupport.groovy:44)
at geb.Page.withFrame(Page.groovy:120)
at pages.googleDocs.DocumentPage.loginToRefWorks_closure8(DocumentPage.groovy:77)
at pages.googleDocs.DocumentPage.loginToRefWorks_closure8(DocumentPage.groovy)
at geb.frame.DefaultFrameSupport.executeWithFrame(DefaultFrameSupport.groovy:69)
at geb.frame.DefaultFrameSupport.executeWithFrame(DefaultFrameSupport.groovy:81)
at geb.frame.DefaultFrameSupport.withFrame(DefaultFrameSupport.groovy:44)
at geb.Page.withFrame(Page.groovy:120)
at pages.googleDocs.DocumentPage.loginToRefWorks(DocumentPage.groovy:76)
at geb.Browser.methodMissing(Browser.groovy:209)
at geb.spock.GebSpec.methodMissing(GebSpec.groovy:56)
at specs.references.CanSearchReferencesSpec.User can select RefWorks add-on(CanSearchReferencesSpec.groovy:18)





To unsubscribe from this group and stop receiving emails from it, send an email to geb-user+u...@googlegroups.com.

Marcin Erdmann

unread,
Mar 16, 2018, 3:21:48 PM3/16/18
to Geb User Mailing List
Ok, so it looks like the navigator you passed to the withFrame() call in DocumentPage on line 77 does not match any elements. I can see from the stacktrace that you are already within a withFrame() call there. I would probably try to confirm that your selectors are right as the first step.

To unsubscribe from this group and stop receiving emails from it, send an email to geb-user+unsubscribe@googlegroups.com.

To post to this group, send email to geb-...@googlegroups.com.
Message has been deleted

Marcin Erdmann

unread,
Mar 28, 2018, 9:41:02 AM3/28/18
to Geb User Mailing List
It's very interesting that you got it to work with plain Selenium. Your plain Selenium code does exactly what Geb does in the equivalent code so I'm baffled. I'm unfortunately not able to offer any more suggestion with the amount of information and visibility of things I have on my end.

On Fri, Mar 23, 2018 at 10:06 PM, Jeff <jeffre...@gmail.com> wrote:
Thanks Marcin.  I tried doing exactly that, and still couldn't get things to work, so I tried the same workflow with the Java version of the Selenium WebDriver.

This works as expected with the Java selenium-api:

driver.switchTo().frame(8);
driver.switchTo().frame("sandboxFrame");
driver.switchTo().frame("userHtmlFrame");
driver.findElement(By.id("email")).sendKeys(username);
driver.findElement(By.id("password")).sendKeys(password);

...but an equivalent workflow using Geb throws a NoSuchFrameException:

withFrame(8) {
    withFrame
('sandboxFrame') {
        withFrame
('userHtmlFrame') {
            $
('#email').value(username)
            $
('#password').value(password)
       
}
   
}
}

The complete exception message is:

org.openqa.selenium.NoSuchFrameException: No frame element found by name or id sandboxFrame
Build info: version: '3.11.0', revision: 'e59cfb3', time: '2018-03-11T20:26:55.152Z'
System info: host: 'C02P10DNG3QC.local', ip: '2601:602:9701:1a30:24ff:4dc1:ac2:3b96', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.13.3', java.version: '1.8.0_91'
Driver info: driver.version: unknown

at org.openqa.selenium.remote.RemoteWebDriver$RemoteTargetLocator.frame(RemoteWebDriver.java:884)
at geb.frame.DefaultFrameSupport.executeWithFrame(DefaultFrameSupport.groovy:57)
at geb.frame.DefaultFrameSupport.withFrame(DefaultFrameSupport.groovy:36)
at geb.Page.withFrame(Page.groovy:120)
at pages.googleDocs.DocumentPage.loginToRefWorks_closure7(DocumentPage.groovy:76)
at pages.googleDocs.DocumentPage.loginToRefWorks_closure7(DocumentPage.groovy)
at geb.frame.DefaultFrameSupport.executeWithFrame(DefaultFrameSupport.groovy:69)
at geb.frame.DefaultFrameSupport.withFrame(DefaultFrameSupport.groovy:36)
at geb.Page.withFrame(Page.groovy:120)
at pages.googleDocs.DocumentPage.loginToRefWorks(DocumentPage.groovy:75)

--
You received this message because you are subscribed to the Google Groups "Geb User Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to geb-user+unsubscribe@googlegroups.com.
To post to this group, send email to geb-...@googlegroups.com.

Nikhil Jain

unread,
Aug 1, 2019, 9:34:29 AM8/1/19
to Geb User Mailing List
Hi,

I was facing issues with handling the iFrames in Geb and this approach worked for me,:

1. Create a model Page class (for example FrameDescribingPage) , your iFrame will be considered as a Page class.
2. Identify your iFrame and define a DSL for it  (example :contentFrame in the code below)
3. In the Method where you plan to interact with the page, use withFrame(contentFrame)
4. Use Navigator Objects to interact with the contents
example: $("input#Login").value user

Note: in Step 4 , DSL did not work , I had to write the element identifiers within the withFrame block


Example

import geb.Page

class YouarPageWithIFramesPage extends Page {
static at = { contentFrame.size() > 0 }

static content = {
contentFrame(page: FrameDescribingPage, wait: true) { $("iframe[id='MyIframe']") }
}

/**
* Method to interact with Iframe.
*/

def MethodToInteractWithIframe(String user, String password) {
withFrame(contentFrame)
{
waitFor{$("input#Login").isDisplayed()}
$("input#Login").value user
$("input#Password").value password
$("button#submit").click()
}
}
}

/**
* model class for page that describes the iframe
*/
class FrameDescribingPage extends Page {
static content = {
}
}



Let me know if this worked for you !

Regards
Nikhil Jain
To unsubscribe from this group and stop receiving emails from it, send an email to geb-...@googlegroups.com.

To post to this group, send email to geb-...@googlegroups.com.

Thomas Hirsch

unread,
Apr 29, 2020, 11:33:15 AM4/29/20
to Geb User Mailing List
Hello Marcin, 

I just came across this issue just now, while having a similar problem with nested frames.
It seemed to me like the browser would always end up in the top level document after a withFrame call, at least adding driver.switchTo().frame() after every call to  withFrame (inside a nested frame (!!!)) is solving the issue for me right now.
Looking at the code of DefaultFrameSupport, there is indeed a call to driver.switchTo().defaultContent(), in the finally block of executeWithFrame...

I am assuming that 
driver.switchTo().defaultContent() would indeed switch to the top level document in the browser, as opposed to the next higher up frame, do you know if that is actually true?

Here is the code of my method inside a page loaded inside a frame (inputs for cardNumber and CVV are inside nested frames)
, and it worked after adding the lines below the comments:

void inputCreditCardDetails(
String cardNumber,
String expiryDate,
String holderName,
String cvv) {

withFrame(cardNumberIframe) {
cardNumberInput << cardNumber
}
// Not sure why we need this extra frame switching here...
driver.switchTo().frame($('.checkout-modal-iframe').firstElement())
expiryDateInput << expiryDate
holderNameInput << holderName
withFrame(cvvInputIframe) {
cvvInput << cvv
}
// Not sure why we need this extra frame switching here...
driver.switchTo().frame($('.checkout-modal-iframe').firstElement())
}

Marcin Erdmann

unread,
Apr 29, 2020, 5:40:28 PM4/29/20
to geb-...@googlegroups.com
Hi Thomas,

Back in the day, the only way to switch out of a frame was to call WebDriver.TargetLocator.defaultContent() which indeed switches to the top level document in the browser and it is what is used at the end of withFrame() execution. But after you brought this to my attention I had another look and it seems that WebDriver.TargetLocator.parentFrame() has been introduced in WebDriver 3.x. I therefore created an issue to switch to using this new method to better support the frame context when nested withFrame() calls are used: https://github.com/geb/issues/issues/612.

Cheers,
Marcin

--
You received this message because you are subscribed to the Google Groups "Geb User Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to geb-user+u...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages