Skip to content
roryprimrose edited this page Oct 18, 2013 · 5 revisions

The most common usage of Headless is to work with HTML documents. There are three models of HTML inspection in Headless. You can inspect the HTML page and find an element using a manual, page or dynamic model.

Manual Model

The manual model refers to coding directly against IHtmlElementFinder to get a reference to a HTML element. It is very verbose and not reusable as it is the underlying engine that the page and dynamic models use.

using Headless;

using (var browser = new Browser())
{
    var page = browser.GoTo(new Uri("https://mysite.com"));
    var query = page.Find<HtmlInput>().ByName("Query");

    query.Value = "Headless browser testing";

    var search = page.Find<HtmlButton>().ByName("Search");

    var resultsPage = search.Click();

    // Assert page results
}

Page Model

The page model refers to creating custom classes that inherit from HtmlPage. These classes can then expose properties that represent HTML elements expected on that page. The page model classes can also provide functional behavior such has executing a log on process for a given account.

While page model may appear to be more code, it provides the benefits of encapsulation, intellisense and ease of refactoring.

using Headless;

public class HomeIndexPage : HtmlPage
{
    public HtmlLink SignIn
    {
        get
        {
            return Find<HtmlLink>().ByText("Sign in");
        }
    }

    public override Uri TargetLocation
    {
        get
        {
            return HomeLocation.Index;
        }
    }
}

public class SignInPage : HtmlPage
{
    public HtmlInput UserName
    {
        get
        {
            return Find<HtmlInput>().ByName("UserName");
        }
    }

    public HtmlInput Password
    {
        get
        {
            return Find<HtmlInput>().ByName("Password");
        }
    }

    public HtmlButton Submit
    {
        get
        {
            return Find<HtmlButton>().ByText("Sign in");
        }
    }

    public override Uri TargetLocation
    {
        get
        {
            return HomeLocation.SignIn;
        }
    }
}

public class AccountIndexPage : HtmlPage
{
    public override Uri TargetLocation
    {
        get
        {
            return AccountLocation.Index;
        }
    }
}

[TestMethod]
public void SignInRedirectsToAccountIndexPageTest()
{
    using (var browser = new Browser())
    {
        var homePage = browser.GoTo<HomeIndexPage>();

        var signInPage = homePage.SignIn.Click<SignInPage>();

        signInPage.UserName.Value = "account name";
        signInPage.Password.Value = "account password";

        // The response from a click using the page model will validate location and 200 status code by default
        signInPage.Submit.Click<AccountIndexPage>();
    }
}

Dynamic Model

The dynamic model uses the dynamic keyword to provide dynamic searching for HTML elements. This model is the most succinct, but sacrifices intellisense, encapsulation and refactoring support. The searching logic uses the following order of precedence when attempting to match an element from a property name:

  1. Match by id attribute
  2. Match by name attribute
  3. Match by case sensitive exact text
  4. Match by case insensitive exact text
using Headless;

[TestMethod]
public void SignInRedirectsToAccountIndexPageTest()
{
    using (var browser = new Browser())
    {
        var homePage = browser.GoTo(HomeLocation.Index);

        var signInPage = homePage.SignIn.Click();

        signInPage.UserName.Value = "account name";
        signInPage.Password.Value = "account password";

        // The response from a click using the dynamic model will only validate a 200 status code by default,
        // it does not validate the ultimate location because there is no known target
        var accountPage = signInPage.Submit.Click();

        // Validate final url of the page against an expected value
        accountPage.IsOn(AccountLocation.Index).Should().BeTrue();
    }
}

Clone this wiki locally