Инструменты: Jest, Vitest, Supertest

При разработке серверных приложений на Iron ключевым этапом становится проверка поведения маршрутов, контроллеров и бизнес-логики. В экосистеме JavaScript основными инструментами для этого выступают Jest, Vitest и Supertest. Их совместное использование позволяет покрыть тестами как внутреннюю логику приложения, так и HTTP-слой без необходимости поднимать полноценный сервер в каждом тесте.

Организация тестовой среды

Типичная структура проекта на Iron с тестами выглядит так:

  • src/ — исходный код приложения
  • routes/ — маршруты и их обработчики
  • controllers/ — бизнес-логика
  • app.js — точка сборки приложения
  • tests/ — тестовые сценарии

Важно отделять создание приложения от запуска сервера. Это позволяет использовать экземпляр приложения в тестах без открытия порта.

// app.js
import Iron from "iron";
import routes from "./routes/index.js";

const app = new Iron();

app.use(routes);

export default app;
// server.js
import app from "./app.js";

app.listen(3000);

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


Jest как основной тестовый раннер

Jest используется для модульного тестирования бизнес-логики и изолированных компонентов Iron-приложения.

Проверка контроллеров

Контроллеры в Iron обычно представляют собой функции, принимающие контекст запроса.

// controllers/userController.js
export const getUser = async (ctx) => {
  const user = await ctx.services.user.findById(ctx.params.id);
  ctx.body = user;
};

Тестирование такой функции с Jest не требует HTTP-слоя:

import { getUser } from "../controllers/userController.js";

test("возвращает пользователя по id", async () => {
  const ctx = {
    params: { id: 1 },
    services: {
      user: {
        findById: async (id) => ({ id, name: "Alex" })
      }
    },
    body: null
  };

  await getUser(ctx);

  expect(ctx.body).toEqual({ id: 1, name: "Alex" });
});

Jest обеспечивает:

  • мокирование зависимостей
  • контроль асинхронных функций
  • сравнение структур данных

Vitest для быстрого цикла разработки

Vitest часто используется как альтернатива Jest в проектах, где важна скорость выполнения тестов и нативная работа с Vite-окружением.

В Iron-проектах Vitest удобен для:

  • быстрых unit-тестов
  • тестирования утилит
  • проверки чистых функций

Пример теста бизнес-логики

import { describe, it, expect } from "vitest";
import { calculateDiscount } from "../services/discount.js";

describe("calculateDiscount", () => {
  it("применяет скидку корректно", () => {
    const result = calculateDiscount(100, 20);
    expect(result).toBe(80);
  });
});

Vitest особенно эффективен в ситуациях, где требуется постоянный цикл «изменение → проверка → исправление», так как поддерживает быстрый HMR-подобный режим выполнения тестов.


Supertest для HTTP-тестирования Iron API

Supertest используется для проверки HTTP-слоя приложения без необходимости запускать сервер на реальном порту. Он работает напрямую с экземпляром приложения.

Тестирование маршрутов

import request from "supertest";
import app from "../app.js";

describe("GET /users/:id", () => {
  it("возвращает пользователя", async () => {
    const response = await request(app.callback())
      .get("/users/1")
      .expect(200);

    expect(response.body).toEqual({
      id: 1,
      name: "Alex"
    });
  });
});

Supertest позволяет проверять:

  • HTTP-статусы
  • заголовки ответа
  • тело ответа
  • параметры запроса

Интеграция Jest и Supertest

На практике Jest и Supertest используются вместе: Jest отвечает за запуск тестов и ассерты, Supertest — за имитацию HTTP-запросов.

import request from "supertest";
import app from "../app.js";

test("POST /users создаёт пользователя", async () => {
  const response = await request(app.callback())
    .post("/users")
    .send({ name: "Alex" })
    .expect(201);

  expect(response.body).toHaveProperty("id");
  expect(response.body.name).toBe("Alex");
});

Такая комбинация позволяет тестировать весь стек:

  • маршрутизацию Iron
  • middleware
  • контроллеры
  • сервисы

Использование Vitest и Supertest вместе

Vitest может полностью заменить Jest, сохранив совместимость с Supertest.

import { describe, it, expect } from "vitest";
import request from "supertest";
import app from "../app.js";

describe("API users", () => {
  it("создаёт и возвращает пользователя", async () => {
    const res = await request(app.callback())
      .post("/users")
      .send({ name: "Anna" });

    expect(res.status).toBe(201);
    expect(res.body.name).toBe("Anna");
  });
});

Тестирование middleware Iron

Middleware в Iron часто используется для авторизации, логирования и обработки ошибок.

export const authMiddleware = async (ctx, next) => {
  if (!ctx.headers.authorization) {
    ctx.status = 401;
    return;
  }

  await next();
};

Тестирование без HTTP-слоя:

test("блокирует запрос без токена", async () => {
  const ctx = { headers: {}, status: 0 };

  await authMiddleware(ctx, async () => {});

  expect(ctx.status).toBe(401);
});

Моки и изоляция зависимостей

Jest и Vitest предоставляют механизмы подмены модулей, что особенно важно при тестировании сервисов Iron.

jest.mock("../services/db.js", () => ({
  findUser: async () => ({ id: 1, name: "Mock" })
}));

или в Vitest:

vi.mock("../services/db.js", () => ({
  findUser: async () => ({ id: 1, name: "Mock" })
}));

Это позволяет:

  • изолировать тестируемый код
  • исключить влияние базы данных
  • ускорить выполнение тестов

Стратегия тестирования Iron-приложений

Практическая схема обычно делится на уровни:

  • Unit-тесты (Jest / Vitest) — чистая логика, сервисы, утилиты
  • Integration-тесты (Supertest) — маршруты и middleware
  • E2E-проверки — полный цикл запроса через приложение

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


Асинхронность и обработка ошибок

Iron активно использует async/await, поэтому тестовые фреймворки должны корректно обрабатывать промисы.

test("обрабатывает ошибку сервиса", async () => {
  const ctx = {
    services: {
      user: {
        findById: async () => {
          throw new Error("DB error");
        }
      }
    },
    params: { id: 1 }
  };

  await expect(getUser(ctx)).rejects.toThrow("DB error");
});

Jest и Vitest одинаково эффективно работают с такими сценариями.


Проверка middleware цепочек через Supertest

Middleware в Iron часто образуют цепочку обработки запроса. Supertest позволяет проверить её поведение целиком.

app.use(authMiddleware);
app.use(loggerMiddleware);
app.use(router);

Тест:

await request(app.callback())
  .get("/secure-route")
  .set("Authorization", "Bearer token")
  .expect(200);

Это подтверждает корректную работу всей цепочки обработки запроса.


Изоляция тестового окружения

При работе с Iron важно разделять:

  • тестовую базу данных
  • конфигурацию окружения
  • внешние API

Jest и Vitest позволяют задавать отдельные .env.test конфигурации и запускать тесты в изолированном режиме.


Параллельный запуск тестов

Vitest и Jest поддерживают параллельное выполнение тестов, что особенно важно для больших Iron-приложений с множеством маршрутов.

Это снижает время прогонки тестового набора и позволяет быстрее выявлять регрессии в API.