Тестирование форм логина

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


Настройка среды

Перед написанием тестов необходимо убедиться, что Cypress установлен и корректно настроен. Конфигурация обычно включает:

npm install cypress --save-dev

После установки создается структура проекта:

cypress/
  ├─ e2e/
  ├─ fixtures/
  ├─ support/
cypress.config.js

В файле конфигурации cypress.config.js можно определить базовый URL приложения:

import { defineConfig } from 'cypress'

export default defineConfig({
  e2e: {
    baseUrl: 'https://example.com',
    viewportWidth: 1280,
    viewportHeight: 720,
  },
})

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


Селекторы и взаимодействие с элементами

Ключевым моментом является выбор правильных селекторов. Cypress рекомендует использовать data-атрибуты (data-cy, data-testid) вместо классов или id, которые могут меняться.

Пример HTML формы логина:

<form data-cy="login-form">
  <input type="text" data-cy="username-input" />
  <input type="password" data-cy="password-input" />
  <button type="submit" data-cy="login-button">Войти</button>
  <p data-cy="error-message" class="error"></p>
</form>

В Cypress взаимодействие выполняется через цепочку команд:

cy.get('[data-cy=username-input]').type('admin')
cy.get('[data-cy=password-input]').type('password123')
cy.get('[data-cy=login-button]').click()

Проверка успешного входа

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

cy.url().should('include', '/dashboard')
cy.get('[data-cy=welcome-message]').should('contain', 'Добро пожаловать, admin')

Использование should позволяет выполнять ассерты с автоматическим ожиданием элемента до появления на странице.


Обработка ошибок и валидация

Формы логина часто содержат встроенную проверку ошибок. Необходимо тестировать:

  • Пустые поля
  • Неверный логин или пароль
  • Ошибки сервера

Пример теста на пустые поля:

cy.get('[data-cy=login-button]').click()
cy.get('[data-cy=error-message]').should('contain', 'Пожалуйста, заполните все поля')

Тест на неверный пароль:

cy.get('[data-cy=username-input]').type('admin')
cy.get('[data-cy=password-input]').type('wrongpassword')
cy.get('[data-cy=login-button]').click()
cy.get('[data-cy=error-message]').should('contain', 'Неверное имя пользователя или пароль')

Cypress автоматически повторяет проверки, ожидая появления элементов, что снижает вероятность ложных срабатываний.


Использование фикстур для тестовых данных

Фикстуры позволяют хранить тестовые данные отдельно и упрощают поддерживаемость тестов:

cypress/fixtures/users.json

{
  "validUser": {
    "username": "admin",
    "password": "password123"
  },
  "invalidUser": {
    "username": "admin",
    "password": "wrongpassword"
  }
}

Пример использования в тесте:

cy.fixture('users').then((users) => {
  cy.get('[data-cy=username-input]').type(users.validUser.username)
  cy.get('[data-cy=password-input]').type(users.validUser.password)
  cy.get('[data-cy=login-button]').click()
})

Тестирование через API

Иногда проверка формы через UI может быть медленной. Cypress позволяет напрямую обращаться к API:

cy.request('POST', '/api/login', {
  username: 'admin',
  password: 'password123'
}).then((response) => {
  expect(response.status).to.eq(200)
  expect(response.body).to.have.property('token')
})

Комбинирование UI и API-тестирования повышает покрытие и сокращает время выполнения тестов.


Параметризация и повторное использование

Для тестирования различных сценариев удобно использовать массивы данных и forEach:

const users = [
  { username: 'admin', password: 'password123', success: true },
  { username: 'admin', password: 'wrong', success: false },
  { username: '', password: '', success: false },
]

users.forEach((user) => {
  it(`логин для ${user.username || 'пустого пользователя'}`, () => {
    cy.get('[data-cy=username-input]').clear().type(user.username)
    cy.get('[data-cy=password-input]').clear().type(user.password)
    cy.get('[data-cy=login-button]').click()

    if (user.success) {
      cy.url().should('include', '/dashboard')
    } else {
      cy.get('[data-cy=error-message]').should('be.visible')
    }
  })
})

Такой подход минимизирует дублирование кода и позволяет быстро добавлять новые сценарии.


Асинхронные действия и ожидания

Формы логина могут включать асинхронные проверки, например, запрос к серверу на валидность токена. Cypress автоматически обрабатывает ожидания, но при необходимости можно явно использовать cy.wait:

cy.intercept('POST', '/api/login').as('loginRequest')
cy.get('[data-cy=login-button]').click()
cy.wait('@loginRequest').its('response.statusCode').should('eq', 200)

intercept позволяет контролировать сетевые запросы и проверять статус ответа.


Рекомендации по надежности тестов

  • Использовать уникальные data-атрибуты для селекторов.
  • Не применять cy.wait с фиксированным таймаутом без необходимости.
  • Разделять тесты на маленькие, независимые сценарии.
  • Сохранять тестовые данные во внешних фикстурах для повторного использования.
  • Комбинировать UI и API-тестирование для ускорения проверки.

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