ИНЖЕНЕРНАЯ ЗАМЕТКА

Настраиваем регрессионный контроль доступности iOS на облачном Mac

Настраиваем регрессионный контроль доступности iOS на облачном Mac

Даже обычное переименование кнопки, замена значка или изменение ограничений может привести к тому, что на экране iOS исчезнет понятная метка, уменьшится область нажатия или обрежется текст при увеличенном размере шрифта. Проверять каждое изменение вручную практически невозможно. Более надёжный подход — зафиксировать состояние симулятора и приложения на облачном Mac, запускать аудит доступности с помощью XCTest и превратить обнаруженные ошибки в воспроизводимое условие для слияния изменений.

Сначала определите границы проверок

Не пытайтесь сразу проверять весь продукт. Начните с часто используемых сценариев: главного экрана после входа, основного экрана редактирования и страницы подтверждения отправки. Каждый тест должен проверять только одно стабильное состояние. Анимации, случайные рекомендации, текущее время и ответы сети изменяют дерево элементов, поэтому в тестовом режиме их следует отключать или заменять фиксированными данными.

На первом этапе рекомендуется проверять четыре категории проблем:

Проверка Типичный дефект Действие в рамках контроля
Описание элемента У кнопки со значком нет понятного названия Немедленная ошибка
Область нажатия Элемент управления виден, но по нему трудно нажать Немедленная ошибка
Контрастность Передний план плохо различим на фоне Исправить после сверки с дизайном
Компоновка текста При крупном шрифте текст обрезается или перекрывается Немедленная ошибка

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

Обеспечьте тесту предсказуемое состояние экрана

Главная проблема UI-тестов — ситуация, когда один и тот же способ входа приводит к разным экранам. Приложение должно распознавать аргументы запуска, предназначенные только для тестирования, очищать временное состояние, загружать фиксированные данные и отключать необязательные анимации. Эти параметры должны влиять только на тестовую среду и не попадать в рабочую бизнес-логику.

let app = XCUIApplication()
app.launchArguments = [
    "-ui-testing",
    "-reset-demo-state",
    "-disable-animations"
]
app.launchEnvironment["TEST_LOCALE"] = "zh-Hans"
app.launch()

Тестовые данные следует подготавливать внутри процесса приложения, а не получать через UI-тест из действующего API. Если необходимо проверить загрузку, отсутствие данных, ошибку и успешный результат, создайте отдельный параметр для каждого состояния. Тогда после сбоя будет достаточно повторить команду, не дожидаясь повторного возникновения нужного условия на удалённой стороне.

Используйте стабильные идентификаторы элементов

Не находите ключевые элементы управления по тексту кнопки или координатам. Текст меняется при локализации, а координаты зависят от размера окна и шрифта. Назначайте интерактивным элементам семантически стабильные значения accessibilityIdentifier:

checkoutButton.accessibilityIdentifier = "checkout.submit"
cartSummary.accessibilityIdentifier = "checkout.summary"

Идентификатор должен описывать назначение элемента, а не его визуальное положение. Название вроде footer.orangeButton потеряет смысл после редизайна, тогда как checkout.submit останется пригодным при любой компоновке.

Запускайте целевой аудит XCTest

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

func testCheckoutAccessibility() throws {
    let app = XCUIApplication()
    app.launchArguments = ["-ui-testing", "-reset-demo-state"]
    app.launch()

    let submit = app.buttons["checkout.submit"]
    XCTAssertTrue(submit.waitForExistence(timeout: 10))

    if #available(iOS 17.0, *) {
        try app.performAccessibilityAudit(for: [
            .sufficientElementDescription,
            .hitRegion,
            .contrast,
            .textClipped
        ])
    }
}

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

Зафиксируйте условия запуска на облачном Mac

Сначала проверьте доступные устройства симулятора и среды выполнения, а затем передавайте в конвейер точное значение destination. Не рассчитывайте, что на каждом узле уже существует устройство с нужным именем.

xcrun simctl list devices available
xcrun simctl list runtimes

export SIM_DESTINATION='platform=iOS Simulator,name=iPhone 15,OS=17.5'

set -o pipefail
xcodebuild test \
  -project ExampleApp.xcodeproj \
  -scheme ExampleAppUITests \
  -destination "$SIM_DESTINATION" \
  -only-testing:ExampleAppUITests/AccessibilityTests \
  -resultBundlePath "$PWD/TestResults/Accessibility.xcresult"

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

Выбор модели облачного Mac и узла не меняет принципов проектирования тестов. Если требуется новая среда выполнения, проверьте доступные конфигурации в консоли и зафиксируйте версии Xcode и среды выполнения, язык и destination. Это позволит повторно запустить тест в тех же условиях.

Разделяйте проверки по уровням и устраняйте типичные ложные срабатывания

Для каждого запроса на слияние запускайте проверки только основных экранов с языком по умолчанию и одним стандартным размером шрифта, чтобы время обратной связи оставалось приемлемым для команды. В основной ветке расширяйте покрытие на другие языки, книжную и альбомную ориентации, тёмное оформление и динамические шрифты. Не объединяйте все комбинации в одном тестовом методе. Разделите тесты по экранам и состояниям, чтобы название сбойного теста сразу указывало область проблемы.

При нестабильном сбое проверяйте возможные причины в следующем порядке:

  1. Убедитесь, что ключевой элемент полностью загрузился, а не просто появился в дереве элементов.
  2. Сопоставьте настройки языка, региона, размера шрифта, ориентации и оформления.
  3. Проверьте, не были ли тестовые данные изменены предыдущим запуском.
  4. Перезапустите только сбойный метод и убедитесь, что проблема воспроизводится стабильно.
  5. Сохраните пакет результатов тестирования, команду запуска и параметры среды, а затем определите, связана ли ошибка с продуктом или недостаточной изоляцией теста.

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

Часто задаваемые вопросы

Может ли автоматический аудит полностью заменить ручную проверку?

Нет. Он находит отсутствующие описания, маленькие области нажатия, слабый контраст и обрезанный текст, но порядок чтения и понятность взаимодействия необходимо проверять вручную.

Почему тест проходит локально, но завершается ошибкой на облачном Mac?

Сравните версию среды симулятора, язык, регион, размер текста, ориентацию и исходные данные. Зафиксируйте эти параметры в конфигурации запуска теста.

Когда следует запускать полный аудит доступности?

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

Выделенный физический узел

Запустите следующую сборку в облачном Mac.

Сравните три конфигурации Apple Silicon и выберите подходящий для текущего рабочего процесса регион среди пяти зарубежных узлов.

Выбрать тариф