Testing a web app with 2 browser windows opened simultaneously

I have published a GitHub project


Here I am going to explain what I have done to test a Blog app using 2 browser windows simultaneously. I used Katalon Studio. I wrote my test scripts in 2 ways; one in the typical Katalon Studio style, another using Page Object Model

This project is meant to be a set of sample codes for myself to develop a large scale test suite in future.

Movie for demonstration

For those who don’t have time, please have a look at the following movie. This shows how my Web UI test works.

Problem to solve

I want to answer to a question raised in the Katalon Forum with a runnable sample code set.

Please imagine. I can create 2 users to be authenticated by the web app. I would open 2 windows of Chrome browsers simultaneously. From each Chrome, I would visit the http://127.0.0.1/ as 2 users each. When a user “Alice” made a post, then another user “Bob” should be able to see the post by Alice in an instant. When Bob made a new post, then soon Alice should be able to see the Bob’s post.

This test scenario — testing a web app with 2 browsers simultaneously — can be extended to business use cases. Suppose that I have an EC site which has dual user interface: Customer UI and Administrator UI. When a user submit an order to purchase some products, then an administrator should be able to see the order in the list of outstanding orders. I want to test both of the Customer UI and the Administrator UI at the same time. My Web UI test should simulate submitting an order in the Customer UI; then my test my test should verify if the order is appearing in the Administrator UI. I want my test to simulate such dual-participants’ interaction.

But how can I open 2 browsers simultaneously in Katalon Studio?

There is a basic problem in Katalon Studio. Using WebUI.openBrowser() keyword, you can not open 2 browsers.

I made a Test Case Test Cases/analysis/WebUI_openBrowser_twice in Katalon Studio to demonstrate this problem.

import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI

WebUI.openBrowser("http://127.0.0.1/")
WebUI.openBrowser("http://127.0.0.1/")

WebUI.delay(1)
WebUI.closeBrowser()

This simple script calls WebUI.openBrowser() keyword twice. Do we see 2 windows of browsers opened? — No. We will see only 1 window opened, we do not see the 2nd window opened.

1st_browser_is_closed

This way the WebUI.openBrowser() is designed. You can not open 2 browses using this keyword.

Solution

opening browsers by WebDriver API

Behind the WebUI.openBrowser() and other WebUI.xxx keywords , an instance of Selenium WebDriver is working. If I write a script that makes an instances of WebDriver class by calling org.openwa.selenium.chrome.ChromeDriver directly, then I can open a Chrome browser. My script can create 2 instances of WebDriver and keep them running. Then I will have 2 windows of Chrome browser. My test script can talk to them via the WebDriver API such as driver.navigate().to("http://127.0.0.1/") .

While opening browsers with WebDriver API, still I want to use WebUI.xxx keywords. There is a pitfall. Katalon’s WebUI.xxx keyword do not work with a browser (a WebDriver instance) that my script instantiated. Let me show you an experiment.

Test Cases/analysis/2_WebUI_keywords_do_not_know

String chrome_executable_path = DriverFactory.getChromeDriverPath()
System.setProperty('webdriver.chrome.driver', chrome_executable_path)

WebDriver browser = new ChromeDriver()
browser.navigate().to('http://127.0.0.1/')

// WebUI.xxx do not know the WebDriver instance created here

String windowTitle = WebUI.getWindowTitle()
assert "Posts - Flaskr" == windowTitle

This script opens a Chrome browser window by calling new ChromeDriver() . But the script does not inform Katalon Studio of the WebDriver instance. WebUI keywords are not aware of the browser. Therefore calling WebUI.getWindowTitle() keyword fails.

2 unable to get title

informing Katalon Studio of browsers opened by WebDriver API

How to fix this error? — call DriverFactory.changeWebDriver(WebDriver browser) .

TestCases/analysis/3_how_to_inform_WebUI_keywords

import org.openqa.selenium.WebDriver
import org.openqa.selenium.chrome.ChromeDriver

import com.kms.katalon.core.webui.driver.DriverFactory
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI

String chrome_executable_path = DriverFactory.getChromeDriverPath()
System.setProperty('webdriver.chrome.driver', chrome_executable_path)

WebDriver browser = new ChromeDriver()
browser.navigate().to('http://127.0.0.1/')

// i can let WebUI.xxx keywords know the WebDriver instance created by my script
DriverFactory.changeWebDriver(browser)

String windowTitle = WebUI.getWindowTitle()
assert "Posts - Flaskr" == windowTitle

This code passes.

capable

Now WebUI.xxx keywords can interact with the browser which was created by my script using new ChromeDriver() API.

Waiting for the page to load

By a call driver.navigate().to("http://127.0.0.1/"), we can open a browser and let it navigate to the URL specified. But this call does NOT perform implicit wait for the page to load completely. If you want to ensure that the page has been loaded, you need to do it explicitly.

There are several ways of implementing “wait for page to load”. The following sample code shows how to use WebUI.verifyElementPresent(TestObject, int timeout) keyword.

// Test Cases/analysis/4_wait_for_the_page_to_load

import org.openqa.selenium.WebDriver
import org.openqa.selenium.chrome.ChromeDriver

import com.kms.katalon.core.model.FailureHandling
import com.kms.katalon.core.testobject.ConditionType
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.webui.driver.DriverFactory
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI

String chrome_executable_path = DriverFactory.getChromeDriverPath()
System.setProperty('webdriver.chrome.driver', chrome_executable_path)

WebDriver browser = new ChromeDriver()
browser.navigate().to('http://127.0.0.1/')

// i can let WebUI.xxx keywords know the WebDriver instance created by my script
DriverFactory.changeWebDriver(browser)

// wait for the page to load
TestObject tObj = makeTestObject("site_name", "//h1[text()='Flaskr']")
//TestObject tObj = makeTestObject("site_name", "//h1[text()='FlaskR']")   // this will fail
WebUI.verifyElementPresent(tObj, 5, FailureHandling.STOP_ON_FAILURE)

WebUI.closeBrowser()

// helper method to create an instance of TestObject
TestObject makeTestObject(String id, String xpath) {
    TestObject tObj = new TestObject(id)
    tObj.addProperty("xpath", ConditionType.EQUALS, xpath)
    return tObj
}

By the way, as you know, the WebUI.openBrowser(String url) keyword does implicit wait. How is its implicit wait implemented? — You can find the source of the keyword at OpenBrowserKeyword.groovy. You can start reading the source and find its internal implementation. I think that explicit wait by WebUI.verifyElementPresent() keyword is easier in this case to implement, than trying to imitate the implicit wait by WebUI.openBrowser() keyword.

Magic spells for opening 2 browsers

In short, the following is the magic spells you need to know.

  1. In Katalon Studio, test script can open 2 browsers by calling new ChromeDriver() API twice.
  2. a test script can call DriverFactory.changeWebDriver(WebDriver) API so that WebUI.xxx keywords can interact with the browser which was created by the script.

you can find more info at FlaskrTestInKatalonStudio | Testing a Blog web app with 2 browser windows using Selenium WebDriver in Katalon Studio. Includes a sample test script in Page Object Model.

A set of running sample test cases is included. I used the design pattern “Page Object Model” as well.

2 Likes

Hello, thank you for the library, it’s been useful in my project. I know you mentioned that you already lost interest with this in a previous post, but I’m using your library and the WebUI keywords do work, but the implicit waits that Katalon seems to do if I open the browser normally are not happening. Any idea of how I could fix this?

Does the following answer to your question?


Waiting for the page to load

By a call driver.navigate().to("http://127.0.0.1/"), we can open a browser and let it navigate to the URL specified. But this call does NOT perform implicit wait for the page to load completely. If you want to ensure that the page has been loaded, you need to do it explicitly.

There are several ways of implementing “wait for page to load”. The following sample code shows how to use WebUI.verifyElementPresent(TestObject, int timeout) keyword.

// Test Cases/analysis/4_wait_for_the_page_to_load

import org.openqa.selenium.WebDriver
import org.openqa.selenium.chrome.ChromeDriver

import com.kms.katalon.core.model.FailureHandling
import com.kms.katalon.core.testobject.ConditionType
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.webui.driver.DriverFactory
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI

String chrome_executable_path = DriverFactory.getChromeDriverPath()
System.setProperty('webdriver.chrome.driver', chrome_executable_path)

WebDriver browser = new ChromeDriver()
browser.navigate().to('http://127.0.0.1/')

// i can let WebUI.xxx keywords know the WebDriver instance created by my script
DriverFactory.changeWebDriver(browser)

// wait for the page to load
TestObject tObj = makeTestObject("site_name", "//h1[text()='Flaskr']")
//TestObject tObj = makeTestObject("site_name", "//h1[text()='FlaskR']")   // this will fail
WebUI.verifyElementPresent(tObj, 5, FailureHandling.STOP_ON_FAILURE)

WebUI.closeBrowser()

// helper method to create an instance of TestObject
TestObject makeTestObject(String id, String xpath) {
    TestObject tObj = new TestObject(id)
    tObj.addProperty("xpath", ConditionType.EQUALS, xpath)
    return tObj
}

By the way, as you know, the WebUI.openBrowser(String url) keyword does implicit wait. How is its implicit wait implemented? — You can find the source of the keyword at OpenBrowserKeyword.groovy. You can start reading the source and find its internal implementation. I think that explicit wait by WebUI.verifyElementPresent() keyword is easier in this case to understand, than trying to imitate the implicit wait by WebUI.openBrowser() keyword.