Флейкові тести: причини, діагностика, артефакти й Allure
Флейковий тест — той, що на тому самому коді то проходить, то падає. Він руйнує довіру до набору, тому його лікують, а не «перезапускають, доки зелений».
Типові причини в Selenium-тестах:
- неправильні очікування:
Thread.sleep, клік до того, як елемент клікабельний, перевірка до завершення асинхронного запиту;
- залежності між тестами: спільні дані, порядок виконання, чужий стан у БД;
- нестабільні локатори: індекси, згенеровані класи, текст, який змінюють;
- середовище: повільний CI, мала пам’ять браузера в контейнері, зовнішні сервіси, час і часові пояси;
- анімації, перекриття, віддалені ресурси без заглушок.
Діагностика: відтворити в циклі (запустити тест 20–50 разів), порівняти упалі й успішні запуски, подивитись скриншот, DOM, логи браузера й сервера та час кроків. Лише після причини вирішують: поправити очікування, ізолювати дані, стабілізувати середовище чи карантинувати тест із тікетом.
Артефакти при падінні: скриншот (((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES)), URL, джерело сторінки, логи, а в Grid ще відео. Їх знімають автоматично: у JUnit 5 — розширення з TestWatcher (testFailed), у TestNG — ITestListener.onTestFailure. Скриншот у @AfterEach «якщо впав» без розширення виходить громіздким і про нього забувають.
Allure збирає це у звіт: підключають allure-jupiter (колишній allure-junit5) чи allure-testng, кроки позначають @Step, вкладення додають Allure.addAttachment(...), результати лежать у allure-results, а HTML будує allure generate. Історія запусків показує, які тести нестабільні.
Автоматичний retry (повтор упалих) допустимий як тимчасова міра й обов’язково з позначкою flaky у звіті. Якщо він мовчки робить усе зеленим, справжні дефекти ховаються.
BiDi замість CDP, Actions, файли, iframe і вікна
CDP проти BiDi. Selenium 4 дає доступ до Chrome DevTools Protocol (((HasDevTools) driver).getDevTools()): перехоплення мережі, емуляція, події консолі. Проте CDP працює лише в Chromium, прив’язаний до версії браузера, а Selenium постачає прив’язки під конкретні версії, тож після оновлення Chrome код може не знайти відповідної реалізації. Документація Selenium називає підтримку CDP тимчасовою, доки не реалізовано WebDriver BiDi: це W3C-стандарт двостороннього зв’язку через WebSocket, кросбраузерний (Chrome, Firefox, Edge).
ChromeOptions options = new ChromeOptions();
options.setCapability("webSocketUrl", true);
WebDriver driver = new ChromeDriver(options);
try (LogInspector logs = new LogInspector(driver)) {
logs.onConsoleEntry(entry -> System.out.println(entry.getText()));
driver.get("https://example.com");
}
Для нового коду BiDi обирають за замовчуванням (події консолі й JS-помилки, мережа, скрипти); CDP — лише коли потрібна можливість, якої в BiDi ще немає. Старий driver.manage().logs() працює лише в Chromium.
Actions API складає складні жести: наведення, перетягування, подвійний/контекстний клік, комбінації клавіш, прокрутка.
new Actions(driver).moveToElement(menu).pause(Duration.ofMillis(200)).click(sub).perform();
new Actions(driver).scrollToElement(footer).perform();
new Actions(driver).dragAndDrop(card, column).perform();
Без perform() нічого не станеться.
Файли. Завантаження: sendKeys з абсолютним шляхом у input type="file" (без кліку по кнопці, діалог ОС Selenium не бачить); на Grid додають setFileDetector(new LocalFileDetector()). Скачування: тека й заборона діалогу задаються в опціях браузера, а далі очікують появи файла.
iframe. Елемент усередині frame невидимий для пошуку, доки не перемкнутись: driver.switchTo().frame(...), назад — parentFrame() або defaultContent(); ExpectedConditions.frameToBeAvailableAndSwitchToIt поєднує очікування й перемикання.
Вікна й вкладки. Запам’ятати поточний handle, дочекатись нового (numberOfWindowsToBe), перемкнутись на інший; driver.switchTo().newWindow(WindowType.TAB) відкриває вкладку. Після close() треба явно повернутись до потрібного вікна, інакше будуть NoSuchWindowException.