Selenium и Node.js: пишем надёжные браузерные тесты

Original author: Todd Chaffee
  • Translation
Есть много хороших статей о том, как начать писать автоматизированные браузерные тесты, используя версию Selenium, предназначенную для Node.js.



В некоторых материалах говорится о том, как оборачивать тесты в Mocha или Jasmine, в некоторых всё автоматизируют с помощью npm, Grunt или Gulp. Во всех подобных публикациях можно найти сведения о том, как установить и настроить всё необходимое. Там же можно посмотреть простые примеры работающего кода. Всё это весьма полезно, так как, для новичка, собрать работающую среду тестирования, состоящую из множества компонентов, может оказаться не так уж и просто.

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

Сегодня мы начнём с того, на чём обычно заканчиваются другие материалы по автоматизации браузерных тестов с помощью Selenium для Node.js. А именно, мы расскажем о том, как повысить надёжность тестов и «отвязать» их от непредсказуемых явлений, которыми полны браузеры и веб-приложения.

Сон — это зло


Метод Selenium driver.sleep — худший враг разработчика тестов. Однако, несмотря на это, его используют повсюду. Возможно, это так из-за краткости документации для Node-версии Selenium, и из-за того, что она покрывает лишь синтаксис API. Ей недостаёт примеров из реальной жизни.

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

Для того, чтобы разобраться с особенностями метода driver.sleep, рассмотрим пример. Предположим, у нас есть анимированная панель, которая, в ходе появления на экране, меняет размеры и положение. Взглянем на неё.


Анимация панели

Это происходит так быстро, что вы, возможно, не заметите, что кнопки и элементы управления внутри панели тоже изменяются в размере и меняют положение.
Вот замедленная версия того же процесса. Обратите внимание на то, как зелёная кнопка Close меняется вместе с панелью:


Замедленная анимация панели

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

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

System.InvalidOperationException : Element is not clickable at point (326, 792.5)

В подобной ситуации многие программисты скажут: «Ага, мне нужно дождаться завершения анимации, поэтому просто использую driver.sleep(1000) для того, чтобы панель пришла в нормальное состояние». Похоже, задача решена? Однако, не всё так просто.

Проблемы driver.sleep


Команда driver.sleep(1000) выполняет именно то, чего от неё можно ожидать. Она останавливает выполнение теста на 1000 миллисекунд и позволяет браузеру продолжать работать: загружать страницы, размещать на них фрагменты документов, анимировать или плавно выводить на экран элементы, или делать что угодно другое.

Возвращаясь к нашему примеру, если предположить, что панель достигает нормального состояния за 800 миллисекунд, команда driver.sleep(1000) обычно помогает достичь того, ради чего её вызывают. Итак, почему бы ей не воспользоваться?

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

Почему же конструкции с driver.sleep не всегда работоспособны? Другими словами, почему это недетерминированный механизм?

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

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

Когда с веб-сайтом работает человек, он ждёт, пока элемент полностью появится, прежде чем по нему щёлкнуть. И когда появление элемента занимает меньше секунды, мы, вероятно, даже не заметим этого «ожидания». Selenium не только быстрее и требовательнее обычного пользователя. Тесты, в ходе работы со страницами, вынуждены сталкиваться с различными непредсказуемыми факторами. Рассмотрим некоторые из них:

  1. Дизайнер может изменить время анимации с 800 миллисекунд на 1200 миллисекунд. В результате тест с driver.sleep(1000) даст сбой.
  2. Браузеры не всегда делают именно то, что от них требуется. Из-за нагрузки на систему анимация может затормозиться и занять больше чем 800 миллисекунд. Возможно, даже больше, чем время ожидания, установленное на 1000 миллисекунд. Как результат — снова отказ теста.
  3. Различные браузеры имеют различные механизмы визуализации данных, назначают разные приоритеты операциям по размещению элементов на экране. Добавьте новый браузер в набор программ для тестирования и тест опять вылетит с ошибкой.
  4. Браузеры, которые контролируют страницы, JavaScript-вызовы, которые меняют их содержимое, по своей природе асинхронны. Если анимация в нашем примере применяется к блоку, который нуждается в информации с сервера, то перед запуском анимации придётся дождаться чего-то вроде результата AJAX-вызова. Теперь, кроме прочего, мы имеем дело с сетевыми задержками. Как результат, невозможно точно оценить время, необходимое для вывода панели на экран. Тест снова не сможет нормально работать.
  5. Конечно, есть и другие причины для сбоев тестов, о которых я не знаю. Даже сами браузеры, без учёта внешних факторов — сложные системы, в которых, к тому же есть ошибки. Разные ошибки в разных браузерах. В результате, пытаясь писать надёжные тесты, мы стремимся к тому, чтобы они работали в разных браузерах различных версий и в нескольких операционных системах различных выпусков. Недетерминированные тесты в подобных условиях рано или поздно дают сбои. Если учесть всё это — становится понятным, почему программисты отказываются от автоматизированных тестов и жалуются на то, как они ненадёжны.

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

Если вы пока ещё не убедились в том, что driver.sleep — это, во многих ситуациях, вредная команда, подумайте вот о чём. Без driver.sleep тесты будут работать гораздо быстрее. Например, мы надеемся, что анимация из нашего примера займёт всего 800 миллисекунд. В реальном тестовом наборе подобное предположение приведёт к использованию чего-то вроде driver.sleep(2000), опять же, в надежде на то, что 2-х секунд хватит на то, чтобы анимация успешно завершилась, какими бы ни были дополнительные факторы, влияющие на браузер и страницу.

Это — более секунды, потерянной всего на один шаг автоматизированного теста. Если подобных шагов будет много, очень быстро набежит немало таких вот «запасных» секунд. Например, недавно переработанный тест для всего одной из наших веб-страниц, который занимал несколько минут из-за чрезмерного использования driver.sleep, теперь выполняется меньше пятнадцати секунд.

Предлагаю вашему вниманию конкретные примеры избавления от driver.sleep и преобразования тестов в надёжные, полностью детерминированные конструкции.

Пара слов о промисах


JavaScript-API для Selenium интенсивно использует промисы. При этом детали скрыты от программиста благодаря использованию встроенного менеджера промисов. Ожидается, что этот функционал уберут, поэтому в будущем вам либо придётся разбираться с тем, как самостоятельно объединять промисы в цепочки, либо с тем, как пользоваться новым механизмом JavaScript async/await.

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

Пишем тесты


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

Как насчёт элемента, который динамически добавляется на страницу и не существует сразу после того, как страница завершит загрузку?

Ожидание появления элемента в DOM


Следующий код не будет работать, если элемент с CSS id my-button был добавлен в DOM после загрузки страницы:

// Код инициализации Selenium опущен для ясности
// Загрузка страницы.
driver.get('https:/foobar.baz');
// Найти элемент.
const button = driver.findElement(By.id('my-button'));
button.click();

Метод driver.findElement ожидает, что элемент уже присутствует в DOM. Он выдаст ошибку, если элемент невозможно немедленно найти. В данном случае «немедленно», из-за вызова driver.get, означает: «после того, как завершится загрузка страницы».

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

Обратите внимание на то, что вышеописанный сценарий не всегда нежелателен. Сам по себе вызов driver.findElement может быть удобен, если вы уверены, что элемент уже имеется в DOM.

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

driver.get('https:/foobar.baz');
// Страница загружается, засыпаем на несколько секунд
driver.sleep(3000);
// Надеемся, что три секунды достаточно для того, чтобы по прошествии этого времени элемент можно было бы найти на странице.
const button = driver.findElement(By.id('my-button'));
button.click();

По причинам, упомянутым выше, такая конструкция может привести к отказу, и, вероятно, приведёт. Нам нужно разобраться с тем, как ждать появления элемента в DOM. Это довольно просто, подобное нередко встречается в примерах, которые можно найти в интернете. Воспользуемся хорошо документированным методом driver.wait для того, чтобы ожидать того момента, когда элемент появится в DOM, не более двадцати секунд.

const button = driver.wait(
  until.elementLocated(By.id('my-button')), 
  20000
);
button.click();

Такой подход сразу же даст нам кучу плюсов. Например, если элемент будет добавлен в DOM в течение одной секунды, метод driver.wait завершит работу за одну секунду. Он не будет ждать все двадцать секунд, которые ему отведены.

Из-за этого поведения мы можем задавать тайм-ауты с большим запасом, не беспокоясь о том, что они замедлят тесты. Такая модель поведения выгодно отличается от driver.sleep, который всегда будет ждать всё заданное время.

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

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

Ожидание появления элемента на экране


Мы будем основываться на предыдущем примере, так как, прежде чем дождаться того, что элемент станет видимым, имеет смысл подождать момента его добавления в DOM. Кроме того, в нижеприведённом коде вы можете видеть первый пример использования цепочки промисов:

const button = driver.wait(
  until.elementLocated(By.id('my-button')), 
  20000
)
.then(element => {
   return driver.wait(
     until.elementIsVisible(element),
     20000
   );
});
button.click();

На этом, в общем-то, можно было бы и остановиться, так как мы уже рассмотрели достаточно для того, чтобы значительно улучшить тесты. С использованием этого кода вы сможете избежать множества ситуаций, которые, в противном случае, вызвали бы отказ теста из-за того, что элемента нет в DOM сразу после завершения загрузки страницы. Или из-за того, что он невидим сразу после загрузки страницы из-за чего-то вроде анимации. Или даже по обеим этим причинам.

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

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

Описание собственных условий


Благодаря методу until JavaScript API для Selenium уже имеет некоторое количество вспомогательных методов, которые можно использовать с driver.wait. Кроме того, можно организовать ожидание до тех пор, пока элемент не будет больше существовать, ожидать появления элемента, содержащего конкретный текст, ожидать показа уведомления, или использовать много других условий.

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

В соответствии с документацией, методу driver.wait можно предоставить функцию, которая возвращает true или false.

Скажем, нам нужно дождаться, чтобы свойство opacity некоего элемента стало бы равным единице:

// Получить элемент.
const element = driver.wait(
  until.elementLocated(By.id('some-id')),
  20000
);
// driver.wait всего лишь нужна функция, которая возвращает true или false.
driver.wait(() => { 
  return element.getCssValue('opacity')      
    .then(opacity => opacity === '1');
});

Такая конструкция кажется полезной и подходящей для повторного использования, поэтому поместим её в функцию:

const waitForOpacity = function(element) {
  return driver.wait(element => element.getCssValue('opacity')      
    .then(opacity => opacity === '1');
  );
};

Теперь воспользуемся этой функцией:

driver.wait(
  until.elementLocated(By.id('some-id')),
  20000
)
.then(waitForOpacity);

А вот тут мы сталкиваемся с проблемой. Что если вы хотите щёлкнуть по элементу, когда он станет полностью непрозрачным? Если мы попытаемся воспользоваться значением, возвращённым вышеприведённым кодом, ничего хорошего у нас не получится:

const element = driver.wait(
  until.elementLocated(By.id('some-id')),
  20000
)
.then(waitForOpacity);
// Вот незадача. Переменная element может быть true или false, это не элемент, у которого есть метод click().
element.click();

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

const element = driver.wait(
  until.elementLocated(By.id('some-id')),
  20000
)
.then(waitForOpacity)
.then(element => {
  // Так тоже не пойдёт, element и здесь является логическим значением.
  element.click();
}); 

Это всё, однако, легко исправить. Вот улучшенный метод:

const waitForOpacity = function(element) {
  return driver.wait(element => element.getCssValue('opacity')      
    .then(opacity => {
      if (opacity === '1') {
        return element;
      } else {
        return false;
    });
  );
};

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

Вот как можно это применить вместе с объединением промисов в цепочки:

driver.wait(
  until.elementLocated(By.id('some-id')),
  20000
)
.then(waitForOpacity)
.then(element => element.click());

Или даже так:

const element = driver.wait(
  until.elementLocated(By.id('some-id')),
  20000
)
.then(waitForOpacity);
element.click();

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

Уходим в минус


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

Предположим, элемент уже присутствует в DOM, но вы не должны с ним взаимодействовать до того, как некоторые данные будут загружены через AJAX. Элемент может быть перекрыт панелью с надписью «Загрузка...».

Если вы обратили пристальное внимание на условия, которые предлагает метод until, вы могли заметить методы вроде elementIsNotVisible или elementIsDisabled или на не столь очевидный метод stalenessOf.

Благодаря одному из этих методов можно организовать проверку на скрытие панели с индикатором загрузки:

// Элемент уже добавлен в DOM, отсюда сразу же произойдёт возврат.
const desiredElement = driver.wait(
  until.elementLocated(By.id('some-id')),
  20000
);
// Но с элементом нельзя взаимодействовать до тех пор, пока панель с индикатором загрузки
// не исчезнет.
driver.wait(
  until.elementIsNotVisible(By.id('loading-panel')),
  20000
);
// Панель с информацией о загрузке больше не видна, с элементом теперь можно взаимодействовать, не опасаясь ошибок.
desiredElement.click();

Исследуя вышеописанные методы, я обнаружил, что метод stalenessOf особенно полезен. Он ожидает, пока элемент не будет удалён из DOM, что, кроме прочих причин, может произойти из-за обновления страницы.

Вот пример ожидания обновления содержимого iframe для продолжения работы:

let iframeElem = driver.wait(
  until.elementLocated(By.className('result-iframe')),
  20000  
);
// Выполняем некое действие, которое приводит к обновлению iframe.
someElement.click();
// Ожидаем пока предыдущий iframe перестанет существовать:
driver.wait(
  until.stalenessOf(iframeElem),
  20000
);
// Переключаемся на новый iframe. 
driver.wait(
  until.ableToSwitchToFrame(By.className('result-iframe')),
  20000
);
// Всё, что будет написано здесь, относится уже к новому iframe.

Итоги


Главная рекомендация, которую можно дать тем, кто стремится писать надёжные тесты на Selenium, заключается в том, что всегда следует стремиться к детерминизму и отказаться от метода sleep. Полагаться на метод sleep — значит основываться на произвольных предположениях. А это, рано или поздно, приводит к сбоям.

Надеюсь, приведённые здесь примеры помогут вам продвинуться по пути создания качественных тестов на Selenium.

Уважаемые читатели! Используете ли вы Selenium для автоматизации тестов?
RUVDS.com
1,464.30
RUVDS – хостинг VDS/VPS серверов
Share post

Comments 20

    +1

    Да, без качественных автоматических функциональных тестов хорошее сложное web-приложение не сделать.
    Однако у оригинального Selenuim-а два недостатка: отличие языка тестов от языка клиентского кода и необходимость наличия webdriver-а для целевого браузера. И если первый недостаток давно решен в библиотеках Webdriver.io, Nightwatch, и тому подобное, позволяя писать на том же ECMA-262 ver 6+, то со вторым недостатком никаких подвижек нет.
    В частности, учитывая обилие устройств, как проверить работоспособность на всевозможных смартфонах, Smart TV и тому подобное. В этом плане TestCafe нет равных, или связке TestCafe + SauceLabs — на случай если у вас нет фермы живых устройств для прогона тестов

      0
      А безголовый хром для этих целей не подходит?
        +2

        Для того, чтобы оттестировать на десятках браузеров — нет.

        0
        а как насчет protractor.ExpectedConditions?

        EC = protractor.ExpectedConditions;
        form = $('.t-login-form-modal');
        browser.wait(EC.or(EC.presenceOf($('.t-privat')), EC.visibilityOf(form.$('.t-alert-danger'))), 10000);
          +1
          Мне не совсем понятно, почему анимация, которая должна отрабатывать за 800 миллисекунд, вдруг начала отрабатывать за 1200 миллисекунд и это не ошибка. Я конечно соглашусь, что писать driver.sleep(800) не хорошо, хотя бы потому, что тут захардкожена константа. Вторая проблема в том, что если у вас браузер все сделал за 200 миллисекунд, то остальные 600 миллисекунд будет просто ждать. Соглашусь, что wait с таймаутом это куда лучше, но то, что в wait так же хардкодятся константы, наверное не хорошо, по мне так лучше эти константы оговорить заранее для всего проекта и вынести в отдельное место, например:

          speed.veryFast= 100;
          speed.fast = 300;
          speed.normal = 1000;
          speed.slow = 10 * 1000;
          speed.verySlow = 100 * 1000;

          И в wait уже использовать эти константы:
          let iframeElem = driver.wait(
            until.elementLocated(By.className('result-iframe')),
            speed.slow
          );

          В таком случае если скорость работы элемента не укладывается в пороговые значения, вы будете анализировать причину почему так случилось и нужно ли элемент из разряда slow переводить в verySlow или же нужно как-то оптимизировать его работу?
            +1
            Мне не совсем понятно, почему анимация, которая должна отрабатывать за 800 миллисекунд, вдруг начала отрабатывать за 1200 миллисекунд и это не ошибка

            Автор не описал один достаточно частый кейс (для мобильного тестирования) как различная среда исполнения.
            К примеру, я мог для локальной машины подобрать слип в 800 миллисекунд где всё исполняется быстро, но на сервере сборки анимация проходила значительно дольше.
            И заранее определить в какой среде будет исполнятся тест — едва ли выполнимая задача.
              +1
              Да, но в данном случае вы говорите не «анимация должна выполняться 800 миллисекунд», а «анимация должна выполняться не более 800 миллисекунд» то есть не зависимо от того в какой среде выполняется тест, анимация должна выполняться не больше указанного времени. Все таки в большинстве случаев мы не знаем насколько загружена может быть машина пользователя, но не хотелось бы, чтобы у пользователя все работало как и задумывалось. Ну и никто не запрещал устанавливать пороговые значения в зависимости от платформы.
              0
              Вам же обьяснили, что вдруг поменялись требования или делался рефакторинг и случайно или специально разработчик увеличил время анимации. И что бы вам с ваших хардкодом не пришлось копатся и увеличивать константы, все будет четенько работать.
                +3
                Если разработчик увеличит время анимации случайно, то тест упадет и разработчик исправит время анимации в приложении. Если разработчик увеличит время анимации специально, то тест упадет и разработчик исправит время анимации в тесте. Изменились требования — изменились тесты, которые эти требования проверяют. Мне кажется, что это как раз обязанность теста. По поводу увеличения констант — их не нужно увеличивать, нужно выбирать другую, они на то и константы. Если у нас элемент стал работать дольше чем «быстро», значит нам нужно или определить почему он стал работать не «быстро» или перевести в категорию «нормально» то есть изменить требования для элемента. И только в крайнем случае нужно пересмотреть выбранные константы для выбранной платформы.
                  0
                  Увы, это не обязанность selenium теста проверять тайминги.

                  Немного притормозил браузер (или сервер), анимация отыгралась медленней — тест развалился. Запустил еще раз — снова нормальный. На седьмой раз — снова развалился.

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

                  Иначе пропадает весь смысл — нельзя доверять результату неоднозначного теста.

                    0
                    Как я и писал выше, вы сами управляете выбором констант и можете выбрать максимально комфортные, которые будут отвечать вашим критериям стабильности. В посте у wait точно также захардкожена константа 20000. Cуть в том, что массово изменить эту константу для тестирования на менее производительном стенду не получится. Неоднозночность, даже в селениум тестах должна быть минимальной. Не плохо, когда тест падает и ошибки анализируются. Плохо, когда тесты не падают, но ошибки и неопределенно поведение происходит уже у пользователя. Вообще тайминги это некоторый контракт между тестировщиком и пользователем «Я гарантирую, что при таких условиях элемент отработает за такое время». Если вы не готовы гарантировать 1 секунду, вы можете гарантировать 100 секунд. Так или иначе используя подход указанный в посте вы тайминг пропишите, но вопрос в том, как этим таймингом вы будете управлять в дальнейшем.
                      0
                      Не понимаю с чем вы спорите.
                      Мой аргумент: Это не обязанность selenium теста проверять тайминги.
                      Ваш аргумент: Можно гарантировать заведомо большие тайминги.

                      Можно. Но это не обязанность selenium теста.

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

                          То есть запустил тест 1000 раз, если 900 раз попало в тайминги — хорошо. Иначе ни о какой детерменированности теста речи быть не может
                            0
                            Почему тест таймингов должен основываться на статистике? Тест таймингов должен основываться на требованиях к системе, а вот требования к системе могут основываться на статистике. Например у вас в интернет магазине кнопка добавления товара в корзину стала отрабатывать на 20 секунд дольше и продажи уменьшились на 80%. Уже проведено бесчисленное количество исследований по производительности пользовательских интерфейсов. Практика показывает, что лучше это не игнорировать. По сути вы предлагаете проверить, что все работает, а я предлагаю проверить, что все работает и работает хорошо.
                              0
                              Я нажимал на кнопку «предпросмотр» на хабре и записал вот такие тайминги ответов:
                              image

                              Статистически можно высчитать, что кнопка загружается в среднем 5 секунд или 20 секунд. А по факту разница в загрузке может достигать порядка-двух из-за влияния канала между сервером и клиентом, загрузки сервера или проблем с самим клиентом.
              +2
              Может кто-нибудь пояснить:
              1. Зачем нам сначала ждать появление элемента в дом, а затем ждать его визибилити. Нельзя ли просто ждать визибилити? Ведь элемент не может появится на странице перед тем как попасть в DOM.
              2. Вопрос по экепшену
              System.InvalidOperationException: Element is not clickable at point (326, 792.5)

              Клик сработал во время анимации
              Но ведь используя wait и ожидания visiblity мы ведь тоже можем столкнутся с этой проблемой? Или visibility condition как-то хитро устроено и определяет окончание анимации?
                0
                Откровенно говоря, это проблема не только с NodeJS, а при работе с Selenium в принципе на любом языке. Пишу тесты на Codeceptuon. Столкнулся с такой лабудой, когда работал с Ajax запросами. По туториалу (одному из) ставил wait(1). Работало раз через раз. Стоило только чуть нагрузить комп, и тесты сразу вылетали. Часто ругался, что элемента какого-то нет. В итоге начал использовать функции хелперы типа waitFor(something) и проблема ушла сама собой. И тесты стали значительно быстрее.
                  0
                  Расскажу как я делал тестирование: селениум использовал для инжектинга js кода на страницу, который выполнял всю работу и возвращал в калбэк результат работы. Такой подход имеет такие плюсы как навешивание промисов на DOM элементы, выполнение кода в любом скопе, да и выполнение происходит быстрее, ведь тут нет множественных обращений к браузеру и пробросу результата через селениум драйвер. А по поводу driver.wait внутри это просто циклическая проверка условия с задержками. Из очевидных плюсов это возможность дебагинга кода тестов прямо в браузере через тот же инжектинг на любой сайт.
                    0
                    В листинге, где описывается функция waitForOpacity первый раз лишняя точка с запятой

                    Only users with full accounts can post comments. Log in, please.