基于 UIHierarchy 创建 UIElementQuery

Creating a UIElementQuery based off of a UIHierarchy

我有一个分层 UI,我正在尝试为其创建一个 UI 测试。我在工作时对 UI 的构造方式没有深入了解,但我可以完全访问源代码。

我正在尝试点击弹出的按钮以 "Confirm" 删除特定条目。但是,我无法在 Swift 中创建一个查询来让我点击正确的按钮。这是错误的完整转储:

UI Test Activity: 
Assertion Failure: ProfileScreen.swift:77: Failed to get matching snapshot: Multiple matching elements found for <XCUIElementQuery: 0x6000007c4d20>.
Sparse tree of matches:
→Application, pid: 92707, label: '******'
  ↳Window (Main)
  ⋅ ↳Other
  ⋅   ↳Other
  ⋅     ↳Button, identifier: 'Remove', label: 'Remove'
  ↳Window
    ↳Other
      ↳Other
        ↳Other
          ↳Other
            ↳Other
              ↳Other
                ↳Other
                  ↳Other
                    ↳Other
                      ↳Other
                        ↳Other
                          ↳Other
                            ↳CollectionView
                              ↳Cell, Selected
                              ⋅ ↳Other
                              ⋅   ↳Button, label: 'Remove'
                              ↳Cell
                                ↳Other
                                  ↳Button, label: 'Remove'
Possibly caused by runtime issues:
Automation type mismatch: computed Other from legacy attributes vs StaticText from modern attribute. Input attributes and values: {
    "XC_kAXXCAttributeAutomationType" = 48;
    "XC_kAXXCAttributeElementBaseType" = UILabel;
    "XC_kAXXCAttributeElementType" = UILabel;
    "XC_kAXXCAttributeTraits" = 8590000128;
}
See test report attachments for more detail.

我必须生成该错误的查询是这样的:

XCUIApplication().buttons["Remove"].tap()

而实际的UI层次结构:

  Window, {{0.0, 0.0}, {414.0, 896.0}}
    Other, {{0.0, 0.0}, {414.0, 896.0}}
      Other, {{0.0, 0.0}, {414.0, 896.0}}
        Other, {{0.0, 0.0}, {414.0, 896.0}}
          Other, {{0.0, 0.0}, {414.0, 896.0}}
            Other, {{0.0, 0.0}, {414.0, 896.0}}
              Other, {{0.0, 0.0}, {414.0, 896.0}}
                Other, {{0.0, 0.0}, {414.0, 896.0}}
                  Other, {{0.0, 0.0}, {414.0, 896.0}}
                    NavigationBar, {{0.0, 44.0}, {414.0, 44.0}}, identifier: 'Payment Information'
                      Button, {{0.0, 44.0}, {44.0, 44.0}}, label: 'Settings'
                      StaticText, {{139.5, 58.5}, {135.0, 17.0}}, label: 'Payment Information'
                    Other, {{0.0, 0.0}, {414.0, 896.0}}
                      Other, {{0.0, 0.0}, {414.0, 896.0}}
                        Other, {{0.0, 88.0}, {414.0, 808.0}}
                          Other, {{0.0, 88.0}, {414.0, 808.0}}
                            CollectionView, {{0.0, 88.0}, {414.0, 808.0}}
                              Cell, {{0.0, 88.0}, {414.0, 72.0}}, Selected
                                Other, {{0.0, 88.0}, {414.0, 72.0}}
                                  Image, {{24.0, 115.0}, {18.0, 18.0}}
                                  Image, {{58.0, 110.0}, {49.5, 28.0}}
                                  StaticText, {{123.5, 114.5}, {36.0, 19.5}}, label: '1111'
                                  Button, {{331.0, 108.5}, {59.0, 31.0}}, label: 'Remove'
                                    StaticText, {{331.0, 114.5}, {59.0, 19.0}}, label: 'Remove'
                                  Other, {{0.0, 159.5}, {414.0, 0.5}}
                              Cell, {{0.0, 160.0}, {414.0, 72.0}}
                                Other, {{0.0, 160.0}, {414.0, 72.0}}
                                  Image, {{24.0, 187.0}, {18.0, 18.0}}
                                  Image, {{58.0, 182.0}, {49.5, 28.0}}
                                  StaticText, {{123.5, 186.5}, {36.0, 19.5}}, label: '2222'
                                  Button, {{331.0, 180.5}, {59.0, 31.0}}, label: 'Remove'
                                    StaticText, {{331.0, 186.5}, {59.0, 19.0}}, label: 'Remove'
                                  Other, {{0.0, 231.5}, {414.0, 0.5}}
                              Cell, {{0.0, 232.0}, {414.0, 72.0}}
                                Other, {{0.0, 232.0}, {414.0, 72.0}}
                                  Image, {{24.0, 259.0}, {18.0, 18.0}}
                                  Other, {{58.0, 254.0}, {49.5, 28.0}}
                                    Button, {{64.2, 257.5}, {37.1, 21.0}}, label: 'Buy with Touch Pay'
                                      StaticText, {{64.2, 257.5}, {0.0, 0.0}}
                                  StaticText, {{123.5, 258.5}, {75.5, 19.5}}, label: 'Touch Pay'
                                  Other, {{0.0, 303.5}, {414.0, 0.5}}
                              Cell, {{0.0, 304.0}, {414.0, 166.0}}
                                Other, {{0.0, 304.0}, {414.0, 166.0}}
                                  Button, {{16.0, 328.0}, {382.0, 60.0}}, label: 'Add New Item'
                                    StaticText, {{107.5, 348.0}, {199.0, 20.0}}, label: 'Add New Item'
                              Other, {{381.0, 105.5}, {30.0, 755.5}}, label: 'Vertical scroll bar, 1 page', value: 0%
                              Other, {{35.0, 863.0}, {344.0, 30.0}}, label: 'Horizontal scroll bar, 1 page', value: 0%
                Other, {{0.0, 840.0}, {414.0, 56.0}}
                  Other, {{0.0, 840.0}, {414.0, 0.5}}
                  Other, {{0.0, 840.0}, {414.0, 56.0}}
                    Button, {{0.0, 840.0}, {103.5, 56.0}}, identifier: 'tab_bar_title-main', label: 'Main'
                    Button, {{103.5, 840.0}, {103.5, 56.0}}, identifier: 'tab_bar_title-secondary', label: 'Secondary'
                    Button, {{207.0, 840.0}, {103.5, 56.0}}, identifier: 'tab_bar_title-todo', label: 'Todo'
                    Button, {{310.5, 840.0}, {103.5, 56.0}}, identifier: 'tab_bar_title-whatsup', label: 'Whatsup', Selected
  Window, {{0.0, 0.0}, {414.0, 896.0}}
    Other, {{0.0, 0.0}, {414.0, 896.0}}
      Other, {{0.0, 0.0}, {414.0, 896.0}}
      Other, {{0.0, 896.0}, {414.0, 243.0}}
  Window (Main), {{0.0, 0.0}, {414.0, 896.0}}
    Other, {{0.0, 0.0}, {414.0, 896.0}}
      Other, {{0.0, 0.0}, {414.0, 896.0}}
      Other, {{67.0, 350.0}, {280.0, 196.5}}
        StaticText, {{101.0, 384.0}, {212.0, 24.0}}, label: 'Remove Item'
        StaticText, {{101.0, 424.0}, {212.0, 38.0}}, label: 'Do you want to remove the Item?'
        Other, {{67.0, 486.0}, {280.0, 0.5}}
        Button, {{67.0, 486.5}, {140.0, 60.0}}, identifier: 'Cancel', label: 'Cancel'
          StaticText, {{112.0, 507.0}, {50.0, 19.0}}, label: 'Cancel'
        Other, {{207.0, 486.0}, {0.5, 60.5}}
        Button, {{207.5, 486.5}, {139.5, 60.0}}, identifier: 'Remove', label: 'Remove'
          StaticText, {{247.0, 506.5}, {61.0, 20.0}}, label: 'Remove'
    Other, {{0.0, 0.0}, {414.0, 896.0}}
      Other, {{0.0, 0.0}, {414.0, 896.0}}

所以它显然找到了这两个按钮。有两个具有相同 staticText 和 Label 的按钮。有没有一种方法可以让我轻松点按已启用或具有当前焦点的那个?

我也很好奇是否有办法将 UI 层次结构转储告诉我的内容转换为可行的查询。

您通常可以 select 唯一、第一个、第 N 个或最后一个按钮。

首次使用:

let app = XCUIApplication()
app.buttons["Remove"].tap()                                // the only
app.buttons["Remove"].element.tap()                        // the only
app.buttons["Remove"].firstMatch.tap()                     // the first
app.buttons["Remove"].element(boundBy: 3)                  // the fourth
app.buttons.matching(identifier: "Remove").lastMatch.tap() // the last

最后一个查询需要扩展:

extension XCUIElementQuery {
    var lastMatch: XCUIElement { return self.element(boundBy: self.count - 1) }
}

在此处阅读有关其他查询的更多信息:https://developer.apple.com/documentation/xctest/xcuielementquery

您也可以尝试使用 https://github.com/forqa/skeleton 等工具为您生成元素列表

在你的代码中 而不是 XCUIApplication().buttons["Remove"].tap()

放这个XCUIApplication().buttons["Remove"].firstMatch.tap()

您可以使用 query 获取第一个元素

XCUIApplication().buttons.matching(identifier: "Remove").element(boundBy: 0).tap()

或第二个元素

XCUIApplication().buttons.matching(identifier: "Remove").element(boundBy: 1).tap()