restaurant4.md 7.1 KB

Тестирование web-приложений (часть 4: функциональное тестирование)

E2E тестирование​

Хотя модульные тесты дают разработчикам определенную степень уверенности, модульные и компонентные тесты ограничены в своих возможностях по обеспечению целостного покрытия приложения при его развертывании в production. E2E-тесты обеспечивают покрытие, пожалуй, самого важного аспекта приложения: того, что происходит, когда пользователи используют ваши приложения.

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

Пишем тест

Где списать пока не нашёл, будем писать по официальной доке

E2e тесты лежат в каталоге ./site/e2e/ (т.к. относятся не к какому-то одному компоненту, а ко всему приложению)

Перед запуском тестов нужно настроить используемые браузеры в настройках ./site/playwright.config.js

Я отключил в секции projects браузеры firefox и webkit (нам для учебных целей хватит и одного)

Первый тест

import { test, expect } from '@playwright/test'

test('На странице есть блюда', async ({ page }) => {
  await page.goto('/')
  await expect(page.locator('.item')).toHaveCount(3)
})
  1. callback-функция асинхронная и в параметрах получаем экземпляр страницы браузера
  2. await page.goto('/') - переходим на главную страницу (у нас она одна, а в многостраничных приложениях урлы могут быть разные)
  3. await expect(page.locator('.item')).toHaveCount(3)
    • метод locator аналог find из vitest - ищет на странице элементы (в нашем случае с классом item)
    • метод toHaveCount проверяет количество найденных элементов

Для закпуска теста выполните команду npm run test:e2e (если Playwright был установлен при создании приложения. Если добавляете тесты в уже существующее приложение, то сначала установите Playwright, а тесты можно запустить командой playwright test)

npm run test:e2e

> site@0.0.0 test:e2e
> playwright test

Running 1 test using 1 worker
  1 passed (1.9s)

To open last HTML report run:

  npx playwright show-report

В консоли не очень наглядно какие тесты выполнялись, в конце написано, что для формирования HTML-отчета нужно запустить команду npx playwright show-report

При запуске команды запускается http-сервер и появляется приглашение открыть страницу

npx playwright show-report

  Serving HTML report at http://localhost:9323. Press Ctrl+C to quit.

Что ещё можно проверить?

Найдем на странице компонент с определённым блюдом и кликнем по кнопке с ценой. Убедимся, что на окне появилась корзина и итог корзины.

test('На странице есть блюдо "Салат" и при клике по нему появляется корзина', async ({ page }) => {
  await page.goto('/')

  const salat = page.getByText('Салат')
  expect(salat).toBeTruthy()

  const salatButton = salat
    .locator('xpath=..')
    .getByRole('button')
  expect(salatButton).toBeTruthy()

  await salatButton.click()
  const cart = page.locator('.cart')
  expect(cart).toBeTruthy()
  expect(cart.getByText('Итого: 100')).toBeTruthy()
})

Разберёмся что тут понаписано:

  • Первым шагом ищем элемент с текстом "Салат":

    const salat = page.getByText('Салат')`
    

    И убеждаемся что он существует

    expect(salat).toBeTruthy()
    
  • Теперь мы должны кликнуть по кнопке найденного компонента, но в предыдущем шаге мы нашли не весь компонент, а только его название

    Напомню структуру компонента:

    <div class="item">
        <img />
        <div>Салат</div>
        <button>
    </div>
    

    Нам, чтобы найти элемент button нужно искать не у элемента salat, а у его родителя:

    const salatButton = salat
        .locator('xpath=..')
        .getByRole('button')
    

    Метод getByRole ищет в родительском элементе кнопку (роль это не тег, а текстовый алиас, со списком ролей можно познакомиться в доке)

  • На последнем шаге кликаем по найденной кнопке (дожидаясь перерисовки)

    await salatButton.click()
    

    И ищем элемент с классом cart и в нём текст с итогом

    const cart = page.locator('.cart')
    expect(cart).toBeTruthy()
    expect(cart.getByText('Итого: 100')).toBeTruthy()
    

Обратная связь

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

<div 
    class="item"
    data-testid="Салат"
>
    <img />
    <div>Салат</div>
    <button>
</div>

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

И теперь поиск делается легло и просто:

const element = page.getByTestId('Салат')