1. #1
    Sencha User
    Join Date
    Jan 2010
    Posts
    132
    Vote Rating
    1
    Answers
    2
    darkling235 is on a distinguished road

      0  

    Default Answered: WebDriver GXT help

    Answered: WebDriver GXT help


    I'm trying to use Webdriver to do integration tests for my system. It loads the page correctly and seems to fire clicks correctly but the clicks don't always seem to do anything. On one of my pages I have a gxt checkbox. The html looks like this:

    HTML Code:
    <div __gwtcellbasedwidgetimpldispatchingfocus="true" __gwtcellbasedwidgetimpldispatchingblur="true" id="scalebase_license_agreement_checkbox" style="margin: 10px; position: relative;">
    <div class="GEHK1BQCMR-com-sencha-gxt-theme-base-client-field-CheckBoxDefaultAppearance-CheckBoxStyle-wrap">
    <input type="checkbox" id="x-auto-0" tabindex="0">
    <label for="x-auto-0" class="GEHK1BQCGR-com-sencha-gxt-theme-base-client-field-CheckBoxDefaultAppearance-CheckBoxStyle-checkBoxLabel">I Agree</label>
    </div>
    </div>
    This HTML is part of a wizard we've built.

    This test case is testing two pages in the Wizard. The first page is just a splash screen which should proceed to the next page when the user clicks the NEXT button.
    This aspect of the webDriver test seems to be working fine.

    The second page has a NEXT button which should be disabled until the user clicks on the I Agree checkbox. The WebDriver finds an element and clicks it but:
    A. I'm not sure if I'm firing the click on the right element OF the checkbox (there are quite a few divs there)
    and
    B. I'm not sure if the code listening for valueChange events will be fired when it does or if I need to do something special here.
    Currently after the click event fires and the test completes, the checkbox is still not checked.


    This is my webDriver demo code. I'm just trying to get a proof of concept going here. Can anyone give me some guidance in which elements to select and call click on in GXT when I need to fire events?
    Code:
    public class TestCreateUser extends TestCase{
    
        private static WebDriver driver;
    
          public static void initWebDriver() throws IOException {
            
            // set the path to the chrome driver
            // http://code.google.com/p/chromium/downloads/list
            System.setProperty("webdriver.chrome.driver", "C:\\chromedriver_win32_2.0\\chromedriver.exe");
            
            // chrome driver will load with no extras, so lets tell it to load with gwtdev plugin
            // get plugin here in chrome url type > "chrome://plugins/" > hit top right details + > find gwt dev mode pluging location:
            DesiredCapabilities capabilities = DesiredCapabilities.chrome();
            String gwtDevPluginPath = "--load-plugin=C:\\chromedriver_win32_2.0\\npGwtDevPlugin.dll";
            capabilities.setCapability("chrome.switches", Arrays.asList(gwtDevPluginPath));
            
            // init driver with GWT Dev Plugin
            driver = new ChromeDriver(capabilities);
          }
    
          @AfterClass
          public static void theEnd() {
            driver.quit();
          }
          
          @Test
          public void testSplashScreen() 
          {
           
              try{
                  initWebDriver();
                // navigate to gwt app - change this to your app url
                String pathToGwtApp = "http://localhost:2701/?forceWizard=true";
                driver.get(pathToGwtApp);
        
        
                By button = By.id("gwt-debug-wizardNextButton");
                WebElement elementRta = fluentWait(button);
                elementRta.click();
                
                
                By checkBox = By.id("scalebase_license_agreement_checkbox");
                WebElement elementCheckBox = fluentWait(checkBox);                        
                elementCheckBox.click();
              }catch(Throwable t)
              {
                  t.printStackTrace();
                  fail();
              }
          }
    
          public WebElement fluentWait(final By locator) {
                Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
                        .withTimeout(30, TimeUnit.SECONDS)
                        .pollingEvery(5, TimeUnit.SECONDS)
                        .ignoring(NoSuchElementException.class);
    
                WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
                    public WebElement apply(WebDriver driver) {
                        return driver.findElement(locator);
                    }
                });
    
                return  foo;
            };
    
    }

    Thanks
    Last edited by darkling235; 15 Jul 2013 at 10:48 AM. Reason: fixed a double copy

  2. Hi darkling235 - I've seen these posts but haven't yet been able to put together a coherent reply to you. Its been a busy few weeks trying to get ready for SenchaCon and get ahead of the bug workload for that time spent chatting rather than typing.

    I love the premise of WebDriver, but am very wary of the default tools provided for testing RIAs. For the standard 'web 1.0' form or page with links, using the built-in By types are great, since the distance between the structure/purpose of the page and the actual markup is so small. But for complex apps written with various tools to assist in development, it is rarely productive to require that each and every dom element of interest have a *and* consistent id - either you might accidently have two elements with the same id (consider a button in a dialog that gets drawn more than once, etc), or you need generated IDs that have the potential to change based on how many widgets have been constructed so far...

    <rant>
    Classes and xpaths are no better, though at least linktext gets close. With a class you are limited from using tools like ClientBundle, Closure Stylesheets, or sass/compass/less to generate css classes, since the code you write has little relationship with the dom structure in the browser. Using an xpath is no better, since that assumes that the actual dom structure has meaning to it, so a different implementation of the same UI means that WebDriver must treat it as if it were a different UI altogether.

    The fact of the matter is that the purpose of an id in GWT/GXT code is very different from the purpose served in webdriver. GXT code might assign an ID at the root level of a widget so that other widgets can do bookkeeping correctly or rapidly find the entire structure in one go, while webdriver wants to use ids to find the exact place where it should send a click or keystroke to. Classes are even worse, since the purpose isn't just for identification, but for *styling*, though there is no (clean, easy to use) way in webdriver to ask for the element with the blue text.
    </rant>

    Here's the by statement you used to find the root of the checkbox:
    Code:
    By checkBox = By.id("scalebase_license_agreement_checkbox");
    As noted, this won't work, since there is extra structure getting drawn to make sure the checkbox looks good. I think there is a id assigned to the input element itseere is another impl that will probably do a better job of what you are after:
    Code:
    By checkBox = new ByChained(By.id("scalebase_license_agreement_checkbox"), By.xpath(".//input"));
    This find the first input object inside the element with the given ID. But this really isn't much better - what if you replace the checkbox with a toggle button, or with a icon that *looks* like a checkbox?

    Instead, why can't we write tests that reflect how users navigate the app itself - I don't want to describe non-visible details like id/class/path, but want to say "Find the checkbox next to the label 'foo', and click it".

    A few ideas:
    * Complex Bys, like the one described above, will get you closer to the actual element you want to interact with.
    * Css class names that describe structure - each panel has one, each button/field/grid, so that you can use the structure to find things (i.e. "Click on '.header .register .loginbtn'), so that you don't need to be stingy or generated with IDs.
    * And finally, why work with raw elements in your tests when you don't work with raw elements when writing the app? The Page Object tools in WebDriver get close to this ideal, but I think we can get closer...

    I've got a library in progress that aims to let you (more or less...) do just that - build models that describe widgets, and with an extra inherits statement in your app, webdriver can do lookups to find out exactly what type of widget a certain element is in, or find all widgets of a certain type and perform other queries on them. Those extended Bys are the first step, but it also includes an api to find nested widgets, and a sort of builder pattern to describe exactly what the user is looking for, usually by text instead of by xpath or html attributes.

    Base GWT tool, setting up the basic functionality: https://github.com/niloc132/gwt-driver
    GXT library, adding support for GXT widgets: https://github.com/niloc132/gxt-driver
    Sample app, runnable either as a standalone app without the extra module, or testable: https://github.com/niloc132/gwt-driver-sample
    GwtDriver talk on the G+ GWT Community hangout in April: http://www.youtube.com/watch?v=UrkD8CWboDE&t=24m20s

    Looking forward to any feedback on the basic idea, as well as specific issues with the library. It is a work in progress, and I welcome bug reports as well as pull requests. This is an open source project under Sencha Labs, not a part of GXT (or GWT) itself.

  3. #2
    Sencha User
    Join Date
    Jan 2010
    Posts
    132
    Vote Rating
    1
    Answers
    2
    darkling235 is on a distinguished road

      0  

    Default


    Has anyone else ever run into these problems?

    I managed to access the checkbox item by using

    By checkBox = By.id("x-auto-0");

    however I don't know if this is wise. The ID looks like it may be variable even if it is the only control on the page. Also when I call click on that By the checkbox is still not clicked. Is there some special trick to trigger a click event and fire event listeners?
    Any help would be most appreciated
    Last edited by darkling235; 22 Jul 2013 at 10:16 AM. Reason: added details of new developments

  4. #3
    Sencha - GXT Dev Team
    Join Date
    Feb 2009
    Location
    Minnesota
    Posts
    2,734
    Vote Rating
    90
    Answers
    109
    Colin Alworth is a glorious beacon of light Colin Alworth is a glorious beacon of light Colin Alworth is a glorious beacon of light Colin Alworth is a glorious beacon of light Colin Alworth is a glorious beacon of light

      0  

    Default


    Hi darkling235 - I've seen these posts but haven't yet been able to put together a coherent reply to you. Its been a busy few weeks trying to get ready for SenchaCon and get ahead of the bug workload for that time spent chatting rather than typing.

    I love the premise of WebDriver, but am very wary of the default tools provided for testing RIAs. For the standard 'web 1.0' form or page with links, using the built-in By types are great, since the distance between the structure/purpose of the page and the actual markup is so small. But for complex apps written with various tools to assist in development, it is rarely productive to require that each and every dom element of interest have a *and* consistent id - either you might accidently have two elements with the same id (consider a button in a dialog that gets drawn more than once, etc), or you need generated IDs that have the potential to change based on how many widgets have been constructed so far...

    <rant>
    Classes and xpaths are no better, though at least linktext gets close. With a class you are limited from using tools like ClientBundle, Closure Stylesheets, or sass/compass/less to generate css classes, since the code you write has little relationship with the dom structure in the browser. Using an xpath is no better, since that assumes that the actual dom structure has meaning to it, so a different implementation of the same UI means that WebDriver must treat it as if it were a different UI altogether.

    The fact of the matter is that the purpose of an id in GWT/GXT code is very different from the purpose served in webdriver. GXT code might assign an ID at the root level of a widget so that other widgets can do bookkeeping correctly or rapidly find the entire structure in one go, while webdriver wants to use ids to find the exact place where it should send a click or keystroke to. Classes are even worse, since the purpose isn't just for identification, but for *styling*, though there is no (clean, easy to use) way in webdriver to ask for the element with the blue text.
    </rant>

    Here's the by statement you used to find the root of the checkbox:
    Code:
    By checkBox = By.id("scalebase_license_agreement_checkbox");
    As noted, this won't work, since there is extra structure getting drawn to make sure the checkbox looks good. I think there is a id assigned to the input element itseere is another impl that will probably do a better job of what you are after:
    Code:
    By checkBox = new ByChained(By.id("scalebase_license_agreement_checkbox"), By.xpath(".//input"));
    This find the first input object inside the element with the given ID. But this really isn't much better - what if you replace the checkbox with a toggle button, or with a icon that *looks* like a checkbox?

    Instead, why can't we write tests that reflect how users navigate the app itself - I don't want to describe non-visible details like id/class/path, but want to say "Find the checkbox next to the label 'foo', and click it".

    A few ideas:
    * Complex Bys, like the one described above, will get you closer to the actual element you want to interact with.
    * Css class names that describe structure - each panel has one, each button/field/grid, so that you can use the structure to find things (i.e. "Click on '.header .register .loginbtn'), so that you don't need to be stingy or generated with IDs.
    * And finally, why work with raw elements in your tests when you don't work with raw elements when writing the app? The Page Object tools in WebDriver get close to this ideal, but I think we can get closer...

    I've got a library in progress that aims to let you (more or less...) do just that - build models that describe widgets, and with an extra inherits statement in your app, webdriver can do lookups to find out exactly what type of widget a certain element is in, or find all widgets of a certain type and perform other queries on them. Those extended Bys are the first step, but it also includes an api to find nested widgets, and a sort of builder pattern to describe exactly what the user is looking for, usually by text instead of by xpath or html attributes.

    Base GWT tool, setting up the basic functionality: https://github.com/niloc132/gwt-driver
    GXT library, adding support for GXT widgets: https://github.com/niloc132/gxt-driver
    Sample app, runnable either as a standalone app without the extra module, or testable: https://github.com/niloc132/gwt-driver-sample
    GwtDriver talk on the G+ GWT Community hangout in April: http://www.youtube.com/watch?v=UrkD8CWboDE&t=24m20s

    Looking forward to any feedback on the basic idea, as well as specific issues with the library. It is a work in progress, and I welcome bug reports as well as pull requests. This is an open source project under Sencha Labs, not a part of GXT (or GWT) itself.

  5. #4
    Sencha Premium Member
    Join Date
    Mar 2010
    Posts
    9
    Vote Rating
    0
    questzen is on a distinguished road

      0  

    Default Element detection

    Element detection


    Quote Originally Posted by Colin Alworth View Post
    Classes and xpaths are no better, though at least linktext gets close. With a class you are limited from using tools like ClientBundle, Closure Stylesheets, or sass/compass/less to generate css classes, since the code you write has little relationship with the dom structure in the browser. Using an xpath is no better, since that assumes that the actual dom structure has meaning to it, so a different implementation of the same UI means that WebDriver must treat it as if it were a different UI altogether.
    Thanks for asserting what I had in my mind. I would request your opinion on the following:

    A: I would like to state that xpath can take a context. It is possible to write context-aware xpath expressions
    Code:
    /div[@text="Explorer Demo"]
    . The challenge is that it is not clean, visual positioning & actual occurence in DOM don't have an exact correlation, XPATH expressions are not human/QA friendly

    B: If we can put semantic correctness aside, the next best thing is to have hidden tags sprinkled in the components,
    Code:
     <code/> or <details/>
    tags seem to be relevant. These tags can hold the meta-data needed for component detection.

    Right now, we see composite button, made up of nested divs, transparent images/filters/gradients. There is no API to findout what this widget is. As part of the html authoring (in Appearance Pattern classes), or by virtue of a id-generator function, we can have this meta-data auto populated. If we allow developers to enter additional meta-data during development [ akeen to setData() on widgets], then testers/tools will be able to make sense of the nature of the components.

    I still have no clue how it would handle issues with respect to layouts, display:none, iframe usage.

  6. #5
    Sencha - GXT Dev Team
    Join Date
    Feb 2009
    Location
    Minnesota
    Posts
    2,734
    Vote Rating
    90
    Answers
    109
    Colin Alworth is a glorious beacon of light Colin Alworth is a glorious beacon of light Colin Alworth is a glorious beacon of light Colin Alworth is a glorious beacon of light Colin Alworth is a glorious beacon of light

      0  

    Default


    A: I would like to state that xpath can take a context. It is possible to write context-aware xpath expressions

    Code:
    /div[@text="Explorer Demo"]
    GwtDriver is full of these, though usually expressed as .//*[text()="Explorer Demo"] so that it isn't dependent on the tag names, and can apply to any descendent.

    XPaths are pretty miserable for this kind of thing, and introducing new tags doesnt make them any better - has the same effect as introducing a new css class name and setting those at the same places in the tree. Plus, the browser supports it. The only advantage to using your own tags is that they make for shorter, quicker to write xpaths.

    My position is that for a RIA, it shouldn't matter the structure of a button any more than the structure of a form or a dialog or a grid should matter. In any case, the app is should be just as usable no matter how the app is structured - no matter which layouts you use, or what dom elements those widgets are composed of. Just as a user will need to be retrained if the app changes in a logical way ("Log in" button moved to the middle of the screen instead of the top and text changed to "Sign In"), the test should only need to be updated in those same cases. Requiring the test to know that the first child of the actual button can be clicked (that's how it works in GXT 3 in order to support the Cell API cleanly), or whether you used a BorderLayoutContainer versus a HorizontalLayoutContainer is absurd.

    The goal of GwtDriver is to have this sort of context expressed in a strongly typed way, rather than piecing together strings and hoping that the structure doesn't change. Consider the xpath to find a button labeled 'Save' inside a window with header 'Edit User', it'd look something like this (assuming header is one element deep, among other things...):

    //*[text()='Edit User']/..//*[text()='Save']

    Usable, but from the perspective of the engineer writing the test, mostly opaque. Do we need one ../ or two? Or more? If I need to add another intermediate panel (say, "Actions"), where do I add this without knowing the xpath?

    If we allow developers to enter additional meta-data during development [ akeen to setData() on widgets], then testers/tools will be able to make sense of the nature of the components.
    My current solution is to expect the widget itself is a logical 'landmark'/context, and the type hierachy is the metadata itself. It can use that to figure out where the user is, what needs to happen next.

    Each model has some specific built-in details that describe what classes to look for. For any field (combobox, textfield, checkbox) it looks for Field itself, so that it matches any subclass automatically.

    Code ends up looking about like this:
    Code:
    // Find the window, in the current driver, with the given text as a header
    Window editWindow = GwtWidget.find(Window.class, driver).withHeading("Edit User").done();
    // do more things...
    // Find and click the button inside the window
    editWindow.find(Button.class).withText("Save").done().click();
    It is very clear what you change if you want a panel inside the window - find a Panel with the Heading "Actions", then find the button within that instead:
    Code:
    // Find the window, in the current driver, with the given text as a header
    Window editWindow = GwtWidget.find(Window.class, driver).withHeading("Edit User").done();
    // do more things...
    // Find and click the button inside the window
    Panel actions = editWindow.find(Panel.class).withHeading("Actions").done();
    actions.find(Button.class).withText("Save").done().click();
    The code is arguably more verbose, but at the same time easier to write and edit with the IDE's code completion. And, no need to worry about the structure of the widget, that's the job of the widget model (here Window, Panel, and Button) that describe the structure and how to interact with it. With one exception (grid, a work in progress anyway), all of these models written so far are actually appearance-agnostic - no matter what structure you change to customize the appearance, these should keep working. This means the widget finders have some uglier xpaths, but those are write-once, use everywhere.

    You could certainly build your own sort of tools for finding, matching widgets with custom appearance impls. GwtDriver doesnt do this so that appearances don't have to get other bloat based on the need to test.

    I still have no clue how it would handle issues with respect to layouts, display:none, iframe usage.
    Display:none can't be tested, webdriver will complain if you try to click or type on something that is invisible. IFrames *I think* are as transparent to WebDriver as they are to users. And when building your test, as a rule I would be no more dependent on the layout structure than the user is when looking at the page.

Thread Participants: 2

Tags for this Thread