How to test GMail

How to test GMail

28.12.14

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. Though 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


28.12.14