Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Основы тестирования

Тест — код, который запускает часть приложения и проверяет результат. В режиме фреймворка удобно, что loader и action — обычные функции: им можно передать запрос и посмотреть, что они вернули. Компоненты, которым нужен роутер, проверяют с помощью createRoutesStub — маленького тестового роутера.

Установка

npm install -D vitest jsdom @testing-library/react

Vitest — тестовый фреймворк для проектов на Vite, jsdom имитирует браузер, Testing Library отрисовывает компоненты. Добавьте в package.json скрипт "test": "vitest".

Плагин reactRouter() из vite.config.ts в тестах не нужен, поэтому создайте отдельный файл настроек:

// vitest.config.ts
import { defineConfig } from "vitest/config";
 
export default defineConfig({
  test: { environment: "jsdom" },
});

Тест загрузчика

Тесты кладут рядом с кодом в файлы *.test.ts. Проверим, что загрузчик статьи выбрасывает 404 для несуществующего id:

// app/routes/post.test.ts
import { describe, expect, it } from "vitest";
import { loader } from "./post";
import type { Route } from "./+types/post";
 
describe("loader статьи", () => {
  it("возвращает 404 для несуществующей статьи", async () => {
    const args = {
      request: new Request("http://localhost/posts/999"),
      params: { postId: "999" },
      context: {},
    } as Route.LoaderArgs;
 
    const error = await loader(args).catch((e: unknown) => e);
    expect(error).toBeInstanceOf(Response);
    expect((error as Response).status).toBe(404);
  });
});

Команда npm test запустит тест, и Vitest напишет в терминале, что он прошёл. Приведение as Route.LoaderArgs нужно потому, что у настоящих аргументов есть ещё служебные поля.

Тест компонента

createRoutesStub создаёт роутер из описаний маршрутов. Загрузчик в нём можно заменить заглушкой:

// app/routes/home.test.tsx
import { render, screen } from "@testing-library/react";
import { createRoutesStub } from "react-router";
import { expect, it } from "vitest";
import Home from "./home";
 
it("показывает список статей", async () => {
  const Stub = createRoutesStub([
    {
      path: "/",
      Component: Home,
      loader: () => ({ posts: [{ id: 1, title: "Привет, мир", body: "" }] }),
    },
  ]);
 
  render(<Stub initialEntries={["/"]} />);
 
  expect(await screen.findByText("Привет, мир")).toBeTruthy();
});

Тест отрисует главную с одной статьёй и найдёт её заголовок. findByText ждёт, пока загрузчик-заглушка отработает. Если компонент ругается на тип пропсов, оберните его: Component: () => ... с хуком useLoaderData.

Что тестировать

ЧтоЧем
Проверку формы в actionVitest, вызов функции
Перенаправление гостя в loaderVitest, проверка выброшенного ответа
Вывод данных и ошибок в компонентеcreateRoutesStub и Testing Library
Весь путь пользователя в браузереСквозные тесты, например Playwright

Частая ошибка

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

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.