📜 ⬆️ ⬇️

Effective UI tests on Selenide

Waiting for miracles


New Year's Eve is a time of miracles. On the eve of the new year, we all remember the outgoing year and make plans for the next. And we hope that all problems will remain in the past, and in the new year a miracle will happen, and we will begin to live a new life.

What kind of Java developer does not dream of a miracle that will overshadow him and allow Java to become the coolest in the world Java Programmer.

Good news: I want to tell just about such a miracle.
')
His name is automatic tests !


Fu, tests?


Yes. Not a wonder framework, not micro / pico / nano services, but discipline will make you a true master of your craft. A discipline that says that a programmer can consider a case finished not when the code is ready, but when automatic tests are written and run for it. And if with unit tests everything is more or less clear, then UI tests remain for developers a dark forest.

Oh, it's boring?


Oh no, trust me! Writing literate autotests is a good challenge, there is something to think about. And it can be very fun and interesting. Only need to use the right tools.

The right tool for writing UI tests is:

Selenide


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

Selenide is the perfect choice for developers because it has a very low learning curve. You do not have to bother with all these technical details, which are usually used by automated testers to spend so much time: the nuances of working with browsers, typical problems with timing and ajax.

Let's see what a simple test on Selenide looks like:

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")); } } 


(of course, instead of Google, your web application will be here)

What's going on here?



This test is easy to read, isn't it?
This test is easy to write, isn't it?

And most importantly, this test is easy to run. See for yourself:


Dive deeper


Of course, life is not so simple. Writing autotests implies a lot of problems, because it's not for nothing that developers are so afraid of them - more than any complex framework or technology.

But here, too, Selenide makes our lives easier by solving most of these problems out of the box.

Let's look at the typical problems of UI tests in more detail.

Problems with Ajax and Timeouts

Nowadays, web applications are all dynamic. Each piece of the application can be drawn / changed dynamically at any time. This creates problems for automated tests. A test that was green yesterday could suddenly turn red without any changes in the code. Just because the browser today got off the wrong foot and launched that javascript a little slower, and the test managed to click a button before it was drawn to the end.

This is just the eternal problem of all. Therefore, automators shove slips everywhere.

It is even more surprising how simple and reliable way Selenide solves this problem.

In short, in Selenide, each method can wait a bit if necessary . People call it “smart expectations.”

When you write
 $("#menu").shouldHave(text("Hello")); 

Selenide will check if an item exists with id = "menu". And if not, Selenide will wait a bit, check more. Then he will wait. And only when the element appears, Selenide will verify that it has the desired text.

Of course, you can not wait forever. Therefore, Selenide waits no more than 4 seconds. Naturally, this timeout can be configured.

Wouldn't this make my tests slow?

No, it will not. Selenide waits only if necessary. If the item is initially present on the page - Selenide is not waiting. If the item appeared after 300 ms - Selenide waits only 300 ms. This is exactly what you need.

Many built-in checks

And what else can you check on the page, besides the text? Pretty much everything.

For example, you can check that the element is visible . If not, Selenide will wait up to 4 seconds.
 $(".loading_progress").shouldBe(visible); 


You can even check that the item does not exist. If the item is still found, Selenide will assume that it is about to disappear and wait up to 4 seconds.
 $(By.name("gender")).should(disappear); 


You can do several checks on one line (the so-called “fluent API” and “method chain”), which will make your tests even more concise:
 $("#menu") .shouldHave(text("Hello"), text("John!")) .shouldBe(enabled, selected); 


Collections

Selenide allows you to work with collections of items very conveniently. You can check multiple items at once on one line.

For example, you can check that there are exactly N such elements on a page:
 $$(".error").shouldHave(size(3)); 


You can filter a subset of items:
 $$("#employees tbody tr") .filter(visible) .shouldHave(size(4)); 


You can check the texts of the elements. In most cases, this is enough to check the whole table or row in the table:
 $$("#employees tbody tr").shouldHave( texts( "John Belushi", "Bruce Willis", "John Malkovich" ) ); 


Download / upload files

With Selenide, uploading files is extremely simple:
 $("#cv").uploadFile(new File("cv.doc")); 


You can even download multiple files at once:
 $("#cv").uploadFile( new File("cv1.doc"), new File("cv2.doc"), new File("cv3.doc") ); 


And downloading files is also extremely simple:
 File pdf = $(".btn#cv").download(); 


Testing "dynamic" web applications

Some web frameworks (such as GWT) generate completely unreadable HTML that cannot be analyzed. There are no permanent IDs, names or classes.

This is just the eternal problem of all. Therefore, automators shove everywhere long "xpath" and are forced to support them until the end of life.

To solve this problem, Selenide offers to search for items by text.

 import static com.codeborne.selenide.Selectors.*; $(byText(", !")) //      .shouldBe(visible); $(withText("")) //     .shouldHave(text(", !")); 


Contrary to popular belief, searching for items by text is not such a bad idea. By the way, this is what the real user is looking for. He does not look for items by ID or class, and certainly not by XPATH. He searches by text. (well, in color, but it is more difficult to automate).

Also in Selenide there are several useful methods for finding child or parent elements. This allows you to navigate between unmarked elements.

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


For example, you can find a cell in a table by text, then find the string tr containing it and find the “Save” button on this line:
 $("table#employees") .find(byText("Joshua")) .closest("tr.employee") .find(byValue("Save")) .click(); 


Page object


When the same element or page is used in many tests, it makes sense to move the logic of the page to a separate class. This class is called Page Object, and they are also very convenient to do with Selenide.

The above example of Google can be remade on the page object in this way:

  @Test public void userCanSearch() { GooglePage page = open("http://google.com/ncr", GooglePage.class); SearchResultsPage results = page.searchFor("selenide"); results.getResults().shouldHave(size(10)); results.getResult(0).shouldHave(text("Selenide: concise UI tests in Java")); } 

Page Object for Google search page:

 public class GooglePage { public SearchResultsPage searchFor(String text) { $(By.name("q")).val(text).pressEnter(); return page(SearchResultsPage.class); } } 

And for the search results page:

 public class SearchResultsPage { public ElementsCollection getResults() { return $$("#ires .g"); } public SelenideElement getResult(int index) { return $("#ires .g", index); } } 


But do not abuse page objects.
I want to draw your attention to the fact that there should be few UI tests. For the simple reason that it’s still a browser,
Ajax, javascript, and all this is relatively slow and unstable. Write one or two UI tests that verify that
the application as a whole works: the page opens, the text is drawn, the buttons are pressed, JavaScript does not crash.

And every possible combinations and rare cases surely check up with the help of modular tests.

A typical mistake is to check everything through UI. Testers are particularly affected in those companies where developers do not write
unit tests. Poor testers simply have no choice but to fence a huge hulking bunch of slow
and unstable UI tests and harness their lifelong support.

But you are a programmer! Do not make people suffer.


... and many other useful things

Selenide has many more features, such as:

 $("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);  .. 


The good news is that you don’t need to memorize it all. Just type $, point and start writing about what you want. For example, "val" or "enter". And see what options your IDE offers.

Use the power of IDE! Do not litter your head with details and concentrate on business logic.

image

Make the world better


I believe that the world will be better when all the developers will write automatic tests for their code. When the developers will quietly get up at 17:00 and go to their children, without fear that they broke something with their changes.

Believe me, I feel confident because while I went for coffee, my tests have already checked my code. And I know for sure that what I pass in testing works.

Let's make the world a better place with the help of automated tests! Be confident in your software, and you do not have to cross your fingers for good luck before each release.

selenide-logo
Happy New Year!
ru.selenide.org

Source: https://habr.com/ru/post/274071/


All Articles