這一週導師讓我研究selenium。selenium支持很多語言,而我使用的是js來測試。需要安裝selenium-webdriver: ^3.5.
。
基礎篇
我參考了很多文章,這裏列下其中一下:
1、
http://jeremy-xu.oschina.io/2016/05/22/web%E7%95%8C%E9%9D%A2%E6%B5%8B%E8%AF%95%E5%AE%9E%E8%B7%B5%E4%B9%8BSelenium-WebDriver/
這篇文章詳細列出了webdriver
的api,包括定位UI元素
,對UI元素的操作
,在窗口或Frame間移動
,操作Alert窗口
,操作瀏覽器的導航及地址欄
,操作Cookie
,操作窗口
,高級用戶接口
,操作等待
,until的用法
…只能說是乾貨多多。給我帶來了不少便利。
2、
https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html
這裏是官網api的介紹。詳細介紹了selenium-webdriver的一些操作。但是沒有until相關操作。很多不確定的東西來這裏看一看都可以找到答案。
3、
http://www.cnblogs.com/fnng/p/5854875.html
蟲師教你如何入門。蟲師對測試方面有很深入的瞭解並寫了Selenium 2自動化測試實戰 基於pyton語言
一書。不過似乎也有java版本的。
這些入門是非常非常快的。上面寫的太好了,我也就不重複了。
進階篇
這裏主要講講我我遇到的錯誤。
Element is not clickable at point (411, 675). Other element would receive the click
元素不可點擊錯誤。這種情況可能有原因有:
元素不可見。比如不在可見的視圖之內。關於元素可見性,請見https://www.w3.org/TR/webdriver/#element-displayedness
。
這個的解決有兩種。
①通過action
driver.actions().mouseMove(ele).click().perform(); //記得加上perform()
②通過js
driver.executeScript("scroll(x,y)"); //x,y是座標
或者
driver.executeScript("arguments[0].scrollIntoView()", webElement);
第一個參數也可以是函數:
driver.executeScript(() => {
domElement.scrollIntoView();
})
頁面正在刷新,所以無法點擊元素。這種情況下可以等頁面加載完成。
driver.wait(function() {
driver.executeScript(() => {
return document.readyState;
})
.then(state => {
driver.isOk = (state === "complete");
})
return driver.isOk;
})
或者使用driver.sleep(ms)
。不過這種機械式的等待我並不喜歡。
該元素被其他元素擋住了。這種情況下需要等到你的目標元素可見。
driver.wait(until.elementIsVisible(webElement))
在這種情況下通過腳本執行點擊也是可以的。
NoSuchElementError: no such element: Unable to locate element:
可能的原因有:
選擇器使用錯誤。使用By.xpath
容易犯錯。
不在一個frame,這是經常遇到的錯誤。
比如你的某個頁面加載了一個iframe。而你要定位iframe中的元素。這時候就會報這個錯誤。所以需要定位到這個iframe。
driver.switchTo().frame(id);
driver.findElement(...);
然後又要重定位主頁面的元素,需要再次切換回到主頁面。
driver.switchTo().defaultContent();
不在一個window中,這時候需要切換window。切換window不像切換iframe那麼簡單。需要拿到window的句柄。
driver.getAllWindowHandles(); // 獲取所有window的句柄,返回一個數組
driver.getWindowHandle(); // 獲取當前window的句柄
然後遍歷所有的window的數組,通過driver.getText()
、driver.getCurrentUrl()
等來判斷是不是你所需要的window。然後:
driver.switchTo().window(string)
這一種原因更常見,比如一個異步請求,請求完成時某個元素纔會在頁面顯示,但是代碼執行的速度非常非常快,執行到這裏的時候元素還沒出現。
可以將driver.wait
和driver.findElement
結合來解決。代碼如下:
driver.wait(() => {
$_(By.css('.group-member-list .search-result-student-item')).then(() => {
driver.isOk = true;
}, () => {
driver.isOk = false;
})
return driver.isOk;
})
delete driver.isOk;
StaleElementReferenceError: stale element reference: element is not attached to the page document
這個問題是一個非常煩的問題。我曾爲它花了兩天時間。爲此我也找過很多資料。http://docs.seleniumhq.org/exceptions/stale_element_reference.jsp這裏是官方給出的原因。
元素被刪除了
1.頁面部分刷新(ajax)或者導航到另一個頁。
2.頁面上的元素被js框架替換成了一個一模一樣的元素。這樣的話元素就是stale的。雖然頁面上觀察不到任何變化。實際上,我一直懷疑我的是這種原因,頁面使用了react,我懷疑當我作出某處操作的時候,頁面重新渲染了。後來的元素和之前的元素一模一樣,但是我已經丟失了之前元素的綁定。
元素不再綁定到dom
比如有一個tab,我們在tab上做切換操作的時候,實際上我們切換的是dom。這時候,之前dom上的元素我們不再使用(頁面上不再使用),變成stale的了。
除了這些之外,我搜索其他資料的時候也發現一些原因:
元素被重定位到頁面其他位置
元素通過ajax重新渲染到頁面
做過渡效果的時候,比如有一個div,想要讓一個新的div來代替它。這時候clone老的div,讓它移出去,而新的div移進來(這塊我也不是很理解,文末有相關鏈接)
爲了解決(儘可能解決)這種錯誤,可能的解決方法有:
每次重新定位元素而不是存儲對元素的引用
每次使用 driver.findElement() 來查找元素而不是:
let ele = driver.findElement()
......
ele.xxx
因爲ele可能會丟失綁定
利用js庫的鉤子
比如jquery中,動畫有一個隊列。可以查詢一個元素上是否有動畫。如果元素處於動畫中,可能會報這個錯誤。
僞代碼
driver.wait(() => {
return animationQueue === 0
})
等一個元素變成stale
如果知道一個元素會變成stale,那麼就等它變成stale再去操作它。until中有一個方法。
driver.wati(until.stalenessOf(ele));
源碼如下:
exports.stalenessOf = function stalenessOf(element) {
return new Condition('element to become stale', function() {
return element.getTagName().then(
function() { return false; },
function(e) {
if (e instanceof error.StaleElementReferenceError) {
return true;
}
throw e;
});
});
};
js中設置window下的變量
$.ajax(url)
.then()
.always(() => {
window.__ISCOMPLETED__ = true;
})
然後在selenium中:
driver.wait(() => {
dirver.executeScript(() => {
driver.isOk = (window.__ISCOMPLETED__ = true);
})
return driver.isOk;
})
將操作移到js而不是使用selenium的操作
driver.executeScript(() => {
documnet.querySelector(selector).click();
})
我就是使用這種方法的。
另外需要說明一下,永遠不要使用try/catch。我不敢說selenium中所有操作是異步的。但是try/catch無法捕捉錯誤。你需要使用:
driver.xxxxxx
.then()
.catch()
番外篇
來自:
http://huziketang.com/blog/posts/detail?postId=58d50da37413fc2e8240855c
想說點關於使用 await 的一些話
你在可能網絡上其他地方看到一些例子,它們並沒有使用 async/await,或者是使用了promise。實際上這樣的代碼是同步的。那麼爲什麼也能 work 的很好呢?坦白地說,我也不知道,看起來像是在 webdriver 中有些trick 的處理。正如 selenium 文檔中說道,在 Node 支持 async/await 之前,這是一個臨時的解決方案。
Selenium 文檔是 Java 語言。它還不完整,但是包含的信息也足夠了,你做幾次測試就能掌握這個技能。
來自:
http://engineeringquality.blogspot.hk/2013/08/ways-of-dealing-with.html
Is that in reality, the selection and the click action will actually be sent as 2 separate calls when it goes over the wire on Selenium’s JSON wire protocol. Doing this all in JavaScript will ensure the call gets executed in the same frame.
就是說我們使用:
driver.findElement().click()
的時候,selenium會分成兩步處理。這是由於JSON wire protocol規定的。
參考
https://stackoverflow.com/questions/11908249/debugging-element-is-not-clickable-at-point-error
http://engineeringquality.blogspot.hk/2013/08/ways-of-dealing-with.html
http://huziketang.com/blog/posts/detail?postId=58d50da37413fc2e8240855c
有問題歡迎聯繫我,可以一起探討。
郵箱:[email protected]
。