Совместное использование команд Cypress в рабочем пространстве Nx

Cypress произвел революцию в области e2e-тестирования. Он успешно устранил многие болевые точки, с которыми сталкивались разработчики при использовании решений для e2e-тестирования. В этой статье мы рассмотрим, как вывести его на новый уровень, научившись использовать Cypress в рабочем пространстве Nx, в частности, как совместно использовать общие пользовательские команды Cypress в монорепо Nx.

Nx ❤️ Cypress

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

При создании нового приложения с помощью Nx вы получите

  • TypeScript установлен и настроен;
  • Jest для модульного тестирования;
  • ESLint для линтинга;
  • Prettier настроен так, что вам не придется размышлять о табуляции и пробелах;
  • и, наконец, Cypress для e2e тестирования (и тестирования компонентов в ближайшее время!).

Каждое приложение (если вы активно не отказываетесь от участия) получает соответствующую настройку Cypress в виде <app-name>-e2e (вы можете изменить это имя, если хотите).

Это делает Nx довольно привлекательным в качестве CLI для разработки по умолчанию, даже если вы не рассчитываете полностью использовать многоприкладное рабочее пространство Nx monorepo.

Предпочитаете видеоверсию?

Вот, пожалуйста! Пожалуйста.

Настройка нового рабочего пространства Nx

Если вы уже настроили рабочее пространство, можете пропустить этот раздел. Здесь нет ничего нового для вас ?. Вместо этого, если вы не совсем понимаете, что такое Nx, пожалуйста, следуйте дальше.

Давайте сгенерируем новое рабочее пространство Nx на основе React.

npx create-nx-workspace nxlovescypress --preset=react --appName=happynrwl
Вход в полноэкранный режим Выйдите из полноэкранного режима

Это сгенерирует новую установку с приложением React happynrwl. Для стилей и настройки Nx Cloud выбирайте все, что вам нравится. Для данной статьи это не имеет значения.

Обратите внимание, вы также можете использовать настройку рабочего пространства Nx на основе Angular. Для данной статьи это не имеет значения. Вы можете обратиться к репозиторию примера на GitHub, ссылка на которую приведена в конце этой статьи, где используется рабочее пространство Nx, содержащее приложение Angular и React.

В итоге у вас должно получиться новое рабочее пространство Nx со следующей ситуацией:

Давайте рассмотрим нашу установку.

Запуск Cypress в рабочем пространстве Nx

happynrwl-e2e — это приложение Cypress, которое было сгенерировано для нашего React-приложения happynrwl.

Вы можете запустить тесты Cypress e2e без головы, используя следующие команды

npx nx e2e happynrwl-e2e
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы также можете передать --watch, чтобы запустить его интерактивно с программой Cypress test runner, чтобы тесты выполнялись заново каждый раз, когда мы меняем исходный код.

Самое замечательное в этом то, что вам вообще не нужно ничего настраивать. Не нужно

  • сначала вручную раскрутить наш сервер разработки, который будет обслуживать наше React-приложение, чтобы мы могли загрузить его в среду тестов Cypress
  • настроить линтинг для нашего проекта e2e (да, написание качественного тестового кода не менее важно).

Пользовательские команды Cypress

В Cypress вы обычно взаимодействуете через глобальный объект cy, например, вы можете написать

cy.get('[data-testid="some-link"]').click();
Войти в полноэкранный режим Выйти из полноэкранного режима

…чтобы захватить некоторый элемент DOM и затем взаимодействовать с ним. В данном случае щелчком по ссылке.

К счастью, Cypress является расширяемым, что позволяет вам добавлять собственные команды к объекту cy, чтобы их можно было легко вызывать в вашей тестовой реализации.

В вашей установке Cypress откройте файл support/commands.ts, чтобы увидеть пример объявления такой пользовательской команды:


// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace Cypress {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  interface Chainable<Subject> {
    login(email: string, password: string): void;
  }
}
//
// -- This is a parent command --
Cypress.Commands.add('login', (email, password) => {
  console.log('Custom command example: Login', email, password);
});
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
Войти в полноэкранный режим Выйти из полноэкранного режима

Подробнее об этом можно прочитать в официальной документации Cypress: https://docs.cypress.io/api/cypress-api/custom-commands.

Совместное использование пользовательских команд Cypress

Рассмотрим простую пользовательскую команду Cypress с именем getEl, которая следует лучшей практике Cypress для захвата элементов через специальное свойство data-testid.

Вот как выглядит чистая реализация.

Cypress.Commands.add('getEl', (identifier: string) => {
  return cy.get(`[data-testid=${identifier}]`);
});
Вход в полноэкранный режим Выход из полноэкранного режима

В идеале мы хотим повторно использовать этот тип команды во всех наших e2e тестах. Давайте рассмотрим, как Nx может существенно помочь нам в этом начинании.

Совместное использование функциональности в рабочем пространстве Nx

Когда вы создаете новое рабочее пространство Nx, вы получаете установку, включающую папки apps и libs. Это различие позволяет нам иметь более модульную архитектуру, следуя методологии разделения проблем, стимулируя организацию нашего исходного кода и логики в более мелкие, более сфокусированные и очень цельные единицы.

Именно здесь также происходит повторное использование и обмен функциями в рабочем пространстве Nx. Nx автоматически создает сопоставления путей TypeScript в файле tsconfig.base.json, чтобы они могли быть легко использованы другими приложениями или библиотеками. Таким образом, функциональность, организованная в библиотеках, может быть импортирована так же легко, как и

import { Button } from '@my-organization/ui';
Вход в полноэкранный режим Выход из полноэкранного режима

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

В этой статье мы используем этот тип настройки, чтобы организовать наши пользовательские команды Cypress в библиотеке Nx для последующего повторного использования, не в других приложениях или библиотеках, а во всех наших тестах Cypress e2e, которые потенциально могут находиться в рабочем пространстве Nx monorepo.

Подробнее о ментальной модели приложений и библиотек можно прочитать в официальной документации Nx: https://nx.dev/structure/applications-and-libraries.

Генерация новой библиотеки для размещения пользовательских команд

Как уже говорилось, нам нужна библиотека для совместного использования функциональности в рабочем пространстве Nx. Поэтому давайте сгенерируем ее:

npx nx generate @nrwl/js:library --name=cypress-commands --directory=shared --buildable=false
Войти в полноэкранный режим Выход из полноэкранного режима

Пакет @nrwl/js используется для создания чистых пакетов TypeScript, не зависящих от фреймворка. Подробнее: https://nx.dev/getting-started/nx-and-typescript

Давайте изучим, что мы получили. Только что созданная библиотека (как и все библиотеки на основе Nx) имеет файл index.ts, который является «публичным API» вашей библиотеки (часто также называемый «файлом бочки»). Эта точка входа позволяет прекрасно контролировать, что должно быть открыто для других библиотек и приложений, а что должно оставаться закрытым внутри самой библиотеки.

Создание нашей пользовательской команды getEl Cypress

В нашей библиотеке мы бы хотели, чтобы наши пользовательские команды были заданы в отдельных файлах. Поэтому давайте создадим get-el-command.ts в нашей библиотеке:

// libs/shared/cypress-commands/src/lib/get-el-command.ts

// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace Cypress {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  interface Chainable<Subject> {
    getEl: (identifier: string) => Chainable<JQuery<HTMLElement>>;
  }
}

Cypress.Commands.add('getEl', (identifier: string) => {
  return cy.get(`[data-testid=${identifier}]`);
});
Вход в полноэкранный режим Выйти из полноэкранного режима

Для того чтобы экспортировать его, нам нужно также экспортировать его из файла index.ts нашей библиотеки:

// libs/shared/cypress-commands/src/index.ts
import './lib/get-el-command';
Войти в полноэкранный режим Выход из полноэкранного режима

? Минутку, мы сделали импорт, а не экспорт в index.ts. Правильно. Это немного особый случай, поскольку команды Cypress создаются путем регистрации функции в глобальном объекте Cypress.Commands. Таким образом, все, что нам нужно сделать, это импортировать файл, чтобы get-el-command.ts был выполнен и, следовательно, наша функция Cypress.Commands.add('getEl',... была вызвана и зарегистрирована.

Добавление поддержки Cypress Type в нашу библиотеку

Вы можете заметить, что TypeScript не распознает глобальный объект Cypress cy в нашей сгенерированной библиотеке cypress-commands.

Каждая библиотека Nx уже настроена и сконфигурирована для работы с TypeScript. Существует

Чтобы заставить типы Cypress работать, нам нужно добавить cypress и node в свойство types свойства compilerOptions в tsconfig.lib.json:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    ...
    "types": ["cypress", "node"]
  },
  ...
}
Вход в полноэкранный режим Выход из полноэкранного режима

Потребление команд Cypress

Мы готовы использовать нашу пользовательскую команду в нашем тесте e2e, а точнее в happynrwl-e2e. Для этого нам нужно импортировать наши пользовательские команды, чтобы убедиться, что они зарегистрированы в Cypress. Перейдите в apps/happynrwl-e2e/src/support/index.ts и импортируйте нашу библиотеку, содержащую общие команды Cypress:

// apps/happynrwl-e2e/src/support/index.ts
...
import '@nxlovescypress/shared/cypress-commands';
Войти в полноэкранный режим Выход из полноэкранного режима

Обратите внимание, как удобно мы можем использовать @nxlovescypress/... . Это работает, потому что Nx автоматически создает сопоставление путей для каждой сгенерированной библиотеки в tsconfig.base.json:

{
  "compileOnSave": false,
  "compilerOptions": {
    ...
    "paths": {
      "@nxlovescypress/shared/cypress-commands": [
        "libs/shared/cypress-commands/src/index.ts"
      ]
    }
  },
  "exclude": ["node_modules", "tmp"]
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Чтобы проверить команду, давайте откроем главный компонент nx-welcome.tsx в приложении happynrwl и изменим область заголовка на текст с надписью Nx ❤️ Cypress:

// apps/happynrwl/src/app/nx-welcome.tsx
<div id="welcome">
  <h1 data-testid="message">
    <span> Hello there, </span>
    Nx ❤️ Cypress
  </h1>
</div>
Вход в полноэкранный режим Выйти из полноэкранного режима

Далее, в соответствующем e2e тесте в apps/happynrwl-e2e/src/integration/app.spec.ts мы изменим его на следующий:

// apps/happynrwl-e2e/src/integration/app.spec.ts
describe('happynrwl', () => {
  beforeEach(() => cy.visit('/'));

  it('should display welcome message', () => {
    cy.getEl('message').should('contain', 'Nx ❤️ Cypress');
  });
});
Войти в полноэкранный режим Выйти из полноэкранного режима

Обратите внимание, что поддержка автозаполнения TypeScript подхвачена правильно и показывает нашу пользовательскую команду Cypress:

Наконец, запуск теста в режиме просмотра должен дать следующее, что демонстрирует успешное использование нашей команды.

npx nx e2e happynrwl-e2e --watch
Вход в полноэкранный режим Выход из полноэкранного режима

Повторное использование команд Cypress в нашем рабочем пространстве Nx

Повторное использование теперь очень просто. Поскольку наша пользовательская команда Cypress теперь заключена в библиотеку в рабочем пространстве Nx, мы можем легко использовать ее в других e2e тестах на базе Cypress. Все, что нужно сделать, это импортировать ее в support/index.ts нашей установки Cypress:

import '@nxlovescypress/shared/cypress-commands';
Вход в полноэкранный режим Выход из полноэкранного режима

Я оставлю на ваше усмотрение

  • сгенерировать новое приложение с соответствующим тестом e2e
  • импортировать наши общие команды
  • использовать их в e2e тестах Cypress.

Заключение

Эта статья должна была дать вам хорошее понимание того, как Nx помогает устанавливать и настраивать Cypress и как использовать библиотеки в рабочем пространстве Nx не только для обмена функциональностью между приложениями, но и между e2e-тестами.

Вот репозиторий GitHub, который я использовал для этой статьи: https://github.com/nrwl/nx-cypress-command-sharing.


Подробнее

? Nx Docs
?? Nx GitHub
? Nrwl Community Slack
? Канал Nrwl Youtube
? Бесплатный курс Egghead
? Нужна помощь с Angular, React, Monorepos, Lerna или Nx? Поговорите с нами ?

Также, если вам понравилось это, нажмите ❤️ и не забудьте следить за Юри и Nx в Twitter, чтобы узнать больше!

#nx

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *