<h2>ElementNotInteractiveException:键盘无法访问元素</h2>
<p><code>Element is not reachable by keyboard</code>用简单的词表示,使用键盘无法访问元素,这意味着您甚至不会与元素进行物理交互。</p>
<h2>原因</h2>
<p>键盘无法访问错误<em>元素的背后可能有多种原因,这些原因可能是:</p>
<ul>
<li>元素是隐藏的,因为现代的以JavaScript为中心的UI样式总是隐藏难看的原始HTML输入字段。<code>hidden</code>属性可以通过以下任一方式实现:
<ul>
<li>其他元素在所需元素上的临时覆盖。</li>
<li>其他元素在所需元素上的永久覆盖。</li>
<li>属性的存在,例如<strong><code>class="ng-hide"</code></strong>,<strong><code>style="display: none"</code></strong>等</li>
<li>根据发送字符序列时的最佳实践,不能尝试在任何<code><p></code>或<code><div></code>标记上调用<code>click()</code>或<code>sendKeys()</code>,而应在<a href="https://stackoverflow.com/questions/48369043/official-locator-strategies-for-the-webdriver/48376890#48376890">Official locator strategies for the webdriver</a>之后的所需<code><input></code>标记上调用<code>click()</code>。</li>
</ul></li>
</ul>
<h2>解决方案</h2>
<p>有不同的方法来解决这个问题。</p>
<ul>
<li><p>在临时覆盖的情况下,使用<a href="http://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/WebDriverWait.html" rel="noreferrer">WebDriverWait</a>与<a href="http://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html" rel="noreferrer">ExpectedConditions</a>相结合,使所需的<em>元素可见/可单击,如下所示:</p>
<pre><code>import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("button.nsg-button"))).click();
</code></pre></li>
<li><p>对于永久覆盖,使用<a href="https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/JavascriptExecutor.html" rel="noreferrer">JavascriptExecutor</a>接口中的<a href="https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/JavascriptExecutor.html#executeScript-java.lang.String-java.lang.Object...-" rel="noreferrer"><strong>^{<cd11>}</strong></a>方法,如下所示:</p>
<pre><code>import org.openqa.selenium.JavascriptExecutor;
String inputText = "Rozmeen";
WebElement myElement = driver.findElement(By.id("u_0_b"));
String js = "arguments[0].setAttribute('value','"+inputText+"')"
((JavascriptExecutor) driver).executeScript(js, myElement);
</code></pre>
<p>您可以在<a href="https://stackoverflow.com/questions/47453087/using-js-to-enter-text-but-if-i-input-text-in-one-text-box-the-value-already-e/47459466#47459466">Using JS to enter text, but if I input text in one text box, the value already entered is getting deleted</a></p>中找到详细的讨论</li>
<li><p>如果存在属性,例如<strong><code>class="ng-hide"</code></strong>,<strong><code>style="display: none"</code></strong>等,请使用<a href="https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/JavascriptExecutor.html" rel="noreferrer">JavascriptExecutor</a>接口中的<a href="https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/JavascriptExecutor.html#executeScript-java.lang.String-java.lang.Object...-" rel="noreferrer"><strong>^{<cd11>}</strong></a>方法编辑并将<strong><code>style="display: none"</code></strong>属性重置为<strong><code>style="display: block"</code></strong>,如下所示:</p>
<pre><code>import org.openqa.selenium.JavascriptExecutor;
((JavascriptExecutor) driver).executeScript("document.getElementById('ID').style.display='block';");
</code></pre>
<p>您可以在<a href="https://stackoverflow.com/questions/47831039/cant-fill-in-the-hidden-text-area-element/47832218#47832218">Can't fill in the Hidden text area element</a></p>中找到详细的讨论</li>
</ul>
<h2>参考文献</h2>
<ul>
<li><a href="https://github.com/mozilla/geckodriver/issues/1173" rel="noreferrer">For input[type=file], should allow sendKeys even when display=none</a></li>
<li><a href="https://github.com/w3c/webdriver/issues/1230" rel="noreferrer">Special-casing file upload controls in keyboard-interactability check</a></li>
<li><a href="https://github.com/mozilla/geckodriver/issues/1184" rel="noreferrer">Element is not reachable by keyboard</a></li>
<li><a href="https://github.com/mozilla/geckodriver/issues/1150" rel="noreferrer">Input field with display: none is not interactable at all?</a></li>
</ul>
<hr/>
<h2>这个问题</h2>
<p>如果查看<em>Facebook</em>登录页面的<em>HTML</em>,应用程序将包含<a href="https://facebook.github.io/react-native/" rel="noreferrer"><strong>React</strong></a><a href="http://www.reactnative.com/" rel="noreferrer"><strong>Native</strong></a>元素。因此,在系统中曾经用<code>id</code>表示为<strong>u0ub</strong>的元素,在下次系统上运行时可能不会用与<strong>u0ub</strong>相同的<code>id</code>表示。因此,我们必须借助<em>动态定位策略</em>。可以使用以下代码块执行预期步骤:</p>
<ul>
<li><p>代码块:</p>
<pre><code>System.setProperty("webdriver.gecko.driver", "C:\\Utility\\BrowserDrivers\\geckodriver.exe");
WebDriver driver = new FirefoxDriver();
driver.get("https://www.facebook.com");
driver.findElement(By.xpath("//input[@name='firstname' and contains(@class,'inputtext')]")).sendKeys("testing it ");
//DOB
Select sel1 = new Select(driver.findElement(By.xpath(".//*[@id='month']")));
sel1.selectByIndex(4);
Select sel2 = new Select(driver.findElement(By.xpath(".//*[@id='day']")));
sel2.selectByValue("6");
Select sel3 = new Select(driver.findElement(By.xpath(".//*[@id='year']")));
sel3.selectByValue("2013");
//clicking sign up
driver.findElement(By.xpath("//button[@name='websubmit' and contains(.,'Sign Up')]")).click();
</code></pre></li>
<li><p>浏览器客户端:</p>
<p><a href="https://i.stack.imgur.com/5hDXR.png" rel="noreferrer"><img src="https://i.stack.imgur.com/5hDXR.png" alt="FacebookRegistration"/></a></p></li>
</ul>
<hr/>
<h2>更新</h2>
<p>解决错误:</p>
<pre><code>org.openqa.selenium.ElementNotInteractableException: Element is not reachable by keyboard
</code></pre>
<p>随着Firefox功能的可用性,<a href="https://github.com/mozilla/geckodriver/#mozwebdriverclick" rel="noreferrer">moz:webdriverClick</a>变得更加容易</p>
<h2>moz:webdriverClick()</h2>
<p>通过<strong><code>webdriverClick()</code></strong>可以传递一个布尔值,指示在执行单击或向元素发送键时要运行哪种交互检查。对于<em>Firefoxen</em>在<strong>v58.0</strong>之前的版本,一些从较旧版本的<a href="https://github.com/SeleniumHQ/selenium/wiki/FirefoxDriver" rel="noreferrer">FirefoxDriver</a>导入的遗留代码正在使用中。使用<strong>Firefox v58</strong>的可用性,默认情况下,<a href="https://w3c.github.io/webdriver/" rel="noreferrer">WebDriver specification</a>所需的可交互性检查是启用的。这意味着geckodriver还将检查一个元素在单击时是否被另一个元素遮挡,以及一个元素是否可用于发送键。由于行为上的这种变化,我们知道可能会返回一些额外的错误。在大多数情况下,所讨论的测试可能需要更新,以便与新的检查一致。</p>
<p>要临时禁用符合WebDriver的检查,请使用此功能的值。</p>
<p><strong>注意</strong>:此功能仅暂时存在,并且一旦稳定了可交互性检查,它将被删除。</p>