Selenium Test Automation Using A Free Monad

I have been working on a project that ended up with a lot of UI and as time passed I realized there is no way I can ensure the quality of the code without test automation. One may say, no one should be writing code for serious production use without having test automation. I agree. It’s just that there is one person doing all the things, there is only so much that can be accomplished. Eventually, the code base stabilized enough that I was confident to go down the automation route. Selenium IDE turned out to be the simplest way of doing UI automation. It was so easy I ended up automating a lot of the flows. All it required was just executing the flow and recording it and practically no code involved.

Except for a few issues, everything was smooth with Selenium IDE. The main issues were a) reusing of the test fragments as if they were function calls so the same test fragment could be executed with different parameters (as far as I can tell there is no way to do this), b) any sort of mass editing is not possible unless it’s manually done directly in the underlying JSON. These are acceptable limitations but I felt that I could have done so much more automation easily if I had these options at my disposal.

After a few weeks, I had to do some major change to the UI in certain flows. That’s when the pain of modifying the tests became evident. With Selenium IDE, on one hand you can easily open up a “.side” file and pick a specific test suite and execute all the tests within it and watch the UI to ensure nothing is broken after a major set of code changes. On the other, if something broke, doing surgery to the already recorded test script felt a bit painful. Again, nothing that a normal user can’t tolerate or anything like that. But for me it all came to speed of changing tests, increasing test coverage and ensuring the stability of tests. This last part of ensuring stability in fact requires post processing a recorded test by carefully sprinkling wait commands.

So while I enjoyed the Selenium IDE and the script files authored with it for the simplicity of easily being able to replay and watch for any bugs, I wanted more control on the authoring process. All searches pointed to writing direct WebDriver code using the underlying API in Java. I didn’t want to pursue that route.

In this backdrop, I was also trying to enhance my understanding of functional programming and one of the things I was learning about was Free Monads. I found the article “What does free buy us?” very helpful in understanding the Free Monad concept. I realized that may be I could solve my Selenium IDE script authoring issue using the Free Monad. How nice it would be to take all the Selenium IDE commands and represent them as a Functor of sum of all the commands and lift them into Free Monad, write tests using the handy “do” notation of Haskell, compose them, reuse with different parameters and at the end, have an interpreter that simply spits out the “side” format which is a simple json format?

This idea of using Free Monad to author tests that can be simply built by composition in Haskell was too tempting that I practically set aside my main project for a few days and worked on this. The end result, I have a nice library and all my tests moved from “side” format to “hs” code (Haskell). Test authoring is a breeze, test coverage increased significantly as I could author tests as monadic functions and pass different parameters and then just “map” over a list of parameters to do all kinds of test coverage.

Below is a small snippet of test code in Haskell using the ESDL I created.

testEmailFbrFree = test "fbr-email-create-free" "Create Free Feedback Request - Email Test" $
   do
     runTest "Login"
     click $ routeHas "Request Feedback"
     click $ routeHas "Create"
     forM_ fbps $ uncurry enterFeedbackProvider
     submitFbr
   where fbps = map (id &&& (++"@example.com")) ["A","B","C","D","E"]

As can be seen, I could use monad constructs like forM_, arrow operators like &&& and all the fun of composing code in Haskell and the amazing fact that all of this eventually as a Free Monad results in a “container” that is peeled one piece at a time and interpreted to create the final JSON Selenium IDE file is a wonderful learning exercise for me.

This entry was posted in Haskell. Bookmark the permalink.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.