Skip to content

Page Object design extension question #320

Closed

Description

@SergeyErmakovMercDev

Hello,
I'm using new page object design with Widget class. And recently caught some unexpected behaviour.
Let me describe my classes:

public class Movies {
    @iOSFindBy(uiAutomator = ".tableViews()[0].cells()")
    public List<Movie> items;
}

public class Movie extends Widget {
    @iOSFindBy(uiAutomator = ".staticTexts()[0]")
    public IOSElement nameElement;

    public IOSElement getNameElement() {
       return nameElement;
    }
}

And these classes I use smth like this:

Movies movies = ...
List<Movie> items = movies.items; //items is not null
Movie item = items.get(0);

IOSElement fieldElement = item.nameElement; // fieldElement is null
IOSElement methodElement = item.getNameElement(); // methodElement is not null

Why does it work so?
Are there any ways to get element directly from field without creating getter?

Activity

  1. TikhomirovSergey commented on Feb 18, 2016

    @TikhomirovSergey
    Contributor

    Hi @SergeyErmakovMercDev

    It is not a bug. It works by design.

    • The first point.
      Are you familiar with Page Object design pattern? Please pay attention to requirenments. So the thing you want conflicts with the pattern spec most likely. I think it makes sense to implement a public method which describes some business-logic/logic of interaction with a widget instead.
    • The second point.
      Have you read this description? Please pay attention to the** "What if interaction with a "widget" has special details for each used platform, but the same at high-level"**. Thing that you want may become senseless when you will want to design something crossplatform.

    If it is interesting I can describe how does it work.

    IOSElement fieldElement = items.nameElement; // fieldElement is null

    because items is not the real object. It is a proxy created via CGLIB. A real object with populated fields is instantiated once when any declared method is invoked. But it stays not available anyway.

    I'm waiting for your response.

  2. SergeyErmakovMercDev commented on Feb 18, 2016

    @SergeyErmakovMercDev
    Author

    @TikhomirovSergey, thanks for responce.

    I've just read the requirements and in most cases in project our team comply them. But in this situation I need to interact with sub-elements in widject directly. Like this:

    public class Movies {
        @iOSFindBy(uiAutomator = ".tableViews()[0].cells()")
        public List<Movie> items;
    
        public void swapMovies(int indexA, int indexB) {
             Point centerA = items.get(indexA).getNameElement().getCenter();
             Point centerB = items.get(indexB).getNameElement().getCenter();
    
             getDriver().swipe(centerA.getX(), centerA.getY(), centerB.getX(), centerB.getY(), DEFAULT_DURATION);
             // and so on
        }
    }

    Of cource I understand that I can make simple getNameCenter() method at Movie and the problem will be closed. But we are using Cucumber + Appium in project, thus in step definitions we get elements via reflection. The reason why we do this is simple: decrease coding time.

    So, everything is okey if we get fields via reflection from pages. And we supposed that widgets work familiar. But they don't.

    Sergey, I'll be so grateful to you, if you'll explain how does this work. And why in one case I got null at other an object.

  3. SergeyErmakovMercDev commented on Feb 18, 2016

    @SergeyErmakovMercDev
    Author

    BTW. Don't afraid about cross-platform. We simply don't need it :)

  4. TikhomirovSergey commented on Feb 19, 2016

    @TikhomirovSergey
    Contributor

    @SergeyErmakovMercDev
    Ok. I got your problem. And it seem I have the solution...

    If it is interesting I can explain how does it work.

    A decorator instance scans a page object instance. If a field has a type of some WebElement/list of WebElement then the decorator works as usual:
    https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/pagefactory/AppiumFieldDecorator.java#L155

    Ok. It tries to create a widget otherwise:
    https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/pagefactory/AppiumFieldDecorator.java#L160
    https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/pagefactory/AppiumFieldDecorator.java#L200
    https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/pagefactory/AppiumFieldDecorator.java#L205

    It creates not real objects, it creates proxies:
    https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/pagefactory/utils/ProxyFactory.java

    Real objects which wrapped inside proxies are created when any declared method is invoked:
    https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/pagefactory/WidgetInterceptor.java#L51
    https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/pagefactory/WidgetListInterceptor.java

    So the problem is that there is no ability to exract a real widget-object, What if there was something like that:

       @FindBy
       Widget widget;
    
       ...
       Object someValue = widget.
               getSelfReference(). //this method would be used in some extraordinary situations like yours
                   publicField;

    ?

    It could fix the known problem:
    #267
    Point: What if interaction with a "widget" has special details for each used platform, but the same at high-level
    To find: ...for now it is not possible to

  5. TikhomirovSergey commented on Feb 19, 2016

    @TikhomirovSergey
    Contributor

    You can propose a PR if you want :) Also don't forget to add a test if you want to try.

  6. added a commit that references this issue on Mar 2, 2016
  7. TikhomirovSergey commented on Mar 2, 2016

    @TikhomirovSergey
    Contributor

    This issue has been fixed and it is going to be published soon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions