How to highlight element in Selenium- Java in Page Object Mode? - java

I'm performing Selenium automation in Java using POM. I need to highlight elements on the following web page. But it doesn't make any effect at all, though I don't get any error message, it simply doesn't highlight the element I've selected.
As I'm using POM pattern I have a separate class including all element functionality methods, such as click, write text, etc.
package pageObjects;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
public class BasePage {
public WebDriver driver;
public WebDriverWait wait;
// Constructor
public BasePage (WebDriver driver) {
this.driver = driver;
wait = new WebDriverWait(driver, 15);
}
// Click Method
public void click (By elementBy) {
waitVisibility(elementBy);
driver.findElement(elementBy).click();
}
I have highlighting element method as following.
// Element highlighter method
public static void highLightElement(WebDriver driver, By elementBy) {
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("arguments[0].setAttribute('style', 'background: yellow; border: 2px solid red;');", elementBy);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
js.executeScript("arguments[0].setAttribute('style','border: solid 2px white');", elementBy);
}
I have changed my click method as following.
public void click_2 (By elementBy) {
waitVisibility(elementBy);
highLightElement(driver,elementBy);
driver.findElement(elementBy).click();
}
And use it in a separate class with all page methods.
package pageObjects;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.Select;
public class HomePage extends BasePage {
// Constructor
public HomePage (WebDriver driver) {
super(driver);
}
// Page Variables
String baseURL = "https://www.bookdepository.com/";
// Web Elements
// --- Sign In UI ---
By signInJoin_button = By.xpath("//div[#class='page-slide']//ul[#class='right-nav mobile-nav-content']//li[3]//a[1]");
By signOut_button = By.xpath("/html/body/div[4]/div[1]/div/ul[2]/li[5]/a");
// Page Methods ---
public HomePage goToBookDepositoryHomePage (){
driver.get(baseURL);
pause();
return this;
}
public LoginPage goToLoginPage (){
click_2(signInJoin_button);
pause();
return new LoginPage(driver);
}
What am I doing wrong here?

You should use WebElement and not By to change the style. Try following code:
public static void highLightElement(WebDriver driver, By elementBy) {
WebElement webElement = driver.findElement(elementBy);
String originalStyle = webElement.getAttribute("style");
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].setAttribute(arguments[1], arguments[2]", webElement, "style", originalStyle + "border: 2px solid red;");
//Do something e.g. make a screenshot
//Reset style
js.executeScript("arguments[0].setAttribute(arguments[1], arguments[2])", webElement, "style", originalStyle);
}
I think it makes sense to keep the original style and just add the border. After doing something with the highlighted element e.g. creating a screenshot, you should reset the style. When you return the original style you could remove the reset part in a separate method.

Try the following code. This will highlight all the web elements of a test page.
I am using the EventFiringWebDriver to highlight the webelements in the below code.
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.events.AbstractWebDriverEventListener;
import org.openqa.selenium.support.events.EventFiringWebDriver;
public class HighLighterEventListener extends AbstractWebDriverEventListener {
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver", "./libs/chromedriver 4");
WebDriver webdriver=new ChromeDriver();
EventFiringWebDriver driver = new EventFiringWebDriver(webdriver);
webdriver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("https://yosuva.com");
driver.register(new HighLighterEventListener());
driver.findElement(By.xpath("//span[text()='Home']"));
driver.findElement(By.xpath("//span[text()='About']"));
driver.findElement(By.xpath("//span[text()='Tools']"));
driver.findElement(By.xpath("//span[text()='News']"));
driver.findElement(By.xpath("//span[text()='Events']"));
driver.findElement(By.xpath("//span[text()='Contact']"));
driver.quit();
}
#Override
public void afterFindBy(By by, WebElement element, WebDriver driver) {
((JavascriptExecutor)driver).executeScript(
"arguments[0].style.border='3px solid green'",element
);
}
}

Related

Wait until element doesn't exists using PageFactory

I'm trying to use only PageFactory in my project, without using fields with type By. And I'm looking to implement something like this:
#FindBy(className = "loading-container")
private WebElement loadingElement;
public LoadingPage(WebDriver driver) {
PageFactory.initElements(driver, this);
this.waitDriver = new WebDriverWait(this.driver, 20);
}
public void waitLoadingToFinish() {
this.waitDriver.until(ExpectedConditions.elementNotExists(loadingElement));
}
Is there a way to implemet custom Expected Condition for this? or any other way to implement this? (without using By fields, only using page factory).
As far as I understand you have some elements on the page that you consider ready for usage only when there is no certain element on the page (like waiting wheel).
There is a special locator class in Selenium called AjaxElementLocator. What you need to do is to extend that type by changing isElementUsable method when you initialize your page so that all the controls you use on that page would first check the condition. Here is the example:
package click.webelement.pagefactory.conditions;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.AjaxElementLocator;
public class LoadablePage {
#FindBy(id = "cntrl-id")
WebElement control;
public LoadablePage(WebDriver driver){
PageFactory.initElements(field -> new AjaxElementLocator(driver, field, 10){
#Override
protected boolean isElementUsable(WebElement element) {
return driver.findElements(By.xpath("//WHEEL_XPATH")).size() == 0;
}
}, this);
}
}
Here you can find more information on such approach.
Selenium has this method
ExpectedConditions.InvisibilityOfElementLocated
An expectation for checking that an element is either invisible or not
present on the DOM.
For your code
public void waitLoadingToFinish() {
this.waitDriver.until(ExpectedConditions.invisibilityOfElementLocated(loadingElement));
}
also, you might try to add a javascript executor to wait until the page is loaded
public static void waitForScriptsToLoad(WebDriver driver) {
WebDriverWait(driver, 30).until((ExpectedCondition<Boolean>) wd ->
((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
}
and then your page constructor becomes this
public LoadingPage(WebDriver driver) {
PageFactory.initElements(driver, this);
this.waitDriver = new WebDriverWait(this.driver, 20);
waitForScriptsToLoad(driver);
}
If you create wait method in your program that is easy and customize in selenium framework
private static WebElement waitForElement(By locator, int timeout)
{
WebElement element=new WebDriverWait(driver,timeout).until(ExpectedConditions.presenceOfElementLocated(locator));
return element;
}
//If you want wait for id following code should use
waitForElement(By.id(""),20);
Here 20 is miliseconds
and you can use any web elements to wait
To simulate an ExpectedConditions like elementNotExists you can use either among invisibilityOfElementLocated() or invisibilityOf().
invisibilityOfElementLocated()
invisibilityOfElementLocated() is the implementation for an expectation for checking that an element is either invisible or not present on the DOM. It is defined as follows:
public static ExpectedCondition<java.lang.Boolean> invisibilityOfElementLocated(By locator)
An expectation for checking that an element is either invisible or not present on the DOM.
Parameters:
locator - used to find the element
Returns:
true if the element is not displayed or the element doesn't exist or stale element
Code Block:
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.WebDriverWait;
public class fooPage {
WebDriver driver;
public fooPage(WebDriver driver)
{
PageFactory.initElements(driver, this);
}
//you don't need this
//#FindBy(className = "loading-container")
//private WebElement loadingElement;
public void foo()
{
Boolean bool = new WebDriverWait(driver, 20).until(ExpectedConditions.invisibilityOfElementLocated(By.className('loading-container')));
//other lines of code
}
}
As an alternative you can also use the invisibilityOf() method as follows:
invisibilityOf()
invisibilityOf() is the implementation for an expectation for checking the element to be invisible. It is defined as follows:
public static ExpectedCondition<java.lang.Boolean> invisibilityOf(WebElement element)
An expectation for checking the element to be invisible
Parameters:
element - used to check its invisibility
Returns:
Boolean true when elements is not visible anymore
Code Block:
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.WebDriverWait;
public class fooPage {
WebDriver driver;
public fooPage(WebDriver driver)
{
PageFactory.initElements(driver, this);
}
#FindBy(className= 'loading-container')
WebElement loadingElement;
public void foo()
{
Boolean bool = new WebDriverWait(driver, 20).until(ExpectedConditions.invisibilityOf(fooPage.getWebElement()));
//other lines of code
}
public WebElement getWebElement()
{
return loadingElement;
}
}
You can find a detailed discussion in How to use explicit waits with PageFactory fields and the PageObject pattern

Selenium non-deterministic loop over List<WebElement>

I am trying to do some quick tests to learn selenium for web scraping purposes. I am trying to loop over the menu items of the taco bell website. What I find confusing is that the first element of the List, isn't what is selected by the first or second click. The actual selection is usually the 2nd or 3rd element. It is non-deterministic. What am I doing wrong?
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
public class Main {
static WebDriver driver;
public static void main(String[] args) throws InterruptedException {
System.setProperty("webdriver.chrome.driver", "/Applications/chromedriver");
driver = new ChromeDriver();
driver.get("https://www.tacobell.com/food");
List<WebElement> listOfMenuCategories = driver.findElements(By.cssSelector(".cls-category-card-item-card"));
for(WebElement webElement : listOfMenuCategories){
scanTacoBellMenuCategory(webElement);
}
System.out.println("1: "+listOfMenuCategories.size());
driver.quit();
}
public static void scanTacoBellMenuCategory(WebElement webElement){
webElement.click();
List<WebElement> listOfSubMenuCategories = driver.findElements(By.cssSelector(".product-item"));
for(WebElement submenuCategory : listOfSubMenuCategories){
scanTacoBellSubMenuCategory(submenuCategory);
}
}
public static void scanTacoBellSubMenuCategory(WebElement webElement){
webElement.click();
}
}
Thanks.
UPDATE-------------------------------
I now realize that my example was unnecessarily complicated and intent was not obvious. Here is a more direct example:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
public class MainTwo {
static WebDriver driver;
public static void main(String[] args) throws InterruptedException {
System.setProperty("webdriver.chrome.driver", "/Applications/chromedriver");
driver = new ChromeDriver();
driver.get("https://www.tacobell.com/food");
List<WebElement> listOfMenuCategories = driver.findElements(By.cssSelector(".cls-category-card-item-card"));
for(WebElement webElement : listOfMenuCategories){
webElement.click();
break;
}
driver.quit();
}
}
The tacobell menu (https://www.tacobell.com/food) has 16 categories in the following order: New, Favorites, Combos, Specialties, Tacos, Burritos, Quesadillas, Nachos, Value Menu, Sweets, Sides, Drinks, Power Menu, Party, Packs, Vegetarian, Breakfast.
When I loop over these items, I "click" the first one in the forEach loop. I would expect that to be the "New" category. I would also expect the result to be repeatable. However, neither of those statements are true. It usually opens one of the "Favorites", "Combos", or "Specialties" menus. However, it can truly open pretty much anything.
It seems as if the Webdriver is non-blocking in some way. In particular, the webElement.click() event doesn't seem to stop the execution of the forEach loop. It is almost as if the the webElement was in another thread.
Why doesn't the "New" menu get displayed when I run the above code and why isn't this deterministic?

Need to input value into field, check result, and then add one character in Selenium Java

This is the first time I have ever coded, so excuse my ignorance.
I have the following Selenium code that is for online ordering from a restaurant. At the end, it is putting a value into a field, checking and printing the result, then what I need to do is change the original input, and do it again. So I need a loop. I think.
package Test;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Action;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.ie.InternetExplorerDriver;
import java.util.Random;
import java.util.Scanner;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class Test {
public static void main(String[] args) throws Exception {
System.setProperty("webdriver.chrome.driver", "C:\\Users\\testuser\\Desktop\\Eclipse\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
Actions action = new Actions(driver);
driver.get("onlineorder.com");
//driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(15,TimeUnit.SECONDS);
WebElement startorder = driver.findElement(By.cssSelector("#startOrder_148"));
startorder.click();
Thread.sleep(4500);
action.sendKeys(Keys.RETURN);
Thread.sleep(3000);
WebElement selectfood = driver.findElement(By.xpath("//a[contains(text(),\"NEW! Steak Po'boy (670 cal)\")]"));
selectfood.click();
Thread.sleep(4000);
WebElement additem = driver.findElement(By.cssSelector("#addItemToOrder"));
additem.click();
Thread.sleep(5000);
WebElement checkout = driver.findElement(By.xpath("//a[contains(text(),'Checkout')]"));
checkout.click();
Thread.sleep(5000);
WebElement loginbutton = driver.findElement(By.cssSelector("#logonCheckoutBtn"));
loginbutton.click();
Thread.sleep(3500);
//WebElement click5 = driver.findElement(By.xpath("//input[#id='email']"));
//action.click(click5).perform();
driver.findElement(By.xpath("//input[#id='email']")).sendKeys("email#gmail.com");
driver.findElement(By.cssSelector("#loginPassword")).sendKeys("password");
WebElement loginbutton2 = driver.findElement(By.cssSelector("#loginButton"));
loginbutton2.click();
Thread.sleep(5500);
WebElement paymenttype = driver.findElement(By.id("selectPaymentType"));
Select payment=new Select(paymenttype);
payment.selectByIndex(3);
driver.findElement(By.id("numberchecker")).sendKeys("1000");
WebElement checkbalance = driver.findElement(By.xpath("//div[#class='clearfix ng-scope']//div[#class='clearfix']//a[#class='numberchecker btn'][contains(text(),'Check balance')]"));
checkbalance.click();
Thread.sleep(1500);
for(WebElement link:driver.findElements(By.xpath("//span[#class='popup_message ng-binding']")))
{
System.out.println(link.getText());
}
WebElement okaybalance = driver.findElement(By.cssSelector("#btnPopupOk"));
okaybalance.click();
Everything works fine until here. What I need to do is go back and change the original input value (1000) by 1 to 1001. The error I get for getInputNumber is "AnnotationName expected after this token". Also, the name of the class "addnumber" gives error "Illegal modifier, only abstract or final is permitted". "class" gives error "syntax error, # expected".
public class addnumber() {
private static float inputNumber= 1000f;
public static float getInputNumber() {
return inputNumber+ 1.0f;
}
}
Thread.sleep(4000);
//driver.quit();
}
}
You have declared class wrongly. It should be
public class Sample{
//Then the stuff you want to do.
}
To access this class you need to create outer class object and them inner
Like this.
Outer d=new Outer();
d.Sample obj=new d.Sample();
But as you have declared member static for sample class you can just call them using classname.

Accessing Instance Variables in Helper Classes

Disclaimer: I come from a dynamic language background (Ruby) and I'm trying to level up my skills in Java. I fear with my problem here I'm thinking too much in the context of Ruby and would appreciate some pointers.
Problem:
I want to see how I can have a helper class know about the existence of a WebDriver instance without having to pass the instance around all the time. The reason I'm trying to avoid that is because it leads to extra method arguments and less fluent test writing.
Context:
I have a test case (LoginIT.java) that looks like this:
package com.testerstories.learning.symbiote;
import static com.testerstories.learning.helpers.Selenium.*;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
public class LoginIT {
WebDriver driver;
#BeforeTest
public void startBrowser() {
driver = new FirefoxDriver();
}
#AfterTest
public void quitBrowser() {
driver.quit();
}
#Test
public void loginAsAdmin() {
driver.get("http://localhost:9292");
withElement("open").click();
waitForPresence("username");
withElement("username").sendKeys("admin");
withElement("password").sendKeys("admin");
withElement("login-button").submit();
waitForPresence("notice");
assertThat(withElement("notice", "className"), equalTo("You are now logged in as admin."));
}
}
The key methods to note here are the calls to withElement and waitForPresence. These are defined on the Selenium class that I created and reference via the static import at the top.
Here is Selenium.java which contains that logic:
package com.testerstories.learning.helpers;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class Selenium {
public static WebElement withElement(String identifier, String locator) {
switch (locator) {
case "className":
return driver.findElement(By.className(identifier));
default:
return withElement(identifier);
}
}
public static WebElement withElement(String identifier) {
return driver.findElement(By.id(identifier));
}
public static void waitForPresence(String identifier, String locator) {
WebDriverWait wait = new WebDriverWait(driver, 10, 500);
switch (locator) {
case "className":
wait.until(ExpectedConditions.visibilityOfElementLocated(By.className(identifier)));
default:
waitForPresence(identifier);
}
}
public static void waitForPresence(String identifier) {
WebDriverWait wait = new WebDriverWait(driver, 10, 500);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(identifier)));
}
}
The key problem here are the lines that reference driver. When these methods were defined in LoginIT.java that wasn't an issue because WebDriver is defined there in the driver instance.
I do know that one answer to my problem is that I could just pass the WebDriver instance to each method. So, for example, I could use this method signature with withElement:
public static WebElement withElement(WebDriver driver, String identifier)
I'm adding another argument to pass in the WebDriver instance. But that means my test logic has to look like this:
withElement(driver, "username").sendKeys("admin");
withElement(driver, "password").sendKeys("admin");
withElement(driver, "login-button").submit();
Not the end of the world but it's less fluent and it just seems like there should be a better way.
Question:
Is there a better way?
Or am I in fact on the right track and should just accept that if I want the helper methods to be separate from the tests the driver reference must be passed in? And thus accept the slightly more verbose test statements?
Other Thought:
The only other thing I can immediately think of is that I create yet a third class that represents just WebDriver itself. This third class is then used by both my test (LoginIt.java) and my test helper (Selenium.java). I'm not sure how best to implement that but I'm also not sure if going that route makes sense.
I say that because it seems if I do that, I'm simply creating a class to wrap the creation of a WebDriver instance. So I have to create a class to then get an instance of that class so that I can create an instance of WebDriver. It seems like I'm adding complexity ... but maybe not. Hence my quest for pointers.
An alternative may be to allow your Selenium class to be initialized. Rather than having the methods be static, you can require the WebDriver reference in the class constructor.
package com.testerstories.learning.helpers;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class Selenium {
private final WebDriver driver;
public Selenium(WebDriver webDriver) {
this.driver = webDriver;
}
public WebElement withElement(String identifier, String locator) {
switch (locator) {
case "className":
return driver.findElement(By.className(identifier));
default:
return withElement(identifier);
}
}
public WebElement withElement(String identifier) {
return driver.findElement(By.id(identifier));
}
public void waitForPresence(String identifier, String locator) {
WebDriverWait wait = new WebDriverWait(driver, 10, 500);
switch (locator) {
case "className":
wait.until(ExpectedConditions.visibilityOfElementLocated(By.className(identifier)));
default:
waitForPresence(identifier);
}
}
public void waitForPresence(String identifier) {
WebDriverWait wait = new WebDriverWait(driver, 10, 500);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(identifier)));
}
}
Your LoginIT.java would then initialize the reference with in the #Before along with the driver, and change the formerly static calls to the instance you stood up:
package com.testerstories.learning.symbiote;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.testerstories.learning.helpers.Selenium;
public class LoginIT {
WebDriver driver;
Selenium selenium;
#BeforeTest
public void startBrowser() {
driver = new FirefoxDriver();
selenium = new Selenium(driver);
}
#AfterTest
public void quitBrowser() {
driver.quit();
}
#Test
public void loginAsAdmin() {
driver.get("http://localhost:9292");
selenium.withElement("open").click();
selenium.waitForPresence("username");
selenium.withElement("username").sendKeys("admin");
selenium.withElement("password").sendKeys("admin");
selenium.withElement("login-button").submit();
selenium.waitForPresence("notice");
assertThat(selenium.withElement("notice", "className"), equalTo("You are now logged in as admin."));
}
}
I'm not entirely certain if this solution follows best design practices, but here is what I ended up doing. (Note: I changed from TestNG to JUnit but other than that, everything is functionally equivalent.)
I created a Driver.java class:
package com.testerstories.learning.helpers;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
public class Driver {
private WebDriver driver;
public WebDriver getDriver() {
if (null == driver) {
driver = new FirefoxDriver();
}
return driver;
}
public void quitDriver() {
if (null != driver) {
driver.quit();
driver = null;
}
}
}
So this class is responsible for creating a driver instance and getting rid of that instance. It checks if the driver is null before creating so it won't keep creating new instances. Here I'm hard-coding a new instance of Firefox. Eventually I would have to make this class create new browser drivers based on what the user wants, but baby steps first.
Then I created DriverFactory.java which looks like this:
package com.testerstories.learning.helpers;
import org.junit.After;
import org.junit.Before;
import org.openqa.selenium.WebDriver;
public class DriverFactory {
private static Driver driver;
#Before
public void createDriver() {
driver = new Driver();
}
public static WebDriver getDriver() {
return driver.getDriver();
}
#After
public void quitDriver() {
driver.quitDriver();
}
}
This factory is used to create the driver instances. Notice the #Before and #After annotations. So this is where the tests have to rely on the driver factory. So what this means is that my tests now inherit the DriverFactory, whose responsibility is to provide an actual driver instance. So my LoginIT.java test now changes to this (continuing to use Jeremiah's provided solution as well):
package com.testerstories.learning.symbiote;
import com.testerstories.learning.helpers.DriverFactory;
import com.testerstories.learning.helpers.Selenium;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
public class LoginIT extends DriverFactory {
WebDriver driver;
Selenium selenium;
#Test
public void loginAsAdmin() {
driver = DriverFactory.getDriver();
selenium = new Selenium(driver);
driver.get("http://localhost:9292");
selenium.withElement("open").click();
selenium.waitForPresence("username");
selenium.withElement("username").sendKeys("admin");
selenium.withElement("password").sendKeys("admin");
selenium.withElement("login-button").submit();
selenium.waitForPresence("notice", "className");
assertThat(selenium.withElement("notice", "className").getText(), equalTo("You are now logged in as admin."));
}
}
I'm still doing some (all?) of the things that jpmc26 was concerned about and I can't honestly say I'm doing this well. But this does work.
If anyone has any thoughts -- particularly critical ones -- I'm most open to hearing them. As mentioned in my original question, I'm attempting to get better at Java after many, many years as a Ruby programmer. It's been rough going, to say the least.

Selenium cannot find element on website (chrome/Java)

Trying to test/learn selenium to login
the error - Exception in thread "main" org.openqa.selenium.ElementNotVisibleException: element not visible
package com.indeed.tests;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
public class test1 {
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver",
"C:\\Users\\****\\Desktop\\neww\\trainingfiles\\chromedriver.exe.exe");
WebDriver driver = new ChromeDriver();
driver.get("http://www.neopets.com/login/index.phtml");
driver.findElement(By.name("username")).sendKeys("test1");
}
private static void sleep(int i) {
}
}
I had a look at that web page. The problem is that there are two input fields with the name "username". One of them is not visible. Probably Selenium is getting that one. What you should do is:
List<WebElement> elements = driver.findElements(...);
and then get the second one (or the first, whatever), then try:
elements.get(1).sendKeys(...);

Categories