? Плюшевый Cypress: 5 советов

Переменные окружения

Разрабатывая веб-приложения, обычно используют как минимум два окружения. Это нужно для того, чтобы проверить работоспособность приложения в разных условиях, до того как оно попадет в продакшен. Скорее всего, эти окружения будут иметь разные базы данных, возможно там будут отличаться API-эндпоинты и переменные. Поэтому если работаешь в Cypress, очень желательно иметь отдельный конфиг-файл для каждого окружения.

Структура файлов и имена файла:

/src/cypress/config
                  /test.json
                  /staging.json
                  /production.json

Посмотрим на staging.json:

{
  "baseUrl": "http://localhost:3000",
  "env": {
    "env": "staging",
    "apiUrl": "https://staging-api.com/api/v1",
  }
}

И production.json:

{
  "baseUrl": "http://localhost:3000",
  "env": {
    "env": "production",
    "apiUrl": "https://api.com/api/v1",
  }
}

(При этом не забудь сохранить свои env-переменные внутри объекта env)

Затем обнови Cypress-скрипты в package.json, чтобы убедиться, что Cypress будет запускаться с правильным конфигом для каждого окружения:

"scripts": {
 "cypress:run:staging": "cypress run --env configFile=staging",
 "test:e2e:staging:run": "start-server-and-test 'npm run start' http://localhost:3000 'npm run cypress:run:staging'",

 "cypress:run:production": "cypress run --env configFile=production",
 "test:e2e:production:run": "start-server-and-test 'npm run start' http://localhost:3000 'npm run cypress:run:production'",
}

// same approach could be used for "cypress open" command.

Модуль «start-server-and-test» запускает приложение, и сразу запускает cypress-тесты.

Дальше вставь в src/cypress/plugins/index.js такой кусок:

const fs = require('fs')
const path = require('path')

function getConfigurationByFile(fileName) {
  const pathToConfigFile = path.resolve(__dirname, `../config/${fileName}.json`);
  let rawData;
  try {
    rawData = fs.readFileSync(pathToConfigFile);
  } catch (e) {
    console.error(e);
  }
  return JSON.parse(rawData);
}

module.exports = (on, config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config

  // this value comes from *cypress run --env configFile=staging*
  const configFile = getConfigurationByFile(config.env.configFile || 'test');

  return { ...config, ...configFile };
};

Теперь Cypress будет запускать тесты с правильным конфигом.

Если все сделано правильно, можно экстрактировать переменные, вот так:

const { apiUrl, env } = Cypress.env();
// to extract baseUrl variable you should use Cypress.config()
// const { baseUrl } = Cypress.config();

Изменение значений fixtures “на лету” 

В основном fixtures (фиксированные наборы данных) применяются, когда нужно имитировать API-ответ при тестировании. Вообще, так делать не очень рекомендуется. Но если есть несколько окружений, рано или поздно возникнет проблема: одинаковые запросы возвращают одни и те же данные из каждого окружения (кроме id). И может быть неудобно дублировать fixture.

Тогда можно записать fixture и env-переменную окружения; затем обновить значение “на лету” в тест-кейсе:

describe('it should test smth', function() {
  beforeEach(() => {
    // user is a env variable
    const { user: userEnv } = Cypress.env();

    cy.fixture('user.json').then(user => {
      user.id = userEnv.id; // updating user id
      // use updated fixture here (e.g. `cy.intercept`)
    });
  });
});

Внимание: если применяется beforeEach, надо обязательно “обернуть” его в describe, чтобы не влияло на остальные тесты. Подробнее в документации по Fixture.

Глобально имитируем API-ответы

Чтобы имитировать сетевой запрос “глобально”, открываем src/cypress/support/index.js, и вставляем туда кусок:

beforeEach(() => {
  cy.intercept({ url: `${apiUrl}/profile*`, middleware: true }, req => {
    req.reply({
      fixture: 'getProfile.json',
    });
});

Подробнее — в документации по intercept.

Кастомные команды

В Cypress возможны кастомные команды. Они позволяют избежать применения шаблонного boilerplate-кода.

Смотрим:

 // you can turn this piece of code
 it('should fill in discount form', function() {
    cy.get('input[name="email"]').type('test@test.com');
    cy.get('input[name="phone"]').type('1231231212');
    cy.get('div[role="checkbox"]').click({ force: true });
    cy.findByText(/Save/i).click({ force: true });
    // ...rest of the test
  });

// into a single line
it('should fill in discount form', function() {
 cy.fillDiscountForm();
 // ...rest of the test
});

Чтобы создать например команду заполнения форм cy.fillDiscountForm(), надо перейти к файлу src/cypress/support/commands.js и создать там кастомную команду:

Cypress.Commands.add('fillDiscountForm', function() {
  cy.get('input[name="email"]').type('test@test.com');
  cy.get('input[name="phone"]').type('1231231212');
  cy.get('div[role="checkbox"]').click({ force: true });
  cy.findByText(/Save/i).click({ force: true });
});

Теперь можно применять команду cy.fillDiscountForm() в любом тесте.

Документация тут.

Ожидания

До того как приложение отобразит данные, оно вероятно получит их с сервера. А если есть проблемы с интернетом, и тесты показали “fail” из-за невыполненных API-запросов? Тогда при каждом API-запросе надо добавить ожидание окончания (cy.wait).

it('should fill in discount form', function() {
  cy.intercept(`${apiUrl}/settings`).as('getSettings');
  cy.visit(`/settings-page`);
  // once a request to get settings responds, 'cy.wait' will resolve
  cy.wait('@getSettings');
  // rest of the test
  // cy.contains(/edit settings/i).click({ force: true });
});

Надо зарегистрировать “перехват” до захОда на страницу /settings-page. Как только заход на страницу настроек состоялся, это триггерит запрос GET ${apiUrl}/settings, и Cypress будет ожидать его завершения, и после этого продолжит выполнение.

Теперь, если API-вызов не прошел по какой-то причине, Cypress выдаст баг, и его намного проще устранить.

Документация по wait

***

Какой была ваша первая зарплата в QA и как вы искали первую работу?

Мега обсуждение в нашем телеграм-канале о поиске первой работы. Обмен опытом и мнения.

Подписаться
Уведомить о
guest

0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии

Мы в Telegram

Наш официальный канал
Полезные материалы и тесты
Готовимся к собеседованию
Project- и Product-менеджмент

? Популярное

? Telegram-обсуждения

Наши подписчики обсуждают, как искали первую работу в QA. Некоторые ищут ее прямо сейчас.
Наши подписчики рассказывают о том, как не бояться задавать тупые вопросы и чувствовать себя уверенно в новой команде.
Обсуждаем, куда лучше податься - в менеджмент или по технической ветке?
Говорим о конфликтных ситуациях в команде и о том, как их избежать
$1100*
медианная зарплата в QA в июне 2023

*по результатам опроса QA-инженеров в нашем телеграм-канале

Собеседование

19%*
IT-специалистов переехало или приняло решение о переезде из России по состоянию на конец марта 2022

*по результатам опроса в нашем телеграм-канале

live

Обсуждают сейчас