Типизация тестов

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

Использование TypeScript в Cypress

Cypress полностью поддерживает TypeScript, что дает возможность:

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

Для включения TypeScript необходимо:

  1. Установить необходимые пакеты:
npm install --save-dev typescript @types/node @cypress/webpack-preprocessor
  1. Создать tsconfig.json в корне проекта с базовой конфигурацией:
{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "types": ["cypress", "node"]
  },
  "include": ["cypress/**/*.ts"]
}
  1. Переименовать файлы тестов с расширения .js на .ts.

Типизация команд Cypress

Cypress предоставляет набор встроенных типов, которые описывают команды и объекты, с которыми работает тестировщик:

  • cy — основной объект для выполнения действий на странице.
  • Cypress.Chainable<T> — универсальный тип цепочек команд Cypress.
  • Cypress.Response<T> — тип ответа для сетевых запросов.
  • Cypress.ConfigOptions — настройки конфигурации Cypress.

Пример типизированного запроса и проверки:

interface User {
  id: number;
  name: string;
  email: string;
}

cy.request<User>('/api/users/1').then((response) => {
  expect(response.status).to.eq(200);
  const user: User = response.body;
  expect(user.name).to.be.a('string');
});

В этом примере тип User гарантирует, что тело ответа соответствует ожидаемой структуре, и исключает ошибки при обращении к свойствам объекта.

Типизация данных в тестах

Для сложных форм и компонентов полезно определять интерфейсы данных, с которыми работают тесты. Это позволяет:

  • Уточнять типы полей формы.
  • Использовать автодополнение при заполнении данных.
  • Исключать опечатки и неверные обращения к свойствам.

Пример типизированной формы:

interface LoginForm {
  username: string;
  password: string;
}

const credentials: LoginForm = {
  username: 'admin',
  password: '12345'
};

cy.get('input[name="username"]').type(credentials.username);
cy.get('input[name="password"]').type(credentials.password);
cy.get('button[type="submit"]').click();

Расширение типов Cypress

Cypress позволяет создавать кастомные команды с полной поддержкой TypeScript. Для этого используется файл cypress/support/commands.ts и расширение интерфейса Cypress.Chainable:

declare namespace Cypress {
  interface Chainable<Subject> {
    login(username: string, password: string): Chainable<void>;
  }
}

Cypress.Commands.add('login', (username, password) => {
  cy.get('input[name="username"]').type(username);
  cy.get('input[name="password"]').type(password);
  cy.get('button[type="submit"]').click();
});

// Использование:
cy.login('admin', '12345');

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

Типизация селекторов и элементов DOM

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

interface LoginPageElements {
  usernameInput: string;
  passwordInput: string;
  submitButton: string;
}

const elements: LoginPageElements = {
  usernameInput: 'input[name="username"]',
  passwordInput: 'input[name="password"]',
  submitButton: 'button[type="submit"]'
};

cy.get(elements.usernameInput).type('user');
cy.get(elements.passwordInput).type('pass');
cy.get(elements.submitButton).click();

Это позволяет централизованно управлять селекторами и избежать дублирования строк по проекту.

Проверка типов через assertions

Cypress интегрируется с Chai, что позволяет типизированно проверять значения:

cy.get('input[name="email"]').invoke('val').then((value: string) => {
  expect(value).to.match(/@/);
});

Приведение типа string гарантирует корректную работу методов для строк и исключает ошибки, связанные с неопределенными типами.

Типизация API-запросов и fixture

Для тестов, зависящих от API, рекомендуется использовать типы для mock-данных и fixtures:

interface TodoItem {
  id: number;
  title: string;
  completed: boolean;
}

cy.fixture<TodoItem[]>('todos.json').then((todos) => {
  expect(todos).to.have.length.greaterThan(0);
});

Это обеспечивает полную предсказуемость структуры данных, используемых в тестах.

Преимущества типизации тестов

  • Раннее обнаружение ошибок: ошибки типов выявляются при компиляции.
  • Чистый и поддерживаемый код: интерфейсы и типы документируют структуру данных.
  • Удобство автодополнения: IDE показывает доступные методы и свойства.
  • Масштабируемость: типизация упрощает поддержку больших тестовых наборов и интеграцию с CI/CD.

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