Page Objects

Page object members

❌ Don't: Leave unused members in page objects

Doing this bloats your page objects and makes them harder to navigate.

✔️ Do: Remove unused page object members

If a member in a page object is not used, simply remove it from the page object.

Responsibility of a page object

❌ Don't: Add non-UI code to page objects

Page objects represent an application's view. They are not a controller. Any backend or businness code should be on an appropriate, separate module.

// MyPageObject.cs
public string GetSQLStatement(string param)
{
    // Oh no! SQL in a PageObject!
    return $"UPDATE table SET value = {param} WHERE other_value = 1";
}

✔️ Do: Keep page objects tightly coupled to the UI

Methods in page objects are highly encouraged, but they also should be added carefully. Your page object should respect the Single Responsibility Principle by only performing UI operations.

Complex page objects

❌ Don't: Have copies of the same page object for different scenarios

This can confuse contributors since they won't know which page object to modify when needed.

[Selector("#MyPageObjectId")]
public class MyPartialPageObject1 : PageObject
{
    public IButton myButton { get; set; }
}

[Selector("#MyPageObjectId")]
public class MyPartialPageObject2 : PageObject
{
    public ITextBox myTextBox { get; set; }
}

✔️ Do: Use a single page object

If possible, use a single page object per screen or page:

[Selector("#MyPageObjectId")]
public class MyPageObject : PageObject
{
    public IButton myButton { get; set; }
    public ITextBox myTextBox { get; set; }
}

✔️ Do: Split up complex UIs into inner page objects

Some screens or pages are too complex to fit in a single page object. If that's the case, they likely have container controls in them: panels, tabs, divs, etc. Split them up per container into smaller page objects and add them as members inside a larger page object. These are called Inner Page Objects:

public class MyPageObject : PageObject
{
    public InnerPageObject InnerPageObject { get; set; }
    public AnotherInnerPageObject AnotherInnerPageObject { get; set; }
}

public class InnerPageObject : PageObject
{
    public IButton myButton { get; set; }
    // more controls...
}

public class AnotherInnerPageObject : PageObject
{
    public ITextBox myTextBox { get; set; }
    // more controls...
}

Inner page object instantiation

❌ Don't: Instantiate inner page objects via the controller

This will result in a duplicate instantiation because inner page objects should instantiate automatically.

public class InnerPageObject : PageObject { }

public class ParentPageObject : PageObject
{
    public InnerPageObject InnerPageObject { get; set; }
    
    // Invoking this method duplicates InnerPageObject's instantiation!
    public void Initialize(UiExecutionController controller)
    {
        this.InnerPageObject = controller.GetPageObject<InnerPageObject>();
    }
}

✔️ Do: Declare inner page objects

All page objects declared as members of a parent page object are instantiated when the parent is.

public class InnerPageObject : PageObject { }

public class ParentPageObject : PageObject
{
    // This will get instantiated alongside ParentPageObject
    public InnerPageObject InnerPageObject { get; set; }
}

Using control collections

❌ Don't: Create control collections from scratch using concrete control implementations

Concrete control implementations can be used to find a control's children. This is used internally by QualityMate and is not intended for clients.

((ElementControl)MyPageObject.MyControl.Controls.First())
        .FindAllControlsFromInterface<IButton>(new Selector("mySelector"));

✔️ Do: Use a Control Collection

Control Collection is a class which allows you to create collections of controls without having to resort to concrete control implementations.

Last updated