Настройка TypeScript в Cypress
Если у вас уже есть проект на TypeScript, вы на шаг впереди! Если нет — вот подробная инструкция:
Установим TypeScript и необходимые зависимости для Cypress:
npm install typescript @types/node @types/cypress --save-devСоздадим конфигурационный файл
tsconfig.jsonв корне проекта:{ "compilerOptions": { "target": "es6", "module": "commonjs", "strict": true, "esModuleInterop": true, "types": ["cypress"] }, "include": ["cypress/**/*.ts"] }Переименуем тестовые файлы с
.jsна.ts. Например, переименуемexample.cy.jsвexample.cy.ts.
Поздравляю, вы только что стали ближе к типизированным тестам!
Обзор типизации в Cypress
После настройки TypeScript начнется магия автозаполнения. Например, если вы начнете писать:
cy.get('.button').
TypeScript предложит автодополнение методов, таких как .click() или .should().
Автодополнение и проверка типов помогут вам избежать случайных ошибок. Например, если вы попытаетесь передать строку туда, где ожидается число, TypeScript сразу покажет ошибку.
Типизация интерфейсов
Интерфейсы в TypeScript — это способ описания структуры объектов. Они помогают явно показывать, какие свойства и типы ожидаются у объекта. В тестах это особенно полезно для работы с mock-данными и проверкой форматов данных.
Рассмотрим пример. Допустим, мы тестируем форму, где нужно отправить данные пользователя. Вот простая структура данных:
interface User {
id: number;
name: string;
email: string;
isAdmin: boolean;
}
С помощью интерфейсов мы можем задавать строгую типизацию данных:
const user: User = {
id: 1,
name: "Иван Иванов",
email: "ivan@example.com",
isAdmin: false,
};
Теперь, если мы случайно забудем указать одно из свойств или используем неверный тип, TypeScript предупредит нас об ошибке.
Использование интерфейсов в тестах
Добавим проверку формы на наличие данных:
cy.get('input[name="name"]').type(user.name);
cy.get('input[name="email"]').type(user.email);
cy.get('button[type="submit"]').click();
cy.get('.user-info')
.should('contain.text', `User: ${user.name}`);
Если что-то изменится в структуре User, мы сразу получим ошибку в местах, где используется этот интерфейс. Это спасает нас от того, чтобы вручную пробегать весь код при изменении структуры данных.
Работа с интерфейсами в тестах
Давайте рассмотрим пример использования интерфейсов для API-ответов. Допустим, у нас есть API-запрос, который возвращает список задач:
interface Task {
id: number;
title: string;
completed: boolean;
}
// Фикстура API-ответа
const mockTasks: Task[] = [
{ id: 1, title: "Купить молоко", completed: false },
{ id: 2, title: "Прочитать книгу", completed: true },
];
Добавляем тест на проверку полученных данных:
cy.intercept('GET', '/api/tasks', mockTasks).as('getTasks');
cy.visit('/tasks');
cy.wait('@getTasks');
cy.get('.task')
.should('have.length', mockTasks.length)
.each(($el, index) =< {
expect($el).to.contain(mockTasks[index].title);
});
Интерфейс Task помогает нам задать структуру данных, которую возвращает сервер. Если структура ответа API изменится, мы сразу узнаем об этом благодаря TypeScript.
Интерфейсы для параметров маршрутов
Представим, что у нас есть динамический маршрут /user/:id, где параметр id — это число. Создадим интерфейс для параметров:
interface RouteParams {
id: number;
}
Теперь используем этот интерфейс для проверки маршрутов:
const params: RouteParams = { id: 123 };
cy.visit(`/user/${params.id}`);
cy.get('.user-profile').should('contain', `User ID: ${params.id}`);
Типизация параметров помогает предотвратить ошибки работы с маршрутами, даже когда они динамические.
Примеры практических сценариев использования типизированных тестов
1. Проверка таблицы с данными
Интерфейс для строки таблицы:
interface TableRow {
id: number;
name: string;
age: number;
}
Проверка:
const mockRows: TableRow[] = [
{ id: 1, name: "Алексей", age: 30 },
{ id: 2, name: "Мария", age: 25 },
];
cy.intercept('GET', '/api/users', mockRows).as('getUsers');
cy.visit('/users');
cy.wait('@getUsers');
cy.get('table tr').should('have.length', mockRows.length + 1); // +1 для заголовка таблицы
cy.get('table tr').each(($row, index) =< {
if (index === 0) return; // Пропускаем заголовок
const rowIndex = index - 1;
cy.wrap($row).should('contain', mockRows[rowIndex].name);
cy.wrap($row).should('contain', mockRows[rowIndex].age.toString());
});
2. Проверка валидации форм
Интерфейс для сообщений об ошибках:
interface ValidationError {
field: string;
message: string;
}
const mockErrors: ValidationError[] = [
{ field: "email", message: "Email обязательно" },
];
Тест:
cy.get('button[type="submit"]').click();
mockErrors.forEach((error) =< {
cy.get(`.error-${error.field}`).should('contain.text', error.message);
});
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ