Jeremy Bellows - Writing Quality Css Selectors for Canopy UI Automation

Writing Quality Css Selectors for Canopy UI Automation

-


Canopy tests are simple and easy to write but how scalable are they? Canopy tests are very scalable if constructed to mitigate casual failures.

Casual Failures

Casual failures are usually caused by content or layout changes of the interface. These are simply fixed by changing test css selectors.

Casual Failure Example

For example, a canopy test asserting that the title of this article contains the word canopy, then the test would look like the following.

let articleTitleSelector = ".post-title"

"The title of the canopy quality css selector article should contain the word 'canopy'" &&& fun _ ->
  url "http://www.jeremybellows.com/Writing-Quality-Css-Selectors-for-Canopy-UI-Automation"

  let articleTitle = read <| element articleTitleSelector
  articleTitle |> contains "canopy"

Confused by the syntax? Try this article first! Using F# and Canopy for UI Testing

What’s wrong with this code?

let articleTitleSelector = ".post-title"

The above line uses a css class as the element selector.

A css class’ primary purpose is to apply visual styling. Coupling test context to styling causes tests to fail if the referred styling changes. This can be useful if the intention of the test is to assert styling.

I recommend using software that is capable of comparing expected visual styling without relying on html selectors. Doing so allows for swift, confident test results from each respective test suite.

Since the example test is only concerned with the domain object article title containing a specific word, then adding styling as a dependency will cause a casual failure.

How do we fix it?

Removing the dependency on styling is the only solution to this problem. The means to do so is to use Html5 attributes.

Changing the html to generate domain specific metadata by using Html5 attributes allows for context specific element selectors to be written.

The previous html for the article title was

<h1 class="post-title entry-title">
  Writing Quality Css Selectors for Canopy UI Automation
</h1>

Adding domain specific metadata looks like

<h1 class="post-title entry-title" data-article-title>
  Writing Quality Css Selectors for Canopy UI Automation
</h1>

Now the css selector can be updated to use the Html5 attribute as the element selector: [data-article-title]

let articleTitleSelector = "[data-article-title]"

"The title of the canopy quality css selector article should contain the word 'canopy'" &&& fun _ ->
  url "http://www.jeremybellows.com/Writing-Quality-Css-Selectors-for-Canopy-UI-Automation"

  let articleTitle = read <| element articleTitleSelector
  articleTitle |> contains "canopy"

Summary

Using Html5 attributes to insert domain specific metadata allows for the decoupling of test html element selectors from css styling. This creates quality tests that are less likely to casually fail.

It is also possible to insert dynamic metadata using html5 attributes.
For example, use a jquery selector :contains in place of the canopy contains code.

Html

<h1 class="post-title entry-title" data-article-title="Writing Quality Css Selectors for Canopy UI Automation">
  Writing Quality Css Selectors for Canopy UI Automation
</h1>

Test

let articleTitleSelector = "[data-article-title]"
let articleTitleSelectorContains word = sprintf "%s:contains('%s')" articleTitleSelector word

"The title of the canopy quality css selector article should contain the word 'canopy'" &&& fun _ ->
  url "http://www.jeremybellows.com/Writing-Quality-Css-Selectors-for-Canopy-UI-Automation"

  "canopy"
  |> articleTitleSelectorContains
  |> exists

Regex Solution

It’s also possible to use the regex comparison operator =~

let articleTitleSelector = "[data-article-title]"

"The title of the canopy quality css selector article should contain the word 'canopy'" &&& fun _ ->
  url "http://www.jeremybellows.com/Writing-Quality-Css-Selectors-for-Canopy-UI-Automation"

  articleTItleSelector =~ "canopy"

Questions?

Reach out to @JeremyBellows, Chris Holt @lefthandedgoat (the creator of Canopy), or the #fsharp community