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

Friday, 28 August 2015

How to check hidden element with Selenide and JavaScript


1. Inspect element in DeveloperTools or Firebug
2. Consider which attribute of the element you need to change to make it visible
3. Experiment with javascript console (DeveloperTools/Firebug > Console)
document.getElementsByName('some name');
document.getElementsByClassName('some class');
document.getElementById('some id');

Then change the attribute type:
// type='hidden' >> type='display'
document.getElementsByName('some hidden element')[0].type='display';

[0] - to get element with index 0 from "getElements..."

4. Use executeJavaScript() with JavaScript expression

executeJavaScript("document.getElementsByName('some hidden element')[0].type='display';"); 

The element is visible now. Done. 




Example: Check hidden quantity field in Cart. 
Object:  (demo) http://demo.prestashop.com


public class HiddenElementsTest {

    @Test
    public void testHiddenElementValue() {
        open("http://fo.demo.prestashop.com/en/blouses/2-blouse.html#/8-color-white/3-size-l");

        // go to Cart
        $(By.xpath(".//*[@name='Submit']")).click();
        $(By.xpath(".//*[@title='Proceed to checkout']")).waitUntil(visible, 2000).click();

        // use javascript to change hidden element to displayed
        executeJavaScript("document.getElementsByName('quantity_2_12_0_0_hidden')[0].type='display';");

        // now this element can be searched with selenide $
        int hiddenQtyValue1 = parseInt($(By.name("quantity_2_12_0_0_hidden")).getAttribute("value"));
        int qtyValue1 =  parseInt($(By.name("quantity_2_12_0_0")).getAttribute("value"));
        System.out.println(hiddenQtyValue1 + " " + qtyValue1); // "1 1"

        // add +1 item to Cart
        $(".icon-plus").click();

        // if you try to get the elements values you will find that the values have not changed yet
        int _hiddenQtyValue2 = parseInt($(By.name("quantity_2_12_0_0_hidden")).getAttribute("value"));
        int _qtyValue2 =  parseInt($(By.name("quantity_2_12_0_0")).getAttribute("value"));
        System.out.println(_hiddenQtyValue2 + " " + _qtyValue2);  // "1 1"

        // it is important to wait some time for changes in values. Lets wait while "2 products" text appears on the page
        $("#summary_products_quantity").waitUntil(hasText("products"), 2000);

        // values changed
        int hiddenQtyValue2 = parseInt($(By.name("quantity_2_12_0_0_hidden")).getAttribute("value"));
        int qtyValue2 =  parseInt($(By.name("quantity_2_12_0_0")).getAttribute("value"));
        System.out.println(hiddenQtyValue2 + " " + qtyValue2); // "2 2"

        assertEquals(hiddenQtyValue1, qtyValue1, "Incorrect qty");
        assertEquals(hiddenQtyValue2, qtyValue2, "Incorrect qty after adding 1 item");
        assertEquals(hiddenQtyValue2, hiddenQtyValue1 + 1, "Hidden qty is not changed");
        assertEquals(qtyValue2, qtyValue1 + 1, "Qty is not changed");

    }
}




Tuesday, 25 August 2015

How to verify elements sorting order


Task: To verify that sorting works:
List view:  ASC and DESC order
Grid view: ASC and DESC order

Object: Shop page with products for sorting (demo).
http://live.guru99.com/index.php/mobile.html?

This site allows use parameters in url to perform sorting ( baseUrl?dir=desc&mode=list&order=name) so I don`t pay attention to clicking all this sorting buttons and just open url with necessary parameters.

public class SortingTest
{

    @Test
    public void userCanSortProductsByNameinList()
    {
     // go to page showing products in list mode
     open("http://live.guru99.com/index.php/mobile.html?mode=list");
     
     // get list with product names
     ArrayList expectedNames = getList(".//*[@class='product-name']/a");
     
     // sort() will return this list sorted in ascending order
     Collections.sort(expectedNames);
     
     // go to page showing products in list mode and sorted by name in ascending order (you can click buttons to get the same result)                      
     open("http://live.guru99.com/index.php/mobile.html?dir=asc&mode=list&order=name");
     
     // get another list with product names
     ArrayList actualNames = getList(".//*[@class='product-name']/a");
     
     // compare lists
     assertEquals(actualNames, expectedNames, "Not sorted by name.");
     
    }

    @Test
    public void userCanSortProductsByNameDescInList()
    {
     // go to page showing products in list mode
     open("http://live.guru99.com/index.php/mobile.html?mode=list");
     
     // get list with product names
     ArrayList expectedNames = getList(".//*[@class='product-name']/a");
     
     // sort() will return this list sorted in ascending order
     Collections.sort(expectedNames);
     
     // reverse() will return this list sorted in reverse => descending order
     Collections.reverse(expectedNames);     
        
     // go to page showing products in list mode and sorted by name in descending order (you can click buttons to get the same result)
     open("http://live.guru99.com/index.php/mobile.html?dir=desc&mode=list&order=name");
     
     // get another list with product names
     ArrayList actualNames = getList(".//*[@class='product-name']/a");
     
     // compare lists
     assertEquals(actualNames, expectedNames, "Not sorted by name in DESC order.");
     
    }

 public ArrayList getList(String xpath){

        /*
        * Find elements by Xpath locator and return ArrayList with elements text attributes.
        */  

     ArrayList list = new ArrayList();
     ElementsCollection elements = $$(By.xpath(".//*[@class='product-name']/a"));
 
     for (SelenideElement el : elements) {
          list.add(el.text());
     }
     return list;
 }

}

Friday, 21 August 2015

How to download file with Selenide using one line of code



Use:
File downloadedFile = $("#your-link").download();
Result:
File downloads  automatically to reportFolder  -- "build/reports/tests" (this is default for Gradle projects).

You can change this folder in test: 
reportFolder="path/to/downloads/folder";

Example:
    
    @Test
    public void userCanDownloadFile() throws FileNotFoundException, IOException
    {
     // Folder to store downloads and screenshots to.
     reportsFolder = "./src/test/profiles/chrome/downloads/";
     
     open("http://chromedriver.storage.googleapis.com/index.html?path=2.16/");

     // Download files
     $("a[href='/2.16/chromedriver_win32.zip']").download();
        $(By.xpath(".//a[@href='/2.16/chromedriver_mac32.zip']")).download();
  
        // Count files in folder, assert 2
        int downloadsCount = new File(reportsFolder+"2.16").listFiles().length;
        assertEquals("Should be 2 files but founded " + downloadsCount,  
              downloadsCount, 2); 
        
        // Clean after test
        FileUtils.deleteDirectory(new File(reportsFolder+"2.16"));
    }

2. Navigation and Browser (Part 1)

Navigation and Browser (Part 1)

  1. Open URL and use some useful methods to verify page
  2. Define browser size and position: maximaze, minimaze
  3. Switch between browser windows or tabs
  4. Perform action "Refresh" and simulate "Back", "Forward"



1. Open URL and use some useful methods to verify page

baseUrl
url()
source()
getWebDriver().getTitle();

To visit page you can just specify url:
        open("http://chromedriver.storage.googleapis.com/index.html?path=2.16");

But it is better to specify base url and use relative urls to visit pages:

baseUrl = "http://chromedriver.storage.googleapis.com";
open("/index.html?path=2.16");

To get current page url use url():

open("https://www.ukr.net/");
url();  // return "https://www.ukr.net/"
assertTrue(Html.text.contains(url(), "https://www.ukr.net/"));

To get current page source use source():

baseUrl = "http://chromedriver.storage.googleapis.com";
        open("/index.html?path=2.16");
        assertTrue(Html.text.containsCaseSensitive(source(), "Parent Directory"));

To get the current page title you need to come back to webdriver and use getWebDriver().getTitle():

open("https://www.ukr.net/");
getWebDriver().getTitle();  // return page title
assertEquals(getWebDriver().getTitle(), "UKR.NET: Всі новини України, останні новини дня в Україні та Світі");


2. Define browser size and position: maximaze, minimaze


Easy,

        startMaximized = true;   //to maximize on start
    baseUrl = "http://www.seleniumhq.org";
   
    open("/");
    sleep(1000);
    getWebDriver().manage().window().setSize(new Dimension(0,0)); // to minimize
    sleep(1000);
        getWebDriver().manage().window().maximize(); // to maximize
        sleep(1000);
    getWebDriver().manage().window().setPosition(new Point(100,100)); // to move
    sleep(1000);

By the way. Avoid using "sleep()" in your tests. Better use implicitly/explicitly waits or be creative or just use Selenide. Yes, selenide understands when to wait (at least - in the most common situations, as said on the official site), for other cases waits methods are available to you.

Remember that "sleep pattern" is evil for your tests. I use sleep in this example to demonstrate changes in size and position.

3. Switch between browser windows or tabs

1 There is no difference between windows and tabs. 
2. But there is difference for your browser settings

When I was preparing example I found that my chrome does not open links in new tabs/new windows. So I used custom chrome profile with extension Click to Tab to open links in new tabs.

Recipe for switching between windows or tabs is the same as for Selenium.
1. Open page#1
2. Click link to page#2
Result: New tab/window is opened
3.  Get all opened tabs
Result:  Number of handled tabs == 2
4. Switch to handled tab with index 1
Result:  You can work with  page#2
5. Switch to handled tab with index 0
Result:  You can work with  page#1
6. Switch to "default content"
Result:  You can work with  page#1
Switch to default content is NOT the same that switch handled tab with index 0. 

Given I open page#1 and click link to page#2.
Result: New tab/window with page#2 is opened but I still work with page#1
Given I get all opened tabs
Result:  Number of handled tabs == 2
Given I switch to tab with index 1
Result:  You can work with  page#2
Given I switch to default content
Result:  You can work with  page#2

Please see below an example with 3 tabs:

public class SwitchBetweenWindowsTabsTest 
{
    @Test
    public void userCanSwitchBetweenTabs() 
    {
   
    baseUrl = "http://www.seleniumhq.org";
    open("/");
        System.out.println("Open, stay on page: " + getWebDriver().getTitle());
    assertEquals(getWebDriver().getTitle(), "Selenium - Web Browser Automation");
   
    $("#menu_projects").click();
    System.out.println("Click '#menu_projects', stay on page: " + getWebDriver().getTitle());
        
    $("#menu_download").click();
        System.out.println("Click '#menu_download', stay on page: " + getWebDriver().getTitle());
        
    // Array<String> realization
        ArrayList<String> tabs = new ArrayList<String> (getWebDriver().getWindowHandles());
        System.out.println("Tabs count = " + tabs.size());
        getWebDriver().switchTo().window(tabs.get(1));        
        System.out.println("After get(1) switch, stay on page: " + getWebDriver().getTitle());
        assertEquals("Downloads", getWebDriver().getTitle());
        
        getWebDriver().switchTo().window(tabs.get(2));        
        System.out.println("After get(2) switch, stay on page: " + getWebDriver().getTitle());
        assertEquals("Selenium Projects", getWebDriver().getTitle());
        
               
        getWebDriver().switchTo().defaultContent();        
        System.out.println("After defaultContent() switch, stay on page: " + getWebDriver().getTitle());
        assertEquals("Selenium Projects", getWebDriver().getTitle());
        
        
        getWebDriver().switchTo().window(tabs.get(0));        
        System.out.println("After get(0) switch, stay on page: " + getWebDriver().getTitle());
        assertEquals("Selenium - Web Browser Automation", getWebDriver().getTitle());

        getWebDriver().switchTo().window(tabs.get(2));        
        System.out.println("Once again get(2) switch, stay on page: " + getWebDriver().getTitle());
        assertEquals("Selenium Projects", getWebDriver().getTitle());
        
    }
}

By the way try to avoid System.out.println() in your real tests. Use normal logging.

4. Perform action "Refresh" and simulate "Back", "Forward"


// refresh current page
    refresh();
  
To simulate "back" and "forward" you can store urls and use open() in necessary order .

public class RefreshBackForwardTest 
{
    @Test
    public void userCanUseRefreshBackForward() 
    {
   
    baseUrl = "http://www.seleniumhq.org";
   
    open("/");
    String defaultUrl = url();
    assertEquals("Selenium - Web Browser Automation", getWebDriver().getTitle());
   
    String projectstUrl = $("#menu_projects a").getAttribute("href");
    String downloadUrl = $("#menu_download a").getAttribute("href");
        
    open(projectstUrl);
    assertEquals("Selenium Projects", getWebDriver().getTitle());
        
    open(downloadUrl);      
        assertEquals("Downloads", getWebDriver().getTitle());
        
        // Simulate "Back"
    open(projectstUrl);
    assertEquals("Selenium Projects", getWebDriver().getTitle());
        
    open(defaultUrl);
    assertEquals(getWebDriver().getTitle(), "Selenium - Web Browser Automation");
   
    // Simulate "Forward"
    open(projectstUrl);
    assertEquals("Selenium Projects", getWebDriver().getTitle());
   
    open(downloadUrl);    
    assertEquals("Downloads", getWebDriver().getTitle());
        
    // And refresh current page
    refresh();

    }
}