I get the following when running my Selenium framework in parallel mode using TestNG.
org.openqa.selenium.NoSuchSessionException: invalid session id
The issue only happens in parallel mode and when it runs in serial mode I have no issues what so ever.
Base Test
package training.testComponents;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.Duration;
import java.util.Properties;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import training.pageobjects.CartPage;
import training.pageobjects.CheckOutPage;
import training.pageobjects.HomePage;
import training.pageobjects.LandingPage;
import training.pageobjects.OrderConfirmationPage;
import training.pageobjects.OrdersPage;
public class BaseTest {
public WebDriver driver;
FileInputStream file;
Properties properties;
final String landingURL = "https://rahulshettyacademy.com/client";
final String landingTitle = "Let's Shop";
final String loginSuccessMessage ="Login Successfully";
final String loginFailMessage ="Incorrect email or password.";
final String cartPageTitle = "My Cart";
final String paymentPageTitle = "Payment Method";
final String successfulOrderText = "THANKYOU FOR THE ORDER.";
final int maxTimeOut = 1;
public LandingPage landing;
public HomePage home;
public CartPage cart;
public OrderConfirmationPage orderConfirmation;
public CheckOutPage checkOut;
public OrdersPage orders;
void initializeDriver() throws IOException {
properties = new Properties();
file = new FileInputStream(
System.getProperty("user.dir") + "\\src\\main\\java\\training\\resources\\GlobalData.properties");
properties.load(file);
String browserName = properties.getProperty("browser");
if (browserName.equalsIgnoreCase("chrome")) {
driver = new ChromeDriver();
}
if (browserName.equalsIgnoreCase("firefox")) {
driver = new FirefoxDriver();
}
if (browserName.equalsIgnoreCase("edge")) {
driver = new EdgeDriver();
}
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(maxTimeOut));
driver.manage().window().setPosition(new Point(0, 0));
driver.manage().window().setSize(new Dimension(1920, 1080));
}
@BeforeMethod(alwaysRun=true)//to run in all groups
public void lunchBrowser() throws IOException {
initializeDriver();
landing = new LandingPage(driver);
home = new HomePage(driver);
cart = new CartPage (driver);
orderConfirmation = new OrderConfirmationPage(driver);
checkOut = new CheckOutPage(driver);
orders = new OrdersPage(driver);
landing.goToLandingPage(landingURL);
Assert.assertTrue(landing.getLandingPageTitle().equalsIgnoreCase(landingTitle));
}
@AfterMethod(alwaysRun=true)//to run in all groups
public void closeBrowser() {
driver.close();
}
public String cartPageHeader() {
return cartPageTitle;
}
public String checkOutHeather() {
return paymentPageTitle;
}
public String orederConfirmationText() {
return successfulOrderText;
}
public String loginSuccessText() {
return loginSuccessMessage;
}
public String loginFailText() {
return loginFailMessage;
}
}
landing = new LandingPage(driver);
home = new HomePage(driver);
cart = new CartPage (driver);
orderConfirmation = new OrderConfirmationPage(driver);
checkOut = new CheckOutPage(driver);
orders = new OrdersPage(driver);
landing.goToLandingPage(landingURL);
Assert.assertTrue(landing.getLandingPageTitle().equalsIgnoreCase(landingTitle));
}
@AfterMethod(alwaysRun=true)//to run in all groups
public void closeBrowser() {
driver.close();
}
public String cartPageHeader() {
return cartPageTitle;
}
public String checkOutHeather() {
return paymentPageTitle;
}
public String orederConfirmationText() {
return successfulOrderText;
}
public String loginSuccessText() {
return loginSuccessMessage;
}
public String loginFailText() {
return loginFailMessage;
}
}
Test Class 1
package training.tests;
import java.io.IOException;
import org.testng.Assert;
import org.testng.annotations.Test;
import training.testComponents.BaseTest;
public class PlaceOrderTests extends BaseTest {
String pass = "Password123";
String user = "randomemail@random.com";
String itemName = "ZARA";
@Test
public void submitOrder() throws IOException {
String inputText = "IND";
String wantedCountry = "india";
// Landing page login
Assert.assertTrue(landing.logInSecuence(user, pass).equalsIgnoreCase(loginSuccessText()));
// Product Catalog Page
Assert.assertTrue(home.addProductToCart(itemName));
home.goToCart();
// my cart page
Assert.assertTrue(cart.getPageHeadther().equalsIgnoreCase(cartPageHeader()));
Assert.assertTrue(cart.verifyItemInCart(itemName));
cart.goToCheckout();
// Checkout page
Assert.assertTrue(checkOut.getPageHeadther().equalsIgnoreCase(checkOutHeather()));
Assert.assertTrue(checkOut.selectCountry(inputText, wantedCountry));
checkOut.placeOrder();
// Order Confirmation
Assert.assertTrue(orderConfirmation.verification().equalsIgnoreCase(orederConfirmationText()));
}
@Test(dependsOnMethods= {"submitOrder"})
public void wrongProductName() throws IOException {
// Landing page login
Assert.assertTrue(landing.logInSecuence(user, pass).equalsIgnoreCase(loginSuccessText()));
// Product Catalog Page
Assert.assertTrue(home.addProductToCart(itemName));
home.goToCart();
// my cart page
Assert.assertTrue(cart.getPageHeadther().equalsIgnoreCase(cartPageHeader()));
Assert.assertFalse(cart.verifyItemInCart(itemName+"AAA"));
}
@Test
public void verifyOrder() throws IOException {
// Landing page login
Assert.assertTrue(landing.logInSecuence(user, pass).equalsIgnoreCase(loginSuccessText()));
// Product Catalog Page
Assert.assertTrue(home.addProductToCart(itemName));
home.goToOrders();
// my cart page
Assert.assertTrue(orders.orderIsDisplayed(itemName));
}
}
Test Class 2
package training.tests;
import org.testng.Assert;
import org.testng.annotations.Test;
import training.testComponents.BaseTest;
public class ErrorValidationsTests extends BaseTest {
String pass = "Password";
String user = "randomemail@random.com";
@Test(groups= {"Error Handling"})
public void wrongPassword() {
Assert.assertTrue(landing.logInSecuence(user, pass).equalsIgnoreCase(loginFailText()));
}
}
Page Objects
package training.pageobjects;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import training.abstractcomponents.AbstractComponents;
public class LandingPage extends AbstractComponents {
// local variables
WebDriver driver;
// constructor
public LandingPage(WebDriver driver) {
// driver initialization
super(driver);
this.driver = driver;
PageFactory.initElements(driver, this);
}
// Page Factory
// UserID box
@FindBy(id = "userEmail")
WebElement userID;
// Password box
@FindBy(id = "userPassword")
WebElement password;
// Login button
@FindBy(id = "login")
WebElement loginButton;
// Login confirmation
@FindBy(xpath = "//*[@aria-label='Login Successfully']")
WebElement loginToast;
// Login failed
@FindBy(className = "toast-error")
WebElement loginToastFail;
// Action Methods
public void goToLandingPage(String landingURL) {
driver.get(landingURL);
}
public String getLandingPageTitle() {
return driver.getTitle();
}
public String logInSecuence(String id, String pass) {
String text = null;
userID.sendKeys(id);
password.sendKeys(pass);
loginButton.click();
try {
if (loginToast.isDisplayed()) {
text = loginToast.getText();
waitForElementInvisibility(loginToast);
}
} catch (NoSuchElementException e) {
if (loginToastFail.isDisplayed() == true) {
text = loginToastFail.getText();
waitForElementInvisibility(loginToastFail);
}
}
return text;
}
}
package training.pageobjects;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import training.abstractcomponents.AbstractComponents;
public class HomePage extends AbstractComponents {
private WebDriver driver;
public HomePage(WebDriver driver) {
// TODO Auto-generated constructor stub
super(driver);
this.driver = driver;
PageFactory.initElements(driver, this);
}
// By locators
// Displayed product name
static By productBy = By.tagName("b");
// Add to cart button
static By addToCart = By.className("w-10");
// Page Factory
// Catalog elements
@FindBy(className = "mb-3")
private List<WebElement> products;
// waiting spinner
@FindBy(className = "ng-animating")
private WebElement spinner;
// added to cart toast
@FindBy(className = "toast-success")
private WebElement toastAdded;
// Action Methods
List<WebElement> getProductCatalog() {
waitForElementVisibility(products.get(1));
return products;
}
public boolean addProductToCart(String productName) {
WebElement prod = getProductCatalog().stream()
.filter(product -> product.findElement(productBy).getText().contains(productName)).findFirst()
.orElse(null);
if (prod != null) {
prod.findElement(addToCart).click();
waitForElementVisibility(spinner);
// waitForElementInvisibility(spinner);
waitForElementVisibility(toastAdded);
waitForElementInvisibility(toastAdded);
return true;
} else {
return false;
}
}
}
package training.pageobjects;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import training.abstractcomponents.AbstractComponents;
public class CartPage extends AbstractComponents {
private WebDriver driver;
// By locators
// Items in cart
static By cartSection = By.xpath("//ul[contains(@class,'cartWrap')]");
public CartPage(WebDriver driver) {
super(driver);
this.driver = driver;
PageFactory.initElements(driver, this);
}
@FindBy(xpath = "//ul[contains(@class,'cartWrap')]")
private List<WebElement> cart;
@FindBy(xpath = "//*[contains(@class, 'totalRow')]/button")
private WebElement checkOutButton;
@FindBy(xpath = "//h1[contains(text(), 'My Cart')]")
static WebElement myCartTitle;
// Action Methods
List<WebElement> getCartItems() {
waitForElementVisibility(cart.get(0));
return cart;
}
public boolean verifyItemInCart(String productName) {
boolean match = getCartItems().stream()
.anyMatch(items -> items.findElement(cartSection).getText().contains(productName));
return match;
}
public void goToCheckout() {
checkOutButton.click();
}
public String getPageHeadther() {
return myCartTitle.getText();
}
}
package training.pageobjects;
import java.util.List;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import training.abstractcomponents.AbstractComponents;
public class CheckOutPage extends AbstractComponents {
private WebDriver driver;
public CheckOutPage(WebDriver driver) {
super(driver);
this.driver = driver;
PageFactory.initElements(driver, this);
}
// country text box
@FindBy(xpath = "//input[@placeholder='Select Country']")
private WebElement countryInput;
// county options
@FindBy(xpath = "//section/button")
private List<WebElement> countryOptions;
// place order button
@FindBy(xpath = "//a[contains(@class, 'submit')]")
private WebElement placeOrder;
@FindBy(xpath = "//*[@class='payment__title']")
static WebElement paymentTitle;
List<WebElement> getCountryOptions(String input) {
countryInput.sendKeys(input);
waitForElementVisibility(countryOptions.get(0));
return countryOptions;
}
public boolean selectCountry(String input, String option) {
List<WebElement> countries = getCountryOptions(input);
suggestiveTextBox(countries, option).get(0).click();
return (getInputText(countryInput).equalsIgnoreCase(option));
}
public void placeOrder() {
placeOrder.click();
}
public String getPageHeadther() {
return paymentTitle.getText();
}
}
package training.pageobjects;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import training.abstractcomponents.AbstractComponents;
public class OrderConfirmationPage extends AbstractComponents {
private WebDriver driver;
public OrderConfirmationPage(WebDriver driver) {
super(driver);
this.driver = driver;
PageFactory.initElements(driver, this);
}
@FindBy(tagName = "h1")
private WebElement confirmationText;
public String verification() {
return confirmationText.getText();
}
}
package training.pageobjects;
import java.util.List;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import training.abstractcomponents.AbstractComponents;
public class OrdersPage extends AbstractComponents{
private WebDriver driver;
@FindBy(xpath = "//tr/td[2]")
private List<WebElement> productNames;
public OrdersPage(WebDriver driver) {
// TODO Auto-generated constructor stub
super(driver);
this.driver = driver;
PageFactory.initElements(driver, this);
}
public boolean orderIsDisplayed(String productName) {
boolean match;
match = productNames.stream().anyMatch(product->product.getText().contains(productName.toLowerCase()));
return match;
}
}
Common methods for the Page Objects
package training.abstractcomponents;
import java.time.Duration;
import java.util.List;
import java.util.stream.Collectors;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import training.pageobjects.CartPage;
import training.pageobjects.HomePage;
import training.pageobjects.OrdersPage;
public class AbstractComponents {
protected WebDriver driver;
int maxDuration = 5;
HomePage home;
OrdersPage orders;
CartPage cart;
public AbstractComponents(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
// Banner Elements
@FindBy(xpath = "//button[@routerlink = '/dashboard/']")
WebElement homeButton;
@FindBy(xpath = "//button[contains(@routerlink,'myorders')]")
WebElement ordersButton;
@FindBy(xpath = "//button[contains(@routerlink,'cart')]")
WebElement cartButton;
@FindBy(className = "fa-sign-out")
WebElement signOutButton;
public HomePage goToHome() {
homeButton.click();
home = new HomePage(driver);
return home;
}
public OrdersPage goToOrders() {
ordersButton.click();
orders = new OrdersPage(driver);
return orders;
}
public CartPage goToCart() {
cartButton.click();
cart = new CartPage(driver);
return cart;
}
public void signOut() {
signOutButton.click();
}
public void waitForElementVisibility(WebElement element) {
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(maxDuration));
wait.until(ExpectedConditions.visibilityOf(element));
}
public void waitForElementInvisibility(WebElement element) {
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(maxDuration));
wait.until(ExpectedConditions.invisibilityOf(element));
}
public List<WebElement> suggestiveTextBox(List<WebElement> elements, String option) {
return elements.stream().filter(country -> country.getText().equalsIgnoreCase(option))
.collect(Collectors.toList());
}
public String getInputText(WebElement countryInput) {
return countryInput.getAttribute("value");
}
}
TestNG XML file
?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="methods">
<test thread-count="5" name="Place Order Tests">
<classes>
<class name="training.tests.PlaceOrderTests"/>
</classes>
</test> <!-- Test -->
<test thread-count="5" name="Login Error Validations Tests">
<classes>
<class name="training.tests.ErrorValidationsTests"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
I have tried changing the driver to static in both the base class and the PO I even tried with ThreadLocal, but wasn't able to make it work.
If anyone wants the full code, it can be found here
https://github.com/MReyes-1/seleniumTraining/tree/main/SeleniumFramework
Looks like there is something with the driver initialization but not sure what