BDD на TypeScript: пишем код, который понимает бизнес

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

BDD на TypeScript: когда код говорит на языке бизнеса

Вы когда-нибудь переводили многостраничный документ с требованиями, чтобы понять, что заказчик имел в виду что-то совсем другое? Знакома ситуация, когда разработчик и аналитик смотрят на одну и ту же задачу, но видят два разных приложения? Если да, то вы уже созрели для BDD (Behaviour-Driven Development) — методологии, которая стирает границу между «хочу» и «сделано».

Сегодня мы поговорим о том, как внедрить BDD на TypeScript. Я покажу, как превратить скучные спецификации в живые, исполняемые сценарии, которые поймут и менеджер, и бэкенд-разработчик. Это не просто про тесты — это про общий язык команды.

Кстати, если вы только начинаете свой путь в TypeScript, рекомендую заглянуть в базу знаний PythonLib — там есть отличные материалы по основам. А мы идём дальше.

Что такое BDD и почему он вам нужен?

Behaviour-Driven Development — это эволюция TDD (Test-Driven Development). Если TDD фокусируется на том, «как» работает код (тесты пишутся до реализации), то BDD отвечает на вопрос «что» система должна делать с точки зрения пользователя.

Главная фишка BDD — Gherkin-синтаксис. Это структура «Дано — Когда — Тогда» (Given — When — Then), которая выглядит так:

Функционал: Авторизация пользователя
  Как зарегистрированный пользователь
  Я хочу войти в систему
  Чтобы получить доступ к личному кабинету

  Сценарий: Успешный вход
    Дано пользователь с email "test@example.com" и паролем "123456"
    Когда пользователь вводит корректные данные
    Тогда система перенаправляет его в личный кабинет

Согласитесь, это понятнее, чем «unit-тест проверяет, что метод login() возвращает true»? Именно в этом сила BDD: тесты на TypeScript становятся документацией, которую может прочесть любой участник команды.

Когда BDD окупается?

  • Сложная бизнес-логика — когда в коде много условий, цепочек действий и сценариев ошибок.
  • Распределённые команды — аналитики в Москве, разработчики в Минске, тестировщики в Новосибе. BDD — их общий язык.
  • Микросервисы — когда нужно чётко описать контракты взаимодействия между сервисами.

Инструменты для BDD на TypeScript

Для внедрения BDD в TypeScript у нас есть два главных инструмента: Cucumber.js (или его вариации) и Jest с плагинами. Давайте разберём оба подхода.

Cucumber.js + TypeScript: классика жанра

Cucumber — это золотой стандарт BDD. Он читает Gherkin-файлы (обычно с расширением .feature) и запускает код-степы, которые вы пишете на TypeScript.

Установка:

npm install --save-dev @cucumber/cucumber typescript ts-node
npm install --save-dev @types/node

Создаём файл features/login.feature:

Функционал: Вход в систему
  Как пользователь
  Я хочу авторизоваться
  Чтобы получить доступ к функциям

  Сценарий: Успешный вход с корректным email и паролем
    Дано я открываю страницу входа
    Когда я ввожу email "admin@test.com"
    И я ввожу пароль "secret"
    И я нажимаю кнопку "Войти"
    Тогда я вижу приветственное сообщение "Добро пожаловать, Admin!"

Теперь пишем степы (шаги) на TypeScript. Создаём features/step_definitions/login.steps.ts:

import { Given, When, Then } from '@cucumber/cucumber';
import { expect } from 'chai';

// Простая имитация состояния приложения
const appState = {
  currentPage: '',
  loggedInUser: ''
};

Given('я открываю страницу входа', function () {
  appState.currentPage = 'login';
  appState.loggedInUser = '';
});

When('я ввожу email {string}', function (email: string) {
  // Здесь могла бы быть работа с реальным UI, но для примера — просто сохраняем
  console.log(`Введён email: ${email}`);
});

When('я ввожу пароль {string}', function (password: string) {
  console.log(`Введён пароль: ${password}`);
});

When('я нажимаю кнопку "Войти"', async function () {
  // Симуляция асинхронного запроса к серверу
  appState.loggedInUser = 'Admin';
  appState.currentPage = 'dashboard';
});

Then('я вижу приветственное сообщение {string}', function (message: string) {
  expect(`Добро пожаловать, ${appState.loggedInUser}!`).to.equal(message);
});

Запускаем:

npx cucumber-js

Cucumber сам найдёт все .feature файлы и выполнит степы. Результат — зелёный отчёт, который показывает, какие сценарии прошли. Это и есть разработка через поведение в действии.

Jest + Jest-Cucumber: лёгкий старт

Если вы уже используете Jest для тестирования, подключать Cucumber целиком может быть избыточно. Для таких случаев есть jest-cucumber — библиотека, которая позволяет писать BDD-тесты прямо в Jest.

Установка:

npm install --save-dev jest-cucumber @types/jest

Создаём файл features/checkout.feature:

Функционал: Оформление заказа
  Сценарий: Успешное оформление с купоном на скидку
    Дано в корзине товары на сумму 5000 рублей
    И у меня есть купон "SALE20" на 20% скидку
    Когда я применяю купон
    Тогда итоговая сумма должна быть 4000 рублей

Теперь тест-файл tests/checkout.test.ts:

import { defineFeature, loadFeature } from 'jest-cucumber';

const feature = loadFeature('./features/checkout.feature');

defineFeature(feature, test => {
  let cartTotal: number;
  let couponCode: string;
  let finalTotal: number;

  test('Успешное оформление с купоном на скидку', ({ given, when, then }) => {
    given(/^в корзине товары на сумму (\d+) рублей$/, (total: string) => {
      cartTotal = parseInt(total, 10); // 5000
    });

    given(/^у меня есть купон "(\w+)" на (\d+)% скидку$/, (code: string, percent: string) => {
      couponCode = code;
      // Сохраняем скидку для проверки
      this.discount = parseInt(percent, 10) / 100; // 0.2
    });

    when('я применяю купон', () => {
      finalTotal = cartTotal * (1 - this.discount); // 4000
    });

    then(/^итоговая сумма должна быть (\d                

Блоги

Рекомендаций по книгам