Как отличить заголовки от статического текста в iOS 13 с помощью тестов пользовательского интерфейса XCTest

Работая на iOS 13 с использованием последних версий Xcode 11, я не могу найти способ различать заголовки и статический текст в тестах пользовательского интерфейса XCTest.

Если я использую Xcode 11, но работаю на iOS 12, я все еще могу найти представления с чертой .header путем фильтрации по типам элементов .other с помощью XCTest, но в iOS 13 представления с чертой .header теперь просто идентифицируются по типу элемента .staticText с XCTest, даже если вы не установили признак доступности .staticText в приложении.

Это создает для нас проблему, потому что мы используем это, чтобы убедиться, что мы не забываем правильно установить признаки заголовка для представлений для доступности, а также чтобы иметь возможность убедиться, что мы смотрим на правильный экран в тестах.

По общему признанию, возможность находить заголовки только по .other не очень хороша, но, по крайней мере, это был способ отличить заголовки от обычного текста.

Вот пример кода для объяснения:

// ViewController.swift

headerLabel.isAccessibilityElement = true // headerLabel is just a UILabel IBOutlet
headerLabel.accessibilityTraits = [.header]
headerLabel.text = "My Header"

// ViewControllerTests.swift

XCTAssertTrue(XCUIApplication().otherElements["My Header"].firstMatch.waitForExistence(timeout: 30)) // This fails on iOS 13 but works on iOS 12 :(
XCTAssertTrue(XCUIApplication().staticTexts["My Header"].firstMatch.waitForExistence(timeout: 30)) // This fails on iOS 12 but works on iOS 13...

Если вы po XCUIApplication() в Xcode, вы можете увидеть, что в iOS 13 заголовок теперь просто staticText такой же, как и любая другая метка.

Я пробовал комбинировать разные свойства доступности (поскольку их может быть несколько), например:

headerLabel.accessibilityTraits = [.header, .staticText]

Но это не помогает.


person Kane Cheshire    schedule 06.11.2019    source источник
comment
Что еще более раздражает, заголовки разделов таблицы по-прежнему .other...   -  person Kane Cheshire    schedule 06.11.2019
comment
Мне это кажется ошибкой в ​​​​XCUI, если я полностью скрою метку от специальных возможностей, она все равно будет отображаться в XCUI, даже если это не предназначено.   -  person Kane Cheshire    schedule 07.11.2019


Ответы (2)


Хорошо, после пары дней расследования у нас есть обходной путь. К сожалению, он использует частный API, но мы не слишком беспокоимся, поскольку он предназначен для тестов и лучше, чем любой другой обходной путь, который мы пробовали до сих пор.

Используя частный API, можно выяснить базовое UIAccessibilityTraits представления, которое представляет XCUIElement:

var underlyingAccessibilityTraits: UIAccessibilityTraits {
    guard let rawValue = value(forKey: "traits") as? UInt64 else { return [] }
    return UIAccessibilityTraits(rawValue: rawValue)
}

Теперь, когда у нас есть трейты, мы можем запросить их так же, как и любые другие OptionSet:

element.underlyingAccessibilityTraits.contains(.header)

И мы можем использовать это для создания нашего собственного запроса, а не использовать XCUIElementQuery:

let allElementsMatchingID = XCUIApplication().descendants(matching: .any).matching(.any, identifier: id) // id is an optional string as an ID, like when using `XCUIApplication().otherElements[id]`
let allHeaders = allElementsMatchingID.allElementsBoundByAccessibilityElement.filter { $0.underlyingAccessibilityTraits.contains(.header) }
let element = allHeaders[index] // index is an int, like when using `element(boundBy: 0`

Недостатком этого (кроме необходимости использования частного API) является то, что в отличие от обычных XCUIElementQuerys, это приведет к сбою, если индекс выходит за пределы, но если вы всегда ожидаете, что элемент существует, то это не такая уж большая проблема.

person Kane Cheshire    schedule 07.11.2019

Вы можете добавить префикс к accessibilityIdentifier вашего заголовка, чтобы отличить его от статического текста, например:

myHeader.accessibilityIdentifier = "Header" + title

и просто используйте то же самое, что и раньше для вашего статического текста

myLabel.accessibilityIdentifier = title
person cesarmarch    schedule 06.11.2019
comment
Да, мы тоже об этом думали, за исключением того, что мы делаем фреймворк, который обертывает XCUI и имеет элемент Header, который ссылается на заголовки с помощью .other, поэтому запрос на получение элемента не будет выполнен для любого, кто использует фреймворк, потому что он staticText. Это основа для справки: github.com/theappbusiness/TABTestKit - person Kane Cheshire; 07.11.2019