Профессиональный тест узнаётся не по тому, что он зелёный, а по тому, что остаётся полезным через год - когда код перепишут, команда сменится, а проверка всё так же будет ловить регрессии и не будет ложно срабатывать. Ниже - восемь признаков такого теста; вместе они складываются не в чек-лист для галочек, а в один принцип: тест должен говорить о поведении системы правдиво и устойчиво.
Начинается с имени. Хорошее имя теста - это предложение, где есть условие и наблюдаемый исход: возвращает 409, когда корзина пуста, а не тест checkout. По одному упавшему имени в логе CI должно быть ясно, что сломалось, без открытия файла. И проверять тест обязан поведение, а не приватный вызов: не был вызван метод calcTotal, а итог заказа равен 120. Проверка внутреннего вызова цементирует реализацию - переименуете приватный метод, и тест покраснеет, хотя пользователь ничего не заметил.
Один happy-path ничего не доказывает. Профессиональный набор берёт четыре класса входов: нормальный (обычная корзина с парой позиций), граничный (пустая корзина, ровно один товар, максимум по лимиту), невалидный (отрицательное количество, неизвестный SKU) и отказной (платёжный шлюз вернул ошибку). Регрессии живут именно на границах и в отказах, а не в середине диапазона, который вы проверяете инстинктивно.
Тест не должен зависеть от того, что вы не контролируете. Сеть заменяется моком на границе, часы - фейковыми таймерами и фиксированной датой, чтобы заказ, оформленный в 23:59, не проваливался ночью. Он не должен опираться на порядок запуска и на state, оставленный соседом: beforeEach возвращает мир в исходное, clearMocks стирает историю моков. Тест, зависящий от этих четырёх вещей - сети, часов, порядка, чужого состояния - рано или поздно станет флаки.
Мок ставят на реальной архитектурной границе - там, где ваш код общается с внешним миром: HTTP-клиент, драйвер базы, платёжный SDK. Мокать собственную бизнес-логику бессмысленно - вы проверите заглушку, а не продукт. И осторожно с подменой: если весь риск в том, как модуль корзины реально ходит в базу, unit-мок этой базы уберёт именно то, что стоило проверить. Такой риск проверяют интеграционным тестом на настоящей (пусть тестовой) границе, а не мокают насквозь.
Упав, тест обязан дать понятный diff. toEqual на объекте заказа показывает, какое поле разошлось; toThrow с конкретным типом ошибки - что упало не так. Assert по одному расплывчатому булеву (expect(ok).toBe(true)) в логе не скажет ничего, кроме false, ожидали true. Диагностируемость падения - это не украшение, а половина ценности теста: тест существует, чтобы в момент поломки за секунды показать причину.
Финальная проверка - мысленный эксперимент: если переписать внутренности, не меняя наблюдаемого поведения, тест обязан остаться зелёным. Красный на безопасном рефакторинге значит, что тест прибит к реализации, а не к контракту, и будет мешать развитию кода. Восемь признаков сводятся к одному: тест описывает, что система делает для пользователя, и молчит о том, как именно. Такой тест переживёт свой код - и в этом вся работа. Опирайтесь на официальные документы Jest 30.4 и Testing Library, а не на догадки об API - это и отличает профессиональную проверку от суеверия.