10 min read

(For more resources related to this topic, see here.)

Understanding actions, build, and perform

We know how to take some basic actions, such as clicking on a button and typing text into a textbox; however, there are many scenarios where we have to perform multiple actions at the same time. For example, keeping the Shift button pressed and typing text for uppercase letters, and the dragging and dropping mouse actions.

Let’s see a simple scenario here. Open the selectable.html file that is attached with this book. You will see tiles of numbers from 1 to 12. If you inspect the elements with Firebug, you will see an ordered list tag (

    ) and 12 list items (
  1. ) under it, as shown in the following code:

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    8. 8
    9. 9
    10. 10
    11. 11
    12. 12

    If you click a number, it’s background color changes to orange. Try selecting the 1, 3, and 5 numbered tiles. You do that by holding the Ctrl key + 1 numbered tile + 3 numbered tile + 5 numbered tile. So, this involves performing multiple actions, that is, holding the Ctrl key continuously and clicking on 1, 3, and 5 tiles. How do we perform these multiple actions using WebDriver? The following code demonstrates that:

    public class ActionBuildPerform {     public static void main(String... args) {       WebDriver driver = new FirefoxDriver();       driver.get("file://C:/selectable.html");       WebElement one = driver.findElement(By.name("one"));       WebElement three = driver.findElement(By.name("three"));      WebElement five = driver.findElement(By.name("five"));       // Add all the actions into the Actions builder.      Actions builder = new Actions(driver);         builder.keyDown( Keys.CONTROL )               .click(one)              .click(three)              .click(five)              .keyUp(Keys.CONTROL);        // Generate the composite action.        Action compositeAction = builder.build();        // Perform the composite action.        compositeAction.perform( );       }    }

    Now, if you see the code, line number 9 is where we are getting introduced to a new class named Actions. This Actions class is the one that is used to emulate all the complex user events. Using this, the developer of the test script could combine all the necessary user gestures into one composite action. From line 9 to line 14, we have declared all the actions that are to be executed to achieve the functionality of clicking on the numbers 1, 3, and 5. Once all the actions are grouped together, we build that into a composite action. This is contained on line 16. Action is an interface that has only the perform() method, which executes the composite action. Line 18 is where we are actually executing the action using the perform() method.

    So, to make WebDriver perform multiple actions at the same time, you need to follow a three-step process of using the user-facing API of the Actions class to group all the actions, then build the composite action, and then the perform the action. This process can be made into a two-step process as the perform() method internally calls the build() method. So the previous code will look as follows:

    public class ActionBuildPerform {     public static void main(String... args) {       WebDriver driver = new FirefoxDriver();       driver.get("file://C:/selectable.html");       WebElement one = driver.findElement(By.name("one"));       WebElement three = driver.findElement(By.name("three"));      WebElement five = driver.findElement(By.name("five"));       // Add all the actions into the Actions builder.     Actions builder = new Actions(driver);         builder.keyDown( Keys.CONTROL )               .click(one)              .click(three)              .click(five)              .keyUp(Keys.CONTROL);        // Perform the action.        builder.perform( );   } }

    In the preceding code, we have directly invoked the perform() method on the Actions instance, which internally calls the build() method to create a composite action before executing it.

    In the subsequent sections of this article, we will take a closer look at the Actions class. All the actions are basically divided into two categories: mouse-based actions and keyboard-based actions. In the following sections, we will discuss all the actions that are specific to the mouse and keyboard available in the Actions class.

    Learning mouse-based interactions

    There are around eight different mouse actions that can be performed using the Actions class. We will see each of their syntax and a working example.

    The moveByOffset action

    The moveByOffset method is used to move the mouse from its current position to another point on the web page. Developers can specify the X distance and Y distance the mouse has to be moved. When the page is loaded, generally the initial position of a mouse would be (0, 0), unless there is an explicit focus declared by the page.

    The API syntax for the moveByOffset method is as follows:

    public Actions moveByOffset(int xOffSet, int yOffSet)

    In the preceding code, xOffSet is the input parameter providing the WebDriver the amount of offset to be moved along the x axis. A positive value is used to move the cursor to the right, and a negative value is used to move the cursor to the left.

    yOffSet is the input parameter providing the WebDriver the amount of offset to be moved along the y axis. A positive value is used to move the cursor down along the y axis and a negative value is used to move the cursor toward the top.

    When the xOffSet and yOffSet values result in moving the cursor out of the document, a MoveTargetOutOfBoundsException is raised.

    Let’s see a working example of it. The objective of the following code is to move the cursor on to the number 3 tile on the web page:

     public class MoveByOffSet{   public static void main(String... args) {     WebDriver driver = new FirefoxDriver();     driver.get("file://C:/Selectable.html");     WebElement three = driver.findElement(By.name("three"));     System.out.println("X coordinate: "+three.getLocation().getX()+"
      Y coordinate: "+three.getLocation().getY());     Actions builder = new Actions(driver);     builder.moveByOffset(three.getLocation().getX()+1,
    three.getLocation().getY()+1);     builder.perform();   }  }

    We have added +1 to the coordinates, because if you observe the element in Firebug, we have a style border of 1 px. Border is a CSS-style attribute, which when applied to an element, will add a border of the specified color around the element with the specified amount of thickness. Though the previous code does move your mouse over tile 3, we don’t realize it because we are not doing any action there. We will see that when we use this moveByOffset() method in combination with the click method shortly.

    The moveByOffset() method may not work in Mac OSX and may raise a JavaScript error when used independently like the previous code.

    The click at current location action

    The click method is used to simulate the left-click of your mouse at its current point of location. This method doesn’t really realize where or on which element it is clicking. It just blindly clicks wherever it is at that point of time. Hence, this method is used in combination with some other action rather than independently, to create a composite action.

    The API syntax for the click method is as follows:

    public Actions click()  

    The click method doesn’t really have any context about where it is performing its action; hence, it doesn’t take any input parameter.

    Let’s see a code example of the click method:

    public class MoveByOffsetAndClick{   public static void main(String... args) {     WebDriver driver = new FirefoxDriver();     driver.get("file://C:/Selectable.html");     WebElement seven = driver.findElement(By.name("seven"));     System.out.println("X coordinate: "+seven.getLocation().getX()+" Y coordinate: "+seven.getLocation().getY());     Actions builder = new Actions(driver);     builder.moveByOffset( seven.getLocation ().getX()+1, seven.getLocation().getY()+1).click();     builder.perform();   } }

    Line 8 is where we have used a combination of the moveByOffset() and click() methods to move the cursor from point (0, 0) to the point of tile 7. Because the initial position of the mouse is (0, 0), the X, Y offset provided for the moveByOffset() method is nothing but the location of the tile 7 element. Now, lets try to move the cursor from tile 1 to tile 11 and from there to tile 5 and see how the code looks. Before we get into the code, let’s inspect the selectable.html page using Firebug. The following is the style of each tile:

    #selectable li {     float: left;     font-size: 4em;     height : 80px;     text-align: center;     width : 100px; } .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {     background: url("images/ui-bg_glass_75_e6e6e6_1x400.png") repeat-x scroll 50% 50% #E6E6E6;     border : 1px solid #D3D3D3;     color: #555555;     font-weight: normal; }

    The three elements with which we are concerned for our offset movement in the preceding style code are: height, width, and the border thickness. Here, the height value is 80px, width value is 100px, and border value is 1px. Use these three factors to calculate the offset to navigate from one tile to the other. Note that the border thickness between any two tiles will result in 2 px; that is, 1 px from each tile. The following is the code that uses the moveByOffset and click() methods to navigate from tile 1 to tile 11, and from there to tile 5:

    public class MoveByOffsetAndClick{   public static void main(String... args) {     WebDriver driver = new FirefoxDriver();     driver.get("file://C:/Selectable.html");     WebElement one = driver.findElement(By.name("one"));     WebElement eleven = driver.findElement(By.name("eleven"));     WebElement five = driver.findElement(By.name("five"));     int border = 1;     int tileWidth = 100;     int tileHeight = 80;     Actions builder = new Actions(driver);     //Click on One     builder.moveByOffset( one.getLocation ().getX()+border, one.getLocation().getY()+border).click();     builder.build().perform();     // Click on Eleven     builder.moveByOffset( 2*tileWidth+4*border, 2*tileHeight+4*border).click();     builder.build().perform();    //Click on Five     builder.moveByOffset( -2*tileWidth-4*border, -tileHeight-2*border).click();     builder.build().perform();    }  }


Subscribe to the weekly Packt Hub newsletter

* indicates required

LEAVE A REPLY

Please enter your comment!
Please enter your name here