Effective UI tests with Selenide

Waiting for miracles

Christmas is a time for miracles. On the eve of the new year we all build plans for the next. And we hope that all problems will leave in the ending year, and a miracle happens in the coming year.

Every Java developer dreams about a miracle that lets him become The Most Effective Java Developer in the world.

I want to show you such a miracle.

It’s called automated tests!

Ugh, tests?

Yes. You will not become a real master thanks to micro/pico/nano services. You will become a real master thanks to discipline. Discipline claiming that developer only then reports jobs as donewhen code and tests are written and run.

But, isn’t testing boring?

Oh no, believe me! Writing of fast and stable automated tests is a great challenge for smartest heads. And it can be very fun and interesting. You only need to use right tools.

The right tool for writing UI tests is:

Selenide

Selenide is an open-source library for writing concise and stable UI tests.

Selenide is an ideal choice for software developers because it has a very low learning curve. Thus, you don’t need to bother with browser details, all these typical ajax and time issues that eat most of QA automation engineers’ time.

Let’s look at a simplest Selenide test:

public class GoogleTest {
  @Test
  public void user_can_search_everything_in_google() {
    open("http://google.com/ncr");
    $(By.name("q")).val("selenide").pressEnter();

    $$("#ires .g").shouldHave(size(10));

    $("#ires .g").shouldBe(visible).shouldHave(
        text("Selenide: concise UI tests in Java"),
        text("selenide.org"));
  }
}

Let’s look closer what happens here.

  • You open a browser with just one command open(url)
  • You find an element on a page with command $.
    You can find element by name, ID, CSS selector, attributes, xpath and even by text.
  • You manipulate the element: enter some text with val() and press enter with (surprise-surprise!) pressEnter().
  • You check the results: find all found results with $$ (it returns a collection of all matched elements). You check the size and content of the collection.

Isn’t this test easy to read? Isn’t this test easy to write?

I believe it is.

Deeper into details

Ajax/timing problems

Nowdays web applications are dynamic. Every single piece of application can be rendered/changed dynamically at any moment. This creates a lot of problems for automated tests. Test that is green today can suddenly become red at any moment, just because browser executed some javascript a little bit longer than usual.

It’s a real pain in the ajjaxx.

Quite unbelievably, but Selenide resolves most of the these problems in a very simple way.

Simply said, every Selenide method waits a little bit if needed. People call it “smart waiting”.

When you write

$("#menu").shouldHave(text("Hello"));

Selenide checks if the element exists and contains text “Hello”.

If not yet, Selenide assumes that probably the element will be updated dynamically soon, and waits a little bit until it happens. The default timeout is 4 seconds, which is typically enough for most web applications. And of course, it’s configurable.

Rich set of matchers

You can check pretty much everything with Selenide. Using “smart waiting” mechanism mentioned above.

For example, you can check if element exists. If not yet, Selenide will wait up to 4 seconds.

$(".loading_progress").shouldBe(visible);

You can even check that element does not exist. If it still exists, Selenide will wait up to 4 seconds until it disappears.

$(By.name("gender")).should(disappear);

And you can use fluent API and chain methods to make your tests really concise:

$("#menu")
  .shouldHave(text("Hello"), text("John!"))
  .shouldBe(enabled, selected);

Collections

Selenide allows you to work with collections, thus checking a lot of elements with one line of code.

For example, you can check that there are exactly N elements on a page:

$$(".error").shouldHave(size(3));

You can find subset of collections:

$$("#employees tbody tr")
  .filter(visible)
  .shouldHave(size(4));

You can check texts of elements. In most cases, it’s sufficient to check the whole table or table row:

$$("#employees tbody tr").shouldHave(
  texts(
      "John Belushi",
      "Bruce Willis",
      "John Malkovich"
  )
);

Upload/download files

It’s pretty easy to upload a file with Selenide:

$("#cv").uploadFile(new File("cv.doc"));

You can even upload multiple files at once:

$("#cv").uploadFile(
  new File("cv1.doc"),
  new File("cv2.doc"),
  new File("cv3.doc")
);

And it’s unbelievably simple to download a file:

File pdf = $(".btn#cv").download();

Testing “highly dynamic” web applications

Some web frameworks (e.g. GWT) generate HTML that is absolutely unreadable. Elements do not have constant IDs or names.

It’s a real pain in the xpathh.

Selenide suggests to resolve this problem by searching elements by text.

import static com.codeborne.selenide.Selectors.*;

$(byText("Hello, Devoxx!"))     // find by the whole text
   .shouldBe(visible);

$(withText("oxx"))              // find by substring
   .shouldHave(text("Hello, Devoxx!"));

Searching by text is not bad idea at all. In fact, I like it because it emulates behaviour of real user. Real user doesn’t find buttons by ID or XPATH – he finds by text (or, well, color).

Another useful set of Selenide methods allows you to navigate between parents and children.

$("td").parent()
$("td").closest("tr")
$(".btn").closest(".modal")
$("div").find(By.name("q"))

For example, you can find a table cell by text, then by its closest tr descendant and find a “Save” button inside this table row:

$("table#employees")
  .find(byText("Joshua"))
  .closest("tr.employee")
  .find(byValue("Save"))
  .click();

… And many other functions

Selenide has many more functions, like:

$("div").scrollTo();
$("div").innerText();
$("div").innerHtml();
$("div").exists();
$("select").isImage();
$("select").getSelectedText();
$("select").getSelectedValue();
$("div").doubleClick();
$("div").contextClick();
$("div").hover();
$("div").dragAndDrop()
zoom(2.5);
...

but the good news is that you don’t need to remember all this stuff. Just put $, put dot and choose from available options suggested by your IDE.

Use the power of IDE! Concentrate on business logic.

Power of IDE

Make the world better

I believe the World will get better when all developers start writing automated tests for their code. When developers will get up at 17:00 and go to their children without fearing that they broke something with last changes.

Let’s make the world better by writing automated tests!

Deliver working software.

Andrei Solntsev

selenide.org