Введение — выбор правильного инструмента

Найти хороший фреймворк — не всегда простая задача. Особенно в джаваскрипте. Вариантов часто много. И всегда новый крутой парень, говорящий, что он лучший… Этот новый фреймворк спасет вам жизнь!

Возможно, я слишком много делаю. Но мне иногда так кажется.
Как будто у каждого инструмента и фреймворка есть «функции страница». Но никаких «недостатков/подводных камней страницы». И когда я выбираю новый инструмент, знайте, что я должен получить выгоду с самого начала (это рекламируется). И все же мне придется самому обнаружить эти недостатки. И это дорого.

Да, это дорого. изучая этот фреймворк, играя с ним, решая, буду ли я использовать его в продакшене, кодируя какое-то реальное приложение… Тогда и только тогда я узнаю, какие проблемы я привнес с этим «крутым» инструментом, который я выберите…

Так! Все это к тому, что я сделал хорошее открытие в последнее время. Я с удовольствием поделюсь ею с вами. И расскажу вам о каком-то недостатке, который я обнаружил.

Кодецепт

https://codecept.io/ — это сквозной инструмент. Это абстракция поверх различных фреймворков, таких как appium, protractor, pupeteer, webdriver… Этот инструмент тестирования рассматривает такой фреймворк, как protactor, как веб-драйвер, а не как тестовый фреймворк. И поэтому сосредоточьтесь на предоставлении вам среды тестирования, позволяющей писать такие вещи:

I.amOnPage("/login"); // visit url /login
I.fillField("username", "lsmod"); // fill input with name=password
I.fillField("password", "STRONGPASSWORD");
I.click("login"); // click on the button login (matching "login" text)
I.see("Hello lsmod!"); // wait some and check if we are logged

Это выглядит просто. Нет .then() .catch(). Нет await, нет повторных попыток. Определенно никаких browser, page, getElement и тому подобного.

Некоторые из моих любимых вещей, которые просто работают:

I.attachFile("form input[name=avatar]", "data/avatar.jpg");
I.checkOption("#agree");
I.selectOption("Choose Plan", "Monthly"); // select by label

Я просто набираю, что делает мой тест и что я хочу видеть на экране. Мне не нужно возиться с асинхронностью и браузером. Codecept ждет и повторяет за меня.

Добро

Во-первых, я использовал codecept с pupeteer для фронтенд-проектов (yew.rs и react) и с appium для реактивно-нативного приложения. И это работает!

Тесты намного менее подробны, чем, например, с кукловодом или кипарисом. Вы можете сосредоточиться на написании текста. В конце концов, легче писать и читать.

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

Еще одна хорошая вещь заключается в том, что вы можете писать собственные помощники. Если вы не найдете то, что вам нужно, например, I.login(); или I.intercepHttpResponse();, чтобы перехватывать HTTP-запросы, сделанные вашим приложением, и сравнивать ответ с тем, что отображается на экране, вы можете легко написать помощник для этого.

Также тесты внутри сценария не запускаются параллельно, просто один за другим. Это может сделать вашу жизнь проще, делая такие вещи, как:

Feature('Admin Dashboard');
Scenario('Add a new user', (I) => {
  I.amOnPage("/admin/new_user");
  I.fillField("username", "newbie41");
  I.fillField("password", "helloCodecept");
  I.click("create");
}
// this test will be executed after adding an user
Scenario('Display recently added users', (I) => {
  I.amOnPage("/admin/dashboard");
  I.see("user account recently created");
  I.see("newbie41");
}

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

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

Плохо

Я должен был создать помощника! И поэтому мне пришлось узнать о кукольниках. Помощник Codecept позволяет вам получить доступ к кукловоду, транспортиру или любому другому «веб-драйверу», который вы решите использовать за сценой.

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

Пользовательский интерфейс https://codecept.io/ui/ все еще находится в стадии бета-тестирования. Это альтернатива кипарису. Но у меня были хорошие надежды на это. Между тем, отчеты, отображаемые в терминале, выполняют свою работу.

Уродливый

Я до сих пор не нашел способа выбрать n-й элемент в списке a<select>.

При использовании codecept с appium я сталкиваюсь с ошибкой. Мой тест работал так:

I.fillField("~new-comment", "Codecept isn't super stable yet"); // ~ say that I want to select an element based on it's accessiblity label
I.click("~submit");

Через несколько недель (вероятно, после npm install) он больше не работал. Мне пришлось использовать tap вместо click

I.fillField("~new-comment", "Codecept isn't super stable yet"); // ~ say that I want to select an element based on it's accessiblity label
I.tap("~submit");

У меня тоже была проблема с прокруткой…

Мой тест не «увидел» некоторый текст, потому что он был за кадром. Я попытался прокрутить его, но безуспешно… Мне пришлось щелкнуть какой-то элемент поверх него, чтобы прокрутить appium к нему (хотя это не проблема с кукловодом).

На самом деле больше не на что жаловаться!

Бонус: перехват HTTP-запросов

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

«Профиль» возвращается API через GET /profile. Поэтому у меня возникла идея захватить http-запрос, сделанный приложением при загрузке целевой страницы, и сравнить его с тем, что отображается.

Я не рекомендую этот способ тестирования, но иногда он может быть удобен (когда у вас нет реального API для тестирования с детерминированной базой данных).

В любом случае, codecept позволяет вам добавлять «помощников», как показано ниже:

const Helper = codecept_helper;
const puppeteer = require("puppeteer");

class HttpIntercepterHelper extends Helper {
  async interceptHttpResponse(url) {
    const httpInspect = async () => {
      const { page } = this.helpers.Puppeteer; // pupeteer is accessible within Helpers

      return new Promise((resolve, reject) => {
        page.on("response", response => {
          if (response.url().endsWith(url)) {
            response.json().then(json => {
              resolve({
                method: response.request().method(),
                url: response.url(),
                body: json,
                status: response.status()
              });
            });
          }
        });
      });
    };
    return await httpInspect();
  }
}

module.exports = HttpIntercepterHelper;

Что вы можете использовать так:

Scenario("I Sign in & see my nickname in greetings", async I => {
  I.login();
  // when loggin-in the app make an API call to /profil to fetch user details
  const response = await I.interceptHttpResponse("/profil");
  const profil = response.body;

  I.waitForElement("#greetings");
  // app displaying fetched nickname ?
  I.see(`Welcome back ${profil.nickname}!!`);
});

Вывод

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

Мы используем его в производстве на работе сейчас.

Еще одно хорошее открытие, сделанное во время личного проекта, используемого на работе, бесплатно для моего работодателя. Именно об этом я говорил в своей предыдущей статье: https://medium.com/@lsmod/homeworking-7bd0a44047cb

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