我正在使用Robot Framework和Selenium来测试一个具有语言选择器的网站。我需要能够选择一种语言,然后验证页面是否已实际更改为该语言。
由于选择新语言后,<html>
标记的lang
属性中的值发生了变化,因此我决定使用它来验证语言是否已成功更改。但是我得到的结果很不稳定,因为我的测试有时通过,有时没有。
这是我正在使用的关键字的定义:
CHANGE LANGUAGE
[Arguments] ${lang}
Select From List By Value ${LANGUAGE SWITCH} ?hl=${lang}
Wait Until Page Contains Element css=html
${doc lang} Get Element Attribute css=html@lang
Should Be True '${doc lang}'=='${lang}' timeout=15s
由于我必须多次执行此关键字(每种可用语言一个),因此我经常收到可怕的"过时元素"错误:| FAIL | stale element reference: element is not attached to the page document
。
我通读了本文和这里的其他一些问题,并了解如果在获取元素引用后对其进行更新,可能会发生这种情况。但是,我不确定我应该如何修改我的关键字以避免出现此错误。
使用每个人都如此友好地提供的信息,我可能已经找到了一个潜在的修复程序(不确定它是否足够强大,不再抛出异常,但经过几次测试运行后,它们都通过了): 我添加了一个"等到关键字成功"并将语言验证移动到一个新的关键字:
VALIDATE PAGE LANGUAGE
[Arguments] ${lang}
${doc lang} Get Element Attribute css=html@lang
Should Be True '${doc lang}'=='${lang}'
CHANGE LANGUAGE
[Arguments] ${lang}
Select From List By Value ${LANGUAGE SWITCH} ?hl=${lang}
Wait For Condition return document.readyState=="complete"
Wait Until Keyword Succeeds 5 5s VALIDATE PAGE LANGUAGE ${lang}
然后,我调用此关键字"更改语言"的次数与我需要测试的语言一样多。
我将其添加为答案而不是注释,以便我可以以更易读的方式显示代码。
为了等待页面准备好在用户操作(例如单击链接或按钮)后进行测试,我发现似乎几乎无懈可击的算法是这样的:
- 获取对 HTML 元素的引用
- 执行将导致页面更改的操作(例如:单击链接或按钮)
- 等待 HTML 元素过时 - 这表示刷新已开始
- 等待
document.readyState
"complete"
第 4 步可能不是必需的,但不会造成伤害。
这对我的团队来说非常有效。这仍然可能会失败,因为您可能有一些异步 javascript 在设置document.readyState
后运行,但根本没有通用解决方案。
如果你的页面有一堆异步javascript,你必须想出自己的方案来知道页面何时最终准备好进行测试。例如,最后一个要完成的作业可以设置一个标志,或者您可以等到没有挂起的异步作业等。
我不确定您是否可以使用机器人关键字执行上述操作,因为它依赖于硒staleness_of
条件。不过,在python中实现它很容易。
这个解决方案的灵感来自这篇博文:如何让Selenium在点击后等待页面加载
如果您将我的页面对象库用于机器人,则它是内置的上下文管理器。
突出显示的Stale Element
错误通常意味着在元素检索和相应的操作之间元素发生了更改。这通常是由于页面刷新。
因此,投资于稳健的等待方法非常重要。不是猜测您的页面/应用程序已完成加载,而是知道它已完成。这不仅可以防止Stale Element
错误,还可以加快测试速度,因为您不会不必要地等待。
由于Get Element Attribute ${DOCUMENT}@lang
导致过时元素错误,而Select From List By Value ${LANGUAGE SWITCH} ?hl=${lang}
导致页面刷新,因此Wait Until Page Contains Element html
将作为等待的临近。
由于<html>
标签始终存在,并且是第一个在 DOM 中加载的标签,因此这不是等待的最佳标签。我会为加载的页面或该页面的最后一个元素建议一些独特的东西。虽然我必须强调,这仍然构成猜测页面已加载。
最好投资于稳健的等待方法。特别是如果你的应用程序使用像Angular,React或jQuery这样的框架,那么你有几个Javascript标记来帮助你解决这个问题。对于某些框架,甚至有支持其特定标记的自定义机器人框架库。
如果您的应用程序不使用框架,请与您的开发人员交谈并让他们为您开发它。最简单的是可见的微调器,但返回True
的 Javascript 函数也可以正常工作。
每当我想单击元素或执行和执行操作时,我都会创建一个自定义关键字,我会称之为自定义关键字。此自定义关键字使用内置关键字"等到关键字成功",该关键字运行指定的关键字,如果失败则重试。 通过此内置关键字,可以配置重试次数和在上次运行失败后再次尝试运行关键字之前等待的时间。
此自定义关键字将调用另一个自定义关键字,其中将调用三个 SeleniumLibrary 关键字。第一个将等待,直到启用元素定位器关键字,这将等到元素未禁用或只读。启用元素后,焦点将转到我们要执行操作的元素上。最后执行该操作。所有这些预防措施都防止了我出现陈旧元素错误。
HighLevelKeyword_Identify And Click Element
[Arguments] ${locator}
Wait Until Keyword Succeeds ${RETRY_ATTEMPTS} ${RETRY_AFTER} Identify And Click Element ${locator}
Identify And Click Element
[Arguments] ${locator}
Wait Until Element Is Enabled ${locator}
Set Focus To Element ${locator}
Click Element ${locator}