Bug in Module when using withFrame(){} ?

234 views
Skip to first unread message

Yori Kurita

unread,
Nov 22, 2016, 6:10:55 AM11/22/16
to Geb User Mailing List
Hi,
I ran into a strange problem and wonder if its my fault or if it is a bug.
Following scenario:
- Page A contains several text fields , whose content i want to verify. 1 of these text fields is within an iframe.
- When i want to verify if the text is correct by using :

def checkText(text){
       withFrame(frame){messageText.contains(text}
}

as a method in PageObejct for PageA , it works.

But since i have several other Pages, where i want to do the same check, i moved it into a module.
When i now run: 

 - module(VerifyMessage).checkText(text) 

I get a timeout. All other elements, I check in the module are found (divs with Text information).
So i moved just the check for the text back into the PageObejct for Page A, then it works again.

Do I do something wrong here? Do you need more Information?


Regards

Marcin Erdmann

unread,
Nov 29, 2016, 4:53:15 PM11/29/16
to Geb User Mailing List
Hi Yori,

Accessing elements inside of iframes from modules should, as you are correctly expecting, work the same way as doing so from pages.

Can you please explain what do you mean by "I get a timeout"? I don't see any waitFor() calls in the code you provided so I'm baffled at why you would get any kind of timeout. Providing a stacktrace you get when you are seeing that timeout would probably also help to understand what is going on here.

One thing that comes to mind that might be causing different behaviour in modules from the one in pages is that modules are scope, i.e. they have a base element (http://www.gebish.org/manual/current/#base-and-context) which is used as the context for any lookups done within the module. Can you please confirm that the frame you are accessing is located within the base element of your module?

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/ba795fd4-dcdb-4cb2-9cb3-a8e55bb3444b%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Yori Kurita

unread,
Nov 30, 2016, 5:37:29 AM11/30/16
to Geb User Mailing List
Hi Marcin,

thanks for your answer. 
First a little informationa bout the Site I am Testing. This site contains several Modules , one of them is the communication module, which in the end is a mailbox similar to gmail. The difference is every message or process i start or read opens up in a new popup window.
The way i implemented the tests at the moment is:

Page A: Communication Page
Page B: Message Page

When i create or read a message i switch from Page A to the new popup Page B and start working in the popup
In Page B I have added the modules like it is described in the manual


This is the PageObejct for the Communication Page

class CommunicationPage extends MainPage {

    static final String windowName = mainWindowName
    static at = { appName.text() == 'communication' }
    static content = {
        commTab { type -> $('div.TabPaneHeaderLabelContainer', title: type) }
        newMessage(required: false, toWait: true) { $('div#IconHolder_newConversation') }
        refreshButton { $('img.Button') }
        messageRows(required: false) { $("[id^=row_conversationsListTable_]") }
        messageSubject(required: false) { subject -> messageRows.$('a', text: subject) }
    }

    def commType(String tab) { commTab(tab).click() }

    def refreshList() { refreshButton.click() }

    def Map startMessage() {
        commType('Messages')
        newMessage.click()
        def Map originals = switchWindow(new MessagePage())
        return originals
    }

    def createMessage(data) {
        def Map originals = startMessage()
        browser.page.fillMessage(data)
        browser.page.send(originals)
    }

    def checkMessage(data) {
        refreshList()
        def Map originals = openMessage(data.subject)
        browser.page.validateMessage(data)
        browser.page.close(originals)
    }


    def Map openMessage(String subject) {
        messageSubject(subject).click()
        def Map originals = switchWindow(new MessagePage())
        return originals
    }
}

switchWindow is defined in the MainPage Class:

    def Map switchWindow(Page windowPage) {
        def String windowName = windowPage.windowName
        def anyMatching = false
        def Map originals = [originalWindow: browser.currentWindow, originalPage: browser.getPage()]
        final String windowHandle = browser.driver.getWindowHandles().find {
            winHandle ->
                browser.withWindow(winHandle) {
                    browser.js.exec('return window.name').toString().startsWith windowName
                }
        }
        try {
            browser.driver.switchTo().window(windowHandle)
            browser.page windowPage
            waitFor { !browser.$('img#emptyWaitImg').displayed }
            browser.verifyAt()
            anyMatching = true
        } finally {
            if (!anyMatching) {
                browser.driver.switchTo().window(originals.originalWindow)
                browser.page originals.originalPage
                throw new NoSuchWindowException("Could not find a window that would match the given Name $windowName")
            } else {
                return originals
            }
        }
    }


Here the MessagePage Page Object :

class MessagePage extends MainPage (<- MainPage extends geb.Page) {
    
    static at = { ...at checker...}
    static content = {
                              .
                              .
                              .
                              .
                            fill { module FillActivity}
                            verify { module VerifyActivity}
    }


    def validateMessage(data) {
        //assert checkMessageText(data.text)
        verify.verifyActivity(data)
    }

}


Here the VerifyActivity Module:

class VerifyActivity extends Module {
    static content = {

        subjectSent(required: false) { $('div.subject') }
        recipientsSent(required: false) { $('table.recipients') }
        targetDateSent(required: false) { $('div.targetDateContainer') }

        frameMessageSent(required: false, wait: true) { $('[id^=frmdbCnv-]') }
        messageTextSent(required: false, wait: true) { $('div.msgContents') }
    }

    def verifyActivity(data) {
        assert checkMessageText(data.text)
        .
        .
        .
        .
    }

     def boolean checkMessageText(String text) {
        withFrame(frameMessageSent) {
B1            messageTextSent.text().contains(text)
        }
    }
}

If I use the method 'checkMessageText()'  and its locators frameMessagesent and messageTextSent in the Page Object MessagePage, all works fine. 
If I use it like this and run the test I get:

at CommunicationPage checkMessage(messagedata)
|                    |            |
|                    |            data.MessageData@1e3d7dd
|                    groovy.lang.MissingMethodException: No signature of method: geb.waiting.UnknownWaitForEvaluationResult.text() is applicable for argument types: () values: []
|                    Possible solutions: getAt(java.lang.String), wait(), wait(long), wait(long, int), every(), find()
pages.CommunicationPage 


When debugging it , and setting a breakpoint (B1) at messageTextSent.text().contains() ,on evaluating navigator.base I get :

stale element reference: element is not attached to the page document
  (Session info: chrome=54.0.2840.99)
  (Driver info: chromedriver=2.25.426923 (0390b88869384d6eb0d5d09729679f934aab9eed),platform=Windows NT 6.1.7601 SP1 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 9 milliseconds


Hope this helps, or do you need more information?


Regards

Yori


Am Dienstag, 29. November 2016 22:53:15 UTC+1 schrieb Marcin Erdmann:
Hi Yori,

Accessing elements inside of iframes from modules should, as you are correctly expecting, work the same way as doing so from pages.

Can you please explain what do you mean by "I get a timeout"? I don't see any waitFor() calls in the code you provided so I'm baffled at why you would get any kind of timeout. Providing a stacktrace you get when you are seeing that timeout would probably also help to understand what is going on here.

One thing that comes to mind that might be causing different behaviour in modules from the one in pages is that modules are scope, i.e. they have a base element (http://www.gebish.org/manual/current/#base-and-context) which is used as the context for any lookups done within the module. Can you please confirm that the frame you are accessing is located within the base element of your module?

Marcin
On Tue, Nov 22, 2016 at 11:10 AM, Yori Kurita <yorik...@gmail.com> wrote:
Hi,
I ran into a strange problem and wonder if its my fault or if it is a bug.
Following scenario:
- Page A contains several text fields , whose content i want to verify. 1 of these text fields is within an iframe.
- When i want to verify if the text is correct by using :

def checkText(text){
       withFrame(frame){messageText.contains(text}
}

as a method in PageObejct for PageA , it works.

But since i have several other Pages, where i want to do the same check, i moved it into a module.
When i now run: 

 - module(VerifyMessage).checkText(text) 

I get a timeout. All other elements, I check in the module are found (divs with Text information).
So i moved just the check for the text back into the PageObejct for Page A, then it works again.

Do I do something wrong here? Do you need more Information?


Regards

--
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.

Marcin Erdmann

unread,
Dec 1, 2016, 4:27:12 PM12/1/16
to Geb User Mailing List
Yes, the error you are getting is down to the fact that everything defined within a module is resolved relatively to that module's base. So in:

boolean checkMessageText(String text) {
    withFrame(frameMessageSent) {
        messageTextSent.text().contains(text)
    }
}

when resolving "messageTextSent" inside of the "withFrame()" block it is resolved using the base of the module which is outside of "frameMessageSent" frame. This causes an exception (I suspect it's a StaleElementReferenceException) and because your content definition for "messageTextSent" has "wait: true, required: false" it returns an instance of UnknownWaitForEvaluationResult, an object returned when last evaluation of a waitFor() call threw an exception, as described at the end of this section of the manual: http://www.gebish.org/manual/current/#content-dsl-wait.

You need to escape the context of the module when looking things up inside of the frame, the easiest way is by introducing a new page for the frame:

class MessageSentFramePage extends Page {
    static content = {
        messageTextSent(required: false, wait: true) { $('div.msgContents') }
    }
}

and in the module:

boolean checkMessageText(String text) {
    withFrame(frameMessageSent, MessageSentFramePage) {
        messageTextSent.text().contains(text)
    }
}

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.

Yori Kurita

unread,
Dec 2, 2016, 7:17:41 AM12/2/16
to Geb User Mailing List
Hi Marcin,

thanks for this hint. I did your suggested changes. 
I needed to do it like this :

boolean checkMessageText(String text) {
    withFrame(frameMessageSent, MessageSentFramePage) {
        browser.page.messageTextSent.text().contains(text)
    }
}

Otherwise i got Selenium stale Element Error:

org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document
|                      (Session info: chrome=54.0.2840.99)
|                      (Driver info: chromedriver=2.25.426923 (0390b88869384d6eb0d5d09729679f934aab9eed),platform=Windows NT 6.1.7601 SP1 x86_64) (WARNING: The server did not provide any stacktrace information)
|                    Command duration or timeout: 6 milliseconds


This works so far with Selenium 2.53.1 and 3.0.1

Marcin Erdmann

unread,
Dec 2, 2016, 9:16:06 AM12/2/16
to Geb User Mailing List
Thanks for reporting back, Yori. 

This is not how I would expect it to work and I'd consider it a bug (the fact that you had to add browser.page at the beginning of your expression inside of withFrame() block). Can you please create an issue for this at https://github.com/geb/issues/issues and link to this thread from it?

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.

Yori Kurita

unread,
Dec 2, 2016, 10:15:04 AM12/2/16
to Geb User Mailing List
Done : https://github.com/geb/issues/issues/461


And thanks for your support :)

Marcin Erdmann

unread,
Dec 2, 2016, 12:35:09 PM12/2/16
to Geb User Mailing List
Awesome, thank you!

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.
Reply all
Reply to author
Forward
0 new messages