Jasmine — это фреймворк для тестирования JavaScript, который поддерживает как синхронные, так и асинхронные сценарии. Асинхронное тестирование особенно важно при работе с сетевыми запросами, таймерами и другими операциями, выполняющимися вне основного потока выполнения. Callback-based подход — один из базовых способов обработки асинхронности.
doneВ Jasmine для обработки асинхронных операций применяется функция
done. Она передаётся как аргумент в тело теста и вызывается
по завершении асинхронной операции. Основные правила её
использования:
it('асинхронный тест с callback', function(done) {
setTimeout(function() {
expect(true).toBe(true);
done();
}, 100);
});
Ключевые моменты:
done должна быть вызвана единожды в
каждом тесте.done не вызывается, тест завершится с ошибкой
таймаута.done.fail() для явного указания на
провал теста при возникновении ошибки.it('тест с обработкой ошибки', function(done) {
asyncOperation(function(err, result) {
if (err) {
done.fail(err);
return;
}
expect(result).toBe(42);
done();
});
});
По умолчанию Jasmine ждёт завершения асинхронного теста 5 секунд.
Этот интервал можно изменить с помощью
jasmine.DEFAULT_TIMEOUT_INTERVAL:
describe('асинхронные операции', function() {
beforeAll(function() {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // 10 секунд
});
it('длинная операция', function(done) {
setTimeout(function() {
expect(true).toBe(true);
done();
}, 8000);
});
});
Важно учитывать, что чрезмерное увеличение таймаута может замедлить тестирование всего проекта.
beforeEach и afterEachCallback-based подход применяется не только к отдельным тестам, но и
к хукам Jasmine, таким как beforeEach и
afterEach:
beforeEach(function(done) {
initializeDatabase(function() {
done();
});
});
afterEach(function(done) {
cleanupDatabase(function() {
done();
});
});
Это позволяет подготовить среду тестирования и очистить её после выполнения каждого сценария, не блокируя поток выполнения.
При работе с несколькими асинхронными операциями подряд важно
корректно управлять вызовом done. Ошибки часто возникают
из-за преждевременного вызова done или его отсутствия:
it('несколько последовательных асинхронных вызовов', function(done) {
firstAsync(function(result1) {
expect(result1).toBe(true);
secondAsync(function(result2) {
expect(result2).toBe(42);
done();
});
});
});
При необходимости параллельного выполнения нескольких операций можно использовать счётчик завершения:
it('параллельные операции', function(done) {
let completed = 0;
function checkDone() {
completed += 1;
if (completed === 2) done();
}
asyncOp1(checkDone);
asyncOp2(checkDone);
});
Ошибки в асинхронных вызовах нельзя поймать обычным
try-catch. Вместо этого используется
done.fail():
it('обработка ошибок', function(done) {
asyncOperation(function(err, result) {
if (err) {
done.fail('Произошла ошибка: ' + err.message);
return;
}
expect(result).toBeTruthy();
done();
});
});
Этот подход обеспечивает корректное отображение ошибок в отчётах Jasmine и предотвращает зависание теста.
Promise и
async/await без адаптации.Callback-based подход остаётся актуальным для понимания основ
асинхронного тестирования и совместимости с legacy-кодом, однако для
более сложных сценариев рекомендуется изучать промисы и
async/await, которые делают код более линейным и
читаемым.