0

I have written a simple Selenium-based automation script for a login page. But I have a separate class for page objects and methods, another class for reusable components, and then the test class.

Page objects and methods

public class LoginPage extends ReusableComponents {
    WebDriver driver;
    
    @FindBy(xpath="//input[@name='username']")
    public WebElement in_username;
    
    @FindBy(xpath="//input[@name='password']")
    WebElement in_password;
    
    @FindBy(xpath="//button[@type='submit']")
    WebElement btn_submit;
    
    public LoginPage(WebDriver driver) {
        super(driver);
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }
    
    public void enterUname(String uname)  {
        in_username.sendKeys(uname);
    }
    
    public void enterPassword(String pass) {
        in_password.sendKeys(pass);
    }
    
    public void clickSubmit() {
        btn_submit.click();
    }   
}

Reusable component class

public class ReusableComponents {
    
    WebDriver driver;

    public ReusableComponents(WebDriver driver) {
        this.driver = driver;
    }
    
    public void setup()  {
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver();
        driver.manage().window().maximize();
        driver.get("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
    }

    public void waitElementToAppear(WebElement findby){
        
        WebDriverWait wait = new WebDriverWait(driver, 30);
        wait.until(ExpectedConditions.visibilityOfElementLocated((By) findby));
                
    }
    
    public void closeBrowser() {
        driver.close();
    }   
}

Test class

public class OpenBrowser {
    static WebDriver driver;

    public static void main(String[] args) {
        
        LoginPage login = new LoginPage(driver);
        ReusableComponents common = new ReusableComponents(driver);
        common.setup();
        common.waitElementToAppear(login.in_username);
        login.enterUname("Admin");
        login.enterPassword("admin123");
        login.clickSubmit();
        common.closeBrowser();
        
    }
}

Error Log

    SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Starting ChromeDriver 114.0.5735.90 (386bc09e8f4f2e025eddae123f36f6263096ae49-refs/branch-heads/5735@{#1052}) on port 31559
Only local connections are allowed.
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
ChromeDriver was started successfully.
Jun 29, 2023 8:43:53 AM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: W3C
Exception in thread "main" java.lang.ClassCastException: class jdk.proxy2.$Proxy4 cannot be cast to class org.openqa.selenium.By (jdk.proxy2.$Proxy4 is in module jdk.proxy2 of loader 'app'; org.openqa.selenium.By is in the unnamed module of loader 'app')
    at com.orange.reusablecomponents.ReusableComponents.waitElementToAppear(ReusableComponents.java:32)
    at com.orangehrm.OpenBrowser.main(OpenBrowser.java:27)

When I hover over the "in_username" object in the test in debug mode it gives me an error as I have attached here. Could someone please help me resolve this?

Screenshot of the error:

Screenshot of the error

I tried creating a webelement object but didn't help.

SternK
  • 11,649
  • 22
  • 32
  • 46
Test Bite
  • 1
  • 1

4 Answers4

0

In your situation, the issue arises when you try to cast an object of type jdk.proxy2.$Proxy4 to org.openqa.selenium.By, which is not a valid casting operation.

When utilizing PageFactory, it creates proxies for variables annotated with @FindBy. The InvocationHandler manages tasks such as searching for elements. For instance, when driver.findElements() is used, it interacts with the proxy, which then invokes the actual method. This is why the class is represented as class jdk.proxy2.$Proxy.

In your specific case, you are actually attempting to cast a proxied object of type org.openqa.selenium.remote.RemoteWebElement to org.openqa.selenium.By, which is not allowed.

By making the following modification to your code, the exception should be resolved:

wait.until(ExpectedConditions.visibilityOf(webelement));
Abhay Chaudhary
  • 1,763
  • 1
  • 8
  • 13
  • Thanks for the solution. I understand why it threw the exception. So here for webelement parameter I anyways have to call the element from login class, right? Or are you saying to use it directly on the test? What I'm trying to do is to get all the reusable components into one class. – Test Bite Jun 29 '23 at 08:41
  • you can call it from login class , there is no problem with that , just use `ExpectedConditions.visibilityOf `method which will take a WebElement type as parameter instead of By and you wont need to cast it , which is why you were getting the exception – Abhay Chaudhary Jun 29 '23 at 12:28
0

Please see the below code it works for me. Just need to add an wait after launching the web URL.

// TODO Auto-generated method stub
    WebDriverManager.chromedriver().setup();
    WebDriver driver = new ChromeDriver();
    driver.manage().window().maximize();        
    driver.get("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
    Thread.sleep(3000);
    driver.findElement(By.name("username")).sendKeys("Admin");
    driver.findElement(By.name("password")).sendKeys("admin123");
    driver.findElement(By.xpath("//button[@type='submit']")).click();
    
arpita biswas
  • 144
  • 1
  • 6
  • Yes this way it will run. But what I have tried is using the Page Factory model. I want to achieve the above script in Page factory model. – Test Bite Jun 29 '23 at 11:19
  • Where you mentioned your driver.get("url"); -> just after this line add wait. public void setup() { WebDriverManager.chromedriver().setup(); driver = new ChromeDriver(); driver.manage().window().maximize(); driver.get("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login"); Thread.sleep(3000); } – arpita biswas Jun 29 '23 at 12:46
0

Instead of explicitly waiting for elements, you can add a default wait time in you page object initialisation code using thie:

// Set the timeout value (in seconds) as per your needs
PageFactory.initElements(new AjaxElementLocatorFactory(driver, 10), this); 
hkanjih
  • 1,271
  • 1
  • 11
  • 29
CodeGreen
  • 31
  • 2
0

In the Page objects and methods class you have used:

PageFactory.initElements(driver, this);

As per the documentation of Class PageFactory:

  • initElements​(SearchContext searchContext, java.lang.Class<T> pageClassToProxy): This method instantiates an instance of the given class, and set a lazy proxy for each of the WebElement and List<WebElement> fields that have been declared, assuming that the field name is also the HTML element's "id" or "name". This method returns an instantiated instance of the class with WebElement and List<WebElement> fields proxied.

So the following @FindBys:

  • @FindBy(xpath="//input[@name='username']") public WebElement in_username;
  • @FindBy(xpath="//input[@name='password']") WebElement in_password;
  • @FindBy(xpath="//button[@type='submit']") WebElement btn_submit;

are proxied fileds. When you try to use those in conjunction with By class:

wait.until(ExpectedConditions.visibilityOfElementLocated((By) findby));

you are facing:

Exception in thread "main" java.lang.ClassCastException: class jdk.proxy2.$Proxy4 cannot be cast to class org.openqa.selenium.By (jdk.proxy2.$Proxy4 is in module jdk.proxy2 of loader 'app'; org.openqa.selenium.By is in unnamed module of loader 'app')

Solution

To wait for the visibility of the in_username field and send a character sequence, you can add two methods in the LoginPage class as follows:

public void LoginPage()
{
    WebElement element = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(LoginPage.getUsernameElement()));
    email.sendKeys("TestBite");
}

public WebElement getUsernameElement()
{
    return in_username;
}

References

You can find a couple of relevant detailed discussion in:

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352