Selenium WebDriver waiters (explicit/implicit) and Protractor
Речь пойдёт о насущной для всех юайных тестов проблеме — подождать. Примеры и особенности будут рассматриваться для протрактора (JS), но суть вейтеров и слипов едина для всех реализаций вебдрайвера, поэтому всем, у кого есть вопросы или недопонимание, будет интересно. В конце ссылка на мою реализацию явного ожидания для протрактора. Это функция, которая:
1. чейнит элемент
2. принимает аргументом время явного ожидания
3. сетит неявное ожидание в ноль
4. ждёт время, переданное аргументом
5. сетит неявное ожидание обратно в дефолтное значение
6. возвращает тот же элемент, т.е. её можно чейнить. Выглядит примерно так:
field.waiReady(5000).click();
Первое, что нужно отчётливо понимать и помнить: слип — не вейтер!
Что такое sleep: browser.sleep(time) — это прерывание выполнения скрипта, т.е. потеря времени в чистом виде. Это просто недопустимо ни под каким предлогом. Почему? Есть 3 главные причины:
1. Действие выполнилось быстрее, остальное время в мусор.
2. Действию понадобилось больше времени и тест вылетел.
3. Я поставлю 1 слип, ведь так быстрее и проще. Здесь же не навредит... Я даже оберну его в метод и назову его... stabilizationTimeout(time)! После чего сработает правило разбитого окна и слипы со стабилизационными таймаутами заполонят нашу жизнь. Печаль-беда.
Что такое waiter: по своей сути вейтер — это поллинг. Ему параметром передаётся максимальное время ожидания. Т.е. если элемент уже готов, то он не будет ждать, а сразу начнёт работать. Если элемент не в порядке, то вейтер будет пытаться с ним взаимодействовать пока не кончится время, переданное параметром.
Вейтеров бывает 2 типа — explicit (явное ожидание) и implicit (неявное ожидание). Разница между ними в том, что implicitWait выставляется один раз и отрабатывает перед каждым действием, а explicit нужно писать руками и явно указывать сколько времени и на какое действие можно потратить.
Как нужно использовать Implicit waiter: он задаётся единым для всех тестов:
browser.manage().timeouts().implicitlyWait(2000);время ожидания должно быть небольшим, иначе, когда мы захотим проверить, что элемента нет на странице, то будем ждать время неявного ожидания впустую.
В случае протрактора нужно учитывать, что он начинает работать только после того, как на странице отработает весь ангуляр (в случае дефолтного browser.ignoreSyncronization=false;). Также в протракторе реализован lazy search, это значит, что реальный поиск элементов в ДОМе начнётся только после выполнения над элементом действия:
let field = element(by.id(‘field’)); // здесь ничего не происходит field.click(); // здесь протрактор ищет элемент на странице и кликает по нему
Пример explicit waiter-a на js:
browser.wait(() => field.isPresent(), 5000, ‘Field not found’);browser.wait() принимает 3 аргумента — функция для поллинга, максимальное время ожидания и третий опциональный аргумент — текст ошибки. Здесь возникает вопрос:
Как работают implicit и explicit вейты вместе:
Работают они в параллели. У них обоих есть таймеры, которые стартуют одновременно и тут зарыта собака. Есть 3 возможных варианта: явное больше неявного, неявное больше явного и 2 таймера равны. Если элемент на странице есть и он хороший, то вне зависимости от вейтера всё случится быстро. Так что мы будем рассматривать вариант, когда всё плохо.
1. Implicit = 3000
Explicit = 3000
Когда таймеры равны, то всё просто и очевидно — мы будем ждать 3 секунды.
2. Implicit = 4000
Explicit = 3000
Таймеры стартанули. Когда implicit добежал до 3 секунд, explicit выдохся, implicit добежал ещё одну секунду и тоже закончился. Всего мы подождали 4 секунды
3. Implicit = 3000
Explicit = 4000
Это самый опасный вариант, тут лежит собака. Таймеры так же стартанули одновременно, через 3 секунды implicit говорит, что не нашёл элемента. В этот момент у explicit есть ещё время, implicit это видит и говорит: «ну тогда я на второй круг пойду». И в итоге мы ждём 2 раза по implicit итого 6 секунд вместо
Что же с этим всем делать:
• (плохо) Делать большой implicit и ставить его в 0 тогда, когда мы ждём, что элемента не будет. Элементы пропадают в том числе когда мы этого не ждём. Т.е. implicitWait всегда должен быть маленьким.
• (лучше) Можно забить на особенности взаимодействия этих вейтеров сделать implicit маленьким и использовать explicit, зная, что он может ждать немногим больше, чем мы этого хотим.
• (хорошо) Лучше всего написать обёртку для explicit, которая будет сетить impliсit в ноль, ждать explicitly и сетить implicit обратно в дефолтное значение. Мой пример для протрактора: github.com/...nnadiii/explicitWaiter.js
• (важно) И самое главное — никогда и ни под каким предлогом не использовать слипы (кроме маленьких слипов в кастомных поллингах с целью не зафлудить сервер).
Ждите правильно и стабильных всем тестов!
66 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів