3

I'm using a Page Object model. And on my website most page have a menu, so I was thinking I should create a class MenuPage that every other page that have a menu would extends it.

But now I would like to regroups all my WebElement from the menu to kinda separate them from the one of the current page.

In other word, if an element is directly on the page, I would access it something like that.

MyPage mypage = new MyPage(); /*MyPage extends MenuPage*/
mypage.myWebElement.click();

But if the webelement is part of the menu, and not part of MyPage, I would like to access it from

MyPage mypage = new MyPage();  /*MyPage extends MenuPage*/
mypage.menu.myWebElement.click();

I know I could create a class menu and instance it into MenuPage, but since it will only be used there, I would prefer not to have it separated from the class MenuPage. And also, the menu also have submenu, and so I would like to represent it with multi-level fields. And having a new class for each submenu could make a lots of class for so little.

What would be the best way to do so, or do you know a other way to approch the problem?

Etienne
  • 165
  • 1
  • 11
  • I think you're seeing some of the argument for composition over inheritance with how complicated this gets using inheritance. I'm not sure I totally understand what is going on with submenus, but if you can clarify a bit there are probably a few different approaches you can use there. – mrfreester Jan 18 '17 at 18:30

3 Answers3

5

Page is not menu. Page has menu. We can extend only if it IS A relationship. Otherwise go with composition over inheritance principle.

I would suggest you to go with Page Fragments for better reusability.

That is, you create reusable components called 'Page Fragments' as shown here and use it in the Page Objects.

enter image description here

vins
  • 15,030
  • 3
  • 36
  • 47
0

To follow Composition over inheritance I would suggest making an interface, like IHasMenu, and it has one method that returns your MenuPage object, like getMenuPage().

That way all of your page objects that have a menu just have to implement that one method to get your menu.

Your code would read similar to what you wanted:

MyPage mypage = new MyPage();
mypage.getMenuPage().myWebElement.click();

The interface would be:

interface IHasMenu{
    public MenuPage getMenuPage();
}

And your MyPage:

public class MyPage implements IHasMenu
{
    public MenuPage getMenuPage()
    {
        return new MenuPage(); //(Or however you initialize your PO's)
        //Or return a private property if you don't want to create a new one
        //every time this is called
    }
}

If adding a GetMenuPage() method for every class that inherits from IHasMenu makes you feel gross about violating the DRY principle, you can use an extension method, and remove the public MenuPage getMenuPage(); from your interface. The extension would be something like this:

public static class IHasMenuExtensions
{
    public static MenuPage GetMenuPage(this IHasMenu hasMenuPageObject)
    {
        return new MenuPage();
    }
}

Just make sure that IHasMenuExtensions is in the same namespace as IHasMenu, than you'll be able to call it just like you would before without adding a custom using statement for your extensions class.

mrfreester
  • 1,981
  • 2
  • 17
  • 36
0

I bet all the menus are similar. You could implement exactly one class SubMenu. You could call its constructor to specify which SubMenu you need, e.g.:

SubMenu sweets = new SubMenu("sweets");
SubMenu vegetables = new SubMenu("vegetables");
Grzegorz Górkiewicz
  • 4,496
  • 4
  • 22
  • 38
  • Good idea, although factory would probably be more appropriate, since a lot of Selenium frameworks end up needing a parameter-less constructor to generically initialize webelements, wait for page to load, etc... but this would work for some frameworks – mrfreester Jan 18 '17 at 18:34
  • Either a factory or [a builder pattern](https://en.wikipedia.org/wiki/Builder_pattern#Java). The builder pattern lets us avoid constructor mess. – Grzegorz Górkiewicz Jan 18 '17 at 18:36
  • Also, if you down voted my answer, could you please explain why? It helps the OP, me, and anybody else trying to figure out why there is something wrong with a particular approach. – mrfreester Jan 18 '17 at 18:37
  • I did not downvote your answer, bro; but I do not find it perfect either. Imho your answer does not eliminate the reason to write as many classes as menus. – Grzegorz Górkiewicz Jan 18 '17 at 18:42
  • Thanks for the feedback, it's meant to address a `MenuPage` object which is a component found on a lot of different page objects, this is a common scenario in the PageObject model. I didn't address a sub menu in my answer which is I think what you're referring to. – mrfreester Jan 18 '17 at 18:46