Protractor的隐式等待如何与显式等待交互?

时间:2017-03-06 14:32:38

标签: javascript selenium webdriver protractor wait

当隐式等待小于显式时会发生误解:

var timeOut = 5000;
var search = element(by.xpath(`//*[@name='qwer']`));
browser.manage().timeouts().implicitlyWait(4000);
browser.ignoreSynchronization = true;

describe('Protractor Test', function () {
    beforeEach(function () {
        browser.get('https://www.google.com.ua');
    });
    it('EC', function () {
        console.log('START');
        // browser.sleep(timeOut);
        browser.wait(protractor.ExpectedConditions.presenceOf(search), timeOut);
    });
});

总时间:8.613秒。隐式设置等待第二个低位:3000,结果为6.865秒。它是如何在引擎盖下工作的? 非常感谢提前!

3 个答案:

答案 0 :(得分:17)

这是个好问题。许多优秀的质量保证自动化专家都对此感到不满。

隐式等待

这是每个driver.findElement(...)上的特殊隐藏自动等待。 如果在页面DOM结构中找不到元素,则原始webdriver(js,python,java)会抛出NoSuchElementException。无论您使用何种定位器,这种等待都将在每个driver.findElement之前完成。当隐式等待超时时,将在findElement函数之外抛出NoSuchElementException。

启用隐式等待

默认情况下,隐式等待超时设置为0browser.manage().timeouts().implicitlyWait(3000)使webdriver自动尝试/捕获此异常,并重试找到此元素。如果传递了3秒(超时),并且DOM中仍然没有元素 - 那么只有你得到NoSuchElementException。

什么时候好:

您的页面修改DOM结构(网站的99.999%),某些元素仍未在DOM中,但在1-3秒内显示。要不进行显式等待,并减少代码量 - 您可以尝试设置隐式等待超时。

什么时候不好: 您想测试DOM中不存在该元素。在每次.findElement调用之前都会添加这种等待,所以当您尝试断言时:

expect($('NON-EXIST-ELEMENT').isPresent()).toBeFalsy()

您的implicitWait仍然在这里工作。首先,你将等待3秒钟才能出现元素,然后抛出异常,并被isPresent()函数捕获,在这种情况下将返回false(我们实际断言的内容)。所以你等了3秒钟!设置implicitWait(0)然后在断言元素不存在(这可能真的很烦人)之后将其设置回来是有意义的。

<强>结论 当你理解它是如何工作的时候,隐含的等待是好的。我建议不要将隐式等待设置超过1-5秒(您应该为每个网站定义自己的值)。此外,如果您计划断言许多不存在的元素 - 将隐式等待重置为0,然后将其重新设置。

显式等待

这种等待你应该自己调用,但它比隐式等待更灵活。在protractorjs中,当您需要等待某事时,您必须致电browser.wait()。它接受谓词函数(只返回true / false的函数,没有例外)。 Webdriver将轮询此函数,直到超时发生(您将其指定为第二个参数)。您还可以指定要作为第三个参数抛出的错误消息。

显然,在Web自动化中,您大多数时间都在等待一些元素条件。为此,人们创建了谓词函数的集合。此函数调用ExpectedConditions,并将为传递给它们的元素返回true / false。

browser.wait(ExpectedConditions.visibilityOf($('NON-EXISTING-ELEMENT')), 3000, 'error message')

好的时候: 当你必须等待你的元素的一些棘手的条件。您可以轻松定义要等待的自己的条件,指定自定义超时等。 在使用可能尚未准备好的元素进行操作之前使用。

什么时候不好: 当您尝试通过组合browser.sleep(),隐式等待和显式等待来帮助您时。默认情况下,browser.sleep()很糟糕,在99%的情况下,您可以使用提供的条件将其替换为browser.wait(),或者编写您自己的条件。

当您拥有隐式等待设置并尝试调用显式等待时,会发生更多有趣的事情。 想像: browser.manage().timeouts().implicitlyWait(10000) browser.wait(EC.stalenessOf($('NON-EXIST-ELEMENT')), 5000) //waiting for 5 seconds for element to disappear

这里发生了什么: 等待函数调用元素的stalenessOf()函数。在其中,driver.findElement()被召唤。隐式等待不要让此函数立即抛出错误,并将网页池化10秒直到发生隐式等待超时,并且我们得到NoSuchElementException。发生异常,执行返回等待功能,已经过了10秒!等待以TimeOutException终止,因为它仅安排了5秒钟。我们的等待时间比预期的要长得多。

另请注意,JS是异步的,并且由于事件循环而无法保证准确的等待时间。通常这会使等待不准确 - 5200毫秒而不是5000(例如)。这是完全不同的故事:)

您的示例中会发生什么

隐式超时 - 4000毫秒。

显式超时 - 5000毫秒。

  1. 等等。第一次调用谓词函数 - presenceOf()
  2. 内部谓词调用原始webdriverjs函数 - driver.findElement(By.xpath('//*[@name='qwer']'))
  3. 由于设置了隐式等待,我们在抛出错误之前等待它。
  4. 传递了4000毫秒的隐式元素等待。只是现在我们将错误返回到谓词函数。
  5. 谓词函数捕获错误,而返回false
  6. 因为我们在显式等待调用谓词函数超时之前仍然有1000毫秒。
  7. 隐含等待再次开始。 4000毫秒之后 - 将错误抛回谓词函数
  8. 谓词返回false
  9. 等待函数变为false,我们的显式等待时间已经过时 - 在理想情况下 - 它大概是8000毫秒,但也要注意异步调用,所以实时会更多
  10. 等待抛出错误 - jasminejs捕获错误,并且测试失败
  11. 我希望这会有所帮助!

答案 1 :(得分:1)

这是一个很好的问题,当使用隐式和显式等待的组合时,这些不可预测的等待时间已被警告&amp;在Selenium documentation中说明。 browser.wait()是明确的等待,您将其与implicit wait - browser.manage().timeouts().implicitlyWait()

结合使用
  

等待使自动任务执行过了一定量   在继续下一步之前的时间。你应该选择使用   显式等待或隐式等待。

     

警告:不要混合隐式和显式等待。这样做可能会导致   不可预测的等待时间。例如,设置隐式等待10   秒和显式等待15秒,可能导致超时   20秒后发生。

答案 2 :(得分:0)

答案是:两个人等待并行。隐式等待轮询4秒并返回失败,此后显式等待仅等待4秒并且还有1个等待。这再次重新发出隐含的等待,并再次轮询4秒并再次失败。 8秒后(2次隐式等待尝试)5秒的显式等待也超时了,最后我们在浪费3个意外秒后得到错误。例如,在Implicit设置为8且Explicit设置为17的情况下,我们将等待8 * 3 = 24秒。请注意,脚本执行需要一些时间,因此如果下一次迭代很慢,则可能无法启动。