Чому 80% E2E-тестів падають у CI прямо перед релізом? Причина — неправильні очікування та платформенні відмінності. Appium — єдиний інструмент, який покриває iOS та Android одним тест-кодом, але за універсальністю стоїть шар абстракції, що поводиться непередбачувано. На одному проєкті доставки ми замінили 200 викликів Thread.sleep() на явні очікування — прохідність тестів зросла з 60% до 95%. Стабільний E2E-фреймворк потребує системного підходу: правильних локаторів, модульної архітектури та інтеграції з CI.
Ми автоматизували тести для більш ніж 20 проєктів за останні п'ять років. Кожного разу стикаємося з одними й тими самими граблями: конфігурація драйверів, нестабільні сесії, відмінності в жестах. Вирішуємо їх системно — через Page Object, явні очікування та хмарні ферми. Замовте налаштування E2E-тестів під ваш проєкт — отримайте стабільний фреймворк за 5 днів з нуля.
Як організувати E2E-тести мобільного застосунку з Appium?
Appium 2: модульна архітектура
Appium 2 — не просто версія, це інша концепція. Замість монолітного сервера — ядро плюс окремо встановлювані драйвери:
npm install -g appium@next appium driver install uiautomator2 # Android appium driver install xcuitest # iOS UIAutomator2Driver для Android, XCUITestDriver для iOS. Обидва підтримують W3C WebDriver Protocol, що робить їх сумісними з WebdriverIO, Selenium Grid та стандартними client-бібліотеками. Згідно з документацією Appium, Appium 2 стабільніший за першу версію на 40%.
| Характеристика | Appium 1 | Appium 2 |
|---|---|---|
| Керування драйверами | Вбудовано | Окреме встановлення |
| Протокол | Mobile JSON Wire | W3C WebDriver |
| Стабільність | Середня | Вища на 40% |
| Підтримка нативних елементів | Через XPath | Через accessibilityId |
Версії, з якими працюємо зараз: Appium 2.5+, appium-uiautomator2-driver 3.x, appium-xcuitest-driver 7.x, WebdriverIO 8.x (JS/TS) або Appium-Python-Client 4.x (Python).
Налаштування сервера та Capabilities
Найболючіше місце — правильний набір Capabilities. Невірний platformVersion або відсутній automationName — і сесія не піднімається з неінформативною помилкою.
Мінімальний робочий конфіг для Android (WebdriverIO):
const capabilities = { platformName: 'Android', 'appium:automationName': 'UiAutomator2', 'appium:deviceName': 'emulator-5554', 'appium:app': path.resolve('./apps/myapp.apk'), 'appium:newCommandTimeout': 240, 'appium:noReset': false, }; Для iOS додається udid пристрою, xcodeOrgId та xcodeSigningId для реального девайса. На симуляторі простіше — але симулятор не дає результатів щодо продуктивності та Push Notifications.
Чому Page Object — основа стабільності?
Сирий Appium-код без паттерну — жах для підтримки. Кожен $('//XCUIElementTypeButton[@name="Login"]') дублюється в десятках тестів, і при зміні UI потрібно виправляти все одразу.
Застосовуємо Page Object з WebdriverIO:
class LoginPage { get emailField() { return $('~email_input'); } // accessibilityId get passwordField() { return $('~password_input'); } get submitButton() { return $('~login_button'); } async login(email: string, password: string) { await this.emailField.setValue(email); await this.passwordField.setValue(password); await this.submitButton.click(); } } export default new LoginPage(); ~ перед рядком — це accessibilityId-локатор. Працює і на iOS (accessibilityIdentifier), і на Android (contentDescription). Надаємо перевагу цьому над XPath — стабільніший при змінах в ієрархії View.
XPath використовуємо тільки коли немає інших варіантів: //android.widget.TextView[contains(@text,'Додати')]. Але довгі XPath-ланцюжки — першопричина нестабільних тестів.
Очікування замість sleep
driver.pause(3000) — антипаттерн. Замінюємо на явні очікування:
await $('~submit_btn').waitForDisplayed({ timeout: 10000 }); await $('~success_screen').waitForExist({ timeout: 15000 }); waitForDisplayed чекає появи елемента у видимій області. waitForExist — просто існування в DOM. Для елементів, які з'являються після анімації — waitForDisplayed з { timeout: 5000, interval: 500 }. Вибір стратегії впливає на стабільність: явні очікування надійніші за неявні в 95% випадків.
| Тип очікування | Швидкість | Надійність | Коли використовувати |
|---|---|---|---|
| Явне (explicit wait) | Помірна | Висока | Завжди, коли елемент може з'явитися не одразу |
| Неявне (implicit wait) | Висока | Середня | Тільки якщо всі елементи завантажуються синхронно |
| Pause | Низька | Низька | Ніколи — замініть на явне |
Інтеграція з CI
Appium у CI потребує запущеного емулятора або підключеного пристрою. Типова схема для GitHub Actions:
- name: Start Android Emulator uses: reactivecircus/android-emulator-runner@v2 with: api-level: 34 target: google_apis arch: x86_64 script: | appium & sleep 5 npx wdio run wdio.conf.ts Для iOS у CI потрібен macOS-раннер. Використовуємо actions/runner на macOS з Xcode pre-installed. Симулятор створюємо через xcrun simctl create. Альтернатива — хмарні ферми пристроїв: Firebase Test Lab, BrowserStack App Automate, Sauce Labs. Вони позбавляють необхідності утримувати власну ферму.
Типові проблеми
StaleElementReferenceError — елемент знайшли, але до кліку UI перебудувався. Обгортаємо в retry-логіку: await browser.waitUntil(async () => { ... }).
Keyboard covers element — на iOS екранна клавіатура перекриває поле. Перед введенням тексту — await driver.hideKeyboard() або скрол до елемента: await element.scrollIntoView().
App не відповідає на команди після background — 'appium:forceAppLaunch': true у capabilities або явний driver.activateApp(bundleId).
Різні локатори на iOS та Android — навіть з accessibilityId іноді потрібні платформо-специфічні локатори. Вирішуємо через умову: const selector = driver.isIOS ? '~ios_id' : '~android_id';.
Що входить у роботу
- Налаштування Appium 2 сервера та драйверів для iOS і Android
- Написання тестів (WebdriverIO/TypeScript або Python)
- Page Object паттерн для всіх ключових екранів
- Інтеграція в CI (GitHub Actions / GitLab CI)
- Налаштування запуску на хмарній фермі за запитом
- Звіт Allure або HTML зі скріншотами по кожному кроку
Терміни орієнтовно
Базова конфігурація та покриття 3–5 ключових флоу — 5 днів. Повне E2E-покриття великого застосунку (15–20 сценаріїв) — 2–3 тижні. Вартість розраховується індивідуально після аналізу застосунку та інфраструктури. Зв'яжіться з нами для оцінки вашого проєкту — ми гарантуємо стабільність тестів та прозорий результат. Отримайте консультацію та дізнайтеся, скільки часу заощадять ваші команди з готовими тестами під ключ.







