? ?WebdriverIO是一款支持mobile app和mobile web自動化測試框架,與appium集成,完成對mobile應用測試。支持ios 和android兩種平臺,且功能豐富,是mobile app自動化測試首選框架。且官方還提供了mobile 應用測試example代碼,大大減少了從0構建移動應用自動化測試base code時間。
? ?如果搭建mobile app應用的UI自動化測試代碼,在選擇框架時需要考慮如下一些點框架是否支持
1.是否支持自動等待?自動等待可提升UI自動化測試穩定性
2.是否支持自動scroll element 到viewport中?如果不支持,UI自動化測試會很脆弱
3.是否支持上下,左右滑動
4.是否支持對目標元素進行拖動
5.是否支持錯誤截圖
6.定位頁面元素selector是否豐富
接下來看看webdriverio是否有上面的特性,以及如何實現上下的特性
WebdriverIO支持自動等待
? ?webdriverIO框架支持自動等待,框架有各種等待超時時間設置。例如可以在全局配置文件中,靈活設置連接appium server的超時時間(connectionRetryTimeout,connectionRetryCount),查找頁面元素超時時間(waitForSelectorTimeout)。除了全局設置,還可以手動設置超時時間,例如使用await element.waitForDisplayed({timeout: 1000})。通過這些超時時間,可以增加整個UI自動化測試穩定性。
WebdriverIO支持自動scroll element到viewport中
? 在查找元素的時候,如果元素不在viewport中,webdriverIO會自動向下滑動,直到找到目標元素。以Android為例,下面有三種寫法查找目標元素,如果目標元素不在viewport中,框架會自動向下滑動頁面,直到找到目標元素。因為三種方式都可以實現向下滑動,建議首選第一種,
//使用UiSelector()直接查找頁面元素,如果元素不存在,會默認向下滑動查找目標元素public async goToFirstPage() {const firstPageSelector = driver.isAndroid? 'android=new UiSelector().resourceId("com.binance.dev:id/2131435629")': '//XCUIElementTypeButton[@name="xx"]';await $(firstPageSelector).click()}
// 使用了UiScrollable,如果元素不存在,會默認向下滑動查找目標元素public async scrollDownToSymbol(symbol: string) {// UiScrollable默認是向下滾動,不會向上滾動const symbolSelector = driver.isAndroid? `android=new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().text("${symbol}"))`: `//XCUIElementTypeStaticText[@name="${symbol}"]`;await $(symbolSelector).click()}// scrollIntoView默認也是向下滾動,不會向上滾動public async scrollIntoView(symbol: string) {const symbolSelector = driver.isAndroid? `android=new UiSelector().text("${symbol}")`: `//XCUIElementTypeStaticText[@name="${symbol}"]`;await $(symbolSelector).scrollIntoView()}
WebdriverIO如何支持上下、左右滑動
? 上面介紹了自動向下滑動,直到找到目標元素,在實際場景中,除了向下滑動,有時候需要向上滑動到界面頂部,或者向上滑動直到找到目標元素。另外,有時候還需要左右滑動,下面是具體實現的代碼。
//向上滑動
public async scrollUpToSymbol(symbol: string) {const topElementSelector = `new UiSelector().text("${symbol}")`;// 使用 mobile: scroll 支持up,down 滾動,不支持左右滾動await driver.execute('mobile: scroll', {strategy: '-android uiautomator',selector: topElementSelector,direction: 'up' // 指定滾動方向為向上});}
//向右滑動public async swipeRight() {const selector = driver.isAndroid? 'android=new UiSelector().resourceId("com.binance.dev:id/tabLayout")': '//XCUIElementTypeButton[@name="xx"]';const scrollableElement = $(selector)await driver.swipe({// swipe right,屏幕會顯示左邊的內容direction: "right",scrollableElement: scrollableElement,percent: 0.8,});}
//向左滑動public async swipeLeft() {const selector = driver.isAndroid? 'android=new UiSelector().resourceId("com.binance.dev:id/tabLayout")': '//XCUIElementTypeButton[@name="xx"]';const scrollableElement = $(selector)await driver.swipe({// swipe left,屏幕會顯示右邊的內容direction: "left",scrollableElement: scrollableElement,percent: 0.8,});}
}
WebdriverIO如何實現拖動目標元素
? 實際項目中,有些場景需要拖動目標元素到另外一個位置,某些應用的登錄頁面,可能就存在拖動的場景,下面是使用webdriverio實現拖動的code。dragAndDrop比較簡單,因為webdriverIO已經進行了封裝,直接調用即可。
it('should demonstrate the dragAndDrop command', async () => {const elem = $('#someElem')const target = $('#someTarget')// drag and drop to other elementawait elem.dragAndDrop(target)// drag and drop relative from current positionawait elem.dragAndDrop({ x: 100, y: 200 })
})
WebdriverIO如何支持錯誤截圖
? UI自動測試中,支持錯誤截圖是非常重要的功能,當有大量自動化case在流水線上每天運行時,維護成本是較大的,支持錯誤截圖可以幫助更快的判斷失敗case的原因,更快的進行修復。支持錯誤截圖非常簡單,在conf.ts文件中增加如下配置即可。即便是對原生app進行錯誤截圖,也適用browser.takeScreenshot()方法。
//在conf配置文件中增加如下的配置
afterTest: async function (test, context, { error, result, duration, passed, retries }) {if (!passed) {const screenshot = await browser.takeScreenshot();const fileName = `FAILED_${test.title.replace(/\s+/g, '_')}.png`;const filePath = path.join(process.cwd(), 'screenshots', fileName);// 確保目錄存在fs.mkdirSync(path.dirname(filePath), { recursive: true });// 保存截圖fs.writeFileSync(filePath, screenshot, 'base64');console.log(`Screenshot taken: ${filePath}`);}},
? webdriverio除了支持錯誤截圖,還支持視覺測試,視覺測試本質就是通過對比兩張截圖來驗證功能是否符合預期,如果某些應用頁面只讀信息比較多,那么可以采用這種方式來進行對比,不用手寫每個頁面元素進行對比,減少編寫代碼成本。
WebdriverIO支持哪些Selector
? ?對于Android應用,基本都采用UiAutomator2?Driver,下面列舉的selector都是UIAutomator2支持的selector,主要通過resourceId,text,className來定位,如果有多個元素,還可以通過.instance(index)來定位,或者先定位parent元素,再定位children元素。如果目標元素有content-des屬性,且該屬性值唯一,那么可以直接使用$('~content-desc')來定位。
public async inputAmount(amount: string) {const amountInputSelector = driver.isAndroid ? 'android=new UiSelector().resourceId("com.binance.dev:id/2131441146")' : "";await $(amountInputSelector).setValue(amount)}public async viewAsset() {const holdingAssetMenu = driver.isAndroid ? 'android=new UiSelector().text("持有幣種")' : "";await $(holdingAssetMenu).click()}public async getPnlValue(index: number) {// 這里查找index=2的時候,沒有自動向下滑動,可以手動調用scrollIntoView的方法const parentSelector = driver.isAndroid ? `android=new UiSelector().resourceId("com.binance.dev:id/2131431738").instance(${index})` : "";const childSelector = driver.isAndroid ? 'android=new UiSelector().resourceId("com.binance.dev:id/tv_asset_daily_pnl_value")' : "";const pnl_value = await $(parentSelector).$(childSelector).getText()}const selector = 'new UiSelector().text("Cancel").className("android.widget.Button")'
const button = await $(`android=${selector}`)
await button.click()
? 對于IOS app,工具也支持多種元素定位方式,最常見的是如果目標元素有accessibility id,那么使用$('~accessibility id')定位,另外還可以通過-ios predicate string來定位目標元素。
const selector = `type == 'XCUIElementTypeSwitch' && name CONTAINS 'Allow'`
const switch = await $(`-ios predicate string:${selector}`)
await switch.click()const element = await $(`-ios predicate string:label == 'Login'`);const element = await $(`-ios predicate string:name BEGINSWITH 'Submit'`);const element = await $(`-ios predicate string:value > 10`);const element = await $(`-ios class chain:**/XCUIElementTypeCell[`name BEGINSWITH "A"`][-1]/XCUIElementTypeButton[10]`);
除此之外,webdriverio的還支持zoom,tap,swipe,longPress操作。例如,可以通過tap模擬點擊右鍵操作。
it('should be able to swipe right 3 times in a custom scroll areas to an element and tap on the element', async () => {const elem = $('~myElement')// Swipe right 3 times in the custom scrollable element to find the elementawait elem.tap({direction: 'right',maxScrolls: 3,scrollableElement: $('#scrollable')})
})
?除了常規的定位頁面元素,操作頁面元素外,webdriverio還支持視覺測試,即通過對比圖片來達到驗證的效果。如果某些app界面變化很小,那么可以采用視覺測試的方法,可有效降低編寫代碼的成本。
WebdriverIO視覺測試
?使用webdriverio開展視覺測試,首先需要在conf文件的services中進行如下配置,配置好后即可開始視覺測試,常用的方法就四個saveElement,checkElement,saveScreenshot,checkScreenshot。
["visual", {baselineFolder: path.join(process.cwd(), "virtual", "baseline"),formatImageName: "{tag}",screenshotPath: path.join(process.cwd(), "virtual", "tmp"),savePerInstance: true,autoSaveBaseline: true,blockOutStatusBar: true,blockOutToolBar: true,ignoreNothing: true,}]//通過saveElement對目標元素進行截圖存放到baseline中,再通過checkElement進行對比,如果對比不一致,會在diff文件中存放不一致的圖片public async saveScreenForNormalFeature() {const selector = driver.isAndroid? 'android=new UiSelector().resourceId("com.binance.dev:id/2131438006")': '//XCUIElementTypeButton[@name="xx"]';await browser.saveElement(await $(selector), "normalFeature", {enableLayoutTesting: true})}public async checkScreenshotNormalFeature() {const selector = driver.isAndroid? 'android=new UiSelector().resourceId("com.binance.dev:id/2131438006")': '//XCUIElementTypeButton[@name="xx"]';await browser.checkElement(await $(selector), "normalFeature", {enableLayoutTesting: true})}
運行測試后,會自動創建響應的目錄,并將目標元素截圖存放到對應folder中。
以上就是對webdriverio工具的總體介紹。