При разработке серверных приложений на 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 используется для модульного тестирования бизнес-логики и изолированных компонентов 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 часто используется как альтернатива Jest в проектах, где важна скорость выполнения тестов и нативная работа с Vite-окружением.
В Iron-проектах Vitest удобен для:
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-слоя приложения без необходимости запускать сервер на реальном порту. Он работает напрямую с экземпляром приложения.
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 позволяет проверять:
На практике 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");
});
Такая комбинация позволяет тестировать весь стек:
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 часто используется для авторизации, логирования и обработки ошибок.
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 активно использует 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 в 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 важно разделять:
Jest и Vitest позволяют задавать отдельные .env.test
конфигурации и запускать тесты в изолированном режиме.
Vitest и Jest поддерживают параллельное выполнение тестов, что особенно важно для больших Iron-приложений с множеством маршрутов.
Это снижает время прогонки тестового набора и позволяет быстрее выявлять регрессии в API.