Brandon Stirnaman

FluentAutomation Creator
Simple, fluent automated testing for web applications.

F14N Founder
Fast, easy automation test creation, execution and management.

The Journey to v3.0

Late February '14 -- while I was thinking over the featureset for v2.4 -- Scott Hanselman blogged about web automation. He has visited this topic several times in the past, always an advocate for end-to-end testing via browser automation. Scott talks through testing in the cloud and shows his preferred method (hopefully we've changed his mind by now!) of writing tests: Python + Selenium.

In the comments one of our great users mentioned FluentAutomation (and I jumped in too), which led to a quick back and forth on Twitter with Scott. Much to my surprise he checked out everything we had -- including a yet-to-be finished REPL.

This conversation, the following blog post and the community reaction/conversations prompted by it provided some much needed motivation to just get things done for FluentAutomation -- now we have a beta of 3.0 to show for it.

Newly focused I started on the backlog and user issues with Multi-browser testing and Sticky Sessions. After a few hours of refactoring to fix these features I realized I'd need a breaking change to get the behavior we wanted for Multi-browser execution. If we were going to break the API anyway then this is the time to clean up the little warts needed to keep expanding Fluent. I weighed the difficulty of user refactoring each time the API changed.

A few weeks of this refactoring gave us the featureset I wanted. Another few weeks addressed issues many of our users wanted (feedback from UserVoice and GitHub Issues). In addition to the API refactoring, I wanted to get a proper test suite established again. With the assistance of my co-founder from F14N, Paul Zumbrun, we built a solid test suite that covers a majority of the points users interact with the Fluent API. This suite will continue to grow and new contributions will need to be properly tested to be accepted.

Our next task is to get some new docs up and fix any issues you help us find in this beta. Now the part you care about...

To install the 3.0 beta, you need to tell NuGet to include pre-release packages in search results, or use the NuGet Package Manager Console:

Install-Package FluentAutomation.SeleniumWebDriver -Pre  

3.0 Changelog

Breaking Changes

  • Func<IElement> is no longer used in the API. All cases have been replaced with the new class ElementProxy which allows us to use I.Find with multi-browser execution.
  • Settings static no longer exists. It has been superceded by the Config functionality (more below). This was needed to allow for scoped configuration.
  • INativeActionSyntaxProvider is now IActionSyntaxProvider. The native reference is due to an old, now removed bit of Remote execution functionality packaged in early 2.0 releases. Several other classes/interfaces were renamed as well:
    • IExpectProvider -> IAssertProvider
    • ExpectProvider -> AssertProvider
    • ExpectSyntaxProvider -> AssertSyntaxProvider
  • Not technically a 'breaking change' and I warned about this in the 2.3 notes/blog post -- Expect by default will not throw exceptions. It can be configured to do so via Config.ExpectIsAssert(true) but the default is to just execute the appropriate callback for OnExpectFailed so that things can be logged but not stop the test execution.


Multiple Browser Execution

This feature actually made its debut in 2.2 but it had severe issues using I.Find which meant many action methods simply didn't work. I've gotten that fixed up and it feels very stable now. Use it and let us know what you think!

Its very simple to enable this mode, just provide multiple browsers to the Bootstrap constructor (only valid when using the SeleniumWebDriver package):

Sticky Sessions

Another feature from the 2.x series that worked well enough.. but has been given some important updates. You can freely call FluentSession.EnableStickySession() now to share browser instances across multiple tests. It will not interrupt a session in progress (so it can be called multiple times in a session with no ill effects) and also is smart enough to close browsers at the end of the test session.

This basically makes it a fire and forget option with none of the difficulty of taking over browser lifecycle management.


Fluent Configuration Syntax

Multiple changes were made to the settings/configuration functionality in this release. We gained two things from this: an easier, nicer mechanism for setting multiple settings in a test and scoped configuration blocks.

The new general configuration syntax is a fluent, chainable set of method calls:


There is also a new mechanism for configuring Fluent settings via saved objects:

public class SampleTest : FluentTest  
    FluentSettings fastFailure = new FluentSettings { WaitUntilTimeout = TimeSpan.FromMilliseconds(500) };
    FluentSettings slowFailure = new FluentSettings { WaitUntilTimeout = TimeSpan.FromSeconds(2) };

    public SampleTest()

    public void Test1()
        // do things

    public void Test2()
        // do things

We have seen many users have a few known configurations they use. This change makes it very easy to switch to the appropriate settings given your needs.

Scoped Configuration

Users had requested a way to have different WaitUntilTimeout values for specific actions (or sets of actions). While working on this feature I decided to take it a step further and provide scoped settings for every value we could (excluding things that don't make much sense to change in this situation).

Lets see what that looks like:

Config.WaitUntilTimeout(5); // configure a global WaitUntil timeout

    .WindowSize(800, 600)
            .Not.Visible("#hidden-thing") // waits for up to 1s
            .Not.Exists("#halp"); // waits for up to 1s

I.Assert.Not.Exists("#other-halp"); // waits for up to 5s  

In this example, we have configured the global timeout to 5s. In our scoped block, starting at With, we begin by configuring the timeout to 1s and changing the size of the browser window (think of how useful this would be for testing responsive designs). As you can see via the comments, the nested Assert waits for 1s as does the one following it. As soon as you break out of the With block though, the configuration is back to default. The function names are a bit different than in global config to make the code a bit less verbose when used often. I think this is an incredibly powerful feature and we're looking for some feedback on it.

Additionally some settings had their names changed in the transition to the new syntax:

  • ExpectFailedCallback -> OnExpectFailed
  • WaitOnAllCommands -> WaitOnAllActions
  • DefaultWaitUntilTimeout -> WaitUntilTimeout
  • DefaultWaitTimeout -> WaitTimeout

.. and WaitUntilTimeout now defaults to 5s instead of 30s.

Window/Frame Handling

There was a standing issue for nearly 2 years -- dealing with apps that launch new windows or use framesets. Somehow this kept getting pushed, then we encounted issues with Selenium and tabs... and it just fell off the map.

Not anymore. Its done:

// frames
I.Switch.Frame(); // back to default frame

// windows
I.Switch.Window("Window Title or URL Fragment");  
I.Switch.Window(); // back to originating window  

Both cases involve matching off names. When switching to a window, you can provide the title of the window or a relative URL (processed via EndsWith, i.e. http://fluent.stirno.com/docs could be matched with /docs).

Relative URL Navigation

With a bit of work, I.Open is now smarter. If passed a relative URL it will navigate using the current base URL + the provided fragment. This allows your tests or PageObject to container simpler URLs that work against multiple sites without you having to manage URL generation.

New Asserts

You can now assert on CSS properties (color, background-color, etc.), Attributes, Visibility and Existence.

I.Assert.Css("color", "rgb(0, 0, 0, 0)").On("#element");  

Now you may think, "Hey, I'm pretty sure I.Assert.Exists() was in 2.3?", and you'd be right. The new bit is....

Negative Asserts

Every assert now has a negative counterpart, accessible via the .Not property. Another user request led to this, as they wanted to assert a property did NOT exist.


Given that we were in a big refactor mode already, I just applied this mechanism globally:

(and so on, on all asserts)
Alert/Confirm/Prompt handling

In v1 we had decent but not terribly reliable handling of javascript alerts. When building v2 it missed the release and just never made it in. It took a few months but eventually a few users noticed and requested it make a return. Its back, in a cleaner better integrated way.

To interact with an alert, we've provided some psuedo elements that the API knows how to interpret:

I.Click(Alert.OK); // click the OK button in a Confirm Dialog or Alert  
I.Click(Alert.Cancel); // cancel out of a Confirm or Prompt

// enter text into a Prompt
I.Enter.Text("Seriously, stop using javascript prompts").In(Alert.Text);

// validate the Alert's message
I.Assert.Text("Crazy, old school alert").In(Alert.Message);  

It should be noted that entering text into a prompt with I.Enter.Text will also close the dialog by clicking OK.

This covers all the cases where we interacted with JavaScript dialogs in older applications and works more consistently than the old methods but it still isn't perfect. Encourage your developers to stop using these archaic methods of user interaction! :)

The rest ...

Exception messages have changed a bit to be shorter and easier to determine the cause of failures. Stack Traces no longer show FluentAutomation internal classes and should 'end' in your tests, not our code.

For those who do want to step into our code, we've started publishing symbols to SymbolSource again so you have some options there. I'll continue to keep them up to date for the life of the 3.0 series.

To finish up, I'd just like to thank the community for helping this project grow. We've got something good here, lets keep improving. Features are driven by you, use UserVoice! Not every feature will get implemented but don't assume we think of everything!

Try the beta out, hit me up on Twitter @stirno or in the FluentAutomation room on JabbR with feedback/questions/whatever.

... the end.