6

I'm trying to use the page object model for my tests and I'm trying to structure my page classes to be able to do a "builder pattern-like" structure (I've not seen it very often so I don't know if it has a name or if it is even a thing) like in this example:

public class Page1 implements Page  {
   public static Page1 goOn(){
       return new Page1();
   }

   public Page1 action1() {
       return this;
   }

   public Page2 gotoPage2() {
       return new Page2();
   }
}

public class Page2 implements Page  {
    public Page2 action2() {
        return this;
    }

    public Page2 gotoPage1() {
        return new Page2();
    }
 }

And then use it like:

Page1.goOn()
     .action1()
     .gotoPage2() //it return a Page2 object which mean you cant use Page1 methods anymore
     .action2()   // avoiding using the Page1 object which wouldnt be usable anymore if we stored it
     .goToPage1() //and poof we can only use Page1 methods again
     .action1()
     //etc...

So this is how I would manage "linear" page change, it allows some nice stuff with auto-completion and forces you to only do valid actions before compile time (which I think is great since I hate runtime errors >:( )

Then I'm trying to handle a login page (its mostly a simple example of what I'm gonna have to do next), there are 2 different outputs possible depending on if the login fails or not. For that specific case I could have done 2 functions: public Page1 logIn(){...} and public Page2 "logInButFail(){...} but for several reasons I would like to do something like:

public Page logIn(User user) {
    //do the login in the page
    //IF login worked:
    //return new Page2();
    //ELSE
    //return this; // or new Page1(), 
}

The problem is, to keep going with that the methods chain thingy I had before I have to do unsafe casts, which... I can handle them fairly nicely and safely but it means breaking java's sacred rule about typing... And well, my static typing fan's lil' brain has been struggling deciding what to do.

So:

  • Is there a way to do it without doing unsafe casts?
  • If not, should I:
  • Do efficient code using unsafe casts (which actually are ok because if those casts fail that means the test failed before)?
  • Do less efficient code but keep java happy? :)

Thanks for any help on the subject, if you need more explanation ask me I will do my best to explain it more precisely (also if you know how this practice is called I'm interested) :)

EDIT: after using the dynamic logIn() I use the following function to assert the type of the page (this is where I have to do the unsafe cast I try to avoid):

public <T extends Page> T assertPage(Class<T> type){
  boolean isgood = (this.getClass.equals(type));
  assertTrue(isgood);
  if(isgood){
    return (T)this; //this is the unsafe cast im trying to avoid
  }else{
    //throw an exception as this is not supposed to happen
  }
}
2
  • This is an interesting set up, I just want to make sure I am understanding correctly -- the core principle here, is that if you call a method on Page1 that navigates you to Page2, you want to return an instance of Page2 from that method call. Something like Page2 result = page1.navigateToPage2(); ? I know this is oversimplified, I just want to make sure I understand correctly. Commented Nov 22, 2019 at 15:12
  • yes, what i am able to do so far is do it in a static way (aka navigateToPage2() only return 1 kind of page type), my problem is doing it in a dynamic way (aka navigateToPageX() return either Page1 or Page2 and then i assert im on the right page) while breaking the less java rules i can :D Commented Nov 24, 2019 at 21:28

1 Answer 1

1

So, you want to page-object method, wich will conditionaly return instance of Page1 or Page2. For that, you created method of type Page. And you want to execute this method and continue to work with instance of Page1 or Page2 depends on condition without cast. Right? You can do it via generics. Here is simplified example:

class Page{
    <T extends Page> T conditionalAction( T pageObject ){
        return pageObject;
    }
}
class Page1 extends Page{
    Page1 action1(){ return this; }
}
class Page2 extends Page{
    Page2 action2(){ return this; }
}

Now, you can do something like:

Page1 page1 = new Page1();
Page2 page2 = new Page2();
page1.action1()
     .conditionalAction( page1 )
     .action1()
     .conditionalAction( page2 )
     .action2();

You are free to use such method of generic return type anywhere in your parent/clild class.

And if you want just to assert the class you get from a method, you can do the check:

public Page conditionalAction( boolean condition ) {
    if ( condition ) {
        return new Page1();
    } else {
        return new Page2();
    }
}

// in test

Page result = new Page1().conditionalAction( true );
if ( result instanceof Page1 ){
    Page1 page1 = (Page1) result;
} else if ( result instanceof Page2 ){
    Page2 page2 = (Page2) result;
}
Sign up to request clarification or add additional context in comments.

9 Comments

mmh mybad i think i should have made it more clear, so far i use genericity to assert the type of the page on the next step (like, public <T extends Page> T assertPage(Class<T>){...}) im gonna update my post to explain it more, but mostly my problem with that method is that i have to do an unsafe cast in it. also, one problem with your method is that you create page object in the "script", (im a lazy dev, i want to write the less code possible in the "scripts") :D
also, with your methods it isnt the function that decide which page it went to, its the guy who make the script that assume it will be this one (which im trying to avoid because not only im lazy but i looking to do those "scripts" in the most brainless way, using the most of autocompletion and corrector help as i can :D )
My code is simplified. It will works with public modifier in separate classes/packages. I guess, you cannot just cast page classes to each other. Or if you can, could you provide example of code that works? You cannot let your compiler decide, wich cresult will return some method, conditionally. This is the greate cybernetic theorem wich was mathematically proved.
Maybe I misunderstood you. Check out my answer,
the more i think about it, the more i start to believe i answered my problem, as, im trying to use types in an already weird way so, as i have to assert the page im on, i have to go from an undertermined page type (as i dont know if action like a login succeded) to a determined one and so cast it. also i wasnt trying to cast one page to another, the goal is that if i dont get the page i want, the test fail but if i get the right page i can keep working with it
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.