Multiple web drivers are not working as expected

Hi,

I want to automate a scenario of our applcaition where I need to open two chrome browser instacnes i,e one in normal mode and the other one in incognito mode. I want to perform some actions on applciations opened in both browsers simulataneously.

After some search I came across similar solution posted by @ [kazurayam] How to open 2 Chrome browser windows and perform test on both simultaneously which suits my requirements. But I am struggling to implememnt this solution slightly in different way. As per the suggeseted solution, we are initializing and using web drives in same test case. My intention is to implement this as

TC1

  • Initialize normal chrome driver
  • Assign web driver to global variable to use it in another TC as
    Globalvariable.normalDriver = DriverFactory.getWebDriver

TC2

  • Initialize incognito driver
    Assign web driver to global variable to use it in another TC as
    Globalvariable.incognitoDriver = DriverFactory.getWebDriver

TC3

  • Implement actual scenario and do actions as

  • Need to perform actions on normal mode browser, do this
    DriverFactory.changeWebDriver(Globalvariable.normalDriver)

  • Perform some actions

  • Need to perform actions on incognito mode browser, do this
    DriverFactory.changeWebDriver(Globalvariable.incognitoDriver)

  • Perform some actions

The Problem - Based on the above logic, I can switch to respective browser instance but somehome, respective drive is not able to identify web elements and actions starts failing with ElementNotFoundException.

If I put all actions/code in a single test case including both web driver initialization then the code works perfectly (as mentioned in given link). I also confirmed from console logs that when I do DriverFactory.changeWebDriver(Globalvariable.incognitoDriver), it is using correct driver info with correct session ID’s. But, unable to click on UI elements somehow.

Now, I am clueless about this problem. I dont want to put all actions/code in single test case because so far my project structure is where I am trying to make test cases as much reuseable as possible. Putting all the stuff in single test case doesn’t fit within my project.

Regards,

I think this would never work.

In a single “test case”, you can use other ways of struturing your codes: such as Groovy class, Groovy functions by def.

I am not sure weather it will work or not so just tried. I also tried like
public class VariableCollection {

public static WebDriver Driver

}
and then

VariableCollection.Driver = DriverFactory.getWebDriver

But getting same results

Actually, I have a dedicated driver initialization test case along with navigating to some URL so that’s why i don’t want to do the same in another test case. My intention is to use web driver initlized in this test case at some other place without doing the same stuff again.

I suppose you think you can do the following:

  1. TestSuiteX calls TestCase1 (initialize WebDriver, store it into a GlobalVariable.normalDriver)
  2. TestSuiteX calls TestCase2 (refer to the GlobalVariable.normalDriver, get a TCP connection to browser)
  3. TestSuiteX calls TestCase3 (refer to the GlobalVariable.normalDriver, get a TCP connection to browser)
  4. TestSuiteX calls TestCase4 (refer to the GlobalVariable.normalDirver, get a TCP connection to browser)

I don’t think it will work reliablly.

Why? You can instaticate a WebDriver in the TestCase1, but that instance will become void as soon as the TestCase1 exits. The TestCase2 can refer to GlobalVariable.normalDirver which is meaningless — there is no TCP session between your test script and Chrome browser is maintained.

Rather you should try the following structure:

  1. TestSuiteX calls TestCase1
    • TestCase1 calls TestCase2
    • TestCase1 calls TestCase3
    • TestCase1 calls TestCase4

TestCase1 will use CallTestCase() keyword like this:

WebDriver driver = DirverFactory.getWebDriver()
WebUI.callTestCase("TestCase2", ["driver": driver])
WebUI.callTestCase("TestCase3", ["driver": driver])
WebUI.callTestCase("TestCase4", ["driver": driver])
// make sure you gently close the TCP session
driver.quit()

Please note that TestCase1 passes driver to TestCase2, 3, 4. The “driver” variable a referece to an active WebDriver instance that maintains a TCP session to browser.

When “TestCase2” is called by “TestCase1” via callTestCase keyword, the “TestCase2” becomes just a subroutine included into the “TestCase1”. Katalon Studio does not regard “TestCase2” as an independent Test Case instance in this case. Therefore you would not see the name “TestCase2” in the built-in report at all.

If you do no like to use callTestCase() keyword, you can do similar modularization using class or def of Groovy language.

I wrote:

Let me explain this more clearly.

See the Groovy language documentation

“3.2 Script class” shows the following example:

import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {                     
    def run() {                                 
        println 'Groovy world!'                 
    }
    static void main(String[] args) {           
        InvokerHelper.runScript(Main, args)     
    }
}

What is called "Test Case " goes inside the def run() { ... }. This is what is actually going behind the scene.

In other words, your test case script can instanciate a Web Driver, as this:

import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {                     
    def run() {                                 
        ...        
        def driver = new ChromeDriver()
        ...
    }
    static void main(String[] args) {           
        InvokerHelper.runScript(Main, args)     
    }
}

The driver variable is valid only inside the scope of run() method, which is actually a TestCase in Katalon term.

Thanks for your detailed reply, reaaly appreciate it.

I am already doing more/less the same way as you suggested. My structure/ requirement is as

TestSuiteX

  • Test Suite SetUp - Call TC1 which will start browser after driver initalization, store driver info at some place.
  • Call TC2 - Do some actions on opened browser
  • TC2 will call TC3 which will start browser in incognito mode, save driver info at some place.
  • TC2 with then try to use first driver instance to do actions in normal browser.
  • TC2 will then try to use second driver instance to do actions in incognito browser.
  • TC2 will close incognito browser once scenario completed
  • Normal browser will keep running for next test execution.

As I mentioned in original post, switching is working fine and even actions like

WebUI.switchToWindowTitle(‘Test App’)
WebUI.delay(1)
WebUI.waitForElementPresent(findTestObject(‘Customer_Widget_Objects/LiveChat/iframe_LiveChatWindow’), 30)

are also working fine after switching to desired browser but after that, nothing is working.

I will try to make a sample project to demonstrate what I am trying to achieve.

This would not work.

Thanks for your feedback. I will look around for some other solution for my scenario.

Anyway, I created a demo project which mimic the same implementation and problem as I do have in my actual project. If someone would like to see what I want to achieve and how I am trying to do this?

multiDriverSwitchingProject.rar (1.1 MB)

I tried to activate your Test Suite/New Test Suite. It gave me an error.

2022-10-12 06:20:29.141 ERROR c.k.k.core.keyword.internal.KeywordMain  - ❌ Web element with id: 'Object Repository/btn_Logout' located by '//a[@title='Log me out']' not found (Root cause: com.kms.katalon.core.exception.StepFailedException: Web element with id: 'Object Repository/btn_Logout' located by '//a[@title='Log me out']' not found
	at com.kms.katalon.core.webui.keyword.internal.WebUIKeywordMain.stepFailed(WebUIKeywordMain.groovy:64)
	at com.kms.katalon.core.webui.keyword.builtin.VerifyElementVisibleKeyword$_verifyElementVisible_closure1.doCall(VerifyElementVisibleKeyword.groovy:89)
	at com.kms.katalon.core.webui.keyword.builtin.VerifyElementVisibleKeyword$_verifyElementVisible_closure1.call(VerifyElementVisibleKeyword.groovy)
	at com.kms.katalon.core.webui.keyword.internal.WebUIKeywordMain.runKeyword(WebUIKeywordMain.groovy:20)
	at com.kms.katalon.core.webui.keyword.builtin.VerifyElementVisibleKeyword.verifyElementVisible(VerifyElementVisibleKeyword.groovy:97)
	at com.kms.katalon.core.webui.keyword.builtin.VerifyElementVisibleKeyword.execute(VerifyElementVisibleKeyword.groovy:67)
	at com.kms.katalon.core.keyword.internal.KeywordExecutor.executeKeywordForPlatform(KeywordExecutor.groovy:74)
	at com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords.verifyElementVisible(WebUiBuiltInKeywords.groovy:376)
	at com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords$verifyElementVisible$4.call(Unknown Source)
	at loginToWebSite.run(loginToWebSite:47)

Your Test Cases/loginToWebSite has the following lines:

DriverFactory.changeWebDriver(VariableCollection.normalDriver)

WebUI.refresh()

// failed at this line
WebUI.verifyElementVisible(findTestObject('btn_Logout'))

WebUI.click(findTestObject('btn_Logout'))

You should not call WebUI.verifyElementVisible() keyword here. It does NOT wait for the target element to appear on the display in 1 or 2 seconds. The verifyELementVisible will fail as soon as it finds the target element is absent while the page is still loading.

Instead, you should write:

WebUI.verifyElementPresent(findTestObject('btn_Logout'), 10)

or WebUI.waitForElementVisible(TestObject, Integer timeout) will do.

Keywords with “timeout” would wait for specified seconds as maximum until the page is loaded completely and the target element becomes present in the page.

The error has nothing to do with the configuration of Multiple WebDrivers.

@ kazurayam - I finally managed to make my script workable using the guidelines you prvided. Marking one of your reply as solution.