Cucumber-JVM: Parallel execution not exactly parallel - java

I had coded two features file and each of the features file open different browser URL for example one is open google.com and secnd one open amazon.com but this is not the case.
Bothe browsers open google.com. Moreover, it cannot interact with the browser, any actions coded to the browser is not get executed. Besides this, closing first browser cause second browser has null pointer exception.
Cucumber version 6 I start with AbstractCucumberTesNG inheritance. Then i create Login.Feature and follow by AddProduct.Feature.
The expected behaviour should be one browser open phptravels.net website and another browser open http://sellerceter.lazada.my.
This is not the case with my current situation where it open two browsers with phptravels.net, after cloing one browser it open seller.lazada website.
public class AddProduct {
private WebDriverWait timeWait;
private AddProductPageObject page;
private ChromeDriver driver;
private Logger log = LogManager.getLogger(AddProduct.class);
// ======================================================================
public AddProduct() {
}
#Given("navigate to manage product")
public void navigateToManageProduct() {
log.info("Start Login");
try {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
this.timeWait = new WebDriverWait(driver, 30);
page = PageFactory.initElements(driver, AddProductPageObject.class);
driver.navigate().to("https://sellercenter.lazada.com.my/apps/seller/login");
timeWait.until(ExpectedConditions.visibilityOfElementLocated(page.getLazadaSellerLogo()));
// Input username
driver.findElement(page.getUsername()).click();
driver.findElement(page.getUsername()).clear();
driver.findElement(page.getUsername()).sendKeys("nicholaswkc34#gmail.com");
// Input password
driver.findElement(page.getPassword()).click();
driver.findElement(page.getPassword()).clear();
driver.findElement(page.getPassword()).sendKeys("wlx_+279295");
// Click submit btn
driver.findElement(page.getSignInButton()).click();
//assertThat(page.getPageTitle())
Wait wait = new Wait();
wait.implicitWait(driver, 5);
} catch (Exception e) {
log.error(e);
}
}
}
public class Login_FE {
private WebDriverWait timeWait;
private LoginPageObject page;
private ChromeDriver driver;
private Logger log = LogManager.getLogger(Login_FE.class);
// ======================================================================
public Login_FE() {
}
#Given("Launch the homepage and login")
public void launchTheHomepageAndLogin() {
log.info("Start Login");
try {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
timeWait = new WebDriverWait(driver, 30);
// Instantiate LoginPageObject
page = PageFactory.initElements(driver, LoginPageObject.class);
log.info("Navigate to phptravels homepage");
driver.navigate().to("https://www.phptravels.net/admin");
timeWait.until(ExpectedConditions.visibilityOfElementLocated(page.getPhpLogo()));
Actions inputAct = new Actions(driver);
inputAct.sendKeys("admin#phptravels.com").perform();
driver.findElement(page.getUsername()).sendKeys("admin#phptravels.com");
Wait wait = new Wait();
wait.implicitWait(driver, 3);
}catch(Exception e) {
log.error(e);
}
log.info("Login Successfully");
}
}

Im using the same concept for testing mobile apps. So in order to open 2 browsers and to interact with them separately you have to store the driver while initiating in a threadlocal like below :
private static ThreadLocal<AppiumDriver<MobileElement>> appiumDriver = new ThreadLocal<>();

Related

How to run two test methods in two different browser in parallel using TestNG?

I have one test case contains two methods. When trying the two test methods in two browser instance, only one browser instance can open the website but the rest of the steps can't execute. Another browser instance can't even open the website (blank page).
I've tried the suggested solution on Stackoverflow. Those solutions do not work in my case.
public class RunSimpleTest{
private String baseUrl = "https://mywebsite";
public WebDriver driver;
GlobalFunctions objGlobalFunc;
#BeforeMethod(alwaysRun = true)
public void setup() {
try{
// declaration and instantiation of objects/variables
System.setProperty("webdriver.chrome.driver", "C:/ChromeDriver/chromedriver.exe");
// Disable Chrome Developer Mode Extension
ChromeOptions options = new ChromeOptions();
options.addArguments("--disable-extensions");
options.addArguments("--start-maximized");
driver = new ChromeDriver(options);
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
objGlobalFunc = new GlobalFunctions(driver);
driver.get(baseUrl);
objGlobalFunc = new GlobalFunctions(driver);
objGlobalFunc.selectEnglishLanguage();
}
catch (Exception e){
e.printStackTrace();
}
}
#Test
public void BTRun1() {
objGlobalFunc.setUserNameValue("ABC");
objGlobalFunc.clickOKBtnOnMEXLoginForm();
}
#Test
public void BTRun2() {
objGlobalFunc.setUserNameValue("ABC");
objGlobalFunc.clickOKBtnOnMEXLoginForm();
}
}
BTRun1 is opened in a chrome browser. And, the user can login.
BTRun2 is opened in another chrome browser. And, the user can login.
The core problem of your code is the usage of global WebDriver object.
When running in parallel, TestNG is creating just one instance of RunSimpleTest, therefore one instance of WebDriver object. That's causing the two test override each other when communicating with the WebDriver object.
One solution would be using ThreadLocalDriver and ThreadLocalGlobalFunctions:
protected ThreadLocalDriver threadLocalDriver;
protected ThreadLocalGlobalFunctions threadLocalGlobalFunctions;
public void setup() {
try{
// declaration and instantiation of objects/variables
System.setProperty("webdriver.chrome.driver", "C:/ChromeDriver/chromedriver.exe");
// Disable Chrome Developer Mode Extension
ChromeOptions options = new ChromeOptions();
options.addArguments("--disable-extensions");
options.addArguments("--start-maximized");
threadLocalDriver = new ThreadLocalDriver(options);
threadLocalDriver.getDriver().manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
objGlobalFunc = new ThreadLocalGlobalFunctions(threadLocalDriver.getDriver());
threadLocalDriver.getDriver().get(baseUrl);
objGlobalFunc.getGlobalFunc().selectEnglishLanguage();
}
catch (Exception e){
e.printStackTrace();
}
}
#Test
public void BTRun1() {
objGlobalFunc.getGlobalFunc().setUserNameValue("ABC");
objGlobalFunc.getGlobalFunc().clickOKBtnOnMEXLoginForm();
}
#Test
public void BTRun2() {
objGlobalFunc.getGlobalFunc().setUserNameValue("ABC");
objGlobalFunc.getGlobalFunc().clickOKBtnOnMEXLoginForm();
}
To learn more about using ThreadLocal with WebDriver, check: http://seleniumautomationhelper.blogspot.com/2014/02/initializing-webdriver-object-as-thread.html

Prompting user input in selenium web driver before launching URL

I am trying to take user input then stored into the variable and i want to use that input into my program .
Here is my code , code is asking for user input but not loading the URL . It is just initiating the driver. Please someone correct me .
Current behavior:
Initiating the driver (IE shows the message " This is the Initial start page for wendriver server"
Asking for prompt .I gave my input in the prompt and click OK.
thats it .. after that code is not getting executed. Please help me
enter image description here
public class app{
public static void main(String[] args) throws Throwable
{
System.setProperty("webdriver.ie.driver", "C:\\Automation\\IEDriverServer.exe");
WebDriver driver = new InternetExplorerDriver();
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("window.promptResponse=prompt('Please enter the USER ID')");
if(isAlertPresent(driver)) {
// switch to alert
Alert alert = driver.switchTo().alert();
// sleep to allow user to input text
Thread.sleep(10000);
// this doesn't seem to work
alert.accept();
String ID = (String) js.executeScript("return window.promptResponse");
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("my application URL");
driver.findElement(By.name("USERID")).sendKeys("username");
driver.findElement(By.name("user_pwd")).sendKeys("mypwd");
driver.findElement(By.name("submit")).submit();
.......
......
// some more code which is doing my application fucntionality
.......
......
........
private static boolean isAlertPresent(WebDriver driver) {
try
{
driver.switchTo().alert();
return true;
} // try
catch (NoAlertPresentException Ex)
{
return false;
}
}
}
If you need to take input (ie. URL) from promp then you may use JOptionPane's showInputDialog() method from Java Swing.
Code snippet:
String URL =JOptionPane.showInputDialog(null,"Enter URL");
Try following code; it should serve your purpose:
public class app{
public static void main(String[] args) throws Throwable
{
System.setProperty("webdriver.ie.driver", "C:\\Automation\\IEDriverServer.exe");
WebDriver driver = new InternetExplorerDriver();
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("window.promptResponse=prompt('Please enter the USER ID')");
isAlertPresent(driver);
String ID = (String) js.executeScript("return window.promptResponse");
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("my application URL");
driver.findElement(By.name("USERID")).sendKeys("username");
driver.findElement(By.name("user_pwd")).sendKeys("mypwd");
driver.findElement(By.name("submit")).submit();
}
private static void isAlertPresent(WebDriver driver) {
try
{
driver.switchTo().alert();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); // even though not needed
isAlertPresent(driver);
} // try
catch (NoAlertPresentException Ex)
{
}
}
}

Multiple Browser Profiles for Multiple (Concurrent) Test Execution?

Multiple Browser Profiles for Multiple (Concurrent) Test Execution?
Is this even possible?
For example I can execute two tests at the same time but when two tests open at the same time within the same browser they seem to share the same cookies.
Please find my main Browser factory class listed below, can anyone advise the best way to alter my code, or settings required which will enable me to meet my objective?
Thanks for your help
public class BrowserFactory implements ISuiteListener {
private static WebDriver webdriver;
public static WebDriver getDriver() throws Exception {
try {
Properties p = new Properties();
FileInputStream fi = new FileInputStream(Constant.CONFIG_PROPERTIES_DIRECTORY);
p.load(fi);
String browserName = p.getProperty("browser");
switch (browserName) {
//firefox setup
case "firefox":
if (null == webdriver) {
System.setProperty("webdriver.gecko.driver", Constant.GECKO_DRIVER_DIRECTORY);
webdriver = new FirefoxDriver();
}
break;
//chrome setup
case "chrome":
if (null == webdriver) {
System.setProperty("webdriver.chrome.driver", Constant.CHROME_DRIVER_DIRECTORY);
DesiredCapabilities caps = DesiredCapabilities.chrome();
LoggingPreferences logPrefs = new LoggingPreferences();
logPrefs.enable(LogType.BROWSER, Level.ALL);
caps.setCapability(CapabilityType.LOGGING_PREFS, logPrefs);
webdriver = new ChromeDriver(caps);
}
break;
//IE setup
case "ie":
if (null == webdriver) {
System.setProperty("webdriver.ie.driver", Constant.IE_DRIVER_DIRECTORY);
webdriver = new InternetExplorerDriver();
}
break;
}
} catch (Exception e) {
System.out.println("Unable to load browser! - Exception: " + e.getMessage());
}
return webdriver;
}
#AfterClass
public void quitDriver() throws Exception {
if (null != webdriver) {
getDriver().manage().deleteAllCookies();
webdriver.quit();
webdriver = null;
}
// Output the time when a test class has ended
String tempTimeEndClass = new SimpleDateFormat("hh.mm.ss").format(new Date());
System.out.println("\nTEST CLASS END TIME: " + tempTimeEndClass);
}
}
Yes, of course it is possible!
They share the same cookies because the instance of the WebDriver you are creating is static, trying removing the static modifier so on every launch of the webdriver you get a unique instance.
public webdriver driver; public WebDriver getDriver() throws Exception
{ }
If the above isn't enough and you want to do additional things with the profiles; just pass it as a parameter via xml or as a String var in the method:
currentProfile = "user-data-dir=/path/to/your/custom/profile";
ChromeOptions options = new ChromeOptions();
options.addArguments(currentProfile);
Again, careful here currentProfile needs to be an instance variable not a static one!
Best of luck!

Selenium Webdriver TestNG tests are "overwriting" each other

I am trying to run Selenium Webdriver tests in parallel on a single machine, using TestNG. I have 3 #Test methods, where 3 different users log in to the same application and reach the home page. I need #Test methods to run in parallel, and write to an ExtentReports report.
My problem is, despite 3 completely different methods in different classes, one of the users will be logged into 2 out of 3 of the browsers, leaving a user out.
The login method is located in a PageFactory page object class.
Here are my 3 test methods:
#Test(enabled = true, priority = 0)
public void JohnLogin() throws Exception {
ExtentTest t = ClientReportFactory.getTest();
try {
Login objLogin = new Login(getDriver());
String username = "John";
String password = "Password";
objLogin.SignIn(username, password);
HomePage objHomePage = new HomePage(getDriver());
assertTrue(objHomePage.clientName.getText().c‌​ontains("John"));
} catch (Exception e) {
}
}
#Test(enabled = true, priority = 1)
public void BobLogin() throws Exception {
ExtentTest t = ClientReportFactory.getTest();
try {
Login objLogin = new Login(getDriver());
String username = "Bob";
String password = "Password";
objLogin.SignIn(username, password);
HomePage objHomePage = new HomePage(getDriver());
assertTrue(objHomePage.clientName.getText().c‌​ontains("Bob"));
} catch (Exception e) {
}
}
#Test(enabled = true, priority = 2)
public void SamLogin() throws Exception {
ExtentTest t = ClientReportFactory.getTest();
try {
Login objLogin = new Login(getDriver());
String username = "Sam";
String password = "Password";
objLogin.SignIn(username, password);
HomePage objHomePage = new HomePage(getDriver());
assertTrue(objHomePage.clientName.getText().c‌​ontains("Sam"));
} catch (Exception e) {
}
}
So, if I pause the tests on the Homepage. I will have 2 browser windows opened as "John", one "Bob" and no "Sam"... Causing failures.
Here's the PageFactory Object's login method.
public void SignIn(String strUsername, String strPassword) throws InterruptedException {
WebDriverWait wait = new WebDriverWait(driver, 15);
username.clear();
username.sendKeys(strUsername);
password.clear();
password.sendKeys(strPassword);
submit.click();
wait.until(ExpectedConditions.visibilityOf(homePagePanel));
}
At first I was sure the problem was in the #BeforeMethod threading (As in, the tests were in a different thread than the #Before and #After). But I don't see how that could be the case. The Base Test method successfully opens and closes 3 browsers. It just seems like the #Test methods use each other's data! But just in case, here's my #Before and #After, with my Threading code.
public class BaseTest {
public String browser;
private ThreadLocal<WebDriver> threadedDriver = new ThreadLocal<WebDriver>();
#BeforeMethod(alwaysRun = true)
#Parameters({ "browser"})
public void setup(String browser)throws MalformedURLException,
InterruptedException {
WebDriver driver = null;
if (browser.equalsIgnoreCase("Internet Explorer")) {
System.setProperty("webdriver.ie.driver", "C:\\Selenium\\IEDriverServer.exe");
driver = new InternetExplorerDriver();
} else if (browser.equalsIgnoreCase("Firefox")) {
System.setProperty("webdriver.gecko.driver", "C:\\Selenium\\geckodriver.exe");
driver = new FirefoxDriver();
} else if (browser.equalsIgnoreCase("chrome")) {
System.setProperty("webdriver.chrome.driver", "C:\\Selenium\\chromedriver.exe");
driver = new ChromeDriver();
} else if (browser.equalsIgnoreCase("MicrosoftEdge")) {
System.setProperty("webdriver.edge.driver", "C:\\Selenium\\MicrosoftWebDriver.exe");
driver = new EdgeDriver();
}
setWebDriver(driver);
this.browser = browser;
ClientReportFactory.getTest(ExtentTestName, ExtentTestDescription);
baseURL = "testApp.com";
driver.get(baseURL);
driver.manage().window().maximize();
}
public WebDriver getDriver(){
return threadedDriver.get();
}
public void setWebDriver(WebDriver driver) {
threadedDriver.set(driver);
}
#AfterMethod
public void afterMethod() {
ClientReportFactory.closeTest(ExtentTestName, ExtentTestDescription);
getDriver().quit();
threadedDriver.set(null);
}
#AfterSuite
public void afterSuite() {
ClientReportFactory.closeReport();
if (getDriver() != null) {
getDriver().quit();
} else {
System.out.println("Drivers already closed");
}
}
Assuming that all of your #Test methods are in different classes, I am guessing that the problem is perhaps due to the fact that your ThreadLocal variable is NOT STATIC but is an instance variable. This causes the behaviour to be per thread per instance rather than the desired behaviour viz., per thread across all instances. You can refer to this StackOverFlow thread for a better explanation on this.
You would resort to using an instance variant of ThreadLocal if and only if all your #Test methods belong to the same test class (Because now you are only trying to ensure that the class level data member WebDriver is shared in a thread safe manner across all the test methods that belong to the same test class)
So if each of your #Test methods reside in its own Test class, then please try changing:
private ThreadLocal<WebDriver> threadedDriver = new ThreadLocal<WebDriver>();
to
private static ThreadLocal<WebDriver> threadedDriver = new ThreadLocal<WebDriver>();
You could try this.
public class DriverFactory(){
private static ThreadLocal<WebDriver> driverThread;
public WebDriver driver;
#Parameters("browser")
public WebDriver instantiateDriverObject(String browser) {
DriverFactory factory = new DriverFactory();
driver = factory.createInstance(browser); //Driver instantiation goes here
driverThread = new ThreadLocal<WebDriver>() {
#Override
protected WebDriver initialValue() {
webDriverPool.add(driver);
return driver;
}
};
return driver;
}
public WebDriver getDriver() {
return driverThread.get();
}
}

Set a firefoxWebDriver.get(...) timeout

i like to access some pages that are not under my control. It could be that this pages execute some slow get requests but the main html is fully loaded and displayed. I tried many options but i could make it. The firefoxWebDriver.get(...) doesn't terminate on some sites in a realistic time.
To reproduice the problem, I wrote this small UnitTest showing the problem:
public class Timeout {
private FirefoxDriver driver;
#Before
public void setup() {
final FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("dom.max_script_run_time", 0);
profile.setPreference("webdriver.load.strategy", "fast");
this.driver = new FirefoxDriver(profile);
// this.driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);
// this.driver.manage().timeouts().setScriptTimeout(10, TimeUnit.SECONDS);
}
#Test(timeout = 15000)
public void shouldRetriveREDCAFEPageQuiteFast() {
this.driver.get("http://redcafe.vn/Home/su-kien-binh-luan/kagawa-tu-choi-mac-ao-so-7");
}
#Test(timeout = 15000)
public void shouldRetriveMUFCPageQuiteFast() {
this.driver.get("http://news.mufc.vn/detail/172-hoan-tat-giay-phep-lao-dong-m-u-chinh-thuc-so-huu-kagawa.html");
}
#After
public void tearDown() {
this.driver.close();
}
}
Thanks for you help.
<driver>.manage().timeouts().pageLoadTimeout(60, TimeUnit.SECONDS);
will set the page load timeout to 60 seconds, after which it will throw an error. You need to set this up before your first get() call.
The API is supported from Webdriver release 2.20.0 onwards.
Refer API Reference for new Timeout API's

Categories

Resources