Automation In Scala: Basic Selenium Tests
Tags: scala, automation, selenium
Published: 2021-05-13 06:30:50

## Scala in test automation

[Scala](https://www.scala-lang.org/) programming language provides a good mix between functional and object-oriented programming. It is used in projects, where pure functions and functional paradigms are crucial. 

But how Selenium tests look like in Scala?

## ScalaTest

The most widespread testing framework in Scala is [ScalaTest](https://www.scalatest.org/). It provides a lot of functionality for writing unit and integration tests.

## Implementation

As for the experiment, we will write a couple of UI tests for the current blog.  
In order to implement the first basic tests you can follow the steps: 

* Add necessary libraries to [build.sbt](https://www.scala-sbt.org/)

```
    libraryDependencies += "org.scalatestplus" %% "selenium-3-141" % "3.2.7.0" % "test"
    libraryDependencies += "org.scalatest" %% "scalatest-flatspec" % "3.2.7" % "test"
    libraryDependencies += "org.scalatest" %% "scalatest-shouldmatchers" % "3.2.7" % "test"
    libraryDependencies += "com.google.guava" % "guava" % "30.1.1-jre"

```

* Add pages objects. In our case, it will be all main pages for the blog: Home Page, Contact Page, About Page.

``` scala
    class HomePage(implicit val driver: ChromeDriver) extends Page {
        val url = "https://alexromanov.github.io/"

        val homePageLink: String = "//a[@href=\"/\"]"
        val aboutPageLink: String = "//a[@href=\"/about/\"]"
        val contactPageLink: String = "//a[@href=\"/contact/\"]"
    }
```

If you want to have an access to "go to page" functionality in tests, you can extend your page class from Page trait and add URL variable. 

* Add class with tests

``` scala
    class BlogTest extends AnyFlatSpec with BeforeAndAfterAll with Matchers with Eventually with WebBrowser {

        implicit val webDriver: ChromeDriver = {
            System.setProperty("webdriver.chrome.driver", "C:\\tools\\chromedriver_win32\\chromedriver.exe")
            new ChromeDriver()
        }

        "User" should "be able to view latest blog post" in {
            val homePage = new HomePage
            go to homePage

            val posts = findAll(CssSelectorQuery("div.post-preview")).toList
            posts should have size 5

            val latestPost = posts.head
            latestPost.text should not be empty
        }

        "User" should "be able to open Contact Page" in {
            val homePage = new HomePage
            go to homePage
            homePage.url should equal (currentUrl)

            click on xpath(homePage.contactPageLink)
            eventually {
                currentUrl != homePage.url
            }

            val contactPage = new ContactPage
            contactPage.url should equal (currentUrl)
        }

        "User" should "be able to send message to author" in {
            val contactPage = new ContactPage
            go to contactPage
            contactPage.url should be (currentUrl)
            
            textField(contactPage.nameField).value = "Reader"

            click on id(contactPage.emailField)
            enter("reader@mail.com")

            click on id(contactPage.phoneField)
            enter( "123456789")

            textArea(contactPage.messageField).value = "Hello Author"

            click on cssSelector(contactPage.sendButton)
        }

        override def afterAll(): Unit = {
            quit()
        }
    }
```

For tests we use AnyFlatSpec and [Should Matchers](https://www.scalatest.org/user_guide/using_matchers). It allows us to write assertions in a readable format with the Should keyword.  

[ScalaTest-Selenium](https://www.scalatest.org/plus/selenium) provides a very nice wrapper against WebDriver. You just need to add WebBrowser trait. As a result, you will have methods such as "click on id()", "enter()", "close()", etc.  

It also defines Webdriver instance as implicit value - so you don't need to pass driver whenever it is used (in tests or pages).  

For adding an additional before and after logic we need to add the BeforeAndAfterAll trait and override desired methods. In our case, the afterAll() method is overridden - it will quit the driver after tests are finished.

## Conclusion

As you can see, UI tests in Scala are very close to human-readable format with using Should matches and scalatest-selenium traits. 

ScalaTest-Selenium provides a nice wrapper of WebDriver, but it is not extensible at first sight. Maybe, it will require a complete framework re-write.  

But for simple UI tests, it is more than enough.  

In the next articles, we will see even more interesting use cases of using Scala in test automation (also with Selenium)  

Full code samples can be found at src/test/scala/ui package in [code samples](https://github.com/alexromanov/scala-automation-samples).