在 XCUITest 裡處理畫面捲動,直到目標元件出現

使用 XCUITest 基本上我們不需要自己處理畫面捲動的問題,例如要點擊某個按鈕,但該按鈕需要捲動畫面直到按鈕顯示後,才能點擊到此按鈕,但其實 XCUITest 只要抓到該元件後,直接點擊該按鈕就會自動捲到此按鈕出現,但有些情況下可能無法這麼順利操作 (可參考此篇官方說明),此時我們就需要自己來處理畫面捲動的操作。

本篇文章將帶大家透過 XCUITest 實作捲動畫面至某個元件出現後就停止捲動。(使用開發環境 Xcode 7.3.1)

例如有一個 TableView 如下圖所示,我們要捲動至第 13 個 Cell 上後,接著再對 UI 驗證或操作。

xc1

在 Stack Overflow 你可能會找到此篇教學,提供的做法如下所示:

首先我們必須擴展原本 XCUIElement,先加入 visible() 這個函示判斷元件是否顯示在畫面上,如果元件已顯示在畫面上則此函示會回傳 true,反之則回傳 false,接著加入 scrollToElement() 函示,可以看到這個函示的實作會一直呼叫 swipeUp() 函示將畫面往上捲動,直到指定的元件出現後就停止捲動。

extension XCUIElement {
	func scrollToElement(element: XCUIElement) {
		while !element.visible() {
			swipeUp()
		}
	}

	func visible() -> Bool {
		guard self.exists && !CGRectIsEmpty(self.frame) else {
			return false
		}

		return CGRectContainsRect(XCUIApplication().windows.elementBoundByIndex(0).frame, self.frame)
	}
}

 

Test Code 如下所示:

func testScrollTable() {
	let app = XCUIApplication()
	let table = app.tables.elementBoundByIndex(0)
	let cell12 = table.cells.elementBoundByIndex(12)
	table.scrollToElement(cell12)
}

 

雖然這做法可能就能處理大部分的情況,不過此做法是使用 XCUITest 裡面本身提供的 swipeUp() 函示來捲動畫面,但這個捲動畫面的位移大小我們並無法控制,如果畫面轉成橫向,呼叫 swipeUp() 一次就會捲動過大,可能導致要捲至的元件早就捲過頭,而程式還一直捲動畫面,如下圖所示:

xcui_1

 

因此必須控制一次要捲動的位移大小,來解決過度捲動的問題,我們可透過設定從某個起始點,點選後再拖動至某個終點,這樣就可以根據不同的需求來客製化要如何捲動,如下圖所示,我們可以知道畫面的原點在左上角,橫向為 X 軸,縱向為 Y 軸。

xc2

有了以上的觀念後,我們就可以根據畫面的座標位置,來設定要拖動的起點與終點,稍微改一下原本的做法,完成後程式碼如下所示:

extension XCUIElement {
	func scrollToElement(element: XCUIElement, scroll:() -> Void) {
		while !element.visible() {
			scroll()
		}
	}

	func visible() -> Bool {
		guard self.exists && !CGRectIsEmpty(self.frame) else {
			return false
		}

		return CGRectIntersectsRect(XCUIApplication().windows.elementBoundByIndex(0).frame, self.frame)
	}
}

 

Test Code 如下所示:

func testScrollTable() {
	let app = XCUIApplication()
	let table = app.tables.elementBoundByIndex(0)
	let cell12 = table.cells.elementBoundByIndex(12)
	let mainWindow = XCUIApplication().windows.elementBoundByIndex(0)

	mainWindow.scrollToElement(cell12) {
		let fromPoint: XCUICoordinate = mainWindow.coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: 0.75))
		let toPoint: XCUICoordinate = mainWindow.coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: 0.25))

		fromPoint.pressForDuration(0, thenDragToCoordinate: toPoint)
	}
}

 

我們將原本使用 XCUITest 提供的 swipeUp() 改用自己客制的 scroll(),這個客製化捲動是使用閉包(Closures)來實作,這樣使用者就可容易地根據不同需求來調整操作。

可以看到以上程式碼,我們會先抓到整個畫面 (window),且指定變數名稱為 mainWindow,接著從 mainWindow 整個畫面中來設定 fromPoint 座標,再拖拉到指定的 toPoint 座標來捲動畫面,而這裡 fromPoint 跟 toPoint 都是透過 Normalized Offset 來抓座標位置,也就是按照百分比位置,舉例來說如果 mainWindow 大小為 500 (High) * 300 (Width),則 fromPoint 會抓到 (150, 375) 而 toPoint 為 (150, 125) ,這樣就可以指定要捲動的位移大小。

經過調整後,我們就可以控制捲動的位移大小,因而解決原本方法會造成過度捲動的問題,如下圖所示:

xcui_2

 

畫面捲動位移的大小須根據不同的需求來選擇適合的方法,本篇教學提供一個可以讓使用者控制要捲動的幅度,希望對大家在處理畫面捲動的問題有所幫助。

 

廣告

5 thoughts on “在 XCUITest 裡處理畫面捲動,直到目標元件出現

  1. 嗨,感謝您的分享,在我的case 當中,由於使用了tableHeaderView,因此直接使用XCUIApplication().windows.elementBoundByIndex(0).frame 與cell 做比對時,會有誤差,因次我改成了XCUIApplication().tables.elementBoundByIndex(0).frame,即可正常運作。

    另外關於UI test 的問題想請教您,不知道是否有測試custom view 的經驗,在我的case 當中,我的tableHeaderView 使用了Custom UIView,他本身還有一個Setting button,我替setting button 加上了accessibilityIdentifier與isAccessibilityElement設為YES,使用voice over 時,可以正常的念出settings button ,也可以在accessibility inspector 當中正確的選中該按鈕,但在進行element query 時,卻沒有辦法正確的query 到這個按鈕,不曉得有沒有相關經驗可以分享呢?

    特別感謝您!

    1. 此問題我也有遇過,只要再多設定 accessibilityElements 就可以解決了,

      可參考這篇說明:http://stackoverflow.com/questions/22459458/custom-uitableviewcell-accessibility

      希望對你有幫助 ^_^

      1. Hi Mark, 非常感謝您的回覆!我參考了此篇Stackoverflow以及它的相關連結後,依然沒有辦法正確使用,我將此問題同步發問於stackoverflow:http://stackoverflow.com/questions/38008917/using-xcuielementquery-to-query-a-button-in-tableheaderview-not-found

        內含部分程式碼,其中,accessibility inspector 的截圖如:http://imgur.com/uUEOVaQ

        不知道我有沒有什麼地方有疏漏呢?

發表迴響

Please log in using one of these methods to post your comment:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s