
When testing requires you to work with multiple open windows or tabs, Selenium is here to help. A new window or tab usually opens when a user clicks on a button or link which triggers the new page that loads to be open in a new window or tab. Whether it is a window or tab that opens depends on the browser you are using. No matter whether you have a new tab or a new window that opens, the methods presented in this post for working with them behave exactly the same. They make no distinctions in regards to what was open (a tab or window).
How can you tell that the page that opens when clicking on a link opens in a new window/tab? By inspecting the links’ ‘target’ attribute. If the value of this attribute is ‘_blank’, than the page that will open will be inside a new window/tab. If there is no ‘target’ specified, or its’ values are different than ‘_blank’, no new window/tab will be open when clicking on this link.
The methods that Selenium provides when working with windows/tabs are as follows: ‘getWindowHandles()’ which returns handles to all currently open windows/tabs (windows which were opened through the driver instance); ‘getWindowHandle()’ which gets the handle to the window in focus (the current window you are working with); ‘window()’ used as ‘driver.switchTo().window(windowHandle)’ which allows to bring another window into focus, in order to interact with the page opened in that window.
1. getWindowHandles()
When you have several open windows, in order to switch from one to the other to allow for page interaction, you will need to have a way of identifying the windows you are trying to switch to. Each window or tab has a value associated to it, called a handle. The handle is nothing more than a unique set of characters that identifies it, like a label. The result of calling the ‘getWindowHandles()’ method from Selenium is: all the handles of the open windows as a Java Set of String values. Calling this method from a test can be done in the following manner:
driver.getWindowHandles()
If you wish to store the result of calling this method, in order to access the handles later in a test, you can use a variable of type Set of String values:
Set<String> setOfWindowHandles = driver.getWindowHandles();
Using the handles returned by this method in tests is exemplified in the Examples section of this post.
One very important aspect to mention is that the window handles returned by the ‘getWindowHandles()’ are only of those windows opened by the automated tests you are running. As you already know, in order to open a page in a browser, you must first initialize (or start) the browser. When you are doing this, you are actually initializing a ‘driver’ instance. Therefore any new page which opens while you are interacting with this driver instance will also be related to the driver instance. Therefore, the ‘getWindowHandles()’ method only returns driver related window handles. Any other browser windows that are open independent of the ‘driver' are not returned by this method. For example, if before running a test which opens a browser, you already had some browser windows open, their handles are not returned by this method.
2. getWindowHandle()
If you need to get a handle to the currently focused window, in order to switch back to it later in a test, you can use the ‘getWindowHandle()’ method. It will return the handle to the currently focused driver instance window as a String.
driver.getWindowHandle()
As you will need this handle later on in the test (that is why you would call this method in the first place), you can store to it to a String variable:
String currentWindowHandle = driver.getWindowHandle();
3. switchTo().window()
Now that you have a way of identifying the open driver instance windows/tabs, they are useful for being able to switch the focus to the desired ones. In order to switch to a window, if you already have its handle saved in variable , you can just pass the variable as parameter to the ‘window()’ method as follows:
driver.switchTo().window(handle);
In case you stored all the window handles in a Set, you will need to iterate through the Set, in order to get to the handle you need, and use that handle as parameter to calling the ‘window()’ method. See the Examples paragraph.
An important thing to remember is that when you are providing a non existent value for the handle as parameter to the ‘window()’ method, you will get a ‘NoSuchWindowException’ exception. This means that you either got the handle wrong (you manually typed it for some reason and did not type the value of an existing handle), or the handle is not valid anymore (the corresponding window was closed between the time the handle was generated and the time when you are trying to switch to it).
Examples Setup
The tests from the upcoming examples will be performed on the following setup: a main page will be opened, named ‘mainPage.html’ (which you can find in my Github repository at the following location: https://github.com/iamalittletester/selenium-tutorial/blob/master/src/main/resources/mainPage.html). On this main page, there are two links (<a> tags). One of them opens a second page in a new window/tab, whose name is ‘secondPage.html’ (the HTML code for this page can be found at the following location: https://github.com/iamalittletester/selenium-tutorial/blob/master/src/main/resources/secondPage.html). The other link opens a third page, with the name ‘thirdPage.html’ (which can be found in the following location: https://github.com/iamalittletester/selenium-tutorial/blob/master/src/main/resources/thirdPage.html)
The relevant part of the HTML code corresponding to the first page (which i will refer to as the ‘main page’ in this chapter) is:
<body>
<header>
   <div class="w3-padding-small w3-center w3-card-4 w3-blue">
       <h1>Welcome to the main page</h1>
   </div>
</header>
<div class="w3-card-4 w3-margin w3-padding-small w3-center" >
   <h3>This is the first page</h3>
   <a href="secondPage.html" target="_blank">Go to second page</a>
   <a href="thirdPage.html" target="_blank">Go to third page</a>
</div>
</body>
As you can see, there are two <a> tags, which both have a ‘target’ attribute with the ‘_blank’ value. Therefore, when any of these links is clicked, the corresponding page (specified as the ‘href’ attribute) will be open in a new window/tab. There is also an <h1> tag with a text indicating that this is the main page.
The relevant part of the HTML code corresponding to the second page is:
<body>
<header>
   <div class="w3-padding-small w3-center w3-card-4 w3-sand">
       <h1>Welcome to the second page</h1>
   </div>
</header>
<div class="w3-card-4 w3-margin w3-padding-small w3-center" >
   <h4>This is the second page</h4>
</div>
</body>
This page also has an <h1> tag whose text indicates that this is the second page.
The relevant part of the HTML code corresponding to the third page is:
<body>
<header>
   <div class="w3-padding-small w3-center w3-card-4 w3-sand">
       <h1>Welcome to the second page</h1>
   </div>
</header>
<div class="w3-card-4 w3-margin w3-padding-small w3-center" >
   <h4>This is the second page</h4>
</div>
</body>
On this page you can also see an <h1> tag, whose text indicates that this is the third page.
A new PageObject class will be defined for the tests in this post, called ‘WindowsPage’. It will only have three WebElements: the two link elements and another one corresponding to the <h1> tag which is present on all three pages that the tests will go through.Â
@FindBy(css = "") public WebElement linkToSecondPage;
@FindBy(css = "") public WebElement linkToThirdPage;
@FindBy(css = "h1") public WebElement h1Element;
There will not be one separate WebElement for each <h1> tag from each page, but instead only one such WebElement. By switching windows, and, for example, using the ‘getText()’ method on the WebElement corresponding to the <h1> tag, you will get the text of the <h1> tag present on the page loaded in the currently selected window (the one which is in focus). When switching to a different window, whose loaded page also contains an <h1> tag, the ‘getText()’ method called on this tag will return the text of the <h1> tag corresponding to the current page.
Inside the test class, ‘WindowsTest’, the used before and after methods are now: @BeforeEach and @AfterEach. This means that the browser will be open before each test method runs, and it will be closed after each test method runs. This is to keep the state of the browser clean for each test start, as each test will open several windows/tabs. It is easiest to cleanup after a test which opens multiple windows/tabs by calling the ‘quit()’ method after the test ran, which closes all the open browser instances (spawned as driver instances). Also, in the @BeforeEach method, the main page is open. From this page new pages (in new windows/tabs) will be opened in each test.
Examples
Scenario 1
Step 1. From the main page, save the window handle (in order to switch to this window in a later step).
Step 2. From the main page, click on both links. Check that there are 3 open windows.
Step 3. Check that the second page opened properly in one of the open windows (by checking that the url of one of the open windows contains the name of the page, which is ‘secondPage’). Check that on the second page the <h1> tag displays the following text: ‘Welcome to the second page’.
Step 4. Switch to the main page window and check that the switch was made correctly.
Solution:
Step 1. As the @BeforeEach method was run, the main page was opened in the currently only open window. Therefore, storing the handle of the currently open window to a variable is done by calling the ‘getWindowHandle()’ method:
String mainPageWindowHandle = driver.getWindowHandle();
Step 2. From the main page, which is loaded in the main window, click on the two links. This will bring up two more window/tabs.
page.linkToSecondPage.click();
page.linkToThirdPage.click();
Now the check that there are 3 open windows/tabs should be done. In order to have something to count, first the handles of all open windows (through the driver instance) will be stored to a variable called ‘setOfWindowHandles’, which is a Set of String values.
Set<String> setOfWindowHandles = driver.getWindowHandles();
In order to check that there are 3 open windows/tabs, we need to check that there are 3 window handles. That means we will check the size of the ‘setOfWindowHandles’ Set.
assertEquals(3, setOfWindowHandles.size());
Step 3. In order to check that the second page (whose name contains the text ‘secondPage’) has loaded in a new window/tab, an iteration through the elements of the Set (the handles) will be made, with a ‘for’ loop. Before the iteration is made, a new boolean variable, called ‘foundWindow’ is created and set to ‘false’. You will see why in a second.
As there is the need to check that the second page is loaded in a new window/tab and also that the <h1> tag on that page needs to have a specified expected text, the iteration will be made as follows: all the existing window handles will be iterated over; if the current window over which is being iterated has a URL containing the text ‘secondPage’, that means that the second page is indeed open in this window; in this case the subsequent check, for the <h1> tag text is made. However, if no window with the expected url is found, without the boolean variable created before the iteration, there would be no way to realize that the window is not present. Therefore, if the window is found in the iteration phase, the boolean is set to true, which means that the window was found. If the window is not found, the boolean’s value is not changed and remains false. After the iteration is done, a check is made that the boolean value was set to true.
If this boolean value would not have been used, within the iterator, if the page was not found, the iterator would simply go through all the window handles, and if no handle whose window was displaying the second page is found, the for loop would just exit successfully.
Therefore, the check for second page to be loaded in a new window/tab, together with the check of the <h1> tag text, is as follows:
boolean foundWindow = false;
       for (String handle : setOfWindowHandles) {
           driver.switchTo().window(handle);
           if (driver.getCurrentUrl().contains("secondPage")) {
               assertEquals("Welcome to the second page", page.h1Element.getText());
               foundWindow = true;
           }
       }
assertTrue(foundWindow, "No such window was open");
Step 4. Now, switch to the window whose handle was saved into the ‘mainPageWindowHandle’ variable in the first step of this test scenario. Check that the main page is in focus. This is done by checking that, after switching to the window whose handle is ‘mainPageWindowHandle’, the URL of the window which is now in focus is that of the ‘mainPage’.
driver.switchTo().window(mainPageWindowHandle);
assertTrue(driver.getCurrentUrl().contains("mainPage"));
Scenario 2
Step 1. From the main page, click the two links. Check that there are now three open windows.
Step 2. Close only the window which displays the second page. Check that now only 2 windows are open.
Step 3. Switch to the main window. Click on the link which opens the second page again. Check that there are now 3 open windows.
Solution:
Step 1. Clicking on the links from the main page is rather simple:
page.linkToSecondPage.click();
page.linkToThirdPage.click();
In order to check that there are currently three open windows, the size of the result of calling the ‘getWindowHandles()’ method is checked to be 3.
assertEquals(3, driver.getWindowHandles().size());
Step 2. Now, switch to the window which displays the second page. Since the order of window handles is random, an iteration will be made through the Set of window handles, and when the window whose current url contains ‘secondPage’ (corresponding to the second page), it will be closed with the ‘close()’ method.
Set<String> setOfWindowHandles = driver.getWindowHandles();
       for (String handle : setOfWindowHandles) {
           driver.switchTo().window(handle);
           if (driver.getCurrentUrl().contains("secondPage")) {
               driver.close();
           }
        }
Now, in order to check the number of open windows, the number of existing window handles needs to be compared to 2.Â
assertEquals(2, driver.getWindowHandles().size());
In the previous code, a variable of type Set of String was created, to store the handles to the open windows. This Set is not relevant anymore, after one of the windows was closed. This is because the window handle corresponding to the window that was closed does not exist anymore. Therefore, trying to switch to the window handle that was previously assigned to the window that was just closed, will lead to an exception of type ‘NoSuchWindowException’. In order for that set to contain relevant and accurate information, it should be regenerated, by calling the ‘getWindowHandles()’ method again and storing the result of this method into the Set variable.
setOfWindowHandles = driver.getWindowHandles();
Step 3. Now, a switch to the main page window needs to be done. In this scenario, the handle of the main page window was not stored into a variable at the beginning (as in Scenario 1), to demonstrate another way of switching to the main page window. In this approach, an iteration with a ‘for’ loop is made over the currently open window handles, by switching to each window. When the main window page is encountered (the current url of the window in focus is checked), the ‘for’ loop will be exited with the ‘break’ option. That means that at the time the ‘break’ is encountered, the currently selected window is that of the main page.
for (String handle : setOfWindowHandles) {
           driver.switchTo().window(handle);
           if (driver.getCurrentUrl().contains("mainPage")) {
               break;
           }
        }
Now, from the main window, the link to the second page is clicked. Then, the check that the number of existing window handles is 3 is done, without regenerating the Set of currently open windows. This is because this Set will not be used in the test anymore, as the check that there are 3 open windows is the last step of this step. Otherwise, if other test steps would be required that would interact with different open windows, the Set of windows handles would need to be regenerated.
page.linkToSecondPage.click();
assertEquals(3, driver.getWindowHandles().size());
GitHub location of example code
PageObject class: https://github.com/iamalittletester/selenium-tutorial/blob/master/src/main/java/tutorialSolution/pages/WindowsPage.java
Test methods: savingHandlesToSet, closeOneOfOpenWindows
HTML code: https://github.com/iamalittletester/selenium-tutorial/blob/master/src/main/resources/mainPage.html; https://github.com/iamalittletester/selenium-tutorial/blob/master/src/main/resources/secondPage.html; https://github.com/iamalittletester/selenium-tutorial/blob/master/src/main/resources/thirdPage.html