How to execute parallel tests using Selenium, Java, and TestNG with the Page Factory pattern?

I am having trouble with my test execution. When running the tests sequentially they pass, but when run in parallel multiple times across different browsers, they fail. I have tried using threadlocal and manipulating driver object hashcodes, but nothing seems to work. Even adjusting the maven threadpoolsize didn't yield the desired results.

I'm stuck and would appreciate any help. I can't seem to find a blog or resource that clearly explains how to execute tests in parallel using the page factory pattern. Simple scripts with all Selenium actions written directly in the test method work fine, but incorporating page factory for code reusability and maintenance seems to throw things off.

My scenario involves multiple test classes and multiple pages. Any assistance would be greatly appreciated.

    public class WebDriverManager {

        private static HashMap<Long, WebDriver> map = new HashMap<>();

        public static WebDriver getDriverInstance() {
            return map.get(Thread.currentThread().getId());
        }

        public static void startDriver(String OS_Browser) throws Exception {
            WebDriver driver;

            if (OS_Browser.equalsIgnoreCase("Win7_Chrome"))
                ChromeDriverManager.getInstance().version("2.31").setup();
                driver = new ChromeDriver();
                map.put(Thread.currentThread().getId(), driver);
        }

        public static void stopDriver() {
            WebDriver driver = map.get(Thread.currentThread().getId());
            if (null != driver) {
                driver.quit();
                driver = null;
            }
        }
    }

<!-- language: java -->

public class Login extends TestBase {

    @Parameters({"OS_Browser"})
    @BeforeMethod(alwaysRun = true)
    protected void oneTimeSetup(@Optional("Win7_Chrome") String OS_Browser) throws Exception {
        WebDriverManager.startDriver(OS_Browser);
    }

    @AfterMethod(alwaysRun = true)
    protected void oneTimeTeardown() {
        WebDriverManager.stopDriver();
    }


    @Test()
    public void Test_Error_Messages_For_Blank_Invalid_Incorrect_login_Credentials() throws Exception {
        WebDriver driver = WebDriverManager.getDriverInstance();
        driver.get(url);

        Login_Page LoginPage = new Login_Page(driver);

        LoginPage.wait_For_Login_PageLoad()
                // UI Validation
                .verify_Color_On_Links()
                .verify_Texts_On_Login_Page()
                .verify_Header_Logos()
                // Check error messages for blank email and password
                .click_SignIn()
                .wait_For_Blank_Credentials_Error_Message()
                // Check error messages for invalid email and password
                .login("admin", "admin")
                .wait_For_Invalid_Credentials_Error_Message()
                // Check error messages for incorrect email and password
                .login("<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2f4e4b4246416f575655014c4042">[email protected]</a>", "admin")
                .wait_For_Incorrect_Credentials_Error_Message();
    }
}
public class Login_Page {

    private final WebDriver driver;

    @FindBy(css = "input#email")
    private WebElement login_username;
    @FindBy(css = "input#password")
    private WebElement login_password;
    @FindBy(css = "button#signin")
    private WebElement button_signIn;

    @FindBy(css = "a[ng-click*='terms']")
    private WebElement terms_of_use;
    @FindBy(css = "a[ng-click*='privacy']")
    private WebElement privacy_policy;
    @FindBy(css = "a[ng-click*='trademarks']")
    private WebElement trademarks;
    @FindBy(css = "a[ng-click*='ContactUs']")
    private WebElement contactus;

    @FindBy(css = "fieldset > div:nth-of-type(1) > p")
    private WebElement signin_text;
    @FindBy(css = ".container.ng-scope>img")
    private WebElement header_logo;

    @FindBy(css = "p[ng-show*='error.email'][aria-hidden='false']")
    private WebElement enter_valid_email_address_error_message;
    @FindBy(css = "p[ng-show*='loginform.emailaddress.$error.required'][aria-hidden='false']")
    private WebElement email_required_error_message;
    @FindBy(css = "p[ng-show*='loginform.password.$error.required'][aria-hidden='false']")
    private WebElement password_required_error_message;
    @FindBy(css = "span[translate='sign_error_msg']")
    private WebElement enter_correct_credentials;

    @FindBy(css = "img[src='img/common/ajax_progress.gif']")
    private WebElement pleaseWait;

    // Constructor takes a reference to the driver
    public Login_Page(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }

    public Login_Page click_SignIn() {
        button_signIn.click();
        return this;
    }

    public Login_Page login(String username, String password) {
        login_username.clear();
        login_username.sendKeys(username);

        login_password.clear();
        login_password.sendKeys(password);

        button_signIn.click();

        (new WebDriverWait(driver, 10))
                .until(ExpectedConditions.invisibilityOf(pleaseWait));
        return this;
    }

    public Login_Page wait_For_Blank_Credentials_Error_Message() throws InterruptedException {
        (new WebDriverWait(driver, 10)).until(ExpectedConditions.and(
                ExpectedConditions.visibilityOf(password_required_error_message),
                ExpectedConditions.visibilityOf(email_required_error_message)));

        String emailRequiredErrorMessage = email_required_error_message.getText().trim();
        Assert.assertEquals(emailRequiredErrorMessage, "Your email address is required to proceed.");

        String passwordRequiredErrorMessage = password_required_error_message.getText().trim();
        Assert.assertEquals(passwordRequiredErrorMessage, "Your password is required to proceed.");

        return this;
    }

    public Login_Page wait_For_Invalid_Credentials_Error_Message() throws InterruptedException {
        (new WebDriverWait(driver, 10))
                .until(ExpectedConditions.visibilityOf(enter_valid_email_address_error_message));

        String ErrorMessage = enter_valid_email_address_error_message.getText().trim();
        Assert.assertEquals(ErrorMessage, "Please enter the email address in a valid format.");

        return this;
    }

    public void wait_For_Incorrect_Credentials_Error_Message() {
        (new WebDriverWait(driver, 10))
                .until(ExpectedConditions.visibilityOf(enter_correct_credentials));
        String ErrorMessage = enter_correct_credentials.getText().trim();
        Assert.assertEquals(ErrorMessage, "Sign-in credentials did not match. If you have not created an account with your email address and a password, you will need to do so before signing in.");
    }

    public Login_Page verify_Color_On_Links() {
        String blue_Link_Color = "#026091";
        List<WebElement> allLinks = driver.findElements(By.cssSelector("body a[href='#']"));
        for (WebElement ele : allLinks) {
            String color = ele.getCssValue("color");
            String colorInHex = Color.fromString(color).asHex();
            assertEquals(colorInHex, blue_Link_Color);
        }
        return this;
    }

    public Login_Page verify_Texts_On_Login_Page() {
        String actual1 = signin_text.getText().trim();
        String expected1 = "Please enter your email address and password in order to proceed.";
        Assert.assertTrue(actual1.contains(expected1));
        return this;
    }

    public Login_Page verify_Header_Logos() {
        int headerLogoWidth = header_logo.getSize().getWidth();
        int headerLogoHeight = header_logo.getSize().getHeight();
        Assert.assertEquals(headerLogoWidth, 480);
        Assert.assertEquals(headerLogoHeight, 100);
        return this;
    }

    public Login_Page wait_For_Login_PageLoad() {
        JSWaiter.waitJQueryAngular();
        (new WebDriverWait(driver, 15)).until(ExpectedConditions.and(
                ExpectedConditions.visibilityOf(login_username),
                ExpectedConditions.visibilityOf(login_password),
                ExpectedConditions.visibilityOf(button_signIn)));
        return this;
    }

}
<?xml version="1.0"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Login Suite" parallel="tests" thread-count="2">
    <parameter name="URL" value="www.google.co.in"/>
    <test name="Login Tests - Win7_Chrome">
        <parameter name="OS_Browser" value="Win7_Chrome"/>
        <classes>
            <class name="com.company.tests.Login"/>
        </classes>
    </test>
    <test name="Login Tests - Win7_IE">
        <parameter name="OS_Browser" value="Win7_IE"/>
        <classes>
            <class name="com.company.tests.Login"/>
        </classes>
    </test>
</suite>

Answer №1

The issue lies within your test code structure. You have implemented the webdriver creation logic within a method annotated with @BeforeTest.

It's important to note that TestNG only triggers a @BeforeTest method once for each <test> tag.

In addition, your code stores webdriver instances in a map using the thread id as the key.

While this setup may work smoothly for sequential execution, problems may arise when transitioning to a parallel execution model. This is because TestNG does not guarantee that a @BeforeTest and a @Test method will run on the same thread.

To address this issue initially, consider switching to using @BeforeMethod instead of @BeforeTest. By storing the webdriver instance in a ThreadLocal, TestNG ensures that @BeforeMethod > @Test > @AfterMethod always run on the same thread.

Alternatively, you can move the webdriver setup and teardown tasks to a listener that you can link to your test classes. This approach maintains separation of concerns and prevents your test class from being cluttered with webdriver lifecycle management.

For more information on managing parallel executions in TestNG using listeners, check out my blog post here.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

WebDriver: Error during compilation in custom wrapper classes for web elements and drivers

// Can I use my own custom elements instead of the predefined selenium web elements such as webElement and WebDriver? To achieve this, I have created two custom wrapper classes: // Custom wrapper for WebDriver package org.rsf.wrapper.driver; import org.o ...

Populating Recyclerview with data from a JSONObject containing a single string with various values

In my application, I am dealing with a `DataList` jsonArray that contains a jsonObject named `Data`. The string within the `Data` object consists of various values separated by the character "´". These values correspond to the keys in the "Headers" obje ...

Managing Windows Authorization using Selenium WebDriver and Internet Explorer 10 - A Step-by-Step Guide

I am experiencing difficulties with Windows authentication while trying to create an automation test (in C#) using Selenium Webdriver with the InternetExplorer Driver. Although I can access https//username:[email protected] successfully through Firef ...

Replacing the previous Excel sheet with a new one in the POI

When I create a new sheet, it works fine. However, when I try to call the same method to create another sheet, it overrides the previous one. After multiple method calls, only the last sheet is showing up. Each time, I am creating a new sheet and not a ne ...

How to efficiently write to a CSV file and add to a list at the same time using Python

Scenario: The code snippet below utilizes Selenium to locate a series of links from the Simply Recipe Index URL, then saves them in a list named linklist. The script proceeds to loop through each link in the linklist, fetching recipe text and storing it i ...

Automate the process of logging into websites by utilizing selenium webdriver technology

Having trouble logging in to a website using selenium webdriver and excel VBA, specifically getting stuck at the log in page Below is the code being used: Dim bot As New WebDriver bot.Start "chrome", "myurl" bot.Get "/" 'select from drop down bot. ...

How can I retrieve the specific date of a LinkedIn post using Selenium for site inspection?

Currently, I am utilizing the Selenium Chrome driver to scrape profiles on LinkedIn. I am conducting an analysis for my blog post. I am looking for a method to extract precise dates from posts on LinkedIn in the format "dd.mm.yyyy" rather than "1 month ag ...

Guide to switching to the next window using Python's selenium package

Task: Log in to the main page using username/password credentials. Once logged in, a new page will appear with a dropdown button. Select an option from the dropdown and capture a snapshot of the page. from selenium import webdriver from selenium.webdriver ...

Issue encountered while creating code - Python Selenium Type Error

My code is throwing an error message that says "selenium.common.exceptions.WebDriverException: Message: TypeError: BrowsingContextFn().currentWindowGlobal is null." Can someone assist me with this? Here is the snippet of my code: from instapy import Insta ...

Firefox seems to be disregarding the designated download location

My issue arises when attempting to download a file by clicking a button in Firefox. Everything seems to be working fine, except that the browser ignores the specified download directory and instead puts everything in the Downloads folder. While running t ...

I have developed a selenium script specifically for the odoo framework using Python. Can this script be utilized for conducting load testing? If so, what would be the recommended approach for implementing

After developing a script with Selenium in the Odoo framework using Python, I am now looking to perform load testing. What would be the most suitable tool for this task? Do I need to create a separate script specifically for load testing, or can I utiliz ...

Having trouble running Selenium through Protractor on Firefox following the Angular 2 update

Following the upgrade from Angular JS 1.4.x to Angular 2, encountering issues running Selenium tests through grunt-protractor-runner on Firefox. Once AngularJS is loaded, an unexpected error pops up: D:\...\node_modules\grunt-protractor-ru ...

Waiting for Elements to be Added to Parent in a Lazy Loading Website with Selenium and Python

When working with Selenium's expected conditions for wait, such as those mentioned here: https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions, I find myself unsure about which one to use or if that is e ...

Looking for guidance on organizing and editing a JSON payload in Java?

Displayed here is a simplified JSON payload that requires some modifications (the original version is longer). { "request": { "jsonRequest": { "Alpha": { "Bravo": [ { "D ...

Selenium error message related to character encoding in UTF-8

I am trying to access all correios agency information in Brazil by web scraping using Selenium. However, I am encountering some issues with utf-8 encoding in my code. How can I resolve this and set everything to utf-8 format? Here is the code snippet I am ...

Trouble with clicking in Selenium when using the MicrosoftEdge webdriver

I attempted the usual var elementForMs = driver.findElement(By.xpath(selector)); driver.executeScript("arguments[0].click()", elementForMs); as well as var elementForMs = driver.findElement(By.css(selector)); driver.executeScript("arguments[0].click()" ...

Encountering difficulties in uploading a file with Selenium in Java

I am facing an issue while trying to upload a picture on this platform. Below is the code snippet that I used: public static void main(String[] args) throws InterruptedException { System.setProperty("webdriver.chrome.driver", "I:\\Selenium ...

The order in which the test cases are executed by TestNG has been altered with the latest update to version 6.14

After updating the TestNG version to 6.14.2, I started encountering issues with running sequences that were not present when using version 6.8.8. Despite trying various solutions such as changing priorities, the tests did not run as expected. For more deta ...

What is the correct way to loop through a collection of web elements in Selenium WebDriver using Python?

My current project involves testing a webpage containing a list of product articles. Each article includes an item title, price, stock availability tag, and an add to cart button. To achieve my goal, I am attempting to gather all the product articles using ...

This method or property is not supported by the object - How to call an Applet in Internet Explorer 9

cmd > java -version Java Version : "1.7.0_11" (Updated) Java(TM) SE Runtime Environment (build 1.7.0_11-b21) Java HotSpot(TM) Client VM (build 23.6-b04, mixed mode, sharing) browsers = IE7,IE8,IE9 (The functionality works smoothly in Google Chrome and ...