Bootstrap Modals and Selenium

I’ve been playing around with Selenium. Today, I’ll add a simple automation task to my Jersey, Gson and DataTables project that uses an explicit selenium wait to handle the Bootstrap modal dialog.

The first step is to update our pom.xml. I’ll be using:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@@ -42,6 +42,24 @@
+
+ <plugin>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <version>${jetty.version}</version>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire.version}</version>
+ <configuration>
+ <systemPropertyVariables>
+ <baseurl>http://localhost:8080/</baseurl>
+ <browser>firefox</browser>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
</plugins>
</build>

@@ -75,9 +93,25 @@
<artifactId>gson</artifactId>
<version>2.3</version>
</dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>${testng.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-java</artifactId>
+ <version>${selenium.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<properties>
<jersey.version>2.12</jersey.version>
+ <jetty.version>9.3.0.M2</jetty.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <testng.version>6.9.4</testng.version>
+ <selenium.version>2.45.0</selenium.version>
+ <surefire.version>2.18.1</surefire.version>
</properties>
</project>

Now, on to the actual test.

  1. I use the maven-surefire-plugin with the testng @Parameters annotation pass the browser and baseurl from the pom to the test method.
    1
    2
    3
    @Parameters({"browser","baseurl"})
    @Test
    public void userCreate( String browser, String baseurl )
  2. There are two hidden buttons on the bootstrap modal dialog - requiring me to specify the “Add User” button via this xpath request
    1
    2
    WebElement openModal  = driver.findElement(By.xpath("//button[contains(text(),'Add User')]"));
    openModal.click();
  3. Because the modal dialog starts out hidden, I use an explicit selenium wait for the modal to become visible. I would be at the mercy of a race condition without this wait.
    1
    2
    WebDriverWait  block = new WebDriverWait(driver,10);
    WebElement modal = block.until(ExpectedConditions.visibilityOfElementLocated(By.id("add-user-modal")));
  4. Since the explicit wait returned the modal dialog WebElement, I can find and set the input elements on the dialog via findElement on the WebElement, not the WebDriver.
    1
    2
    input    = modal.findElement(By.id("add-user-email"));
    input.sendKeys("abe@example.com");
  5. And finally, I explicity click the submit button (you can simply invoke the submit method on any form element in many cases - this didn’t work for me)
    1
    2
    input    = driver.findElement(By.id("user-post"));
    input.click();

After that, it is simply a matter of finding and setting the input elements on the dialog, followed by submitting the form. Here is the full class definition.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.ideoplex.tutorial;


import java.util.concurrent.TimeUnit;
import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;


public class SetupTest {

@Parameters({"browser","baseurl"})
@Test
public void userCreate( String browser, String baseurl )
throws Exception
{

WebDriver driver = "chrome".equalsIgnoreCase(browser)
? new ChromeDriver()
: new FirefoxDriver();
driver.get(baseurl);

WebElement openModal = driver.findElement(By.xpath("//button[contains(text(),'Add User')]"));
openModal.click();

WebDriverWait block = new WebDriverWait(driver,10);
WebElement modal = block.until(ExpectedConditions.visibilityOfElementLocated(By.id("add-user-modal")));
WebElement input;
input = modal.findElement(By.id("add-user-email"));
input.sendKeys("abe@example.com");
input = modal.findElement(By.id("add-user-givenName"));
input.sendKeys("Abraham");
input = modal.findElement(By.id("add-user-surName"));
input.sendKeys("Lincoln");

input = driver.findElement(By.id("user-post"));
input.click();

Thread.sleep(10000);
driver.quit();
}
}

To run this project:

  1. Open two terminal windows and navigate to the project route in both.
  2. In the 1st window
    1
    mvn jetty:run
  3. In the 2nd window
    1
    mvn test

And voilà, the Abraham Lincoln user is added to the webapp.

You can view the full source to Jerson, Gson and Datatables on github.

16 Nov: DataTables ajax error handling
14 Jun: DataTables and Selenium