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
Related
I'm trying to check login page control by using dataprovider but i don't want to initialize webdriver again and again for each username password control. Once i come into login page, checking all concerned scenarios on login page in single time without starting another driver seems more convenient to me but i couldn't figure it out. When running following code, data[0][0] and data[0][1] is being correctly checked but it gives no such element on Login method having second priority test annotation when being tried to be typed data[1][0] and data[1][1]. Probably, it causes because driver is not looking at that page on that time. How can I handle this issue ?
error:
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//div[#class='q-input-wrapper email-input']//input[#class='q-input']"}
code:
public class TestCaseFirst {
public WebDriver driver;
#BeforeTest
public void Start() throws InterruptedException {
WebDriverManager.chromedriver().setup();
driver= new ChromeDriver();
driver.get("https://www.faxzas.com/");
driver.manage().window().maximize();
Thread.sleep(2000);}
#Test(priority=1)
public void RoadtoLogin() throws InterruptedException {
driver.findElement(By.xpath("//a[#title='Close']")).click();
Thread.sleep(1000);
driver.findElement(By.xpath("//div[#class='login-container']//span[#id='not-logged-in-container']")).click();;
Thread.sleep(1000);
}
#Test(dataProvider="loginInfos", priority=2)
public void Login(String mail, String password) throws InterruptedException {
driver.findElement(By.xpath("//div[#class='q-input-wrapper email-input']//input[#class='q-input']")).sendKeys(mail);
Thread.sleep(1000);
driver.findElement(By.xpath("//div[#class='q-input-wrapper']//input[#class='q-input']")).sendKeys(password);
Thread.sleep(1000);
driver.findElement(By.xpath("//button[#type='submit']")).click();
Thread.sleep(1000);
String description = driver.findElement(By.xpath("//div[#id='error-box-wrapper']//span[#class='message']")).getText();
System.out.println(description);
}
#DataProvider(name="loginInfos")
public Object[][] getData(){
Object[][] data = new Object[6][2];
data[0][0]="blackkfredo#gmail.com";
data[0][1]="";
data[1][0]="blackkfredo#gmail.com";
data[1][1]="443242";
data[2][0]="";
data[2][1]="1a2b3c4d";
data[3][0]="";
data[3][1]="";
data[4][0]="blackkfredogmail.com";
data[4][1]="1a2b3c4d";
data[5][0]="blackkfredo#gmail.com";
data[5][1]="1a2b3c4d";
return data;
}
}
You need to reset your page to the login page where you are expecting the element to be. Either put an #AfterMethod and go back to the page you are trying to test or put an #BeforeMethod for the same. You may even want to wrap up your find element calls and handle the exceptions by going back to the main page.
I try practicing to execute tests in parallel using TestNG invocationCount and threadPoolSize.
A. I write a all-in-one test like this, and it is successful
#Test(invocationCount = 5, threadPoolSize = 5)
public void testThreadPool() {
WebDriver driver = new ChromeDriver();
driver.get("http://www.google.com");
driver.findElement(By.name("q")).sendKeys("Amazon");
driver.quit();*/
}
=> 5 Chrome browsers are opened at the same time (parallel), and tests are successfully executed.
B. I define my test in #before and #after, and it doesn't work
#BeforeTest
public void setUp() {
WebDriver driver = driverManager.setupDriver("chrome");
}
#Test(invocationCount = 5, threadPoolSize = 5)
public void testThreadPool() {
driver.get("http://www.google.com");
driver.findElement(By.name("q")).sendKeys("Amazon");
}
#AfterTest
public void tearDown() {
driver.quit()
}
=> 1 chrome browser is opened, and it seems it is refreshed 5 times, and at the end, there are 5 Amazon words entered in text field, with the following log message:
[1593594530,792][SEVERE]: bind() failed: Cannot assign requested address (99)
ChromeDriver was started successfully.
Jul 01, 2020 11:08:51 AM org.openqa.selenium.remote.ProtocolHandshake createSession
I understand that, with B, 5 threads use the same object driver, that's why only one chrome is opened. But I don't know how to manage driver object in this case so I can get the same result like in A.
Any idea appreciated.
You can use ThreadLocal class to make your webdriver Threadsafe
private ThreadLocal<WebDriver> webdriver = new ThreadLocal<WebDriver>();
#BeforeMethod
public void setUp() {
webdriver.set(driverManager.setupDriver("chrome"));
}
#Test(invocationCount = 5, threadPoolSize = 5)
public void testThreadPool() {
webdriver.get().get("http://www.google.com");
webdriver.get().findElement(By.name("q")).sendKeys("Amazon");
}
#AfterMethod
public void tearDown() {
webdriver.get().quit()
}
Edit : You will need to use BeforeMethod/AfterMethod in above context.
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
I wrote automated tests with help of JUnit, Selenium Webdriver (v. 3.141.59) and Chromedriver (v. 2.45).
Firstly, I wrote a login test:
[...]
void loginTest() {
driver().findElement(By.id("login-button")).click();
driver().findElement(By.id("name")).sendKeys("mail#xx.com");
driver().findElement(By.id("password")).sendKeys("password");
driver().findElement(By.id("send")).click();
assertTrue(driver().findElement(By.id("logged-in-msg")).isDisplayed());
}
Everything worked fine, all good, test green.
Then I got some more and more complicated and long ids and xpaths I had to use, so I decided to keep tests short and nice and put all my locators in separate class, like this:
public class LocatorsList {
public static final String
SIGN_IN_BUTTON = "login-button",
LOG_IN_USERNAME = "name",
LOG_IN_PASSWORD = "password",
LOG_IN_BUTTON = "send",
SUCCESS_MSG = "logged-in-msg";
}
And my test:
[...]
void loginTest() {
driver().findElement(By.id(SIGN_IN_BUTTON)).click();
driver().findElement(By.id(LOG_IN_USERNAME)).sendKeys("mail#xx.com");
driver().findElement(By.id(LOG_IN_PASSWORD)).sendKeys("password");
driver().findElement(By.id(LOG_IN_BUTTON)).click();
assertTrue(driver().findElement(By.id(SUCCESS_MSG)).isDisplayed());
}
Then it stopped working. Webdriver sends errors:
org.openqa.selenium.NoSuchElementException: no such element:
Unable to locate element: {"method":"id","selector":"name"}
As I watched my test going, this element was right there on the page, webdriver even clicked at it as if it wanted to fill the field... but it didn't. Says 'unable to locate element'.
I tried to change chromedriver and selenium versions but it didn't help.
If that's honestly the only real change to the code, then could it be as simple as you missing the class name before the string? I.e:
driver().findElement(By.id(LocatorsList.SIGN_IN_BUTTON)).click()
This is most probably due to element not present, you need to wait for the element to be loaded. Use
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.presenceOfElementLocated((By.id(LOG_IN_USERNAME))));
After that you can perform the action on that particular element say sendKeys event.
public class Testing {
public static final String
SIGN_IN_BUTTON = "jsid-login-button",
LOG_IN_USERNAME = "login-email-name",
LOG_IN_PASSWORD = "login-email-password",
LOG_IN_BUTTON = "input[type='submit']";
WebDriver driver;
#BeforeMethod
public void setUp() {
System.setProperty("webdriver.chrome.driver", <driverLocation>);
driver = new ChromeDriver();
driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
driver.get("https://9gag.com/");
}
#Test
public void demoTest() {
driver.findElement(By.id(SIGN_IN_BUTTON)).click();
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.presenceOfElementLocated((By.id(LOG_IN_USERNAME))));
driver.findElement(By.id(LOG_IN_USERNAME)).sendKeys(<YOUR_EMAIL>);
driver.findElement(By.id(LOG_IN_PASSWORD)).sendKeys(<YOUR_PASSWORD>);
driver.findElement(By.cssSelector(LOG_IN_BUTTON)).click();
}
#AfterMethod
public void tearDown() {
driver.quit();
}
}
Is there any chance to use annotatios with system properties in Selenium?
#Test
public void
testSigninMobile()
{
if(System.getProperty("browser").equals("iphone")){
login();
}else{
driver.quit();
}
}
I would like to have annotations like that:
#Test if broswer is iphone, firefox but not if it is IE or Edge etc.
public void
testSigninMobile()
{...
I mean the situation where you have for instance 50 tests but your app is not full ready for every browser. I think that it is silly to write to those 50 test such a browser checking logic?
You can write logics inside the #Test method using Capabilities - getBrowserName().
#Test
public void testSigninMobile()
{
Capabilities cap = ((RemoteWebDriver) driver).getCapabilities();
String browserName = cap.getBrowserName().toLowerCase();
System.out.println(browserName);
if("blabla".equalsIgnoreCase(browserName))
{
// Your code
}
else
{
throw new SkipException("Skipping this excecution");
}
}