Ders
Ders

Reputation: 1742

How to resolve ElementNotInteractableException thrown by sendKeys method of Selenium WebDriver?

As an exercise in learning Selenium WebDriver I am trying to visit the Twitter log in page and log in. I am finally able to navigate to the page and get the desired* element for the username field:

<input class="text-input email-input js-signin-email" name="session[username_or_email]" type="text">

*I have tried to find what types of elements sendKeys operates with but I can't. I think this element is the one I want since the tag is of the <input> type.

When I call sendKeys on the element after assigning it I get an ElementNotInteractableException. I have tried using explicit waits with the ExpectedConditions of visibilityOf and invisibilityOf. The respective interpretation of the TimeoutException and ElementNotInteractableException tells me that the element I mentioned above loads in the DOM tree but never becomes visible*. How do I get around this? Is there a solution using a JavascriptExecutor?

*The surrounding html might reveal why the element remains invisible:

<form class="t1-form clearfix signin js-signin"
action="https://twitter.com/sessions" method="post">
  ::before
  <fieldset>
    <legend class="visuallyhidden">Log in</legend>
    <div class="clearfix field">
      ::before
      <input class="text-input email-input js-signin-email"
      name="session[username_or_email]" type="text">

.

**For those on the hunt, this question is helpful to look at especially if the issue is caused by the click method instead.

Upvotes: 2

Views: 5142

Answers (2)

Ders
Ders

Reputation: 1742

EDIT: apparently I didn't do quite enough research, although I didn't see this question on StackOverflow. Going to leave this question in case it helps someone.

Using JavascriptExecutor (Source 1.):

  1. Import: import org.openqa.selenium.JavascriptExecutor;
  2. General idea: JavascriptExecutor executor= (JavascriptExecutor) driver; executor.executeScript(script, arguments);
  3. For a sendKeys alternative we need to execute a bit of JS that sets the text value of the element using dot notation. We have to find the element first. (Source 1.) Use document.getElementById('id'), document.getElementsByTagName('name'), or document.getElementsByClassName('class') to find the element (Source 2.). Note that for the last two options for locating the element multiple elements are gathered, so index the one you want.

An example line of code that turned out to be my solution: executor.executeScript("document.getElementsByClassName('js-username-field email-input js-initial-focus')[0].value='someValue';");

Note that .getElementById('id') is probably preferred, but in my case the website designers decided to be uncooperative and not provide an id attribute.

Here are two (incredible!) resources on the subject--check them out!

  1. https://www.softwaretestingmaterial.com/javascriptexecutor-selenium-webdriver/
  2. https://www.w3schools.com/js/js_htmldom_document.asp

Upvotes: 1

Andrei
Andrei

Reputation: 5637

You can use this code:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

public class Test  {
  public static void main(String[] args) throws InterruptedException {
    final WebDriver driver = new ChromeDriver();

    driver.get("https://twitter.com/login?lang=en");

    WebDriverWait wait = new WebDriverWait(driver, 10);

    // locate login input
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//input[@placeholder = 'Phone, email or username']")));
    WebElement loginInput = driver.findElement(By.xpath("//input[@placeholder = 'Phone, email or username']"));
    loginInput.click();
    loginInput.sendKeys("login");

    // locate password input
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//fieldset//input[@placeholder = 'Password']")));
    WebElement passInput = driver.findElement(By.xpath("//fieldset//input[@placeholder = 'Password']")); // this xPath does the trick
    passInput.click();
    passInput.sendKeys("password");
    Thread.sleep(3000); // only to see the result

    //locate submit button
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//button[@type= 'submit']")));
    WebElement submitBtn = driver.findElement(By.xpath("//button[@type= 'submit']"));
    submitBtn.click();

    Thread.sleep(3000); // only to see the result
    driver.quit();
  }
}

Upvotes: 1

Related Questions