問題描述
當隱式等待小于顯式時,就會發(fā)生誤解:
The misunderstanding happens when implicit wait is less than explicit:
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,結(jié)果為 6.865 秒.它是如何在引擎蓋下工作的?提前非常感謝!
Overall time: 8.613 seconds. Set implicitlyWait a second lower: 3000 and result is 6.865 seconds. How does it work under the hood? Big thanks in advance!
推薦答案
這是個好問題.很多優(yōu)秀的 QA 自動化人員對此感到震驚.
Thats nice question. A lot of good QA automation guys broke their heads with this.
這是每個 driver.findElement(...)
上的特殊隱藏自動等待.如果在頁面 DOM 結(jié)構(gòu)中找不到元素,原始 webdriver(js、python、java)會拋出 NoSuchElementException.這種等待將在每個 driver.findElement
之前完成,無論您使用哪種定位器.當隱式等待超時時,將在 findElement
函數(shù)之外拋出 NoSuchElementException.
This is special hidden automatic wait, on each driver.findElement(...)
.
Original webdriver (js, python, java) throws NoSuchElementException if element cannot be found in page DOM structure. This kind of wait will be done before EVERY driver.findElement
, no matter what kind of locator do you use. When implicit wait timed out, NoSuchElementException will be thrown outside findElement
function.
啟用隱式等待
默認情況下,隱式等待超時設置為 0
.browser.manage().timeouts().implicitlyWait(3000)
使 webdriver 自動嘗試/捕獲此異常,并重試查找此元素.如果 3 秒(超時)過去了,并且元素仍然不存在于 DOM 中 - 只有這樣你才會得到 NoSuchElementException.
By default implicit wait timeout is set to 0
. browser.manage().timeouts().implicitlyWait(3000)
makes webdriver automatically try/catch this exception, and retry to find this element. If 3 seconds (timeout) passed, and element is still not present in DOM - only then you are getting NoSuchElementException.
好的時候:
您的頁面修改了 DOM 結(jié)構(gòu)(網(wǎng)站的 99.999%)并且一些元素仍然不在 DOM 中,但會在 1-3 秒內(nèi)出現(xiàn).為了不進行顯式等待并減少代碼量 - 您可以嘗試設置隱式等待超時.
Your page modify DOM structure (99.999% of website) and some elements still not in the DOM, but appear within 1-3 seconds. To not make explicit waits, and reduce amount of code - you can try to set implicit wait timeout.
不好的時候:您想測試 DOM 中不存在該元素.這種等待是在每個 .findElement
調(diào)用之前添加的,所以當你嘗試這樣斷言時:
When it is bad:
You want to test that element is not present in the DOM. This kind of wait is added before every .findElement
call, so when you are trying to assert like this:
expect($('NON-EXIST-ELEMENT').isPresent()).toBeFalsy()
您的 implicitWait
仍在此處工作.首先,您將等待 3 秒元素出現(xiàn),然后將拋出異常,并由 isPresent() 函數(shù)捕獲,在這種情況下將返回 false(我們實際斷言的內(nèi)容).所以你要多等 3 秒!設置 implicitWait(0)
并在斷言元素不存在后將其設置回來是有意義的(這可能真的很煩人).
Your implicitWait
still working here. First you will wait for 3 seconds to element to be present, then exception will be thrown, and caught by isPresent() function, that will return false in this case (what we actually asserting). So you are waiting for 3 extra seconds! It makes sense to set implicitWait(0)
and then set it back after asserting element is not present (which might be really annoying).
結(jié)論當您了解它的工作原理時,隱式等待很好.我建議不要將隱式等待設置為超過 1-5 秒(您應該為每個網(wǎng)站定義自己的值).此外,如果您打算斷言許多不存在的元素 - 將隱式等待重置為 0,然后將其設置回來.
Conclusion Implicit waits are good, when you understand how it is works. I recommend to not set implicit wait more than 1-5 seconds (you should define own value for each website). Also if you plan to assert lot of not-present elements - reset implicit wait to 0, and then set it back.
這種等待你應該自己調(diào)用,但它比隱式等待靈活得多.在protractorjs中,當你需要等待某些東西時,你必須調(diào)用browser.wait()
.它接受謂詞函數(shù)(只返回真/假,沒有異常的函數(shù)).Webdriver 將輪詢此函數(shù),直到發(fā)生超時(您將其指定為第二個參數(shù)).您還可以指定要作為第三個參數(shù)拋出的錯誤消息.
This kind of waiting that you should call by yourself, but it much more flexible than implicit waits. In protractorjs, when you need to wait for something, you must call browser.wait()
. It accepts predicate function (function that will return only true/false, no exceptions). Webdriver will poll this function until timeout occurs (you specify it as second param). Also you can specify error message that you want to throw as third parameter.
顯然,在網(wǎng)絡自動化中,您大部分時間都在等待某些元素條件.為此,這些人創(chuàng)建了謂詞函數(shù)集合.此函數(shù)調(diào)用 ExpectedConditions,并將為傳遞給它們的元素返回 true/false.
Obviously, that in web automation you wait for some element conditions most of the time. For this guys have created collection of predicate functions. This functions calls ExpectedConditions, and will return true/false for element that was passed to them.
browser.wait(ExpectedConditions.visibilityOf($('NON-EXISTING-ELEMENT')), 3000, '錯誤信息')
好的時候:當您必須等待元素的一些棘手條件時.您可以輕松定義自己想要等待的條件、指定自定義超時等.在處理可能尚未準備好的元素之前使用.
When it is good: When you have to wait for some tricky conditions of your elements. You can easily define own conditions that you want to wait, specify custom timeout and so on. Use before manipulating with elements that might not be ready yet.
不好的時候:當您嘗試通過組合 browser.sleep()
來幫助您時,隱式等待和顯式等待結(jié)合在一起.browser.sleep()
默認是不好的,在 99% 的情況下你可以用 browser.wait()
替換它并提供條件,或者編寫你自己的條件.
When it is bad:
When you try to help you by combining browser.sleep()
, implicit waits and explicit waits together. browser.sleep()
is bad by default, in 99% of cases you can replace it with browser.wait()
with provided conditions, or write your own condition.
當您設置了隱式等待并嘗試調(diào)用顯式等待時,會發(fā)生更多有趣的事情.想象:browser.manage().timeouts().implicitlyWait(10000)
browser.wait(EC.stalenessOf($('NON-EXIST-ELEMENT')), 5000)//等待5秒讓元素消失
Much more fun happens when you have your implicit wait set, and you trying to call explicit wait.
Imagine:
browser.manage().timeouts().implicitlyWait(10000)
browser.wait(EC.stalenessOf($('NON-EXIST-ELEMENT')), 5000) //waiting for 5 seconds for element to disappear
這里發(fā)生了什么:等待函數(shù)為您的元素調(diào)用 stalenessOf()
函數(shù).在其中,driver.findElement()
被調(diào)用.隱式等待不要讓這個函數(shù)立即拋出錯誤,并將網(wǎng)頁池化 10 秒,直到發(fā)生隱式等待超時,我們得到 NoSuchElementException.發(fā)生異常,執(zhí)行返回等待函數(shù),已經(jīng)過了 10 秒!等待以 TimeOutException 終止,因為它只安排了 5 秒.我們收到錯誤,等待時間比預期的要長.
What happens here:
Wait function calls stalenessOf()
function for your element. Inside it, driver.findElement()
got called. Implicit wait don't let this function to throw error immediately, and pools webpage for 10 seconds until implicit wait timeout happens, and we are getting NoSuchElementException. Exception happens, and execution returns to wait function, 10 seconds are passed already! Wait is terminated with TimeOutException, because it was scheduled only for 5 seconds. We are getting error with wait time much longer that expected.
另外請記住,JS 是異步的,由于事件循環(huán),不能保證準確的等待時間.通常這會使等待不準確 - 5200 毫秒而不是 5000 毫秒(例如).這是完全不同的故事:)
Also keep in mind that JS is async, and cannot guarantee exact wait time because of Event Loop. Usually this makes waiting not exact - 5200 ms instead 5000 (as example). This is absolutely different story :)
隱式超時 - 4000 毫秒.
implicit timeout - 4000 milliseconds.
顯式超時 - 5000 毫秒.
explicit timeout - 5000 milliseconds.
- 等待開始.第一次調(diào)用謂詞函數(shù) -
presenceOf()
- 內(nèi)部謂詞調(diào)用原始 webdriverjs 函數(shù) -
driver.findElement(By.xpath('//*[@name='qwer']'))
- 由于設置了隱式等待,我們在拋出錯誤之前等待它.
- 經(jīng)過了 4000 毫秒的隱式元素等待.只是現(xiàn)在我們將錯誤返回到謂詞函數(shù).
- 謂詞函數(shù)捕獲錯誤,并改為返回 false
- 由于在顯式等待超時之前我們還有 1000 毫秒的時間 - 再次調(diào)用謂詞函數(shù).
- 隱式等待再次開始.4000 毫秒后 - 將錯誤返回到謂詞函數(shù)
- 謂詞返回 false
- Wait 函數(shù)為 false,我們的顯式等待超時 - 在理想情況下 - 大約為 8000 毫秒,但也要注意異步調(diào)用,因此實時會更多
- 等待拋出錯誤 - jasminejs 捕獲錯誤,并且測試失敗
我希望這會有所幫助!
這篇關(guān)于Protractor 的隱式等待如何與顯式等待交互?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!