Как стать автором
Обновить

Комментарии 17

Это безумие. И код, и тесты.

А можно поконкретнее про клиническу картину безумства? Примеру максимально упрощены, чтобы отразить суть проблемы.
При использовании такого подхода не забывайте восстанавливать все "как было" через вызов clock.restore(), иначе рискуете испортить тесты соседа.

Тест должен максимально локализовывать ошибку. А при таком подходе ошибку будут искать там, где её нет.

Это суть Sinon fake timers — они подменяют стандартные реализации setTimeout и setInterval, но взамен дают контроль за их исполнением. С другой стороны в тестах должно соблюдаться правило: испортил глобальный объект для теста — верни на место. Иначе последствия будут непредсказуемы.

Какой вариант вы предлагаете? Как правильно локализовать ошибку в указанном примере?
используйте jest, он предоставляет манипуляции с таймерами
Посмотрел на Jest. Сразу бросаются параллельный запуск тестов и поддержка coverage — это интересно.

По сути обсуждения:
— Работа а асинхронным кодом построена по той же схеме, что и в Мокка: либо через callback, либо через Promise, тут отличий нет.
— Работа с setTimeout реализована аналогично четвертому рассмотренному в статье решению (Sinon fake timers). Плюс в примерах рассматривается ситуация посложнее — с вложенными друг в друга вызовами setTimeout. И это приятно: чувствуется, что люди разгребали похожие проблемы.

В целом — заслуживающий внимания тестовый фрейморк, многие вещи доступны из «коробки», в то время как в нашем случае мы используем сторонние решения. Плюс в доке освещены интересные паттерны тестов.

Спасибо за наводку, мы к Мокке пришли давно, может уже стоить рассмотреть альтернативы.
На счет вложенности setTimeout это да, придется делать что-то свое. Хорошо, что кейс не такой распространенный.
В целом, Jest уже 4 года, видимо отстали от общих тенденций, что часто бывает в мире фронтенда.

Когда уже Вы перестанете переводить термины?! Мокка, промизы…
Остановитесь, пока не поздно.

Простите. Но с другой стороны язык впитывает иностранные термины, и те же «браузер» или «фрейморк» уже не кажутся чем-то инородным. Найти границу бывает сложно, иногда в подобных текстах предложения превращаются в череду русских и английских слов, что тоже не очень. Но я учту, спасибо.
Насколько бредовой является идея абстрагировать тесты от любой асинхронщины с помощью zone.js? Может у кого-нибудь есть опыт интеграции, за пределами Angular.
В принципе идея получить больше контроля над асинхронным flow заманчива. Мы даже сделали что-то подобное для получения бОльшего количества информации в серверных логах: наш фреймворк изоморфен и работает в т.ч. на сервере, собранным в виде надстройки над V8. Там развитая система логирования, в коллстеках можно отслеживать контекст вызова некоторых других асинхронных операций.

Насколько я понял zone.js не стандартизован?
Zone.js несколько лет используется в Angular, в том числе и в тестах. Например, хелпер fakeAsync angular.io/api/core/testing/fakeAsync даёт возможность выполнить тест практически любого асинхронного кода синхронно.

Про стандартизацию мне ни чего не известно. А зачем?

Зачем вообще setTimeout в UI? Разве что setTimeout 0 для разрыва контекста, и то это на самом деле нужно очень редко.

Реальность жизни в асинхронном мире, использоваться может случайно либо намеренно.

Часто это последствия каких-то оптимизаций или используемых подходов.

Но не менее часто вставка setTimeout является костылем ad hoc, но реальность такова, что другого варианта у разработчика перед дедлайном просто нет. А потом оказывается, что у него из-за изменения кода еще и юнит-тест упал, надо исправлять. Это все плохо, в итоге копится технический долг, который надо как-то отдавать… но это уже тема отдельного разговора. Тут же я рассматриваю ситацию, как с этим жить.
Но если это ad hoc то вы получается делаете фреймворк для костылей.
Не поймите неправильно, технически подход к проблеме верный, но я думаю что если пишутся setTimeout то это систематическая ошибка и должна решаться обучением/написанием фреймворка убирающего потребность в setTimeout.
Тут ниже про анимации вспоминали, если приложить усилий то можно условно надёжно(целевым был только хром, в лисе тоже работает остальное не тестировалось) не только систематизировать подход к анимациям, но и за счёт обработки событий анимаций полностью избавиться от таймаутов как в коде приложения, так и в коде тестов. Мне кажется это более правильный подход, что конечно не отменяет поддержку легаси и решение проблем «уже есть 100500 setTimeout везде»
Да, одна из причин в нашем случае это именно legacy: у нас большой объем кода где-то 15-летней выдержки. В свое время решили зафиксировать его поведение юнит-тестами, чтобы разработчики, исправляя баг, не вносили новые.
Например таймеры часто используются в анимациях, обработке последовательностей событий и тому подобных вещах, которые завязаны на время.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий