问题描述
h:selectOneRadio
在表中产生<input type="radio">
,在表中的<input type="radio">
中产生p:selectOneRadio
,在input
周围有一些div
.两者的ID都是[form id]:[selectOneRadio id]:[option number]
,使用@FindBy(id="[...]")
访问它时,我可以在石墨烯功能测试中成功地将其用于普通JSF,而PrimeFaces变体由于org.openqa.selenium.ElementNotInteractableException
而失败.调查生成的HTML,我看不出有什么区别
A h:selectOneRadio
results in <input type="radio">
in a table and p:selectOneRadio
in <input type="radio">
in a table with some div
s around the input
. The id for both is [form id]:[selectOneRadio id]:[option number]
which I can use successfully for the plain JSF in a Graphene functional test when accessing it with @FindBy(id="[...]")
whereas the PrimeFaces variant fails due to org.openqa.selenium.ElementNotInteractableException
. Investigating the generated HTML I don't see the difference
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link type="text/css" rel="stylesheet" href="/34696ceb-eeaa-4b35-88dd-f3c8fc5901bf/javax.faces.resource/theme.css.xhtml?ln=primefaces-aristo">
<link type="text/css" rel="stylesheet" href="/34696ceb-eeaa-4b35-88dd-f3c8fc5901bf/javax.faces.resource/primefaces.css.xhtml;jsessionid=48ca919d0b7e89661f92149ac321?ln=primefaces&v=5.0">
<script type="text/javascript" src="/34696ceb-eeaa-4b35-88dd-f3c8fc5901bf/javax.faces.resource/jquery/jquery.js.xhtml;jsessionid=48ca919d0b7e89661f92149ac321?ln=primefaces&v=5.0"></script>
<script type="text/javascript" src="/34696ceb-eeaa-4b35-88dd-f3c8fc5901bf/javax.faces.resource/primefaces.js.xhtml;jsessionid=48ca919d0b7e89661f92149ac321?ln=primefaces&v=5.0"></script>
<title>Facelet Title</title>
</head>
<body>
<form id="mainForm" name="mainForm" method="post" action="/34696ceb-eeaa-4b35-88dd-f3c8fc5901bf/index.xhtml;jsessionid=48ca919d0b7e89661f92149ac321" enctype="application/x-www-form-urlencoded">
<input name="mainForm" value="mainForm" type="hidden">
<table id="mainForm:mainSelectOneRadio">
<tbody>
<tr>
<td>
<input name="mainForm:mainSelectOneRadio" id="mainForm:mainSelectOneRadio:0" value="a" type="radio">
<label for="mainForm:mainSelectOneRadio:0"> a</label>
</td>
<td>
<input name="mainForm:mainSelectOneRadio" id="mainForm:mainSelectOneRadio:1" value="b" type="radio">
<label for="mainForm:mainSelectOneRadio:1"> b</label>
</td>
<td>
<input name="mainForm:mainSelectOneRadio" id="mainForm:mainSelectOneRadio:2" value="c" type="radio">
<label for="mainForm:mainSelectOneRadio:2"> c</label>
</td>
</tr>
</tbody>
</table>
<table id="mainForm:mainSelectOneRadioPrime" class="ui-selectoneradio ui-widget">
<tbody>
<tr>
<td>
<div class="ui-radiobutton ui-widget">
<div class="ui-helper-hidden-accessible">
<input id="mainForm:mainSelectOneRadioPrime:0" name="mainForm:mainSelectOneRadioPrime" value="aPrime" type="radio">
</div>
<div class="ui-radiobutton-box ui-widget ui-corner-all ui-state-default"><span class="ui-radiobutton-icon ui-icon ui-icon-blank"></span>
</div>
</div>
</td>
<td>
<label for="mainForm:mainSelectOneRadioPrime:0">aPrime</label>
</td>
<td>
<div class="ui-radiobutton ui-widget">
<div class="ui-helper-hidden-accessible">
<input id="mainForm:mainSelectOneRadioPrime:1" name="mainForm:mainSelectOneRadioPrime" value="bPrime" type="radio">
</div>
<div class="ui-radiobutton-box ui-widget ui-corner-all ui-state-default"><span class="ui-radiobutton-icon ui-icon ui-icon-blank"></span>
</div>
</div>
</td>
<td>
<label for="mainForm:mainSelectOneRadioPrime:1">bPrime</label>
</td>
<td>
<div class="ui-radiobutton ui-widget">
<div class="ui-helper-hidden-accessible">
<input id="mainForm:mainSelectOneRadioPrime:2" name="mainForm:mainSelectOneRadioPrime" value="cPrime" type="radio">
</div>
<div class="ui-radiobutton-box ui-widget ui-corner-all ui-state-default"><span class="ui-radiobutton-icon ui-icon ui-icon-blank"></span>
</div>
</div>
</td>
<td>
<label for="mainForm:mainSelectOneRadioPrime:2">cPrime</label>
</td>
</tr>
</tbody>
</table>
<input name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="-485558793831512050:990657069126697889" autocomplete="off" type="hidden">
</form>
</body>
</html>
如果我在Payara 4.1.2或ElementNotInteractableException
的任何其他原因上部署应用程序,也不会.
nor do I if I deploy the application on Payara 4.1.2 or any other reason for the ElementNotInteractableException
.
访问完成
@RunWith(Arquillian.class)
public class MyManagedBeanTest {
private static final String WEBAPP_SRC = "src/main/webapp";
private final static Logger LOGGER = LoggerFactory.getLogger(MyManagedBeanTest.class);
@Deployment(testable = false)
public static Archive<?> createDeployment0() throws TransformerException, XPathExpressionException, ParserConfigurationException, SAXException, IOException {
WebArchive retValue = ShrinkWrap.create(WebArchive.class)
.add(EmptyAsset.INSTANCE, "beans.xml")
.addClasses(MyManagedBean.class)
.addAsWebInfResource(
new StringAsset("<faces-config version=\"2.0\"/>"),
"faces-config.xml");
Maven.configureResolver().workOffline().resolve("richtercloud:graphene-click-input-radio:war:1.0-SNAPSHOT").withoutTransitivity().asList(JavaArchive.class).forEach(dependency -> retValue.addAsLibrary(dependency));
//add all webapp resources
retValue.merge(ShrinkWrap.create(GenericArchive.class)
.as(ExplodedImporter.class)
.importDirectory(WEBAPP_SRC)
.as(GenericArchive.class), "/", Filters.include(".*\\.(xhtml|css|js|png)$"));
ByteArrayOutputStream archiveContentOutputStream = new ByteArrayOutputStream();
retValue.writeTo(archiveContentOutputStream, Formatters.VERBOSE);
LOGGER.info(archiveContentOutputStream.toString());
return retValue;
}
@Drone
private WebDriver browser;
@ArquillianResource
private URL deploymentUrl;
@FindBy(id = "mainForm:mainSelectOneRadio:0")
private WebElement mainSelectOneRadioOption0;
@FindBy(id = "mainForm:mainSelectOneRadioPrime:0")
private WebElement mainSelectOneRadioPrimeOption0;
@Test
public void testAll() {
browser.get(deploymentUrl.toExternalForm()+"index.xhtml");
LOGGER.debug(browser.getPageSource());
mainSelectOneRadioOption0.click();
mainSelectOneRadioPrimeOption0.click();
}
}
我正在寻找一种触发JSF操作方法和AJAX侦听器的解决方案!
I'm searching for a solution which triggers JSF action methods and AJAX listeners!
我也会对通用方法感兴趣,例如p:selectOneButton
产生
I'd be interested in a generic approach as well, e.g. p:selectOneButton
produces
<div id="mainForm:mainSelectOneButtonPrime" class="ui-selectonebutton ui-buttonset ui-widget ui-corner-all">
<div class="ui-button ui-widget ui-state-default ui-button-text-only ui-corner-left">
<input id="mainForm:mainSelectOneButtonPrime:0" name="mainForm:mainSelectOneButtonPrime" value="aPrime" class="ui-helper-hidden" type="radio">
<span class="ui-button-text ui-c">aPrime</span>
</div>
<div class="ui-button ui-widget ui-state-default ui-button-text-only">
<input id="mainForm:mainSelectOneButtonPrime:1" name="mainForm:mainSelectOneButtonPrime" value="bPrime" class="ui-helper-hidden" type="radio">
<span class="ui-button-text ui-c">bPrime</span>
</div>
<div class="ui-button ui-widget ui-state-default ui-button-text-only ui-corner-right">
<input id="mainForm:mainSelectOneButtonPrime:2" name="mainForm:mainSelectOneButtonPrime" value="cPrime" class="ui-helper-hidden" type="radio">
<span class="ui-button-text ui-c">cPrime</span>
</div>
</div>
<input name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="-5130093024933213812:2291815208147638618" autocomplete="off" type="hidden">
乍一看似乎与为p:selectOneRadio
生成的HTML没有任何共同之处.也许有一个窍门.
which doesn't seem to have anything in common with the HTML generated for p:selectOneRadio
at first sight. Maybe there's a trick.
可以在> https://github.com/krichter722/graphene中找到SSCCE -click-input-radio .
我正在使用PrimeFaces 6.1.
I'm using PrimeFaces 6.1.
推荐答案
@Guy的答案正确.
@Guy has the right answer.
这里的问题是PrimeFaces在HTML之上应用了自己的样式,该样式覆盖了您要单击的元素.
The issue here is that PrimeFaces is applying its own styling on top of the HTML which is covering the element you are trying to click.
Selenium在单击顶部的元素时检查目标元素mainForm:mainSelectOneRadio:0
是否接收到事件.但是在这种情况下,覆盖是通过同级容器完成的,而同级容器不是目标元素的后代.因此,Selenium假定该元素将不会接收事件,并引发ElementNotInteractableException
(请参阅事件冒泡和传播).
Selenium checks that the targeted element mainForm:mainSelectOneRadio:0
receives the events when the element on top is clicked. But in this case the overlay is done with a sibling container which is not an descendant of targeted element. Thus Selenium assumes that the element will not receive the events and raises an ElementNotInteractableException
(see event bubbling and propagation).
通过访问 oneRadio.xhtml ,您可以清楚地看到此问题.并通过右键单击检查单选按钮.您会看到所选的DOM元素和<input>
位于DOM树的两个不同分支中.
You can clearly see the issue by visiting oneRadio.xhtml and by inspecting the radio button with a right click. You'll see that the selected DOM element and the <input>
are located in two different branches of the DOM tree.
要解决此问题,请单击标签,因为它没有覆盖层(请参阅@Guy的解决方案).标签具有for
属性,这意味着所有事件都转发到分配给目标<input>
的for
元素.
To overcome this issue, either click the label since it has no overlay (see solution from @Guy). The label has the for
attribute which mean that all the events are forwarded to the element assigned to for
which is the targeted <input>
.
您也可以直接单击叠加层.不过,您必须使用XPath来表达这种关系.
You could also directly click the overlay. Though, you'll have to use an XPath to express the relationship.
目标<input>
的父母的父母:
@FindBy(xpath = "id('mainForm:mainSelectOneRadioPrime:2')/../..")
private WebElement mainSelectOneRadioPrimeOption0;
或具有目标<input>
的第一个<td>
:
@FindBy(xpath = "//td[.//input[@id='mainForm:mainSelectOneRadioPrime:2']]")
private WebElement mainSelectOneRadioPrimeOption0;
这篇关于为什么我单击带有h:selectOneRadio的type = radio的输入,而不单击带有石墨烯/硒的p:selectOneRadio的输入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!