Controlling a Web Browser With Selenium WebDriver
After we have finished this lesson, we
- Know how we can open a web page with Selenium WebDriver.
- Understand how we can click an HTML element with Selenium WebDriver.
- Can submit a form with Selenium WebDriver.
This lesson assumes that:
Opening a Web Page
We can open a web page by invoking the get() method of the WebDriver interface. This method opens the requested page by using a GET request and takes the url address of the web page as a method parameter.
After we have written an end-to-end test that opens a new web page, the source code of our test class looks as follows:
1import org.junit.Test;
2import org.junit.experimental.categories.Category;
3import org.junit.runner.RunWith;
4import org.openqa.selenium.WebDriver;
5import org.openqa.selenium.chrome.ChromeDriver;
6
7import static org.assertj.core.api.Assertions.assertThat;
8
9@RunWith(SeleniumTestRunner.class)
10@SeleniumTest(driver = ChromeDriver.class)
11@Category(EndToEndTest.class)
12public class RenderClickSourcePageTest {
13
14 @SeleniumWebDriver
15 private WebDriver browser;
16
17 @Test
18 public void shouldOpenClickSourcePage() {
19 browser.get("http://localhost:8080/click-source");
20 assertThat(browser.getTitle()).isEqualTo("Click Source Page");
21 }
22}
Additional Reading:
Also, we should understand that the get() method will block until the requested page is loaded. It will also follow all redirects issued by the server or by the returned HTML document (meta-redirect).
However, there are two situations when we cannot trust that the get() method has loaded the entire DOM. These situations are:
- The loaded page uses Javascript that makes changes to its DOM. If this is the case, our test should wait until the DOM has been constructed.
- The returned page has a meta-redirect that waits before it redirects the browser to another page. If this is the case, our test should wait until this timeout is over because otherwise our test might be processing the wrong page.
The next section of this lesson describes how we can write end-to-end tests that wait until a specific condition is true.
Let’s move on and find out how we can click an HTML element.
Clicking an HTML Element
Now we will write an end-to-end test that demonstrates how we can click an element that is found from the loaded HTML document. Our test clicks a link found from the HTML page that looks as follows:
1<!DOCTYPE html>
2<html>
3<head>
4 <title>Click Source Page</title>
5</head>
6<body>
7 <a id="click-target-link" href="/click-target">Click this link</a>
8</body>
9</html>
When we click the link found from the loaded HTML document, our application opens another HTML document that looks as follows:
1<!DOCTYPE html>
2<html>
3<head>
4 <title>Click Target Page</title>
5</head>
6<body>
7 <p>This is the click target page</p>
8</body>
9</html>
We can write our end-to-end test by following these steps:
First, we have to create an end-to-end test class and ensure that the first page is loaded before our test method is run. After we have created our test class, its source code looks as follows:
1import org.junit.Before;
2import org.junit.experimental.categories.Category;
3import org.junit.runner.RunWith;
4import org.openqa.selenium.WebDriver;
5import org.openqa.selenium.chrome.ChromeDriver;
6
7import java.util.function.Predicate;
8
9import static org.assertj.core.api.Assertions.assertThat;
10
11@RunWith(SeleniumTestRunner.class)
12@SeleniumTest(driver = ChromeDriver.class)
13@Category(EndToEndTest.class)
14public class ClickTargetLinkTest {
15
16 @SeleniumWebDriver
17 private WebDriver browser;
18
19 @Before
20 public void openClickSourcePage() {
21 browser.get("http://localhost:8080/click-source");
22 }
23}
Second, we have to write a test method that finds the link element by using its id and clicks the found link. After we have written this test method, the source code of our end-to-end test class looks as follows:
1import org.junit.Before;
2import org.junit.Test;
3import org.junit.experimental.categories.Category;
4import org.junit.runner.RunWith;
5import org.openqa.selenium.By;
6import org.openqa.selenium.WebDriver;
7import org.openqa.selenium.WebElement;
8import org.openqa.selenium.chrome.ChromeDriver;
9
10@RunWith(SeleniumTestRunner.class)
11@SeleniumTest(driver = ChromeDriver.class)
12@Category(EndToEndTest.class)
13public class ClickTargetLinkTest {
14
15 @SeleniumWebDriver
16 private WebDriver browser;
17
18 @Before
19 public void openClickSourcePage() {
20 browser.get("http://localhost:8080/click-source");
21 }
22
23 @Test
24 public void shouldOpenClickTargetPage() {
25 WebElement targetLink = browser.findElement(
26 By.id("click-target-link")
27 );
28 targetLink.click();
29 }
30}
Additional Reading:
Third, because the click() method doesn’t necessarily wait until the next page is loaded, we have to ensure that our test waits as long as necessary. We can do this by following these steps:
- Create a new
WebDriverWaitobject. When we create a newWebDriverWaitobject, we will configure the timeout which specifies the maximum wait time in seconds. - Invoke the
until()method of theWebDriverWaitclass. When we invoke this method, we have to specify the condition that must returntruewhen our end-to-end test can stop waiting. TheExpectedConditionsclass provides static factory methods that are suitable for most use cases, and we will use one of these methods for creating a condition that waits until the url of the current page is correct.
After we have ensured that our end-to-end test waits as long as necessary, the source code of our test class looks as follows:
1import org.junit.Before;
2import org.junit.Test;
3import org.junit.experimental.categories.Category;
4import org.junit.runner.RunWith;
5import org.openqa.selenium.By;
6import org.openqa.selenium.WebDriver;
7import org.openqa.selenium.WebElement;
8import org.openqa.selenium.chrome.ChromeDriver;
9import org.openqa.selenium.support.ui.ExpectedConditions;
10import org.openqa.selenium.support.ui.WebDriverWait;
11
12@RunWith(SeleniumTestRunner.class)
13@SeleniumTest(driver = ChromeDriver.class)
14@Category(EndToEndTest.class)
15public class ClickTargetLinkTest {
16
17 @SeleniumWebDriver
18 private WebDriver browser;
19
20 @Before
21 public void openClickSourcePage() {
22 browser.get("http://localhost:8080/click-source");
23 }
24
25 @Test
26 public void shouldOpenClickTargetPage() {
27 WebElement targetLink = browser.findElement(
28 By.id("click-target-link")
29 );
30 targetLink.click();
31
32 WebDriverWait wait = new WebDriverWait(browser, 3);
33 wait.until(
34 ExpectedConditions.urlToBe("http://localhost:8080/click-target")
35 );
36 }
37}
If your end-to-end test doesn’t compile when you try to use the ExpectedConditions class, you have to update your Google Guava version to 21.0.
Additional Reading:
Fourth, we have to verify that the loaded page has the correct title. After we have written our assertion, the source code of our test class looks as follows:
1import org.junit.Before;
2import org.junit.Test;
3import org.junit.experimental.categories.Category;
4import org.junit.runner.RunWith;
5import org.openqa.selenium.By;
6import org.openqa.selenium.WebDriver;
7import org.openqa.selenium.WebElement;
8import org.openqa.selenium.chrome.ChromeDriver;
9import org.openqa.selenium.support.ui.ExpectedConditions;
10import org.openqa.selenium.support.ui.WebDriverWait;
11
12import static org.assertj.core.api.Assertions.assertThat;
13
14@RunWith(SeleniumTestRunner.class)
15@SeleniumTest(driver = ChromeDriver.class)
16@Category(EndToEndTest.class)
17public class ClickTargetLinkTest {
18
19 @SeleniumWebDriver
20 private WebDriver browser;
21
22 @Before
23 public void openClickSourcePage() {
24 browser.get("http://localhost:8080/click-source");
25 }
26
27 @Test
28 public void shouldOpenClickTargetPage() {
29 WebElement targetLink = browser.findElement(
30 By.id("click-target-link")
31 );
32 targetLink.click();
33
34 WebDriverWait wait = new WebDriverWait(browser, 3);
35 wait.until(
36 ExpectedConditions.urlToBe("http://localhost:8080/click-target")
37 );
38
39 assertThat(browser.getTitle()).isEqualTo("Click Target Page");
40 }
41}
Next, we will find out how we can submit a form.
Submitting a Form
Now we will write an end-to-end test which submits a form and verifies that the correct information is shown on the result page. The source code of the JSP page that contains the submitted form looks as follows:
1<!DOCTYPE html>
2<%@ page contentType="text/html;charset=UTF-8" language="java" %>
3<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
4<html>
5<head>
6 <title>Example Form Page</title>
7</head>
8<body>
9 <h1 id="page-header">Example Form Page</h1>
10 <form:form id="form"
11 action="${pageContext.request.contextPath}/form"
12 method="POST"
13 modelAttribute="form"
14 enctype="utf8"
15 role="form">
16 <div>
17 <label for="message">Message</label>
18 <form:input id="message" path="message"/>
19 </div>
20 <div>
21 <label for="number">Number</label>
22 <form:select id="number" path="number" multiple="false">
23 <form:option value="1"/>
24 <form:option value="2"/>
25 <form:option value="3"/>
26 </form:select>
27 </div>
28 <div>
29 <label for="checkbox">Checkbox</label>
30 <form:checkbox id="checkbox" path="checkbox" value="true"/>
31 </div>
32 <div>
33 <label for="radio-button">RadioButton</label>
34 <form:radiobutton id="radio-button"
35 path="radioButton"
36 value="true"/>
37 </div>
38 <button type="submit">Submit</button>
39 </form:form>
40</body>
41</html>
When we submit this form, our application renders a result page that displays the information that was entered to our form fields. The source code of the result page looks as follows:
1<!DOCTYPE html>
2<%@ page contentType="text/html;charset=UTF-8" language="java" %>
3<html>
4<head>
5 <title>Form Result Page</title>
6</head>
7<body>
8 <h1 id="page-header">Form Result Page</h1>
9 <div id="form-content">
10 <div id="form-message">
11 <div id="form-message-label">Message: </div>
12 <div id="form-message-value">${form.message}</div>
13 </div>
14 <div id="form-number">
15 <div id="form-number-label">Number: </div>
16 <div id="form-number-value">${form.number}</div>
17 </div>
18 <div id="form-checkbox">
19 <div id="form-checkbox-label">Checkbox: </div>
20 <div id="form-checkbox-value">${form.checkbox}</div>
21 </div>
22 <div id="form-radio-button">
23 <div id="form-radio-button-label">Radio Button: </div>
24 <div id="form-radio-button-value">${form.radioButton}</div>
25 </div>
26 </div>
27</body>
28</html>
We can write our end-to-end test by following these steps:
First, we have to create a new test class and ensure that the form page is loaded before our test method is run. After we have created our end-to-end test class, its source code looks as follows:
1import org.junit.Before;
2import org.junit.experimental.categories.Category;
3import org.junit.runner.RunWith;
4import org.openqa.selenium.WebDriver;
5import org.openqa.selenium.chrome.ChromeDriver;
6
7@RunWith(SeleniumTestRunner.class)
8@SeleniumTest(driver = ChromeDriver.class)
9@Category(EndToEndTest.class)
10public class SubmitExampleFormTest {
11
12 @SeleniumWebDriver
13 private WebDriver browser;
14
15 @Before
16 public void openFormPage() {
17 browser.get("http://localhost:8080/form");
18 }
19}
Second, we have to add two constants to our test class. These constants specify the values that are entered to the fields of the submitted form. After we have added these fields to our test class, its source code looks as follows:
1import org.junit.Before;
2import org.junit.experimental.categories.Category;
3import org.junit.runner.RunWith;
4import org.openqa.selenium.WebDriver;
5import org.openqa.selenium.chrome.ChromeDriver;
6
7@RunWith(SeleniumTestRunner.class)
8@SeleniumTest(driver = ChromeDriver.class)
9@Category(EndToEndTest.class)
10public class SubmitExampleFormTest {
11
12 private static final String MESSAGE = "Hello world";
13 private static final String NUMBER = "2";
14
15 @SeleniumWebDriver
16 private WebDriver browser;
17
18 @Before
19 public void openFormPage() {
20 browser.get("http://localhost:8080/form");
21 }
22}
Third, we have to implement a method that sets the field values of our form and submits the form. After we have written this method, the source code of our end-to-end test class looks as follows:
1import com.testwithspring.intermediate.EndToEndTest;
2import com.testwithspring.intermediate.SeleniumTest;
3import com.testwithspring.intermediate.SeleniumTestRunner;
4import com.testwithspring.intermediate.SeleniumWebDriver;
5import org.junit.Before;
6import org.junit.experimental.categories.Category;
7import org.junit.runner.RunWith;
8import org.openqa.selenium.By;
9import org.openqa.selenium.WebDriver;
10import org.openqa.selenium.WebElement;
11import org.openqa.selenium.chrome.ChromeDriver;
12import org.openqa.selenium.support.ui.Select;
13
14@RunWith(SeleniumTestRunner.class)
15@SeleniumTest(driver = ChromeDriver.class)
16@Category(EndToEndTest.class)
17public class SubmitExampleFormTest {
18
19 private static final String MESSAGE = "Hello world";
20 private static final String NUMBER = "2";
21
22 @SeleniumWebDriver
23 private WebDriver browser;
24
25 @Before
26 public void openFormPage() {
27 browser.get("http://localhost:8080/form");
28 }
29
30 private void fillAndSubmitForm() {
31 WebElement messageInput = browser.findElement(By.id("message"));
32 messageInput.sendKeys(MESSAGE);
33
34 Select numberSelect = new Select(browser.findElement(
35 By.id("number"))
36 );
37 numberSelect.selectByValue(NUMBER);
38
39 WebElement checkbox = browser.findElement(By.id("checkbox"));
40 checkbox.click();
41
42 WebElement radioButton = browser.findElement(By.id("radio-button"));
43 radioButton.click();
44
45 browser.findElement(By.id("form")).submit();
46 }
47}
Also, we must understand that the submit() method blocks until the new page is loaded. This means that we don’t have to add any additional wait logic to our end-to-end test.
Additional Reading:
Fourth, we have to write an end-to-end test which verifies that the correct information is shown on the result page. After we have written this test method, the source code of our test class looks as follows:
1import org.junit.Before;
2import org.junit.Test;
3import org.junit.experimental.categories.Category;
4import org.junit.runner.RunWith;
5import org.openqa.selenium.By;
6import org.openqa.selenium.WebDriver;
7import org.openqa.selenium.WebElement;
8import org.openqa.selenium.chrome.ChromeDriver;
9import org.openqa.selenium.support.ui.Select;
10
11import static org.assertj.core.api.Assertions.assertThat;
12
13@RunWith(SeleniumTestRunner.class)
14@SeleniumTest(driver = ChromeDriver.class)
15@Category(EndToEndTest.class)
16public class SubmitExampleFormTest {
17
18 private static final String MESSAGE = "Hello world";
19 private static final String NUMBER = "2";
20
21 @SeleniumWebDriver
22 private WebDriver browser;
23
24 @Before
25 public void openFormPage() {
26 browser.get("http://localhost:8080/form");
27 }
28
29 @Test
30 public void shouldRenderFormResultPageCorrectValues() {
31 fillAndSubmitForm();
32
33 WebElement message = browser.findElement(
34 By.id("form-message-value")
35 );
36 assertThat(message.getText()).isEqualTo(MESSAGE);
37
38 WebElement number = browser.findElement(
39 By.id("form-number-value")
40 );
41 assertThat(number.getText()).isEqualTo(NUMBER);
42
43 WebElement checkbox = browser.findElement(
44 By.id("form-checkbox-value")
45 );
46 assertThat(checkbox.getText()).isEqualTo("true");
47
48 WebElement radioButton = browser.findElement(
49 By.id("form-radio-button-value")
50 );
51 assertThat(radioButton.getText()).isEqualTo("true");
52 }
53
54 private void fillAndSubmitForm() {
55 WebElement messageInput = browser.findElement(By.id("message"));
56 messageInput.sendKeys(MESSAGE);
57
58 Select numberSelect = new Select(browser.findElement(
59 By.id("number"))
60 );
61 numberSelect.selectByValue(NUMBER);
62
63 WebElement checkbox = browser.findElement(By.id("checkbox"));
64 checkbox.click();
65
66 WebElement radioButton = browser.findElement(By.id("radio-button"));
67 radioButton.click();
68
69 browser.findElement(By.id("form")).submit();
70 }
71}
We have now written end-to-end tests that control our web browser by using Selenium WebDriver. Let’s summarize what we learned from this lesson.
Summary
This lesson has taught us five things:
- We can open a web page by using the
get()method of theWebDriverinterface. - We can click an element found from an HTML document by using the
click()method of theWebElementinterface. - We can submit a form by using the
submit()method of theWebElementinterface. - If we click a link, we have to add additional wait logic to our end-to-end test because the
click()method doesn’t wait until the new page is loaded. - If we open a web page or submit a form, we don’t have to add any wait logic to our end-to-end test because these methods wait until the new page is loaded.