【问题标题】:Is there a way to find if the XCUIElement has focus or not?有没有办法找到 XCUIElement 是否有焦点?
【发布时间】:2015-12-30 02:36:09
【问题描述】:

我的一个屏幕有多个文本字段,我可以从不同的其他屏幕登陆到这个屏幕。在每种情况下,我都会将一个或另一个文本字段作为第一响应者。我无法编写测试来确定所需的 textField 是否具有焦点。

当我在控制台中打印文本字段时 -

输出:{ TextField 0x131171d40:特征:146031247360,Focused,{{6.0, 108.3}, {402.0, 35.0}},值:​ }

但我在 XCUIElement 上找不到任何 focus/isFocus 属性。

有没有办法做到这一点?

【问题讨论】:

  • XCUIElement 似乎从可访问性特征中派生了一些属性,但不一定公开这些特征。您是否尝试过 selected 属性,看看它是否能满足您的需求?
  • selected 属性为我的文本字段返回 false/nil。
  • 有属性hasKeyboardFocus,请看下面我的回答。

标签: ios xcode7 ui-testing xcode-ui-testing


【解决方案1】:

基于@hris.to's excellent answer,我整理了这个小扩展(也适用于 Swift 4)...

extension XCUIElement
{
    func hasFocus() -> Bool {
        let hasKeyboardFocus = (self.value(forKey: "hasKeyboardFocus") as? Bool) ?? false
        return hasKeyboardFocus
    }
}

【讨论】:

  • 也可以是计算变量,例如var hasFocus: Bool { return ... }
【解决方案2】:

我参加聚会有点晚了 :) 然而,从转储变量 XCUIElement 中我可以看出,它有一个有趣的属性:

属性名称:hasKeyboardFocus

属性类型:TB,R

因此您可以通过以下方式检查您的元素是否具有焦点:

let hasFocus = (yourTextField.value(forKey: "hasKeyboardFocus") as? Bool) ?? false

注意:您可以转储任何具有以下扩展名的 NSObject 子类的属性变量:

extension NSObject {
    func dumpProperties() {
        var outCount: UInt32 = 0

        let properties = class_copyPropertyList(self.dynamicType, &outCount)
        for index in 0...outCount {
            let property = properties[Int(index)]
            if nil == property {
                continue
            }
            if let propertyName = String.fromCString(property_getName(property)) {
                print("property name: \(propertyName)")
            }
            if let propertyType = String.fromCString(property_getAttributes(property)) {
                print("property type: \(propertyType)")
            }
        }
    }
}

更新:属性转储,Swift 4:*

extension NSObject {
    func dumpProperties() {
        var outCount: UInt32 = 0

        let properties = class_copyPropertyList(type(of: self), &outCount)
        for index in 0...outCount {
            guard let property = properties?[Int(index)] else {
                continue
            }
            let propertyName = String(cString: property_getName(property))
            print("property name: \(propertyName)")
            guard let propertyAttributes = property_getAttributes(property) else {
                continue
            }
            let propertyType = String(cString: propertyAttributes)
            print("property type: \(propertyType)")
        }
    }
}

【讨论】:

  • 很棒的发现,感谢您回复此答案!
  • 出色的答案!如果你喜欢等待有焦点的元素,只需使用谓词和期望 let focusPredicate = NSPredicate(format: "exists == true && hasKeyboardFocus == true")
  • 很好的发现!! Apple 的文档指出“XCUIElement 采用的 XCUIElementAttributes 协议提供了用于查询 UI 元素属性的当前状态的附加属性。”该协议有一个“hasFocus”变量,但是当尝试实际使用它时,您会从 xcode 收到“XCUIElement has no member 'hasFocus'”消息。再次感谢!
  • @hris.to 您是如何找到名为“hasKeyboardFocus”的属性的?甚至 Apple 的文档也没有显示它。你能把上面的代码优化到 Swift 4 及更高版本吗?它在“self.dynamicType”行中抛出错误
  • @leanne 非常感谢您的编辑!一疑。属性类型的含义是什么?比如“TB,R”是什么意思?
【解决方案3】:

我观察到一些情况

XCUIApplication().textFields[{index/identifier}].selected

即使我将光标聚焦在文本字段上但我能够使用.typeText() 输入文本时,也不会返回 true。但是,.enabled 正确返回 true ,“启用”值表示 UI 元素已启用可访问性并且您可以与其交互。

不是一个干净的解决方案,但你可以尝试,

XCUIApplication().textFields.elementMatchingPredicate("predicate")

.elementMatchingType() 获取 XCUIElement 并编写测试块,同时使用 guard 语句在未找到 textField 时抛出适当的错误。

【讨论】:

  • enable 在这里无济于事。 Enable tell - 是否为用户交互启用元素。我的 textField 都没有处于禁用状态。你明白我的问题了吗?我在问如何验证我的 textField 是否是第一响应者。
  • 复制那个。从你的问题中,我读到你的目标是确定 Textfield 是否有焦点,以便你可以与之交互。如果你想从 UIView 验证当前的第一响应者是您预期的 UITextField 元素,您可以查看此要点链接 (gist.github.com/steipete/8737196)。一个 hacky 解决方法可能是让第一响应者 UIView 标题与您预期的 textField 标题匹配并编写您的条件测试。
【解决方案4】:

NSObject 上有一个通过extension (来自UIAccessibility.h)的方法,该方法在XCUIElement 上可用,名为accessibilityElementIsFocused(),但它似乎不会返回true,即使debugDescription该元素的明确表示Focused。还有一些其他相关的方法accessibilityElementDidLoseFocus()accessibilityElementDidBecomeFocused(),它们似乎是打算被NSObject 的子类覆盖的方法,以便在Focused 状态发生更改时得到通知。

经过这次挖掘,我倾向于说我们正在讨论的Focused 的概念与firstResponder 状态不同,这可能是您希望知道的。我相信在这一点上,焦点表明该元素是一些辅助技术的焦点,例如 VoiceOver,基于这些方法的一些 cmets。

如果您想直接判断一个项目是否为firstResponder,我认为现在是提交错误报告的时候了。

如果有一种方法可以直接与软件键盘进行交互,那么一个巧妙的解决方法可能是为您的UITextField 获取一个XCUIElement,然后比较您的UITextField 元素在键入前后的value 与键盘(您可能想要键入一个字符,然后键入一个退格键)。话虽如此,但粗略地尝试一下,我无法弄清楚如何直接获得键盘。

【讨论】:

    【解决方案5】:

    我不知道,但也许 XCUIElement 上的 selected 属性是您正在寻找的。试试看。

    【讨论】:

    • 没用。在我的情况下,它为 textFields 返回 false/nil。
    猜你喜欢
    • 1970-01-01
    • 2017-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多