Quantcast
Channel: Selenide
Viewing all 45 articles
Browse latest View live

What is Selenide

$
0
0

Many of you have tried Selenium WebDriver - one of the most popular tools for UI Testing.

Writing UI Tests is not simple. There are a number of typical problems, including Ajax, dynamic pages and timeouts. The goal of Selenide is to resolve these problems.

right

What is Selenide

Selenide is a wrapper for Selenium WebDriver that allows you easier and faster writing of UI Tests. With Selenide you can concentrate on business logic instead of solving all these endless browser/ajax/timeouts problems.

This is an example of UI Test. As you see, the amount of code is minimal. Just type open - and browser comes.

@Test
public void testLogin() {
  open("/login");
  $(By.name("user.name")).sendKeys("johny");
  $("#submitButton").click();
  $("#username").shouldHave(text("Hello, Johny!"));
  $(".error").shouldNotBe(visible);
}

When you first execute open, Selenide automatically runs web browser and opens page http://localhost:8080/login (host and port are configurable). And closes the browser automatically when all tests are finished.

Selenide key features

Shortly, these are the key features of Selenide

  • Concise API inspired by jQuery
  • Automatic handling of most problems with Ajax, waiting and timeouts
  • Automatic handling of browser lifecycle
  • Automatic screenshots on test failures

In short, the purpose of Selenide - is to focus on business logic and not to engage in perpetual annoying minor problems.

Additional methods

Selenide provides additional methods for actions that cannot be done with a single command in Selenium WebDriver. These are radiobutton selection, selectbox selection, taking screenshots, clearing browser cache etc.

@Test
public void canFillComplexForm() {
  open("/client/registration");
  $(By.name("user.name")).setValue("johny");
  selectRadio("user.gender", "male");
  $(By.name("user.securityQuestion")).selectOption("What is my first car?");
  $(By.name("user.preferredLayout")).selectOptionByValue("plain");
  $("#submit").followLink();
  takeScreenShot("complex-form.png");
}

@Before
public void clearCache() {
  clearBrowserCache();
}

How Selenide overcomes Ajax?

Ajax is PITA (pain in the ass) for UI Testers.

Nowdays most of applications use Ajax. When testing web application that uses Ajax, you need to invent code that waits for something. Wait until button gets green, wait until div gets required text, or wait until error message disappears. You can find tons of web pages suggesting tricks how to make Selenium wait something.

Selenide resolves this problem like no other. Unbelievably simple! While Selenium provides you a rich API for waiting different events see this for example, Selenide suggests you just to not bother. If you want to check that button is green, but button is not yet green, Selenide just waits until the button gets green. (Of course, timeout is configurable. Default is 4 seconds). It's an unique solution - as easy and stable as possible.

Enjoy code samples:

@Test
public void pageUsingAjax() {
  $("#username").shouldBe(visible);   // waits until elemens appears
  $("#username").shouldHave(text("Hello, Johny!")); // waits until elements gets text "Hello, Johny!"
  $("#login-button").shouldHave(cssClass("green-button")); // waits until button gets green
  $("#login-button").shouldBe(disabled); // waits until button gets disabled
  $(".error").shouldNotBe(visible);  // waits until element disappears
  $(".error").should(disappear);     // try to the same with a standard Selenium WebDriver!
}

How to make screenshots automatically?

That's easy! If you are using JUnit, just add this line to your base test class:

   @Rule
   public ScreenShooter makeScreenshotOnFailure = ScreenShooter.failedTests();

This line will cause Selenide to automatically take screenshot after every failed test. For your convenience, Selenide creates even 2 files: .PNG и .HTML.

If you want to shot all tests (not only failed), you can use this line:

   @Rule
   public ScreenShooter makeScreenshotOnEveryTest =
              ScreenShooter.failedTests().succeededTests();

TestNG users can add this annotation to their base test class:

@Listeners({ ScreenShooter.class})

I want to try, how to start?

Just add Selenide dependency to your project:

<dependency>
    <groupId>com.codeborne</groupId>
    <artifactId>selenide</artifactId>
    <version>2.19</version>
</dependency>

Import required classes:

import static com.codeborne.selenide.Selenide.*
import static com.codeborne.selenide.Condition.*

and it's ready! Start writing tests!

Why yet another testing library?

We have been using Selenium in different projects. And we discovered that every time we need to write the same code in order to start browser, close browser, take screenshots and so one. You can find a huge amount of topics ala "How to do this and that in Selenium" with a huge amount of code that you need to copy-pase into your project.

We asked ourself: why should UI Testing be so tedious? We decided to extract our repeating code into a separate open-source library. That's how Selenide was born.

Does somebody use Selenide?

Yes. In Codeborne we have been using Selenide for 2 years in different project:

  • Internet-banks
  • Self-service portals
  • etc.

with different languages and testing frameworks:

  • Java + ANT + JUnit
  • Java + Gradle + JUnit
  • Scala + ANT + ScalaTest
  • Groovy + ANT
  • etc.

So you can be sure that Selenide is not just another raw open-source project. It's actually used and supported.

Show me a working example!

You can find a reference open-source project that uses Selenide: Hangman game.

We have also created project Selenide examples, where you can find examples of using Selenide for testing different sites like Gmail and Github.

What means the name "Selenide"?

In chemistry, Selenide is chemical compound containing Selenium + something.

So for UI Tests:

  • Selenide = Selenium + JUnit
  • Selenide = Selenium + TestNG
  • Selenide = Selenium + ScalaTest
  • Selenide = Selenium + что угодно

Enjoy the open-source chemistry!

Share your experience with us!

We would be glad to get your feedback - tell us what you tried, how it worked. What succeeded, what failed? Feel free to write your feedback or questions to googlegroup or privately to me!


Video: Selenide on SeleniumCamp 2013

$
0
0

This is our talk about Selenide on SeleniumCamp 2013 conference in Kiev.

The talk is in Russian.

First part - introduction to Selenide:

Second part - live demonstration of Selenide:

  • pair programming
  • ping-pong programming
  • programming a real internet bank

Can PhantomJS take screenshots?

$
0
0

Many people think that PhantomJS (as a headless browser) cannot take screenshots.

This is not true!

According to PhantomJS documentation, it can take screenshots.

Let's try to do that.

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

public class TestPhantomScreenshot {
  public static void main(String[] args) {
    System.setProperty("browser", "phantomjs");
    open("http://google.com");
    screenshot("google-com-screenshot");
    close();
  }
}

It works!

Though, it does not work ideally. Well, screenshots of google.com, habrahabr.ru and skype.com look good, but screenshot of selenide.org is quite strange.

Does it mean that PhantomJS is not mature enough yet? I don't know. But at least PhantomJS can do screenshots.

google.comhabrahabr.ruskype.comselenide.org

Selenide Harlem Shake

$
0
0

Good morning!

This is a video demonstrating how easy is to start writing automated tests with Selenide.

We wanted to make a screencast that would be short, funny and informative enough. By the way, this is a real-life project, not another "Hello World" application.

Watch with sound!

Selenide Harlem Shake from Selenide on Vimeo.

Selenide T-shirt

$
0
0

Hi seleniders!

You could have noticed that Selenide has got a new logo and design.

And even own T-shirts! Like real men!

We will share three of these T-shirts next week on the XP Days conference in Kiev.

frontback

Selenide in five minutes by Glen Smith

$
0
0

Wow!

Glen Smith presented Selenide at Canberra JUG. This is a really great 5-min live demo of Selenide. It took only 5 minutes to tell, write and run a full working test for google image service. You know, it's not that easy: there is Ajax under the hood...


Please enjoy!



Original blog post: Selenide in Five Minutes: A lightning talk


Glen Smith is an Australian engineer, co-author of "Grails in Action" book.

You can find more info in his blog.

Good job, @glenasmith!

Selenide downloads: over 200 unique ips

$
0
0

As you probably know, the Central Maven Repo publishes download statistics for different artifacts.


Today was published Selenide download statistics for February, 2014. The image below shows number of unique IPs that downloaded selenide.jar from the central maven repository.


It seems that we have great success! Yeah!



Changes in Selenide 2.9

$
0
0

Good evening!

Today was released Selenide 2.9. Let me tell you about the changes in the new version.

New functionality

Added support for Safari browser

Indeed, Safari driver doesn't seem to be stable yet. At least, some Selenide tests still fail on Safari.

Another problem with Safari is that it doesn't support JS alerts and cannot open local files like file://c:/tmp.txt.

Please feel free to share your experience with Safari webdriver!

Added condition or

Now you can declare composite conditions like this:

    Condition completed = or("completed", started, inProgress, loading);

and use them in your tests:

    $("div#page").shouldBe(completed);

Actually I am not sure it's a good idea. I believe that test should always know exactly, in which state the element should be at any moment. But folks insisted that or condition can be useful.

Added method ScreenShooter.to(folder)

Now JUnit users can declare screenshooter like this:

public class MyTest {
  @Rule
  public ScreenShooter photographer = failedTests().to("test-results/reports");
}

In most cases it's not needed, because path for screenshots can be declared using system property: -Dselenide.reports=test-results/reports or programmatically: Configuration.reportsFolder=test-results/reports. So, the new method can only be useful if you need different paths for different tests.

Bugfixes and improvements

Method $.download() throws FileNotFoundException (if server returns 40x error) or RuntimeException (for 50x status)

In older versions, method $.download() returned an empty file in case of server error during downloading file. It's certainly not convenient for testing.

Chrome browser window is also maximized.

Because of a bug in ChromeDriver Chrome browser window was not maximized. Now it is. Indeed I had to use java.awt black magic for this.

Method $.shouldHave(text()) also ignores the \u00a0 character (so called "non-breaking space")

In older versions, a check $(".error").shouldHave(text("Hello, Johny!")) ignored spaces and tabs. But we forgot about the \u00a0 characters which is widely used in web - e.g. for formatting amounts and dates. For example, this check could fail:

  $(".amount").shouldHave(text("123.45 EUR"));

Now it works.

Improved automatic closing of browser window in case of multi-threaded tests run with TestNG

In older versions, Selenide opened and closed browser in the same thread. In most cases it's sufficient.

But folks found that TestNG executes tests and @AfterSuite methods in different threads. We had to rework this code. Now Selenide watches all threads and automatically closes unused browser windows once corresponding threads are done.
P.S. Let me remind you that you do not need to manually close webdriver, because Selenide does it automatically.

Including webdriver exception

When a check like $.shouldBe(visible) fails because of webdriver exception, this error is not ignored anymore, but added to a standard Selenide error message like Element should be visible. It can be possible if browser behaves incorrectly. For example, folks found that IE sometimes throws InvalidSelectorException for a valid XPath.

If Selenide fails to take screenshot, it logs corresponding exception with stack trace.

Actually I am not sure that it's really useful. To avoid spamming logs, Selenide writes stack trace only once (on the first error).

Selenide saves page source in correct encoding (UTF-8)

In older versions, Selenide could store page HTML in wrong encoding, depending on default system preferences.

Removed INFO messages about “reportsUrl” and “BUILD_URL”

Some users were confused by these messages.

Indeed, it's a really fantastic feature: Selenide can automatically take screenshots and make them available as HTTP links in Jenkins reports. I will write a separate blog post about this feature.

Using "jQuery" word instead of "$"

Sometimes Selenide used character "$" to support javascript events. It could cause problems when testing applications using both jQuery and Prototype (or some other JS framework).

Upgraded to Selenium 2.40.0, HtmlUnit 2.14 and TestNG 6.8.8

As usually, we upgraded to last versions of Selenium and TestNG.

NB! In the latest TestNG 6.8.8 was removed JUnit support. So be careful if you use both TestNG and JUnit in your project, and the latter was loaded transitively. Now you will need to add JUnit dependency explicitly.


So, life is going on!


And what's new with you?



Changes in Selenide 2.10

$
0
0

Hi all!

Recently we released Selenide 2.10. Let me introduce you the news!

New functions

Working with windows/tabs

Selenium WebDriver does not support convenient API for working with windows and tabs. It only suggests method getWindowHandles() that returns set of strings - identifiers of opened windows. It's not trivial to find the needed one from these handles.

As Selenide primary goal is to free developer's head from browser technical details, we want to make working with windows/tabs easy and intuitive. We started this movement from a simple thing: we have added method

Selenide.switchToWindow(String title)

You can find a sample usage in Selenide tests:

@Test
  public void canSwitchToWindowByTitle() {
    $(byText("Page2: alerts")).click();
    $(byText("Page1: uploads")).click();

    switchToWindow("Test::alerts");
    $("h1").shouldHave(text("Page with alerts"));

    switchToWindow("Test::uploads");
    $("h1").shouldHave(text("File uploads"));
  }

We are planning to continue working on simplifying windows/tabs API - probably with help of new Java 8 features.

How would you like to use windows? Please feel free to share your ideas!

New methods $.hover()и $.dragAndDropTo(target)


Method $.hover() emulates moving mouse over the element (without clicking). Find example here.

Method $.dragAndDropTo(target) can drag an element and drop into another element. Example:

  $("#from").dragAndDropTo("#to")


New methods for searching parent/ancestors $.parent() and $.closest()

I often need to get a parent element. Or even ancestor, not direct parent. For example, I often search a DIV by text - this DIV is located inside a table. Then I want to find the table row containing the DIV. The only way to find it was using XPATH.

Now you can use convenient $.parent() or $.closest() methods:

  $(byText("Row 1")).parent();
  $(byText("Row 2")).closest("tr");
  $(By.name("firstName")).closest(".form");

You can find more examples here

Tracing JavaScript errors

Now Selenide tries to automatically catch all JavaScript errors that happened on a page.

What we do we them?

First of all, Selenide automatically adds JS errors to the error message when your test fails. Basically, it's sufficient. If you want more control, you can use the following methods:

  • Selenide.getJavascriptErrors() - returns all JavaScript errors on current page.
  • Selenide.assertNoJavascriptErrors() - fails the test if there have been some JavaScript errors on current page.


P.S. By now it's implemented very simply (using the window.onerror function). I am not sure it works pretty well in all browsers. And it cannot catch all errors. So, feel free to share you ideas how to implement it better.


Bugfixes and improvements

Closing webdrivers

Mechanism of automatic closing webdrivers was improved for case when one of webdrivers is hanging (and thus cannot be closed and prevents closing of other webdrivers). Thanks to Aleksander Gavrilenko for this nontrivial fix!

Selenide does not wait for <body>

Method open(url) doesn't wait until the tag <body> appears in the document. This is just an old code that is not needed since Selenide automatically waits for required conditions.

Upgrade to Selenium 2.41.0

As usually, we upgraded to latest Selenium WebDriver version.

We haven't observed any problems with the new Selenium. It works.

Other news

March statistics of Selenide downloads is just great!

We became twice as much during one month! Wow!


And what's new with you?


Changes in Selenide 2.11

$
0
0

Hello!

We have released Selenide 2.11. It does contains no new features, but removes old unused features, that made our life complex and broke down the progress.

Please be so nice and run your tests with Selenide 2.11. Notify us if some tests got broken.

What we cleaned up

Removed dependency on jQuery

Methods $.selectOption() and $.selectOptionByValue() tried to trigger "change" event using jQuery. It was done a long time ago to fight against some odd test failures on Windows in IE. Now it's actual anymore - at least all our tests are passing without this hack.

The whole class com.codeborne.selenide.JQuery is marked as deprecated. Please be sure that you do not use it in your tests.


Cleaned up annoying logs

When closing Firefox, you could see the following annoying error message in log: java “UnreachableBrowserException: Error communicating with the remote browser. It may have died.”

We researched this problem and found that this is a bug (or feature?) of Selenium Firefox webdriver. When calling method webdriver.close() it throws UnreachableBrowserException, but still closes the browser (at least, in Linux and Mac OS).

We removed this pointless log.

And what we updated

Upgraded to PhantomJS 1.2.0

As before, all tests of Selenide itself run successfully in PhantomJS, but some tests in our real projects fail. That's why we still cannot use PhantomJS in real work.


And what's new with you?


Changes in Selenide 2.12

$
0
0

Hello QA geeks!

Great news: we have released Selenide 2.12. Let's see what's coming with it.

Added function $.uploadFile(File)

The function allows you to upload a file.

   File cv = new File("src/test/resources/cv.pdf");
   $("#cvFileUpload").uploadFile(cv);

Selenide already had a similar function $.uploadFromClasspath(String fileName). It searched the file for uploading in classpath. We believe that holding test file together with test sources is a good practice (meaning that test files get to classpath during project compilation).

But we realized that sometimes it's convenient to upload some file from another place.


Fixed function $.uploadFromClasspath

It appeared that webdriver fails when trying to upload a file like c:/src/test/java/../resources/cv.pdf. We improved function $.uploadFromClasspath, so that it removes extra ".." parts from file name.

   $("#cvFileUpload").uploadFromClasspath("cv.pdf");


Function $.val("john") also works for selects

Function $.val has got a little bit smarter. It called on SELECT field, it chooses the right OPTION with corresponding value. This is one more step towards the idea that developer doesn't need to think about implementation details and can concentrate on business logic. You just write $("#sex").val("female") and don't think either it's INPUT or SELECT - Selenide detects it automatically and performs required action.

Technically, $("select").val("yes") - is a synonym for $("select").selectOptionByValue("yes").


Added function getWebDriverLogs().

The function reads webdriver logs. Technically it's synonym for webdriver.manager().logs(). In theory, these logs can contain very useful information about browser errors, javascript errors, performance problems etc. In practice, webdriver logs are not well supported by all webdrivers. We do not understand how to use them efficiently. Please share with us if you have any experience with webdriver logs!


Upgraded to Selenium 2.42.2 and HtmlUnit 2.15

We haven't experienced any problems with the new Selenium.

Thanks again to Selenium authors for the great product!


And what's new with you?


Shorten your code

$
0
0

Hi all!

This is Prezi presentation about Selenide from Ashwin Dalvi.



Pros, Cons and Myths:


Selenide: Shorten your code!


Selenide usage simple notes: IE, TestNG, Bootstrap dropdown

$
0
0

Hello!

My name is Sergey Shimkiv. Below you can find some notes about Selenide/Selenium usage.

IE notes

IE 11 x32/x64. In some cases after the actions with HTML elements (click() for example) you can receive an exception.
The cause of it could be synthetic events usage. The workaround is to use native events for IE:

   capabilities.setCapability("nativeEvents", "true");

https://code.google.com/p/selenium/wiki/InternetExplorerDriver

One way to add Selenide screenshot into the TestNG HTML reporter

In some cases you might want to add Selenide's screenshots of failed tests into your TestNG HTML reporter.

For example: You write two tests (Test1 and Test2) which must be linked (Test2 depends on Test1 results). But you know that Test1 will fail because of application bug(s). So you will write something like this:

   @Test(...)
   public void Test1() {
    ...
    try {
      // Test block with known bug
    } catch(...) {
      // Some actions
    } finally {
      // You want to perform some actions here to ensure correct preconditions for the Test2
    }
   }

Let's assume that you're using own test listener that extends TestListenerAdapter. And you have overridden onTestFailure(ITestResult result) method to collect some additional information into the HTML report - your own screenshots for example. In such case it is possible that your screenshot gathering implementation will collect incorrect data because finally block can be performed before screenshot will be taken.

Just keep in mind that Selenide's screenshot file name (that will be taken directly after some exception) could be taken from result.getThrowable().getMessage();

One way to work with customized Bootstrap HTML elements

Tests often get complicated when you need to test customized HTML controls with complex logic.

For example, Bootstrap's dropdown elements are represented via set of HTML elements. In common:

<div class="dropdown">
    <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown">
      Dropdown
      <span class="caret"></span>
    </button>
    <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
      <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
      <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
      <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
      <li role="presentation" class="divider"></li>
      <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
    </ul>
  </div>

The problem is that the <ul> element initially is not visible for the Selenium (and for Selenide too). To be able to select some dropdown element value you can:

   SelenideElement parentDiv = $(".dropdown");

   // Find `<button>` element and `click()` on it
   parentDiv.find("button").scrollTo().click();

   // Now you can find needed dropdown element value by text
   parentDiv.find(".dropdown-menu").find(withText("Action")).parent().click();


In the next post I would like to share experience in the automated testing environment deployment (based on Grid2).

Thanks to the Selenide's authors for their great tool ;)

Sergey Shimkiv

Changes in 2.13 and 2.14

$
0
0

Hi Seleniders!

In September we released two versions of Selenide: 2.13 and 2.14. There is not so much new functions, but there is one new function that I want to discuss with you. Let's start with it.

Fast method $.setValue

In Codeborne we analyzed performance of tests in few real projects and discovered that the most slow part of tests is filling text fields (not XPath search as many of us think). In other words, method $.setValue (or WebElement.sendKeys) is the bottleneck. It's because Selenium emulates keypress of every single key with all related events: keyDown, keyUp etc. - thus making method sendKeys quite slow.

It's possible to disable generating events, but in this case some functionality will be broken that uses these events: autocompletion, autosuggestions etc.

We have found a solution. Let's Selenide have two separate methods: $.sendKeys and $.setValue. The first one will work like Selenium by default: slowly and with generating events. The second one will be fast, setting values to text fields using JavaScript. So test author can decide in which case which method is needed. In most cases the fast method $.setValue can be used, because there is not so much autocompletions comparing to "regular" text fields.

In our projects using of fast $.setValue method gave 10% of performance improvement.

NB! This is experimental feature. It can be enabled by flag -Dselenide.fastSetValue=true. By default it's disabled, thus $.setValue works exactly the same as $.sendKeys.

Added method for checking images $("img").isImage()

Method $("img").isImage() returns true if the image has been correctly loaded. The method can be used only for <img> elements.

An example of usage can be found in test ImageTest.

NB! The functions does not work in HtmlUnit.

Added possibility to add descriptions to asserts (like in JUnit and TestNG asserts)

Now you can add a custom message to all should-methods:

$("#kpp").shouldBe("Private customers cannot have KPP", empty);

In case of test failure this description will be added to the error message:

Element should be empty {By.id: kpp} because Private customers cannot have KPP
Element: '<input id="kpp">012973891263</input>'
Screenshot: file:/Users/andrei/projects/selenide/build/reports/tests/integration/SelenideMethodsTest/waitUntilMethodMayContainOptionalMessageThatIsPartOfErrorMessage/1411898416054.0.png
Timeout: 4 s.

I am not sure that this feature is designed in the most convenient way. So, I am waiting for your suggestions. How could it be made more easy to use?

Maybe this API would be more convenient?

$("#kpp").shouldBe(empty.because("Private customers cannot have KPP"));

But in this case you will need to duplicate the description if you want to check multiple conditions in a line.

One more option:

$("#kpp").because("Private customers cannot have KPP").shouldBe(empty);

And finally, the "because" word is doubtful: in different situations you may find more appropriate to use other words.

What do you think?

Added wrappers be and have.

Now you have alternative way to write checks:

$("#username").should(have(text("Ivan")));
$("br").should(be(empty));

It may be useful when using Selenide with frameworks like EasyB that also use terms shouldBe or shouldHave for their needs.


Upgraded to Selenium 2.43.1.

Many testers have been waiting for this upgrade for a while. First of all, because of FireFox 32 support. And also because of new InternetExplorer driver.

We have not encountered any problems with the new Selenium 2.43.1.


And what's up with you?


How to start writing UI tests in 10 minutes

$
0
0

Hi!

People often ask: how to learn writing tests? How to start? How to write first test in Selenium?

Now we have an answer!

This video tutorial demonstrates how to create a project with Maven and write a test that opens a Google in browser, enters a word and checks for search results.

How to start writing UI tests in 10 minutes from Selenide on Vimeo.

Selenide tutorial

Please feel free to give your feedback!



Changes in Selenide 2.15

$
0
0

Good evening!

Good news: we have released Selenide 2.15. This time we have a lot of new features.

Sizzle selectors (CSS3)

Now you can use CSS3 selectors in Selenide for searching web elements!

For example:

$(":contains('Tere Martin!')").shouldBe(visible);
$(":not(a#id)");
$$(":not(div,p)").shouldHave(size(3));
$("[value!='johnny']");
$("div:has(span)");
$(":input");
$(":text");
$(":checkbox");
$(":file");
$(":password");
$(":image");
$(":header");
$(":first");
$(":last");
$(":even");

To enable Sizzle selectors, add this line to your tests:

Configuration.selectorMode = Sizzle;

Feel free to share your experience with us. Did it work for you?

Multifile upload

Now functions $.uploadFile() and $.uploadFileFromClasspath() can accept multiple arguments. This means that you can upload multiple files with Selenide!

Standard Selenium webdriver doesn't provide such function, so we had to make it with a help of black magic. Please share your experience, if it worked for you.

Support for BrowserMob proxy

We added convenient way for Selenide to add Proxy server to webdriver. First of all, it was needed for BrowserMob proxy - a popular tool among testers. It allows to intercept http requests between web application and browser, thus making possible many things that are now allowed with pure Selenium webdriver:

  • file download from server,
  • authorization on site,
  • asserting HTTP statuses,
  • and so on

Thanks to Vladimir Denisov for this pull request!

Here is an example of using BrowserMob Proxy with Selenide BrowserMobProxyTest.java:

ProxyServer proxyServer = new ProxyServer(findFreePort());
proxyServer.start();
proxyServer.newHar("google-test");
WebDriverRunner.setProxy(proxyServer.seleniumProxy());

open("http://google.com");

List<HarEntry> harEntries = proxyServer.getHar().getLog().getEntries();
assertTrue(harEntries.get(0).getRequest().getUrl().equals("http://google.com"));


You can zoom page now!

You can find sample usage in tests:

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

zoom(2.0); // Enlarge page zoom twice
zoom(0.5); // Zoom out twice

It can be useful for testing responsive design.

Support for JSON and iCal

You can now open non-html pages with Selenide.

It can be useful for testing json, iCal etc. resources. Sometimes it's useful to check them inside UI tests.

assertThat(source(), containsString("DTSTART:20140409T090000"));

Support for tabs and windows/tabs

Now Selenide allows switching between tabs/windows/frames not only by title, but also by index (0, 1, 2, ...).

Examples of switching between frames:

switchTo().frame(0);
assertTrue(source().contains("Hello, WinRar!"));

switchTo().defaultContent();
switchTo().frame(1);
$("h1").shouldHave(text("Page with dynamic select"));

Examples of switching between tabs:

switchToWindow(1); 
$("h1").shouldHave(text("Page with JQuery"));

switchToWindow(2); 
$("h1").shouldHave(text("File uploads"));

switchToWindow(3); 
$("h1").shouldHave(text("Page with alerts"));

switchToWindow(0); 
$("h1").shouldHave(text("Tabs"));

Support for Allure Framework

We have added function to get screenshot as a file:

import static com.codeborne.selenide.Screenshots.getScreenShotAsFile;

File screenshot = getScreenShotAsFile();

It can be used for integration with Allure Framework.

Thanks to Vladimir Denisov for this pull request!

Upgraded to Selenium 2.44.0.

  • Note that it brings upgrade of Google Guava to version 18.0.
  • Unfortunately, PhantomJS 1.2 does not work with Selenium webdriver 2.44.0 :( We have already committed Pull Request в ghostdriver for ghostdriver. Now waiting until it gets released.


And what's up with you?


You find wrong bugs

$
0
0

When I was on the last SQA Days conference in Saint-Petersburg, there happened an incident. At that moment, I didn't realize what happened. I just smiled. And only a few days later I got the idea.

So,

when I finished my speech about really effective automated testing, a man took a microphone and started asking criticizing questions. After a few answers of mine, he sat down discordant, saying:

You find wrong bugs.

I just smiled.

Only a few days later I catched up why he was basically wrong.

No, I am not going to say that we find good bugs.

I am going to say that

WE DO NOT SEARCH FOR BUGS AT ALL.


What is Quality Assurance

This is very, very important. Every QA engineer should know it from the childhood.

QA means "Quality Assurance". It means "being sure that software works". Our first job is not to find all bugs. Our first job is to be sure that software does its job.

For example

If we develop an internet-shop for selling TVs, the job of QA is to assure that user can find TV, press the big "Buy" button and pay money. This is the most important job.

Maybe banner looks bad. Maybe "Print PDF" button opens a new empty window. May be the "login" disappears sometimes. Surely, these are errors, but these are secondary errors. Surely, it's bad if you have such errors, but the business still will work. But if the "Buy" button is not clickable - it's the end of the business. User cannot pay his money. It's a big difference!

And there are a plenty of thirdly errors - when user enters 1000 chinese characters into "login" field and gets 500 error. No one normal user will do that. And if he does, let him get this 500 error.

I am not saying that these secondary and thirdly errors should not be searched and fixed. Sure, You should find and fix them. But only when you are sure that the business works.

So,

the main conclusion:

  1. Your first test should be "green path". A typical scenario that bring the money:
    Find TV - "Buy" - pay. Whatever you do: write automated tests or test manually. Your first test - green path.

This approach has one psychological disadvantage. This is the most boring test. This is a guarantee to find less bugs than your colleagues. This is a guarantee to make your boss feeling that you are not doing anything useful. But this is still the most important job of QA department.

  1. All these stupid tests about "1000 chinese characters in the login field" - you can do them, but only if all other things are ok. And you have free time that you cannot spend to anything else. In practice, that means - never.

But this is exactly the sort of bugs that QA engineers do generate during every release. Again and again. These meaningless bug reports waste your time, waste your resources, waste your attention, thus letting the real bugs appear unnoticed.

But this is a guarantee to find 50 new bugs at every release. This is a guarantee to get a top employee of the month. It's call "local optimization", and this is the most powerful of devil's inventions.

Do not run chase for bugs. You cannot catch all bugs in the world. It's like pimple: you squeeze one - three more will appear. You don't need to watch the pimples - you need to monitor the overall health. Do sport, do healthy eating, do hygiene - and pimples will disappear automatically. Do write the most important tests first. Make them fast. Make them stable. It's better to have tests green (and you will feel alarm when then get red once) than having a lot of tests red (and nobody will catch sight of the real problem).

That's because I am saying:

We do not search for bugs

We assure that software works. We write automated test to assure that user can buy TV. It allows us to avoid wasting time for maintaining plenty of meaningless bug reports and useless tests. It frees up our resources for quickly reacting to real problems that will always appear in production, not depending on QA department existence. It allows us to develop and maintain a complicated software with a small team. Small, but very effective team.

In testo veritas!


The fast and the continuous @ SQA Days 16

How to allocate time for refactoring?

$
0
0

One of the most common IT questions is: How to allocate time for refactoring?

It's common for both developers and testers. Both get very quickly a heap of dirty unreadable code, a plenty of slow, unmaintainable, unreadable tests. It's getting harder and harder to live with it. Development/testing is getting slower. Motivation decreases. Sometimes you happen to clean up some lines in the evening time, but... it seems to be something wrong with the evening-time work?..

  • Where is the justice?
  • Am I the only who needs it?
  • Why doesn't my boss allocate me time for refactoring?

I know. I also went through it.

No way

Now, let's face the truth. If somebody comes to me and asks to allocate one week for refactoring, I will refuse.

Let me explain why. Because refactoring can last endlessly, but somebody should do the work.

10 years ago I was hurt to hear this. Now I am saying it by myself. Moreover, I claim that cleaning code at evening hours is not unfairly - it's unprofessional.

So, have I lost my ideal?

Absolutely not.

Exactly the opposite. Now I am pretty sure that refactoring is absolutely required. Code must be continuously cleaned up through thick and thin. It just needs to be performed a little bit differently.

You must not ask anybody to allocate a separate time for refactoring. Refactoring is not a separate thing, independent from development/testing. Refactoring is part of coding. Refactoring is part of writing automated tests. It's the same natural and necessary part as typing, compilation and run.

The following is my receipt:

Small steps!

Recall TDD. Your process should look like this:

  • Write test (red) - 1 hour
  • Write code (to make test green) - 1 hour
  • Refactor (to make code/tests readable and clean) - 1 hour
  • Make a tea, go to step 1.

This is a continuous process. Small steps. Continuous progress. Hot tea.

(Depending on programming language, project and people "1 hour" can be replaced by "5 minutes" or whatever else.)

But what my boss would think about it?

Nobody will blame you that you are wasting time, if you show continuous progress. If you create new features every day. In case of testers - create new automated tests every day.

Nobody ever got fired for doing feature in 6 hours instead of 5 hours.

Think about it. You boss does not know exactly, how long this feature should be implemented. It means that he can never prove that you wasted additional time for writing tests or refactoring. The opposite is also true - you cannot prove (with facts and numbers) that refactoring speeds up the development time. Both of you can prove nothing. So, just work so as you believe is good to work.

Don't get me wrong, I am not calling for sabotage. I am not calling for doing your job longer than needed. Just opposite: I believe that this simple receipt lets you do your job faster:

Small steps: Test. Code. Refactor.

So, I don't need to ask for permission?

If somebody comes to me asking to allocate time for refactoring, I will reject. For the very simple reason: he does not know the TDD mantra. He will almost certainly refucktor this week, and nothing gets remarkably better as a result.

Good doctor doesn't ask permission to wash his hands before a surgery. Good artist doesn't ask permission to spend time for tuning his instrument. Somehow all the people understand that this is needed. Without wasting time on washing hands and tuning the instrument, they just cannot do their job well. So, are you worse, my dear professional developers and testers?

But don't forget that doctor manages to cure at least somebody in a day. And artist manages to play at least few songs per concert. That's why refactoring for a week, and not refactoring at all are both bad.

Small steps. Continuous progress. Tea with ginger.

And with cookies.


How to test GMail

$
0
0

Hi all!

How would you test GMail if you were Google developer? It's a great exercise, try it once!

Automated testing of GMail is not trivial. It heavily uses ajax, elements are loaded dynamically, loading may take more than few seconds, and there is no reasonable IDs/selectors. You would need to add "wait" for almost every operator!

Project "GMail test"

But it's possible! In Selenide Examples series we present a github project for testing GMail. It checks inbox content and composes a new message. Then it clicks "Undo", edits the message body and sends it again. And finally waits until the "Undo" button disappears.

Video

Here is a short video for demonstrating how it works:

Let's analyze this

Here is the github project: https://github.com/selenide-examples/gmail

Let's take a look under the hood!

Settings

Before test run we need to set longer timeout, because GMail element tend to load longer than 4 seconds (which is a default timeout in Selenide). Let's set 10 seconds. Thought at some conferences with slow WiFi even 10 was not sufficient long.

  @BeforeClass
  public static void openInbox() {
    timeout = 10000;
    baseUrl = "http://gmail.com";

    open("/");
    $(byText("Loading")).should(disappear);
    login();
  }

Have you noticed how we wait until the page gets loaded? This show the power of Selenide: it's easy to find element by text, and it's easy to wait until it disappears.

Login

Performing user login is easy:

  private static void login() {
    $("#Email").val(System.getProperty("gmail.username", "enter-your-gmail-username"));
    $("#Passwd").val(System.getProperty("gmail.password", "enter-your-gmail-password"));
    $("#signIn").click();
    $(".error-msg").waitUntil(disappears, 2000);
  }

The last line is needed to fail fast if you configured wrong username or password.

Unread messages counter

In a real life, I would run tests with a predefined data set. Say, with 4 unread messages. And check for presence of text "Inbox (4)":

  @Test
  public void showsNumberOfUnreadMessages() {
    $(By.xpath("//div[@role='navigation']")).find(withText("Inbox (4)")).shouldBe(visible);
  }

(But our case is harder: we need to test web application with real data that is not constant. Therefore let's limit ourselves to just check availability of text "Inbox".)

Verifying inbox content

Unfortunately all the GMail selectors are obfuscated. We cannot ID or other selectors. So, let's just verify that some texts are present on a page. We know that such messages should be definitely in my inbox:

  @Test
  public void inboxShowsUnreadMessages() {
    $$(byText("Gmail Team")).filter(visible).shouldHave(size(1));
    $$(byText("LastPass")).filter(visible).shouldHave(size(3));
    $$(byText("Pivotal Tracker")).filter(visible).shouldHave(size(3));
  }

Refreshing inbox

GMail interface has a "Refresh" button for reloading inbox. Let's find it by attribute title=Refresh.

  @Test
  public void userCanRefreshMessages() {
    // In a real life:: INSERT INTO messages ...
    $(by("title", "Refresh")).click();
    // In a real life: verify that the new message has appeared in the inbox
  }

In a real project I would add a new message into database, and verify that the new message has appeared in the inbox after pressing "Refresh" button.

New message

To compose a new message, let's click the "COMPOSE" button:

    $(byText("COMPOSE")).click();

Enter recipient address, subject and text:

    $(By.name("to")).val("andrei.solntsev@gmail.com").pressTab();
    $(by("placeholder", "Subject")).val("ConfetQA demo!").pressTab();

    $(".editable").val("Hello braza!").pressEnter();
    $(byText("Send")).click();

Isn't it easy?

And finally, let's verify that the message has been sent:

    $(withText("Your message has been sent.")).shouldBe(visible);

Undo - redo

There is a very cool (but experimental) feature in GMail - "Undo". After an email has been sent, you can undo it during next 10 seconds. By clicking the "Undo" button, user can cancel sending the last message and go back to editing. It's incredibly useful when, say, you sent message to a wrong recipient.

So, let's try to test "Undo" feature. In the end of previous test, let's add the following lines:

    $(byText("Undo")).click();
    highlight($(byText("Sending has been undone.")).should(appear));

Edit the message body and send again:

    $(".editable").should(appear).append("Hello from ConfetQA Selen").pressEnter().pressEnter();

    $(byText("Send")).click();

And finally wait for 10 seconds until the "Undo" button disappears:

    highlight($(withText("Your message has been sent.")).should(appear));
    highlight($(byText("Undo")).should(appear)).waitUntil(disappears, 12000);
    $(byText("Sent Mail")).click();

The message has been finally sent.

Now GMail is tested. Google can sleep peacefully. :)

Findings

As you see, web interface without IDs can also be tested. Long loading time and ajax requests are not obstacles. Dynamic content is not stopper. The following are simple receipts to overcome these problems:

  • Find elements by text
    This is how real users behave. This is less dependent on application implementation details.
  • Test only important things
    There are still a lot of things in GMail that left untested. It seems that it's not possible to test them (unable to use pre-generated test data in tests, absence of static locators). But it's not that important - important is the fact that the critical functionality is tested: inbox content and sending new message. Always start from testing functionality that is most critical for business.
  • Use appropriate instruments
    Selenide automatically resolves problems with timeouts, ajax, dynamic content, searching by text. Tests are not polluted with long scary XPath. Tests contain only business logic. Tests are readable.


Wish you simple tests!

Andrei Solntsev
selenide.org


Viewing all 45 articles
Browse latest View live