Wednesday, 9 September 2015

Mobile Automation: Appium + Selenide (example with Calculator app, Android)

Mobile Automation: Appium + Selenide (example with Calculator app, Android)


How To:


1. add selenide.jar to the project

2. set your driver with WebDriverRunner.setWebDriver(your_driver);

3. write the test with selenide syntax sugar:

Example: standard android Calculator app.

capabilities.setCapability(MobileCapabilityType.APP_PACKAGE, "com.android.calculator2");


capabilities.setCapability(MobileCapabilityType.APP_ACTIVITY, "com.android.calculator2.Calculator");



package test;

import org.openqa.selenium.By;
import org.testng.annotations.*;

import static com.codeborne.selenide.Selenide.$;
import static com.codeborne.selenide.Condition.text;

import utilits.TestBase;


public class CalculatorTest extends TestBase {


@Test
public void testCalculator(){

    $(By.name("2")).click();
    $(By.name("+")).click();
    $(By.name("4")).click();
    $(By.name("=")).click();

    $(By.className("android.widget.EditText")).shouldHave(text("6"));
  }

}



Link to gist

Tuesday, 1 September 2015

9. Reporting: Selenide + Allure

Reporting:  Selenide + Allure


Concise UI tests require nice Allure reports :)

1. Selenide + Allure + TestNg

2. Selenide + Allure + JUnit  





1. Selenide + Allure + TestNg


Here is an example of test project from 8. Page Object (but using TestNG instead of Junit) with Allure reports. 


Clone a repository from selenide-allure-testng and go to project folder.

To run tests and generate Allure report:

$ mvn clean test
$ mvn site

Report folder:  /target/site/allure-maven-plugin/

To see a report:

$ mvn jetty:run

open http://localhost:8080 in your browser



2. Selenide + Allure + JUnit


Here is an official example from Selenide:
https://github.com/selenide-examples/selenide-allure-junit






Monday, 31 August 2015

8. Page Object

Page Object


1. How to start

2. Example with Google search



1. How to start


Refresh in memory 1. Introduction

Pay attention to:
Vimeo: How to write UI test in 10 minutes
Selenide site: http://selenide.org/documentation/page-objects.html


2. Example with Google search


You can find concise examples for Classic Selenium Page Object, Selenide Page Object, Selenide Page Object with fields here: selenide-examples (official source) .

The example below is just another variation and not pretending to be something more than simple quick example with a chain of methods inside the test. 

Example:



// test/GoogleTest.java

package ua.in.externalqa.test;

import org.junit.Test;


public class GoogleTest extends TestBase {
  @Test
  public void userCanSearch() {
    onGooglePage()
    .searchFor("selenide")
    .ensureResultsContains("concise UI tests in Java")
    .ensureResultsHaveSize(10);
    
  }
}



// test/TestBase.java

package ua.in.externalqa.test;
import ua.in.externalqa.pages.GooglePage;
import static com.codeborne.selenide.Selenide.open;
import static com.codeborne.selenide.Configuration.baseUrl;

public class TestBase {
    
public GooglePage onGooglePage(){
baseUrl = "http://google.com";
GooglePage page = open("/ncr", GooglePage.class);
return page;
}

}



// pages/GooglePage.java

package ua.in.externalqa.pages;

import static com.codeborne.selenide.Selenide.$;
import static com.codeborne.selenide.Selenide.page;

public class GooglePage {
public SearchResultsPage searchFor(String text) {
        $("#lst-ib").val(text).pressEnter();
    return page(SearchResultsPage.class);
  }
}




// pages/SearchResultsPage.java

package ua.in.externalqa.pages;

import com.codeborne.selenide.ElementsCollection;
import static com.codeborne.selenide.CollectionCondition.size;
import static com.codeborne.selenide.Condition.visible;
import static com.codeborne.selenide.Selenide.$;
import static com.codeborne.selenide.Selenide.$$;

import org.openqa.selenium.By;

public class SearchResultsPage {
  
public SearchResultsPage ensureResultsContains(String text ) {
$(By.partialLinkText(text)).shouldBe(visible);
return this; 
}
public SearchResultsPage ensureResultsHaveSize(int size ) {
getResults().shouldHave(size(size));
return this; 
}
public ElementsCollection getResults() {
    return $$(By.className("rc"));
  }
}




Sunday, 30 August 2015

7. Querying


Querying



1. How to find and filter data in table

2. How to check if image is broken

3. How to check if condition is true

1. How to find and filter data in table


Use findBy("text") or filterBy("text") to get row with "text" from table.

Use excludeWith("text") to get rows without "text" from table.


Example: 

@Test
    public void testTableFilter() {

        open("https://the-internet.herokuapp.com/tables");

        SelenideElement _row = $$("#table1 > tbody > tr").findBy(text("Smith"));
        /* Result:
        *  Smith John jsmith@gmail.com $50.00 http://www.jsmith.com edit delete
        */
    

        ElementsCollection rows = $$("#table1 > tbody > tr").excludeWith(text("Doe"));
        /* Result:
        *  Smith John jsmith@gmail.com $50.00 http://www.jsmith.com edit delete
        *  Bach Frank fbach@yahoo.com $51.00 http://www.frank.com edit delete
        *  Conway Tim tconway@earthlink.net $50.00 http://www.timconway.com edit delete
        */


        ElementsCollection rows1 = $$("#table1.tablesorter tbody tr td").filterBy(text("Conway"));
        /* Result:
        *  Conway
        *  tconway@earthlink.net
        * /
    }



2. How to check if image is broken


        open("https://the-internet.herokuapp.com/broken_images");

        assertTrue("Broken image1", $(By.xpath(".//*[@id='content']/div/img[1]")).isImage()); // fail
        assertTrue("Broken image2", $(By.xpath(".//*[@id='content']/div/img[2]")).isImage()); // fail
        assertTrue("Broken image3", $(By.xpath(".//*[@id='content']/div/img[3]")).isImage()); // pass



3. How to check if condition is true


The most common conditions:

          $("#element").isSelected();
        $("#element").isDisplayed();
        $("#element").isEnabled();
        $("#element").exists();
        $("#element").isImage();

Or mix is() with other conditions. To get more information about Conditions please refer to 5. Conditions and Assertions

        $("#element").is(Condition condition);



6. Waits

Waits



1. Wait for element state

2. Wait for element text

3. Wait for element value

4. Wait for element attribute


Element + waitUntil + Condition or Conditions + Time in ms

For more information about Conditions please refer to 5. Conditions and Assertions 

1. Wait for element state



        $("#username").waitUntil(present, 5000);

        $("#username").waitUntil(enabled, 5000);

        $("#username").waitUntil(disabled, 5000);

        $("#username").waitUntil(visible, 5000);

        $("#username").waitUntil(appears, 5000);

        $("#username").waitUntil(disappears, 5000);

        $("#username").waitUntil(empty, 5000);

        $("#username").waitUntil(focused, 5000);

        $("#username").waitUntil(selected, 5000);   




2. Wait for element text


        $("#welcome").waitUntil(hasText("Hello, Johny!"), 2000);
                
        $("#username").waitUntil(matchesText("Johny"), 2000);
                
        $("#username").waitUntil(not(matchesText("Noname")), 2000);
                
        $("#username").waitUntil(matchText("^Johny$"), 2000);
        



3. Wait for element value


        $("#username").waitUntil(hasValue("123"), 2000);




4. Wait for element attribute


        $("#username").waitUntil(hasAttribute("name", "user.name"), 2000);

        $("#username").waitUntil(hasClass("green-button"), 2000);

5. Conditions and Assertions

Conditions and Assertions


1. How to check element state?

2. How to check that element has text (exactly match)?

3. How to check that element contains some text (pattern match)?

4. How to check that element contains some text (regexp match)?

5. How to check that element has some attribute?

6. How to check that elements collection have expected size?

7. How to check hidden element?




How To:

Element + Assertions + Conditions == Check that element has something expected (text, value or state)




1. How to check element state?


You can use conditions with assertions to check if element  is visible or disappears or focused etc.

The most common conditions related to element state are available in Selenide.

Condition | Another name of condition

visible  or appear (appears)
present  or exist
notPresent (deprecated)
hidden or disappear (disappears) or not(visible)
readonly
enabled
disabled
focused
empty
selected




$("#element")  +  should() or shouldBe() +  condition or conditions
$("#element")  +  shouldNotBe() +  condition or conditions




Usage:

        $("input").shouldBe(visible, enabled); //visible | appear
        $("input").shouldBe(exist); //present | exist
        $("input").shouldBe(hidden); //hidden | disappear | not(visible)
        $("input").shouldBe(readonly);
        $("input").shouldBe(focused);
        $(".errors").shouldBe(Condition.empty);
        $$(".errors").shouldHave(CollectionCondition.empty);
        $(".errors").shouldBe(notPresent); 
        $(".errors").shouldBe(selected);
        $("input").shouldNotBe(visible, enabled);
        $("input").shouldNotBe(visible, disabled);





2.0 How to check that element has some text  ?




        $("#element")  +  shouldHave() +  condition or conditions
        $("#element")  +  shouldNotHave() +  condition or conditions




Usage:

         $(".element").shouldHave(text("text"));
         $(".element").shouldHave(textCaseSensitive("text"));

         $$(".errors").shouldHave(texts("text 1", "text 2"));




2.  How to check that element has text (exactly match)?


      
        $(".element").shouldHave(exactText("text"));
        $(".element").shouldHave(exactTextCaseSensitive("text"));

For elements:

        $$(".errors").shouldHave(exactTexts("text 1", "text 2"));



3. How to check that element contains some text (pattern match)?


         $(".element").shouldHave(matchesText("text"));

or assert $(".element").text().contains("text");




4  How to check that element contains some text (regexp match)?


        $(".element").shouldHave(matchText("^text$"));




5. How to check that element has some attribute?



to check that element has expected value:

        $(".element").shouldHave(hasValue("text"));

to check that element has expected class:
       
        $(".element").shouldHave(hasAttribute("class", "g"));
      
        $(".element").shouldHave(hasClass("nav"));

to check that element has expected id:

        $(".element").shouldHave(id("password"));

to check that element has expected name:

        $(".element").shouldHave(name("name"));         

to check that element has expected type:

        $(".element").shouldHave(type("file"));



6. How to check that elements collection have expected size?


        $$(".errors").shouldHave(size(2));
        $$(".errors").shouldHaveSize(2);


        $$(".errors").shouldBe(empty);




4. Forms and other elements (Part 2)



Forms and other elements (Part 2)



4.2 Interacting with forms



1. Basic authorization

2. TextField and TextArea

3. Radio button

4. CheckBox

5. Dropdown List

6. Frames





1. Basic authorization


    @Test
    public void testBasicAuthOk() {

        // login="admin", password="admin"
        open("http://admin:admin@the-internet.herokuapp.com/basic_auth");
        
        $("html").shouldHave(text("Congratulations! You must have the proper credentials."));

    }


2. TextField and TextArea


Login Form:

    @Test
    public void testLoginOk() {

        // login="tomsmith", password="SuperSecretPassword!"

        // Version 1
       open("http://the-internet.herokuapp.com/login");

        $("#username").val("tomsmith"); // or setValue("tomsmith")
        $("#password").val("SuperSecretPassword!"); // or setValue("SuperSecretPassword!")
        $(byText("Login")).submit();

        $("html").shouldHave(text("You logged into a secure area!"));


        // Version 2
        open("http://the-internet.herokuapp.com/login");

        $(byText("Username")).sendKeys("tomsmith");
        $(byText("Password")).sendKeys("SuperSecretPassword!");
        $(byText("Login")).submit();

        $("html").shouldHave(text("You logged into a secure area!"));

    }


Might be useful:

$("#username").click();
$("#username").clear();


TextArea:

open("http://derp-bear.herokuapp.com/forms/basic_form_example");

$("#free_text_area").val("At w3schools.com you will learn how to make a website.\n" +
                "We offer free tutorials in all web development technologies.\n\n" +
                " :)");

Should get multiline text in the text area :
"At w3schools.com you will learn how to make a website. 
We offer free tutorials in all web development technologies.

:)"


3. Radio button


    open("http://derp-bear.herokuapp.com/forms/basic_form_example");

    $(byText("Female")).setSelected(true);
    $(byText("Male")).setSelected(false);
    $("#female").shouldBe(selected);
    $("#male").shouldNotBe(selected);


    $(byText("Male")).click();
    $("#female").shouldNotBe(selected);
    $("#male").shouldBe(selected);



4. Checkboxes


   open("http://the-internet.herokuapp.com/checkboxes");

 // to set selected all checkboxes
        for (SelenideElement checkbox : $$("#checkboxes>input")){
            System.out.println("Is selected? " + checkbox.isSelected());
            if (!checkbox.isSelected()) {
                checkbox.setSelected(true);
            }
        }

// mark checkboxes as definitely checked or unchecked
        $$("#checkboxes>input").get(0).setSelected(true);
        $$("#checkboxes>input").get(1).setSelected(false);

// or use click to change from checked to unchecked and vice versa
        $$("#checkboxes>input").get(0).click();
        $$("#checkboxes>input").get(1).click();

5. Dropdown List


Usually it is easy to select some option from dropdown menu:

$("#menu").selectOption("text");
$("#menu").selectOptionByValue("value");

Example (not so easy to select some option from dropdown list):


    open("http://derp-bear.herokuapp.com/forms/basic_form_example");

    $(".select").$("#pet_select").click();

    $(".select").$(byText("Rabbit")).click();
    $(byText("Rabbit")).shouldBe(selected);

    $(".select").$(byText("Dog")).setSelected(true);
    $(byText("Dog")).shouldBe(selected);


    /* Not working for this example. Please see example below with JavaScript
    $(".select").selectOption("Horse");
    $(byText("Horse")).shouldBe(selected);

    $(".select").$(byValue("23")).click();
    $(byText("Snake")).shouldBe(selected);

    */

        
      executeJavaScript("document.getElementById('pet_select').style='';");
    $("#pet_select").selectOption("Horse");
    $(byText("Horse")).shouldBe(selected);

    $("#pet_select").selectOptionByValue("23");
    $(byText("Snake")).shouldBe(selected);
    }


6. Frames


open("http://demo.prestashop.com/");
switchTo().frame($("#framelive"));

Saturday, 29 August 2015

4. Forms and other elements (Part 1)

Forms and other elements



4.1. Clicking links and buttons



1. Buttons & Hyperlinks

2. Keys combinations

3. Actions

4. Execute JavaScript





1. Buttons & Hyperlinks


$("#element").click();

$("#element").doubleClick();


$(By.linkText("Logout")).click();

$("#agreement").submit();

$(".g").contextClick();    // context menu


2. Keys combinations


Submit with Enter:

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

$("#lst-ib").val("qwertyuiop").pressEnter();

$("q").pressEnter();


To navigate (Tab):

$("q").pressTab();


To select all (Ctrl-A):

 open("http://google.com");
 $("#lst-ib").val("qwertyuiop");

 $("#lst-ib").sendKeys(Keys.chord(Keys.CONTROL, "a"));

To copy (Ctrl-C):

 open("http://google.com");
 $("#lst-ib").val("qwertyuiop");
 $("#lst-ib").sendKeys(Keys.chord(Keys.CONTROL, "a"));

 $("#lst-ib").sendKeys(Keys.chord(Keys.CONTROL, "c"));

To cut (Ctrl-X):

 open("http://google.com");
 $("#lst-ib").val("qwertyuiop");
 $("#lst-ib").sendKeys(Keys.chord(Keys.CONTROL, "a"));

 $("#lst-ib").sendKeys(Keys.chord(Keys.CONTROL, "x"));

To paste (Ctrl-V):

 $("#lst-ib").sendKeys(Keys.chord(Keys.CONTROL, "v"));



3. Actions


actions().click($("#lst-ib").val("selenide")).build().perform();



4. Execute JavaScript


executeJavaScript("console.log('Hello')");




Source: Selenide Cheat Sheet

3. Locating elements

3. Locating elements


0.  $ and $$

1. Locating element by id

2. Locating element by css selector

3. Locating element by xpath selector

4. Locating element by class name

5. Locating element by name

6. Locating element by tag name

7. Locating element by link text

8. Locating element by partial link text

9. Locating element by text

10. Locating element with text

11. Locating element by title

12. Locating element by attribute

13. Locating element by value 

14. Locating one element in another element by chain


0. $ and $$


Use "$" to find one element:
$("#someId")  is the same as driver.findElement(By.id("someId"))

Use "$$" to find all elements:
$$(".someCssSelector") is the same as driver.findElements(By.cssSelector("someCssSelector"))


1. Locating element by id


$("#someId");
$(By.id("someId"));

2. Locating element by css selector


$(".someCssSelector");
$(By.cssSelector(".someCssSelector"));


3. Locating element by xpath selector


$(By.xpath(".//*[@class='price']"));

4. Locating element by class name


$(By.className("nav"));



5. Locating element by name


$(By.className("someName"));


6. Locating element by tag name


$(By.tagName("a"));


7. Locating element by link text


$(By.linkText("Logout"));


8. Locating element by partial link text


$(By.partialLinkText("out"));


9. Locating element by exact text


$(byText("Logout")); 


10. Locating element with text  (substring)


$(withText("out")); 
    


11. Locating element by title attribute


$(byTitle("someTitle")); 


12. Locating element by attribute


$(byAttribute("class", "g")); 



13. Locating element by value attribute 


$(byValue("someValue"));

          

14. Locating one element in another element by chain


$("#mainElement").$("#subElement")



Source: Selenide Cheat Sheet

How to drag and drop and upload file with Selenide and JavaScriptExecutor


Demo page: http://demo.tutorialzine.com/2011/09/html5-file-upload-jquery-php/

This page contains drag and drop area but has no <input type='file'> tags.

So  $("#fileInput").uploadFile(file); is not working in this situation.
Drag and drop actions chain is not working too because we need to take files from user`s side.

Here is a workaround.
JavaScript part
1. Create fake input field with type="file" and other necessary attributes
2. Add it to DOM 
3. Dispatch drag and drop event
4. Remove the fake input field (optionally)

Java part
1. prepare files
2. execute javascript to get new input field
3. use $("#fileInput").uploadFile(file);   from Selenide to send file
4. execute javascript to dispatch drag and drop event

  

public class DragAndDropFilesTest{


    @Test

    public void testUserCanDragAndDropFiles() {
        open("http://demo.tutorialzine.com/2011/09/html5-file-upload-jquery-php/");

        // prepare files

        ArrayList<File> files = new ArrayList<File> ();
        files.add(new File("/path/to/file/file1.png"));
        files.add(new File("/path/to/file/file2.png"));

        // drag and drop area

        SelenideElement dragTarget = $("#dropbox");

        // drag and drop the 1st file

        
        dragAndDropFile(files.get(0), dragTarget);
        // drag and drop the 2nd file
        //  it might be necessary to wait for uploaded files appearing on the page. Css selector ".uploaded"         
        dragAndDropFile(files.get(1), dragTarget, ".uploaded");

        assertEquals($$(".uploaded").size(), files.size(), "Not all files are attached");



    }


    public void dragAndDropFile(File file, SelenideElement dragTarget) {

    /*
    *    Usage:
    *    dragAndDropFile(files.get(0), $("#dragAndDropAreaId");
    *
    */
        createInputFile();
        SelenideElement fileInput = $("#selenideUpload");
        fileInput.uploadFile(file);

        dispatchFileDragAndDropEvent("dragenter", "document", fileInput);

        dispatchFileDragAndDropEvent("dragover", "document", fileInput);
        dispatchFileDragAndDropEvent("drop", dragTarget, fileInput);

        // remove fake input file element

        executeJavaScript("arguments[0].parentNode.removeChild(arguments[0]);", fileInput);
    }

    public void dragAndDropFile(File file, SelenideElement dragTarget, String waitForCss ) {

    /*
    *    Usage:
    *    dragAndDropFile(files.get(0), $("#dragAndDropAreaId", ".uploaded");
    *
    */
        createInputFile();
        SelenideElement fileInput = $("#selenideUpload");
        fileInput.uploadFile(file);

        dispatchFileDragAndDropEvent("dragenter", "document", fileInput);

        dispatchFileDragAndDropEvent("dragover", "document", fileInput);
        dispatchFileDragAndDropEvent("drop", dragTarget, fileInput);
        $(waitForCss).waitUntil(appears, 5000); // wait until file appears on the page
        // remove fake input file element
        executeJavaScript("arguments[0].parentNode.removeChild(arguments[0]);", fileInput);
    }

    public void dragAndDrop(SelenideElement fileInput, SelenideElement dragTarget) {

    /*
    *         Usage:
    *
    *         // upload the first file
    *        createInputFile();
    *        SelenideElement fileInput = $("#selenideUpload");
    *        fileInput.uploadFile(files.get(0));
    *
    *        // upload the second file
    *        createInputFile();
    *        SelenideElement fileInput = $("#selenideUpload");
    *        fileInput.uploadFile(files.get(1));
    *
    */
        dispatchFileDragAndDropEvent("dragenter", "document", fileInput);
        dispatchFileDragAndDropEvent("dragover", "document", fileInput);
        dispatchFileDragAndDropEvent("drop", dragTarget, fileInput);
        $(".uploaded").waitUntil(appears, 5000); // wait until file appears on the page
        executeJavaScript("arguments[0].parentNode.removeChild(arguments[0]);", fileInput);
    }

    public void createInputFile() {

        // Generate a fake input file selector
        executeJavaScript("var input = document.createElement('input');" +
                "input.id = 'selenideUpload';" +
                "input.type = 'file';" +
                "input.style.display = 'block';" +
                "input.style.opacity = '1';" +
                "input.style['transform']='translate(0px, 0px) scale(1)';" +
                "input.style['MozTransform']='translate(0px, 0px) scale(1)';" +
                "input.style['WebkitTransform']='translate(0px, 0px) scale(1)';" +
                "input.style['msTransform']='translate(0px, 0px) scale(1)';" +
                "input.style['OTransform']='translate(0px, 0px) scale(1)';" +
                "input.style.visibility = 'visible';" +
                "input.style.height = '1px';" +
                "input.style.width = '1px';" +
                "input.name = 'uploadfile';" +
                "if (document.body.childElementCount > 0) {" +
                "document.body.insertBefore(input, document.body.childNodes[0]);" +
                "} else {" +
                "document.body.appendChild(input);" +
                "}");

    }


    public void dispatchFileDragAndDropEvent(String eventName, Object to, SelenideElement fileInputId){

    String script =  "var files = arguments[0].files;" +
            "var items = [];" +
            "var types = [];" +
            "for (var i = 0; i < files.length; i++) {" +
            " items[i] = {kind: 'file', type: files[i].type};" +
            " types[i] = 'Files';" +
            "}" +
            "var event = document.createEvent('CustomEvent');" +
            "event.initCustomEvent(arguments[1], true, true, 0);" +
            "event.dataTransfer = {" +
            " files: files," +
            " items: items," +
            " types: types" +
            "};" +
            "arguments[2].dispatchEvent(event);";

        if (to instanceof String) {        // for "document" in dispatchFileDragAndDropEvent("dragenter", "document", fileInput)

            script = script.replace("arguments[2]", to.toString());
        } else {
            executeJavaScript(script,fileInputId, eventName, to);
        }

    }


}


JavaScript Source: Thanks for idea to PT024/ProfessionalTester-December2013-Herrmann.pdf