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属性解析为一个数组。

XSLT:复制 <mathml> 的所有子元素,不带 m: 命名空间,而无需为每个元素创建模板

如何强制Selenium WebDriver点击当前不可见的元素?

如何使用 Selenium 和 Java 通过 PageFactory 等待元素不可见

selenium定位元素提示‘元素不可见’问题解决方法