Selenium 不可见使用 XSLT 模板创建的元素
Posted
技术标签:
【中文标题】Selenium 不可见使用 XSLT 模板创建的元素【英文标题】:Element created with XSLT templating not visible by Selenium 【发布时间】:2015-12-11 23:57:28 【问题描述】:问题是当我尝试为输入设置值时,selenium 返回以下错误: RuntimeError:元素当前不可见,因此可能无法与之交互
但是,输入是完全可见的。在这个测试中,我使用的是 Firefox,因为它是正确加载应用程序的浏览器。
我无法更改应用程序代码,并且该应用程序有很多旧代码,但我重新创建了最简单的示例,您可以在其中看到问题。
您知道任何不修改应用程序代码的解决方法吗?
我正在使用 webdriverio:
this.browser
.url('http://localhost/main.xml')
.setValue('[name=inputId]', 'aaaaaaaa')
.close()
.then(callback)
main.xml 内容:
<?xml version="1.0" encoding="iso-8859-1" ?>
<?xml-stylesheet type="text/xsl" href="main.xsl" ?>
<CONTEXTO></CONTEXTO>
main.xsl 内容:
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="iso-8859-1"/>
<xsl:include href="helper.xsl"/>
<xsl:template match="CONTEXTO">
<html>
<head>
<title>Test main</title>
<style>
* margin:0;
form position: absolute;
input border: 1px black solid;
</style>
</head>
<body>
<form name="" action="" method="POST">
<label for="inputId">inputId
<input type="text" name="inputId" id="inputId" value="" />
</label>
</form>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
helper.xsl 内容:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<script></script>
<xsl:apply-templates select="CONTEXTO"/>
</xsl:template>
</xsl:stylesheet>
【问题讨论】:
【参考方案1】:也许您在使用 XML 内容时遇到了 Selenium 的限制,因为浏览器对它的处理方式与 HTML 内容不同。您可以尝试改用 SendKeys 来解决此问题。但是如果它找不到元素,你将不得不通过按键导航来找到元素,这可能会很棘手。
或者,尝试使用find_element_by_name
or find_element_by_id
or use XPath 或this webdriver.io alternative 查找元素。如果没有工作,您可以通过从根节点到下一个节点遍历树来查找。如果不起作用,那么我的猜测是,Selenium 看到的是 XML DOM(尝试查找根元素),而不是 XSLT 生成的 DOM。
【讨论】:
谢谢@Abel。我可以使用 Selenium 找到该元素,但不识别为可见。使用 webdriver.io 的 selectorExecute 方法返回此错误:RuntimeError: waiting for doc.body failed。我找到了issue about this in Selenium Developers group,当 xml 文档格式错误时,在浏览器中执行 js 似乎是 firefox 中的一个错误。 @atena,如果 XML 文档格式不正确,XSLT 甚至都无法正常运行。如果您在没有 Selenium 的情况下加载文档,它会正确呈现吗?如果您检查源代码,您将看到呈现的 XML,它是否格式正确且有效(也许处理器启动,并在发现非法内容时中断,这是 XSLT 允许且符合标准的方法) 是的,@Abel,该应用程序是旧 Intranet 的一部分,它只适用于某些 firefox 和 ie 版本。我认为问题在于 html 标记之前包含的脚本标记,但这是我无法更改的。 @atena,哎呀,html标签之前的脚本标签?这是非常违法的。它将需要具有一个根元素的 HTML 转换为具有两个根文档的非文档。在 XSLT 中,允许创建它,但不允许处理它。我可以理解这会带来麻烦。【参考方案2】:先尝试等待输入值存在:
.waitForExist('[name=inputId]', 1000)
.setValue('[name=inputId]', 'aaaaaaaa')
【讨论】:
感谢 jrader。输入存在,但对于 selenium 仍然不可见。 即使在使用 waitForExist 之后也会出现错误?你得到什么错误? @atena,我猜你遇到了 Selenium 的错误,或者 webdriver-io 的错误。你应该报告它。但我怀疑他们对此做了很多,这种类型的渲染(带有 xsl-stylesheet PI 的 XML 文件)在实际生产环境中很少使用(你在我的回答下删除了你的评论,所以我在这里重新发布) @jrader,是的,错误:RuntimeError:元素当前不可见,因此可能无法与之交互 @Abel,对不起,我的评论有误 :) 关于这个错误,是的,我几天前在 Selenium 社区报告了这个错误(尝试从 Ruby 中返回相同的错误太)但还没有人批准。再次感谢!【参考方案3】:问题在于 XSL 正在生成格式错误的 HTML。助手将匹配/
并生成一个脚本标签并应用CONTEXTO
模板,从而生成如下文档:
<script></script>
<html>....</html>
这不像 HTML 那样有太多意义。
由于某种原因,firefox 的 TransformiIX 引擎在这种情况下忽略了输出方法 HTML
并回退到 text
输出,这导致包含名为 transformiix:result
的包装器标记。 (请参阅此link 以供参考)。
您可以像我一样通过向 webdriver 发出 getPageSource() 并将其打印到日志来检查这一点。您将看到转换的结果输出是:
<transformiix:result>
<script></script>
<html>....</html>
</transformiix:result>
这使得 webdriver 完全无法与页面交互。
推荐的解决方法是修复 XSLT。如果这不是一个选项(影响非常大),您可以在页面加载之后(或在第一次尝试与页面交互之前)使用 webdriver 的 executeScript 执行以下脚本。
document.getRootNode().replaceChild(document.getElementsByTagName('html')[0], document.getElementsByTagName('transformiix:result')[0])
这将使用html
标记替换文档根节点transformiix:result
。
请注意,如果在您当前的开发中,您的 helper.xsl 中包含了更多内容,您可能还需要获取这些标签,然后将其移动到标题标签中,作为上述脚本的一部分。
编辑:您还可以通过在 firefox 调试窗口中执行以下代码来重现 XSL 问题:
//Execute in a firefox inspect console
var p = new XSLTProcessor();
var toTransform = document.implementation.createDocument(null, "CONTEXTO");
var parser = new DOMParser();
var xmlString = `<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="iso-8859-1"/>
<xsl:template match="/">
<script></script>
<xsl:apply-templates select="CONTEXTO"/>
</xsl:template>
<xsl:template match="CONTEXTO">
<html>
<body>
Hello
</body>
</html>
</xsl:template>
</xsl:stylesheet>
`;
p.importStylesheet(parser.parseFromString(xmlString, "text/xml"));
var doc = p.transformToDocument(toTransform);
console.log(doc.getRootNode().children[0].outerHTML);
【讨论】:
以上是关于Selenium 不可见使用 XSLT 模板创建的元素的主要内容,如果未能解决你的问题,请参考以下文章
XTDE0160:XSLT 1.0 兼容模式在此配置中不可用,在未命名模式下 /invoice:request 的内置模板规则中
XSLT:复制 <mathml> 的所有子元素,不带 m: 命名空间,而无需为每个元素创建模板
如何强制Selenium WebDriver点击当前不可见的元素?