← Назад к вопросам

Нужны ли тесты на Frontend

1.3 Junior🔥 201 комментариев
#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Нужны ли тесты на Frontend

Да, тесты на Frontend необходимы. Это не опционально, а критически важно для поддержки качества, безопасности и надёжности приложения. Фронтенд — это не просто красивый интерфейс, это бизнес-логика, которая работает у пользователя прямо в браузере.

Почему тесты важны для Frontend

1. Предотвращение регрессий

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

function FilterList({ items, onFilter }) {
  const [filter, setFilter] = useState("");
  const filtered = items.filter(item =>
    item.name.toLowerCase().includes(filter.toLowerCase())
  );
  return (
    <div>
      <input
        value={filter}
        onChange={(e) => setFilter(e.target.value)}
        placeholder="Поиск..."
      />
      <ul>
        {filtered.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}

2. Документация кода

Тесты показывают, как использовать компонент:

describe("Button Component", () => {
  it("должен вызвать onClick при клике", () => {
    const handleClick = jest.fn();
    const { getByRole } = render(
      <Button onClick={handleClick}>Кнопка</Button>
    );
    fireEvent.click(getByRole("button"));
    expect(handleClick).toHaveBeenCalled();
  });
});

3. Безопасность

Тесты ловят уязвимости, например XSS атаки:

it("должен санитизировать HTML", () => {
  const { container } = render(
    <Comment content="<img src=x>" />
  );
  expect(container.innerHTML).not.toContain("onerror");
});

Типы тестов на Frontend

Unit тесты

Тестируют отдельные компоненты и функции:

describe("formatDate", () => {
  it("должен форматировать дату правильно", () => {
    const date = new Date("2024-01-15");
    expect(formatDate(date)).toBe("15 Jan 2024");
  });
});

Integration тесты

Тестируют несколько компонентов вместе:

describe("User Registration", () => {
  it("должен зарегистрировать пользователя", async () => {
    const { getByPlaceholderText, getByRole } = render(<SignupForm />);
    fireEvent.change(getByPlaceholderText("Email"), {
      target: { value: "user@example.com" }
    });
    fireEvent.click(getByRole("button", { name: /Sign up/i }));
    await waitFor(() => {
      expect(getByText(/Welcome!/)).toBeInTheDocument();
    });
  });
});

E2E тесты

Тестируют весь путь пользователя с Playwright:

test("должен завершить покупку", async ({ page }) => {
  await page.goto("https://shop.example.com");
  await page.click("text=Add to Cart");
  await page.click("text=Cart");
  expect(page).toHaveURL(/\/cart/);
  await page.click("text=Checkout");
  await page.fill('input[name="email"]', "user@example.com");
  await page.click("text=Place Order");
  await expect(page.locator("text=Order confirmed")).toBeVisible();
});

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

1. Логика компонентов

describe("ShoppingCart", () => {
  it("должен вычислить корректную сумму", () => {
    const items = [
      { id: 1, price: 100, quantity: 2 },
      { id: 2, price: 50, quantity: 1 }
    ];
    const { getByText } = render(<ShoppingCart items={items} />);
    expect(getByText("Total: $250")).toBeInTheDocument();
  });
});

2. Обработка ошибок

it("должен отобразить ошибку при неудачной загрузке", async () => {
  global.fetch = jest.fn(() =>
    Promise.reject(new Error("Network error"))
  );
  const { getByText } = render(<DataFetcher />);
  await waitFor(() => {
    expect(getByText(/Error loading data/)).toBeInTheDocument();
  });
});

3. Интерактивность и события

it("должен открыть модальное окно при клике", () => {
  const { getByRole, getByText } = render(<Modal />);
  fireEvent.click(getByRole("button", { name: /Open/ }));
  expect(getByText(/Modal content/)).toBeVisible();
});

4. API интеграция

Используй mock для API запросов:

it("должен загрузить и отобразить данные", async () => {
  global.fetch = jest.fn(() =>
    Promise.resolve({
      ok: true,
      json: () => Promise.resolve({ users: [{ id: 1, name: "John" }] })
    })
  );
  const { getByText } = render(<UserList />);
  await waitFor(() => {
    expect(getByText("John")).toBeInTheDocument();
  });
});

Инструменты и фреймворки

Jest — Unit и integration тесты, мокирование, утверждения Vitest — Быстрые unit тесты, совместимо с Vite React Testing Library — Тестирование компонентов как пользователь Playwright — E2E тесты, автоматизация браузера Cypress — E2E тесты с красивым интерфейсом MSW — Мокирование API запросов

Практические советы

1. Не тестируй детали реализации

// Хорошо: тестируем поведение
it("должен переключить видимость при клике", () => {
  const { getByRole, getByText } = render(<Toggle />);
  fireEvent.click(getByRole("button"));
  expect(getByText("Hidden content")).toBeVisible();
});

2. Тестируй как пользователь

// Хорошо: поиск как пользователь видит
const emailInput = getByPlaceholderText("Enter email");

3. Пиши быстрые тесты

Тесты должны выполняться за миллисекунды, не делай реальные API запросы.

Метрики качества

Рекомендуемое покрытие:

  • Минимум 70% для лучших практик
  • 80-90% для production приложений
  • 90%+ для критичных компонентов

Заключение

Тесты на Frontend — это не балласт, это инвестиция в качество. Хорошо протестированный код:

  • Ломается реже
  • Легче рефакторить
  • Проще поддерживать
  • Вызывает доверие пользователей