## iOS 謂詞(Predicate)
*注意*: iOS 謂詞(Predicate)在 iOS 9.3及以下系統,使用 `-ios uiautomation` 定位策略,在 iOS 10 及以上系統,使用 `-ios predicate string` 定位策略。
在查看 *'-ios uiautomation'* 搜索策略時了解 **謂詞(Predicate)** 十分必要。 [UIAutomation JavaScript API](https://web.archive.org/web/20160904214108/https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/)有下列幾種非常有用的方法:
```center
(UIAElement) UIAElementArray.firstWithPredicate(PredicateString predicateString)
(UIAElementArray) UIAElementArray.withPredicate(PredicateString predicateString)
```
原生的JS搜索策略(由Apple提供)提供了更大的靈活性,并且和XPath很像。
**[謂詞(Predicate)](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Predicates/predicates.html)** 可以通過使用多個匹配條件來準確定位某一個或某一組元素(相當于只有搜索條件與元素的計算結果為 true 時這些元素才會被認為是匹配的)。
(翻譯備注:XPath 是一門用來定位 xml 文檔中的元素的語言,能提供基于路徑、元素屬性等條件的定位策略)
使用 '-ios uiautomation'示例:
```java
// java
appiumDriver.findElementsByIosUIAutomation("collectionViews()[0].cells().withPredicate(\"ANY staticTexts.isVisible == TRUE\")")
```
使用 '-ios predicate string'示例:
```java
// java
appiumDriver.findElementsByIosNsPredicate("isWDVisible == 1");
```
\- 將只選擇那些在主視圖第一個 ```UIACollectionView``` 元素下的、擁有可見子元素 ```UIAStaticText``` 的 ```UIACollectionCell``` 元素。在這里, ```staticTexts()``` 和 ```isVisible()``` 分別是```UIAElementArray``` 和 ```UIAElement``` 的子方法。 **注意: ```UIAElementArray``` 序列編號從 ```0``` 開始,而不是像 Xpath 那樣從 ```1```開始**
以下是所有可用的謂詞(Predicate)的列表(主要取自 [謂詞(Predicate) 編程指南](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Predicates/predicates.html))
### 基本比較
= , ==
- 左邊表達式等于右邊表達式:
```javascript
tableViews()[1].cells().firstWithPredicate("label == 'Olivia' ")
same in Xpath: /UIATableView[2]/UIATableCell[@label = 'Olivia'][1]
```
\>= , =\>
- 左邊表達式大于或等于右邊表達式。
<= , =<
- 左邊表達式小于或等于右邊表達式。
\>
- 左邊表達式大于右邊表達式。
<
- 左邊表達式小于右邊表達式。
!= , <\>
- 左邊表達式不等于右邊表達式。
BETWEEN
- 左邊表達式的值在右邊表達式的兩個邊界值之間或等于其中一個邊界值。右邊表達式為一個有兩個值的數組,數組的第一個值是上限,第二個值是下限(這個順序是固定的) ,例如 ```1 BETWEEN { 0 , 33 }```, 或者 ```$INPUT BETWEEN { $LOWER, $UPPER }```。
在 Objective-C, 你可以創建一個自定義的 BETWEEN 謂詞(Predicate),如下面的示例所示:
```center
NSPredicate *betweenPredicate =
[NSPredicate predicateWithFormat: @"attributeName BETWEEN %@", @[@1, @10]];
```
這創建了一個等價于 ```( ( 1 <= attributeValue ) && ( attributeValue <= 10 ) )``` 的謂詞
### 布爾值謂詞
TRUEPREDICATE
- 計算結果恒等于 ```TRUE``` 。
FALSEPREDICATE
- 計算結果恒等于 ```FALSE```。
### 基本的復合謂詞
AND , &&
- 邏輯與。
OR , ||
- 邏輯或。
NOT , !
- 邏輯非。
### 字符串比較
在默認情況下,字符串比較是區分大小寫和音調( diacritic )的,你可以在方括號中用關鍵字符 ```c``` 和 ```d``` 來修改操作符以相應的指定不區分大小寫和變音符號。例如 名字的開頭 ```firstName BEGINSWITH[cd] $FIRST_NAME```
(翻譯備注:這里的音調是指英文字母的音調,如 `"náive"` 和 `"naive"`。如果不加關鍵字 `d`,這兩個字符串會認為是不等價的。)
BEGINSWITH
- 左邊的表達式以右邊的表達式作為開始。
```center
scrollViews()[3].buttons().firstWithPredicate("name BEGINSWITH 'results toggle' ")
same in Xpath: /UIAScrollView[4]/UIAButton[starts-with(@name, 'results toggle')][1]
```
CONTAINS
- 左邊的表達式包含右邊的表達式。
```center
tableViews()[1].cells().withPredicate("ANY collectionViews[0].buttons.name CONTAINS 'opera'")
same in Xpath: /UIATableView[2]/UIATableCell[UIACollectionView[1]/UIAButton[contains(@name, 'opera')]]
```
ENDSWITH
- 左邊的表達式以右邊的表達式作為結束。
LIKE
- 左邊表達式等于右邊表達式: ? 和 *可作為通配符, 其中 ? 匹配 1 個字符, * 匹配 0 個或者多個字符。 在 Mac OS X v10.4, 通配符不能匹配換行符。
```center
tableViews()[0].cells().firstWithPredicate("name LIKE '*Total: $*' ")
same in Xpath: /UIATableView[1]/UIATableCell[matches(@name, '.*Total: \$.*')][1]
```
MATCHES
- 左邊表達式根據ICU v3的正則表達式風格比較,等于右邊表達式 (詳情請看ICU用戶指南中的 [正則表達式](http://userguide.icu-project.org/strings/regexp))。
```center
tableViews().firstWithPredicate("value MATCHES '.*of 7' ")
same in Xpath: /UIATableView[matches(@value, '.*of 7')][1]
```
### 聚合操作
ANY , SOME
- 指定匹配后續表達式的任意元素。例如 ```ANY children.age < 18``` 。
```center
tableViews()[0].cells().firstWithPredicate("SOME staticTexts.name = 'red'").staticTexts().withName('red')
same in Xpath: /UIATableView[1]/UIATableCell[UIAStaticText/@name = 'red'][1]/UIAStaticText[@name = 'red']
```
ALL
- 指定匹配后續表達式的所有元素。例如 ```ALL children.age < 18``` 。
NONE
- 指定不匹配后續表達式的元素。例如 ```NONE children.age < 18``` 。 邏輯上等價于 ```NOT (ANY ...)``` 。
IN
- 等價于 SQL 的 IN 操作,左邊的表達必須出現在右邊指定的集合中。例如 ```name IN { 'Ben', 'Melissa', 'Matthew' }``` 。 這個集合可以是一個數組( array ),一個列表( set ), 或者一個字典( dictionary )。當這個集合是字典時,這里使用的是它的值( value )。
array[index]
- 指定數組中特定索引處的元素。
array[FIRST]
- 指定數組中的第一個元素。
array[LAST]
- 指定數組中的最后一個元素。
array[SIZE]
- 指定數組的大小
```center
elements()[0].tableViews()[0].cells().withPredicate("staticTexts[SIZE] > 2")
same in Xpath: /*[1]/UIATableView[1]/UIATableCell[count(UIAStaticText) > 2]
```
### 標識符
**C語言標識符**
- 任何C語言的標識符都不是保留字。
**\#symbol**
- 用來把一個保留字轉義為用戶標識符。
**[\\]{octaldigit}{3}**
- 用來表示一個八進制數 ( ```\```后面加上3位八進制數字)。
**[\\][xX]{hexdigit}{2}**
- 用于表示十六進制數 ( ```\x``` 或 ```\X``` 后面加上2個十六進制數字)。
**[\\][uU]{hexdigit}{4}**
- 用于表示 Unicode 編碼 ( ```\u``` 或 ```\U``` 后面加上4個十六進制數字)。
### 文字 (Literals)
(翻譯備注:Literals 在編程語言領域的意思是在代碼中可以看得到的(或說可視的)那些值。例如字符串 `"a"`,數組 `[1, 2]`,你可以在代碼中一眼看出這是一個字符串,數組還是別的數據類型并知道它的值。這一節說的就是這些值的寫法)
單引號和雙引號都能產生相同的結果,但他們不會匹配對方(單引號不會匹配雙引號)。例如:```"abc"``` and ```'abc'``` 都是可識別的 ,但是 ```"a'b'c"``` 等價于```a, 'b', c```。
FALSE , NO
- 表示邏輯上的 false。
TRUE , YES
- 表示邏輯上的 true。
NULL , NIL
- 空值。
SELF
- 代表被使用的對象本身。
"text"
- 一個字符串。
'text'
- 同上,也是一個字符串。
**以逗號分隔的文本數組**
- 舉個例子 ```{ 'comma', 'separated', 'literal', 'array' }``` 。
**標準的整數和小數**
- 舉個例子 ```1 , 27 , 2.71828 , 19.75``` 。
**帶有冪指數的小數**
- 舉個例子 ```9.2e-5``` 。
0x
- 十六進制數的前綴, 如`0x11`表示十六進制數11,等同于十進制的17。
0o
- 八進制數的前綴。
0b
- 二進制數的前綴。
### 保留字
下面的都是保留字:
`AND, OR, IN, NOT, ALL, ANY, SOME, NONE, LIKE, CASEINSENSITIVE, CI, MATCHES, CONTAINS, BEGINSWITH, ENDSWITH, BETWEEN, NULL, NIL, SELF, TRUE, YES, FALSE, NO, FIRST, LAST, SIZE, ANYKEY, SUBQUERY, CAST, TRUEPREDICATE, FALSEPREDICATE`
### Appium 謂詞(predicate)幫助文檔
Appium 在app.js中有 [專門的謂詞(predicate)使用幫助文檔](https://github.com/appium/appium-uiauto/blob/3052dace828db2ab3d722281fb7853cbcbc3252f/uiauto/appium/app.js#L68) :
- `getFirstWithPredicate`
- `getFirstWithPredicateWeighted`
- `getAllWithPredicate`
- `getNameContains`
如下是個Ruby的例子
```ruby
# Ruby example
text = 'Various uses'
predicate = "name contains[c] '#{text}' || label contains[c] '#{text}' || value contains[c] '#{text}'"
element = execute_script(%Q(au.mainApp().getFirstWithPredicate("#{predicate}");))
puts element.name # Buttons, Various uses of UIButton
```
- 關于TesterHome和MTSC
- 關于Appium
- 簡介
- Appium 客戶端
- 入門指南
- 已支持的平臺
- API 文檔
- Appium驅動
- XCUITest (iOS)
- XCUITest Real Devices (iOS)
- UIAutomation (iOS)
- UIAutomation Safari Launcher (iOS)
- UIAutomator (Android)
- UIAutomator2 (Android)
- Espresso (Android)
- Windows
- Mac
- Appium命令
- Status
- Execute Mobile Command
- Session
- Create
- End
- Get Session Capabilities
- Go Back
- Screenshot
- Source
- Timeouts
- Timeouts
- Implicit Wait
- Async Script
- Orientation
- Get Orientation
- Set Orientation
- Geolocation
- Get Geolocation
- Set Geolocation
- Logs
- Get Log Types
- Get Logs
- Events
- Log event
- Get events
- Settings
- Update Settings
- Get Device Settings
- Settings
- Update Settings
- Get Device Settings
- Execute Driver Script
- Device
- Activity
- Start Activity
- Current Activity
- Current Package
- App
- Install App
- Is App Installed
- Launch App
- Background App
- Close App
- Reset App
- Remove App
- Activate App
- Terminate App
- Get App State
- Get App Strings
- End Test Coverage
- Clipboard
- Get Clipboard
- Set Clipboard
- Emulator
- Power AC
- Power Capacity
- Files
- Push File
- Pull File
- Pull Folder
- Interactions
- Shake
- Lock
- Unlock
- Is Locked
- Rotate
- Keys
- Press keycode
- Long press keycode
- Hide Keyboard
- Is Keyboard Shown
- Network
- Toggle Airplane Mode
- Toggle Data
- Toggle WiFi
- Toggle Location Services
- Send SMS
- GSM Call
- GSM Signal
- GSM Voice
- Network Speed
- Performance Data
- Get Performance Data
- Performance Data Types
- Screen Recording
- Start Screen Recording
- Stop Screen Recording
- Simulator
- Perform Touch ID
- Toggle Touch ID Enrollment
- System
- Open Notifications
- System Bars
- System Time
- Display density
- Authentication
- Finger Print
- Element
- Find Element
- Find Elements
- Actions
- Click
- Send Keys
- Clear
- Attributes
- Text
- Name
- Attribute
- Selected
- Enabled
- Displayed
- Location
- Size
- Rect
- CSS Property
- Location in View
- Other
- Submit
- Active Element
- Equals Element
- Context
- Get Context
- Get All Contexts
- Set Context
- Interactions
- Mouse
- Move To
- Click
- Double Click
- Button Down
- Button Up
- Touch
- Single Tap
- Double Tap
- Move
- Touch Down
- Touch Up
- Long Press
- Scroll
- Flick
- Multi Touch Perform
- Touch Perform
- W3C Actions
- Web
- Window
- Set Window
- Close Window
- Get Handle
- Get Handles
- Get Title
- Get Window Size
- Set Window Size
- Get Window Position
- Set Window Position
- Maximize Window
- Navigation
- Go to URL
- Get URL
- Back
- Forward
- Refresh
- Storage
- Get All Cookies
- Set Cookie
- Delete Cookie
- Delete All Cookies
- Frame
- Switch to Frame
- Switch to Parent Frame
- Execute Async
- Execute
- 編寫 & 運行Appium腳本
- Running Tests
- Desired Capabilities
- The --default-capabilities flag
- Finding Elements
- Touch Actions
- CLI Arguments
- Server Security
- Web/Web Views
- Mobile Web Testing
- Automating Hybrid Apps
- Using ios-webkit-debug-proxy
- Using Chromedriver
- Image Comparison
- iOS
- Low-Level Insights on iOS Input Events
- XCUITest Mobile Gestures
- XCUITest Mobile App Management
- iOS Pasteboard Guide
- iOS Predicate Guide
- iOS Touch ID Guide
- iOS Install Certificate
- tvOS support
- Pushing/Pulling files
- Audio Capture
- Android
- Low-Level Insights on Android Input Events
- UiSelector Guide
- Espresso Datamatcher Guide
- Android Code Coverage Guide
- Activities Startup Troubleshooting Guide
- How To Execute Shell Commands On The Remote Device
- Android Device Screen Streaming
- How To Emulate IME Actions Generation
- How To Test Android App Bundle
- Other
- Reset Strategies
- Network Connection Guide
- Using Unicode with Appium
- Troubleshooting
- Tutorial
- Swipe Tutorial
- Screen
- Element
- Partial screen
- Simple
- Multiple scroll views
- Add scroll layout
- Tricks and Tips
- Screen
- Element
- Element search
- Fast
- Slow
- Guide
- 進階概念
- 定位圖像中的元素
- 使用定位元素的插件
- 遷移到 XCUITest
- 在 Appium 中使用 Selenium Grid
- Appium Logs Filtering
- 跨域 iframes
- 使用自定義 WDA 服務器
- 使用不同版本的 Xcode 運行
- The Event Timings API
- 并行測試的設置
- The Settings API
- Memory Collection
- 向Appium項目做貢獻
- 從源代碼運行 Appium
- 開發者概述
- 標準開發命令
- Appium 風格指南
- 如何編寫文檔
- Appium 包結構
- 鳴謝