Canopy : Automate your browser tests the F# way!



I’d like to introduce you Canopy, a Selenium overlay written in F#. It brings you the concision and the clarity of F# to your selenium tests.

First of all, we have to create a new F# console application, then we install canopy in our project: canopytryout-install-package

As you can see, the canopy nuget will bring back the selenium ecosystem.

Lets create our first test. It will check that a search of “canopy F#” in google will feature the official Canopy website as the first result. Here is the little bootstrapping needed by Canopy :

open canopy
open runner
start firefox
"first result for canopy f# in google is the project homepage" &&& fun _ ->
// here com the actual test code
printfn "press [enter] to exit"
System.Console.ReadLine |> ignore

Fisrt, we load the dependencies : the canopy core libray (of course) and the canopy runner, that is basically a wrapper over the selenium driver,
Then we start a browser (firefox, for instance).

After that come the body of the test itself (we see it later), and the instruction to run the test suite. The quit() instruction will handle everything to finalize the test run, like closing the browser.

Let’s take a look at the test itself. Here is an implementation proposal :

"first result for canopy f# in google is the project homepage" &&& fun _ ->
url ""
"#lst-ib" << "canopy f#"
click "button[name=btnG]"
click (first "div.srg a")
on ""

It’s a very basic test. The first line is the test case definition.
The test body starts with a navigation to the Google’s homepage.
Then, we fill the search field with the “Canopy F#” value. Here is a little subtility here, with the way the Google homepage works: as soon we start to type, the page layout changes, the search box shows a kind of dropdown list with search suggestion. Once the search word is fully typed into the search box, we click on the search button.
Then we click on the first result in the results list.
Finally, we can make our assertion. In this case, the ‘on “url”‘ will assert that we are on the expected page.


Are we done? No!
The test code as to be as clean as the production code, so lets do some refactoring.
We can start by applying the page object pattern: it’s a way to abtract a page, and to encapsulate its behaviour, so the test become way more readable.

Lets add a google.fs file to our solution (do not forget to move it above program.fs)

with the following content :

namespace PageObjects
module Google =
open canopy
let goToFirstResultFor (search:string) =
url ""
"#lst-ib" << search
click "button[name=btnG]"
click (first "div.srg a")

Here, i just extract the interactions with the Google homepage.
It greatly simplifies my test case, which becomes :

open PageObjects.Google
"first result for canopy f# in google is the project homepage" &&& fun _ ->
PageObjects.Google.goToFirstResultFor "canopy f#"
on ""

That’s all for this first Canopy Automation & Testing framework and the Page Object pattern in F#. More to come about this soon!

P.S. : You can find the source code for this example on my github repo.


6 thoughts on “Canopy : Automate your browser tests the F# way!

  1. Norm says:

    Could be quite usefull. Given a quick test (as a F# newbee). The test CanopyTryout basically work for Chrome.
    For me, the click test on button works on chrome, but not on Ie 64-bit. I added tests for hyperlink and ajax_button, but they both failed in both Chrome and Ie (wonder why?)
    I pass you the info. Cmd refers to
    canopy.fs line 437
    program.fs line 38
    runner.fs line 102
    Line 38 of program.fs being
    “#link_clicked” == “button not clicked”
    click “#hyperlink”
    “#link_clicked” == “button clicked”
    Thank you for sharing on GitHub.


    • Hello Ashish,

      Within the WebDriver logic, you don’t actually have to scroll down. You rather want to find the last search result by locating it with a CSS selector like “div.srg > h3.r:last-child > a” then apply the click on the element. (disclaimer, I didn’t test the selector).

      keep in mind that you can use webdriver with some headlessbrowser like PhantomJS, so you don’t have to interact with the browser itself but with the dom of the page, to access page elements.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s