Encodera

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

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

Оглавление

Тестирование с supertest

Автотест — код, который сам открывает страницы и проверяет ответы. Его запускают после каждой правки и за секунды узнают, не сломалось ли что-то. В Node.js встроен модуль node:test для запуска тестов, а пакет supertest отправляет запросы прямо в приложение Express, не занимая порт.

Установка

npm install --save-dev supertest

Флаг --save-dev записывает пакет в зависимости для разработки: на рабочем сервере он не нужен.

Почему app.js отдельно

В уроке о структуре проекта приложение вынесено в src/app.js, а запуск — в src/server.js. Теперь это пригодится: тест импортирует готовое приложение, а supertest сам запускает его на время запроса.

Отдельная база для тестов

Тесты не должны трогать настоящие статьи. Создайте файл .env.test с базой в памяти — она исчезает после завершения тестов:

SESSION_SECRET=test-session-secret
JWT_SECRET=test-jwt-secret
DATABASE_FILE=:memory:

И добавьте скрипт в package.json:

{
  "scripts": {
    "test": "node --env-file=.env.test --test"
  }
}

Команда node --test сама находит файлы, имя которых заканчивается на .test.js.

Первый тест

Создайте файл test/posts.test.js:

// test/posts.test.js
import { test } from 'node:test';
import assert from 'node:assert/strict';
import request from 'supertest';
import app from '../src/app.js';
 
test('список статей отвечает массивом', async () => {
  const response = await request(app).get('/api/posts');
 
  assert.equal(response.status, 200);
  assert.ok(Array.isArray(response.body));
});

request(app).get() отправляет запрос и возвращает ответ: код в status, разобранный JSON в body, HTML — в text. Модуль assert проверяет ожидания.

Запуск

npm test

В терминале появится отчёт: название теста с отметкой ✔, а внизу — число пройденных и упавших тестов. Если тест упал, отчёт покажет, какое значение ожидалось и какое пришло.

Ещё проверки

Тесты удобно писать на каждый важный случай — особенно на ошибки:

// test/posts.test.js
test('несуществующая статья даёт 404', async () => {
  const response = await request(app).get('/api/posts/99999');
  assert.equal(response.status, 404);
});
 
test('создание без токена запрещено', async () => {
  const response = await request(app)
    .post('/api/posts')
    .send({ title: 'Тест', body: 'Текст' });
 
  assert.equal(response.status, 401);
});
 
test('главная страница блога открывается', async () => {
  const response = await request(app).get('/posts');
 
  assert.equal(response.status, 200);
  assert.match(response.text, /Все статьи/);
});

Метод .send() с объектом отправляет тело как JSON и сам выставляет заголовок Content-Type.

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

Не вызывайте app.listen() в src/app.js. Иначе при импорте в тест запустится настоящий сервер: порт может оказаться занят другим процессом, а npm test не завершится после тестов, потому что сервер продолжает ждать запросы. Запуск должен быть только в src/server.js, который тесты не импортируют.

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

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