Unicorn.TAF logo Unicorn.TAF

Unicorn has Core UI library in its ecosystem which provides generic mechanism and utilities for platform depenent UI testing modules and contains common utilities and UI assertions.

Common interfaces

Search mechanism

Elements search is built over BaseSearchContext class which provides methods to search elements by different criteria. BaseSearchContext is used as a base class for all search contexts.

There are two ways to search elements: using search context direct methods calls or using page object approach.

Search context methods

Control locator is presented by Unicorn.UI.Core.Driver.ByLocator which consists of search method and search query. Supported locators are:

Examples:

var searchContext; // let it be some search context

Button button = searchContext.Find<Button>(ByLocator.Id("buttonId"));
TextBox input = searchContext.Find<TextBox>(ByLocator.Name("inputName"));
List<Checkbox> list = searchContext.FindList<CheckBox>(ByLocator.Class("checkBoxClass"));

bool windowFound = searchContext.TryGetChild(ByLocator.Id("childId"), out Window childControl);

PageObject approach

PageObject approach is a way to organize your tests in a more structured and readable way. It involves creating a class that represents a page/screen/window etc. and then using that class to interact with the page elements. This approach can help you to avoid duplicating code and make your tests easier to maintain. In Unicorn each control could be a PageObject for it’s child controls what increases UI code re-use rate.

public class PageObjectExample
{
    // Page object controls could be class properties (should have a setter).
    [Name("Page title")]
    [Find(Using.WebCss, "section[style *= block] h1.heading-separator")]
    public WebControl MainTitle { get; set; }

    // Or class fields
    // Each page object control could have readable name specified through NameAttribute.
    // This generate human friendly ToString for the control and makes reports and logs more readable.
    [Name("Page footer")]
    [Find(Using.Id, "footer")]
    private readonly WebControl _footer;
    
    // Besides generic FindAttribute there are simlified shortcuts for locators
    [Name("Page header")]
    [ById("hero")]
    public WebControl Header { get; set; }

    // If a control has the same locator across all the places, then the locator and the name could be specified for the control type using the same FindAttribute and NameAttribute.
    // In such case the control also will be initialized with page object.
    public ModalWindow Modal { get; set; }
}

// Typified or complex UI control should inherit WebControl
[Name("Modal window")]
[Find(Using.Id, "modalWindow")]
public class ModalWindow : WebControl
{
    [Name("Close button"), Find(Using.WebCss, "a[onclick]")]
    private WebControl closeButton;

    [Name("Text content"), ById("caption")]
    public WebControl TextContent { get; set; }
}

Available locator attributes shortcuts:

Explicit waits

There are built-in explicit waiters for a control to be in desired state (visible, enabled etc.). These waiters are available as extension methods for IControl interface (Unicorn.UI.Core.Synchronization.ControlWaits). Waiters based on specific conditions are available in Unicorn.UI.Core.Synchronization.Conditions.Until class. Next conditions are available from the box as extensions:

You can also create your own conditions. Here is an example of custom condition extension:

public static class CustomConditions
{
    // condition to wait until control has some expected text
    public static TTarget HasText<TTarget>(this TTarget element, string expectedText) 
        where TTarget : class, IControl
    {
        if (!element.Text.Equals(expectedText))
        {
            return null;
        }

        return element;
    }
}

Here are examples of usage of explicit waits:

using Unicorn.UI.Core.Synchronization;
using Unicorn.UI.Core.Synchronization.Conditions;

Window window; // assume the control is already initialized

// wait for 10 seconds until window is visible
window.Wait(Until.Visible, TimeSpan.FromSeconds(10));

// wait for 1 minute until window is disabled with custom error message
window.Wait(Until.Disabled, TimeSpan.FromMinutes(1), 
    "Window is not disabled after 1 minute");

// chain waits
window.Wait(Until.AttributeContains, "value", "someValue")
    .Wait(CustomConditions.HasText, "expectedText", TimeSpan.FromSeconds(10));