FluentWait Not Working Properly: Youtube Example - java

So I had it working earlier but I messed up something in my code and now the FluentWait method doesnt seem to call properly. If I run it using quickRun set to false it works as intended (because of the implicit) but when I set it to true it doesnt as it will not wait for the elements to load correctly. Does anyone know exactly what I did wrong?
package myPackage;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.safari.SafariDriver;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
import com.google.common.base.Function;
//import com.gargoylesoftware.htmlunit.javascript.host.Console;
//https://www.codeproject.com/articles/143430/test-your-web-application-s-ui-with-junit-and-sele
//this will open a dynamic page example (ie. youtube) trending
public class youtubeTest {
public boolean quickRun = false; //Disable for debugging otherwise full speed
private static int defaultDebugDelay = 2; //Time in sec for next test to occur in debug
//do no change any of the below
private String testUrl; //target url destination ie youtube
private WebDriver driver; //webdriver instance to reference within class
private int testIndex = 1; //initial index value for console outputting
public WebElement fluentWait(final By locator) {
Wait < WebDriver > wait = new FluentWait < WebDriver > (driver)
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(1, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement foo = wait.until(new Function < WebDriver, WebElement > () {
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
});
return foo;
};
#
Before
public void beforeTest() {
driver = new SafariDriver();
System.out.println("Setting up Test...");
if (quickRun) {
System.out.println("Test Type: Quick Run (Fastest Mode)");
} else {
System.out.println("Test Type: Slow Run (Debug Mode) - Each Test has a " + defaultDebugDelay + " sec call time buffer");
}
testUrl = "https://www.youtube.com";
driver.get(testUrl);
System.out.println("Setting Driver " + driver + "for url: " + testUrl);
}
#
Test
public void Test() {
//insert unit tests within here
//open yt nav menu
locateClickableElement("#appbar-guide-button");
//go to trending
locateClickableElement("#trending-guide-item");
//click on 4th Trending video from list
//locateClickableElement(".expanded-shelf-content-item-wrapper", 3);
locateClickableElement(".expanded-shelf-content-item-wrapper");
}
#
After
public void afterTest() throws Exception {
//wait 10 sec before closing test indefinitely
System.out.println("Test auto ending in 10 seconds...");
Thread.sleep(10000);
stopTest();
}
//individual unit tests
private void locateClickableElement(String ExpectedElement, int child) {
//format string into something like: "ELEMENT:nth-child(1)"
String formattedString = ExpectedElement + ":nth-child(" + child + ")";
System.out.println("Strung: " + formattedString);
locateClickableElement(formattedString);
}
private void locateClickableElement(String ExpectedElement) {
try {
System.out.println("Test " + testIndex + ": locateClickableElement(" + ExpectedElement + ")");
//do absolute delay for visual debugging
if (!quickRun) Thread.sleep(2000);
//click on target if found
fluentWait(By.cssSelector(ExpectedElement)).click();
System.out.println("Test " + testIndex + ": Successful Click on Element(" + ExpectedElement + ")");
} catch (Exception e) {
//whenever error is found output it and end program
System.out.println("Error Could not locateClickableElement(" + ExpectedElement + ")");
System.out.println("Exception Handled:" + e.getMessage());
stopTest("error");
}
testIndex++;
}
private void stopTest() {
System.out.println("Test Completed: Reached End.");
driver.quit();
}
private void stopTest(String typeError) {
System.out.println("Test Completed: With an Error.");
driver.quit();
}
}

I would write this a different way and offer some advice.
Don't slow your test down using "debug mode". If you want to debug your test, use breakpoints and step through the code to see how it's working.
You don't need FluentWait here. A simple WebDriverWait using ExpectedConditions.elementToBeClickable(locator) will work just fine and is less complicated. You shouldn't even need it, if you accept my changes.
Don't pass locators using String, use the intended locator class, By. You won't have to interpret it, translate it, etc. and it will be faster and more flexible.
Unless you are trying to test the UI (which I'm assuming you don't work for youtube), then you can just navigate to the Trending page using the Trending link at the top of the page. It will save you time and clicks. If you aren't testing it, don't test it... get to where you are going as fast as possible. You don't want your test failing due to UI you aren't trying to test and you always want your tests to go as fast as possible. (NOTE: You could even navigate directly to the trending URL.)
You don't need the locateClickableElement() functions. Just click the links... it should be a one liner. If there's an error, it will be obvious. You don't need to print, "There was an error." after an exception message was printed.
You don't need the stopTest() functions... just stop the test. When the browser closes, it will be obvious the test is complete.
The rewritten code is below. It's nice and simple (and short) and should be faster.
public class youtubeTest
{
// do no change any of the below
private String testUrl = "https://www.youtube.com"; // target url destination ie youtube
private WebDriver driver; // webdriver instance to reference within class
private By trendingGuideLinkLocator = By.cssSelector("#trending-guide-item");
private By trendingLinkLocator = By.xpath("//h2[contains(.,'Trending')]");
#Before
public void beforeTest()
{
System.out.println("Setting up Test..."); // if you are going to have this statement, put it at the start of beforeTest()
driver = new SafariDriver();
driver.get(testUrl);
System.out.println("Set Driver " + driver + "for url: " + testUrl);
}
#Test
public void Test()
{
// insert unit tests within here
driver.findElement(trendingLinkLocator).click(); // just click the Trending link, it's faster
driver.findElements(trendingGuideLinkLocator).get(3).click();
}
#After
public void afterTest()
{
driver.close();
driver.quit();
}
}
If you don't want to change all this, the simple answer to your question is replace FluentWait with WebDriverWait.
fluentWait(By.cssSelector(ExpectedElement)).click();
would be replaced by
new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(trendingLinkLocator)).click();

Related

chromedriver NullPointerException error on linux

I'm currently learning selenium. I have followed a step by step walkthrough on how to start selenium-chromedriver. However I am experiencing this error here and I am have no idea how to solve it.
The following are the source code the walkthrough has given me.
package driverUtilities;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
public class DriverUtilities {
private static DriverUtilities instanceOfDriverUtilities;
private WebDriver driver;
public static DriverUtilities getInstanceOfDriverUtilities() {
if (instanceOfDriverUtilities == null) {
instanceOfDriverUtilities = new DriverUtilities();
}
return instanceOfDriverUtilities;
}
public WebDriver getDriver() {
if (driver == null) {
CreateDriver();
}
return driver;
}
private String GetDriverName() {
Properties config = new Properties();
String driverName = "";
try {
config.load(new FileInputStream("config.properties"));
} catch (FileNotFoundException e) {
System.out.println("Config file is not present");
e.printStackTrace();
} catch (IOException e) {
System.out.println("Error when loading config file");
e.printStackTrace();
}
for (String key : config.stringPropertyNames()) {
if (key.equals("browser")) {
driverName = config.getProperty(key);
}
}
return driverName;
}
private void CreateDriver() {
String driverName = GetDriverName();
switch (driverName) {
case "Google Chrome":
System.setProperty("webdriver.chrome.driver", "chromedriver");
this.driver = new ChromeDriver();
break;
case "Firefox":
System.setProperty("webdriver.gecko.driver", "geckodriver.exe");
this.driver = new FirefoxDriver();
break;
default:
break;
}
}
}
This is the Driver Utilities class
package test;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import driverUtilities.DriverUtilities;
public class Mod08_Slide_16_Navigation_Commands {
#Test
public void navigationCommands() {
DriverUtilities myDriverUtilities = new DriverUtilities();
WebDriver driver = myDriverUtilities.getDriver();
System.out.println("Start the Test Case");
// Load the website - http://www.bbc.co.uk
driver.get("http://www.bbc.co.uk");
System.out.println("\nLoad the website - http://www.bbc.co.uk");
// Refresh the page
driver.navigate().refresh();
System.out.println("\nRefresh the page");
// Load the website - http://www.google.co.uk
driver.get("http://www.google.co.uk");
System.out.println("\nLoad the website - http://www.google.co.uk");
// Go back to the website - http://www.bbc.co.uk
driver.navigate().back();
System.out.println("\nGo back to the website - http://www.bbc.co.uk");
// Go forward to the website - http://www.google.co.uk
driver.navigate().forward();
System.out.println("\nGo forward to the website - http://www.google.co.uk");
// Close the browser window
driver.close();
System.out.println("\nClose the browser window");
System.out.println("\nEnd of Test Case \"Navigation Commands\"");
}
}
This is the java test class I am trying to make work of
# Change the browser to use for testing purposes, accepted values are Google Chrome and Firefox
browser=Google Chrome
I also have the pom.xml file and a config.properties file and will share it if its required.
Note: My assumptions is that the setproperty function is not locating the correct path to chromedriver. However, I'm a arch linux user thus I'm not sure if the value inside the setproperty function is set to "chromedriver" or "/usr/bin/chromedriver"
Note 1: I have navigated to the .metadata of the Eclipse IDE and deleted it after reading some stackoverflow posts. However, this did not work*
Note 2: I am completely new to Selenium however, I have some experiences with Java and understand that nullpointerexception occurs when I declare a variable but did not create an object and assign that variable to it.
Edit 1: I have included the config.properties as specified
One suggestion I have is to hard-code the creation of the driver (without config.properties) and once you have the code working, you can work on optimizations such as dynamically creating the web driver based on a key value like you are doing here. To do this, simply replace this line
WebDriver driver = myDriverUtilities.getDriver();
with
System.setProperty("webdriver.chrome.driver", "C:\\Program Files\\WebDrivers\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
Obviously, make sure the path to the chromedriver.exe is resolved correctly for your system. By the way, unless your web drivers are in the root folder of your code project, that path is not correct. I will double check that is the case.
I ran your code with this recommendation and it worked. That tells me either your web driver path is not correct, or there is something funky with your config.properties.
Lastly, this loop isn't correct either
for (String key : config.stringPropertyNames()) {
if (key.equals("browser")) {
driverName = config.getProperty(key);
}
}
You don't want to loop through all your browser keys. If you have more than one "key", it will iterate through them and return the last one found. Instead, you need to call getProperty() once your properties file is loaded:
String propValue = props.getProperty("browser");
Then, once you have the correct propValue, you should pass it to your switch to properly instantiate the web driver.
switch(propValue) {
case "chrome":
this.driver = new ChromeDriver();
break;
case "firefox":
this.driver = new GeckoDriver();
break;
default:
// throw some exception here
throw new IllegalArgumentException(propValue + " is not a supported browser.");
}

How to handle browser popup (using Selenium WebDriver)?

I have been trying to login to faceboook and search a friend using Selenium. But I am stuck on this particular popup, and can't resolve this issue to proceed further.
public class FbAutomation {
public static void main(String[] args) {
FirefoxDriver browser = new FirefoxDriver();
browser.get("https://www.facebook.com/");
browser.manage().window().maximize();
browser.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
browser.findElement(By.xpath("//input[#name='email']")).sendKeys("user-email");
browser.findElement(By.xpath("//input[#name='pass']")).sendKeys("password");
/*Dimension radi = browser.findElement(By.xpath("//label[#id='loginbutton']")).getSize();
System.out.println("height is " + radi.height + " and width is " + radi.width);*/
browser.findElement(By.xpath("//label[#id='loginbutton']")).submit();
browser.navigate().to("https://www.facebook.com/imshaiknasir");
Alert alt = browser.switchTo().alert();
alt.accept();
/*
* Not able to handle "Allow notification" popUp box.
*/`enter code here`
browser.close();
}
}

Can't find an element by name using chrome driver in selenium?

I have my simple selenium program that validate if the value search box in the google is equal to hello world but i got this error:
Exception in thread "main"
org.openqa.selenium.NoSuchElementException: no such element: Unable to
locate element: {"method":"name","selector":"q"}....
Here's my complete code
public class SimpleSelenium {
WebDriver driver = null;
public static void main(String args[]) {
SimpleSelenium ss = new SimpleSelenium();
ss.openBrowserInChrome();
ss.getPage();
ss.listenForHelloWorld();
ss.quitPage();
}
private void openBrowserInChrome(){
System.setProperty("webdriver.chrome.driver", "C:/chromedriver.exe");
driver = new ChromeDriver();
}
private void quitPage() {
driver.quit();
}
private void getPage() {
driver.get("http://www.google.com");
}
private void listenForHelloWorld() {
WebElement searchField = driver.findElement(By.name("q"));
int count = 1;
while (count++ < 20) {
if (searchField.getAttribute("value").equalsIgnoreCase("hello world")) {
break;
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Do you wait until the page is ready and element displayed?
I've often got this error when the page is still loading. You could add something like
(MochaJS example, pretty much the same API for JAVA tests)
test.it('should check the field existence', function (done) {
let field_by = By.id(ID_OF_THE_FIELD);
driver.wait(until.elementLocated(field_by,
driver.wait(until.elementIsVisible(driver.findElement(field_by)), TIME_TO_WAIT_MS);
done();
});
You wait until the element is visible. If it failed, the timeout of TIME_TO_WAIT_MS will be raised.
The google search bar will never have "hello world" in it because you haven't typed it in?
Also the search field value doesn't seem to update when you type in a search (if you inspect the element using the Console).
If your just learning I would just write a test like this and the click the search button, then confirm the "hello world" text in the search results:
WebElement searchField = driver.findElement(By.name("q"))
searchField.sendKeys("Hello World")
//Add code to click search button
//Add code to assert results on next page
Also I would completely change your listenForHelloWorld() method and use the built in WebDriver ExpectedConditions:
new WebDriverWait(driver, 10)
.until(ExpectedConditions.textToBePresentInElement(searchField, "Hello World"))

Keeping Selenium browser active

I'm using Selenium HtmlUnitDriver and wondering is it possible somehow to keep the state of this driver.
I mean that to test something on the page I have to load the driver -> load and add cookies -> go through the login page -> get required page.
It takes too much time to do it everytime.
Is there something like a 'server state' or maybe I need to serialize and save-load the driver?
Thank you.
Since I've managed to solve my question, I'll leave this here:
1. I took selenium-server-standalone and run it with -browserSessionReuse -timeout 3600 -browserTimeout 600 to keep my session alive.
2. Made my class:
public class MyRemoteWebDriver extends RemoteWebDriver {
....
#Override
protected void startSession(Capabilities desiredCapabilities, Capabilities requiredCapabilities) {
String sid = loadSessionID("SID_NAME");
if (sid != null) {
super.startSession(desiredCapabilities, requiredCapabilities);
log.info("Old SID: " + sid);
setSessionId(sid);
try {
getCurrentUrl();
log.info("Old url: " + getCurrentUrl());
} catch (WebDriverException e) {
sid = null;
}
}
if (sid == null) {
super.startSession(desiredCapabilities, requiredCapabilities);
saveSessionID(getSessionId().toString());
log.info("New SID: " + getSessionId().toString());
}
}
}
So, this way I can store this SessionId in the db and re-use it.
You can try to use a singleton webdriver instead of creating one for each test.
Something like that:
class SingletonWebdriver {
private static Webdriver driver;
public static Webdriver getDriver() {
if(driver == null) {
createDriver();
}
return driver;
}
}
And then you may call getDriver to retrieve the same driver, but in many cases it's a good practice to make each test in a diferent session.

Attempting to execute Selenium IDE exported code and getting this runtime error: Exception in thread "main" java.lang.NoSuchMethodError: main

My end goal is to confirm that I have Java, Selenium WebDriver, and JUnit functioning such that I can run an automated test case utilizing these technologies.
What I have done so far:
installed Selenium IDE (v 2.8.0) for Firefox (v 34.0.5)
recorded a simple test case using Selenium IDE and added the test case to a test suite
in Selenium IDE exported the test case using the option: File->Export Test Case As...->Java / JUnit 4 / WebDriver
downloaded and installed JUnit 4 from: https://github.com/junit-team/junit/wiki/Download-and-Install (Plain-old jar method)
downloaded and installed Selenium client and WebDriver Java language binding (v 2.44.0) from: http://www.seleniumhq.org/download/
performed some slight modifications to the code generated in step 3 such as removing the package statement at the beginning
compiled the code with the following command (windows command prompt):
C:\docs\tech\code\myCode\java\testing\selenium\utest\practice>C:\java\jdk\bin\javac.exe -cp C:\docs\installs\programming\automation\test\xUnit\java\jUnit\junit\v4_12\junit-4.12.jar;C:\docs\installs\programming\automation\test\xUnit\java\jUnit\hamcrest\hamcrest-core-1.3.jar;C:\docs\installs\programming\automation\web\selenuim\webdriver\java\selenium-2.44.0\selenium-java-2.44.0.jar C:\docs\tech\code\myCode\java\testing\selenium\utest\practice\TestGooglePlayApp.java
this compiles with no warnings/errors
attempt to execute the code with the following command:
C:\docs\tech\code\myCode\java\testing\selenium\utest\practice>java -cp .;C:\docs\installs\programming\automation\test\xUnit\java\jUnit\junit\v4_12\junit-4.12.jar;C:\docs\installs\programming\automation\test\xUnit\java\jUnit\hamcrest\hamcrest-core-1.3.jar;C:\docs\installs\programming\automation\web\selenuim\webdriver\java\selenium-2.44.0\selenium-java-2.44.0.jar TestGooglePlayApp
Actual Result:
The output of this attempt is:
Exception in thread "main" java.lang.NoSuchMethodError: main
No other error/warning is given and no indication is given that the code begins to execute
Expected Result:
This is my first time interacting with these technologies so I'm learning as I go! However, based on the research I have done my expectation is that a local Selenium WebDriver instance will be initialized as a Firefox Driver. This Firefox Driver will be sent instructions by the Java code in order to carry out the steps in the test case. JUnit will then indicate somehow on the command line the Pass/Fail status of the test case.
The big assumption I have here is that the Selenium Server/Selenium RC is not required in this case since all I intend to do is execute a local Selenium WebDriver script. Furthermore, my hope is that this can be launched directly from the command-line independent of Eclipse, Maven, etc. I would like to be able to send the final Java class to a colleague and the only dependency for expected execution would be a working SDK of Java on the end machine.
What's Next?
I'm looking for advice on what I can do to get this code up and running under the restraints I have outlined. It may be that the code needs to be modified. It may be that my expectations need to be tempered down and it's just not possible to do everything I want directly from the command-line. It may be that I did not compile the code correctly or some library is missing. It may be that... okay you get the point!
Other Relevant Details:
OS = Windows 7 - 64 bit
Here is the contents of TestGoogleApp.java:
import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;
public class TestGooglePlayApp {
private WebDriver driver;
private String baseUrl;
private boolean acceptNextAlert = true;
private StringBuffer verificationErrors = new StringBuffer();
#Before
public void setUp() throws Exception {
driver = new FirefoxDriver();
baseUrl = "https://www.google.com/";
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
#Test
public void test000() throws Exception {
driver.get("http://www.google.com/");
// COMMENT: Assert the 'Apps' icon is present and then click on it
assertTrue(isElementPresent(By.cssSelector("a.gb_C.gb_Sa")));
driver.findElement(By.cssSelector("a.gb_C.gb_Sa")).click();
// COMMENT: Assert the 'Play' app is present and then click on the 'Play' app and wait for the expected contents to load
assertTrue(isElementPresent(By.cssSelector("#gb78 > span.gb_s")));
driver.findElement(By.cssSelector("#gb78 > span.gb_s")).click();
// COMMENT: Assert that the input element associated with search queries is present and then type 'Testing' in the input element associated with search queries
assertTrue(isElementPresent(By.id("gbqfq")));
driver.findElement(By.id("gbqfq")).clear();
driver.findElement(By.id("gbqfq")).sendKeys("Testing");
// COMMENT: Click on the 'Search' element to perform a query for the input query term previously entered and wait for the expected contents to load
driver.findElement(By.id("gbqfb")).click();
// COMMENT: Assert that the desired result is contained in the search results returned and then click on the desired search result and wait for the expected contents to load
for (int second = 0;; second++) {
if (second >= 60) fail("timeout");
try { if (isElementPresent(By.linkText("Software Testing Concepts"))) break; } catch (Exception e) {}
Thread.sleep(1000);
}
driver.findElement(By.linkText("Software Testing Concepts")).click();
for (int second = 0;; second++) {
if (second >= 60) fail("timeout");
try { if ("Software Testing Concepts - Android Apps on Google Play".equals(driver.getTitle())) break; } catch (Exception e) {}
Thread.sleep(1000);
}
// COMMENT: Assert that the page contains the expected content as follows: 1) title of app 2) user rating 3) number of users who have rated the app 4) format of text value of user rating (4.0) 5) format of text value for number of user who have rated the app (128)
for (int second = 0;; second++) {
if (second >= 60) fail("timeout");
try { if (isElementPresent(By.cssSelector("div.score"))) break; } catch (Exception e) {}
Thread.sleep(1000);
}
for (int second = 0;; second++) {
if (second >= 60) fail("timeout");
try { if (isElementPresent(By.cssSelector("span.reviews-num"))) break; } catch (Exception e) {}
Thread.sleep(1000);
}
try {
assertTrue(Pattern.compile("[0-9]\\.[0-9]").matcher(driver.findElement(By.cssSelector("div.score")).getText()).find());
} catch (Error e) {
verificationErrors.append(e.toString());
}
try {
assertTrue(Pattern.compile("[0-9]+").matcher(driver.findElement(By.cssSelector("span.reviews-num")).getText()).find());
} catch (Error e) {
verificationErrors.append(e.toString());
}
// COMMENT: store value for user rating and store value for number of users who have rated the app
String _currentUserRating = driver.findElement(By.cssSelector("div.score")).getText();
System.out.println(_currentUserRating);
String _numOfUserRatings = driver.findElement(By.cssSelector("span.reviews-num")).getText();
System.out.println(_numOfUserRatings + "HELLO");
}
#After
public void tearDown() throws Exception {
driver.quit();
String verificationErrorString = verificationErrors.toString();
if (!"".equals(verificationErrorString)) {
fail(verificationErrorString);
}
}
private boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
private boolean isAlertPresent() {
try {
driver.switchTo().alert();
return true;
} catch (NoAlertPresentException e) {
return false;
}
}
private String closeAlertAndGetItsText() {
try {
Alert alert = driver.switchTo().alert();
String alertText = alert.getText();
if (acceptNextAlert) {
alert.accept();
} else {
alert.dismiss();
}
return alertText;
} finally {
acceptNextAlert = true;
}
}
}

Categories