Средство запуска тестов
Исходный код: lib/test.js
Модуль node:test упрощает создание тестов JavaScript. Чтобы получить к нему доступ:
Модули JavaScript
import test from 'node:test';
CommonJS
const test = require('node:test');Этот модуль доступен только в схеме node:. Следующий код не будет работать:
Модули JavaScript
import test from 'test';
CommonJS
const test = require('test');Тесты, созданные с помощью модуля test, состоят из одной функции, которая обрабатывается одним из трех способов:
- Синхронная функция, которая считается не пройденной, если выбрасывает исключение, и пройденной в противном случае.
- Функция, возвращающая
Promise, которая считается не пройденной, еслиPromiseотклоняется, и пройденной, еслиPromiseвыполняется успешно. - Функция, получающая функцию обратного вызова. Если обратный вызов получает любое истинное значение в качестве первого аргумента, тест считается не пройденным. Если в качестве первого аргумента обратному вызову передано ложное значение, тест считается пройденным. Если тестовая функция получает функцию обратного вызова и также возвращает
Promise, тест не будет пройден.
В следующем примере показано, как писать тесты с помощью модуля test.
test('synchronous passing test', (t) => {
// This test passes because it does not throw an exception.
assert.strictEqual(1, 1);
});
test('synchronous failing test', (t) => {
// This test fails because it throws an exception.
assert.strictEqual(1, 2);
});
test('asynchronous passing test', async (t) => {
// This test passes because the Promise returned by the async
// function is settled and not rejected.
assert.strictEqual(1, 1);
});
test('asynchronous failing test', async (t) => {
// This test fails because the Promise returned by the async
// function is rejected.
assert.strictEqual(1, 2);
});
test('failing test using Promises', (t) => {
// Promises can be used directly as well.
return new Promise((resolve, reject) => {
setImmediate(() => {
reject(new Error('this will cause the test to fail'));
});
});
});
test('callback passing test', (t, done) => {
// done() is the callback function. When the setImmediate() runs, it invokes
// done() with no arguments.
setImmediate(done);
});
test('callback failing test', (t, done) => {
// When the setImmediate() runs, done() is invoked with an Error object and
// the test fails.
setImmediate(() => {
done(new Error('callback failure'));
});
}); copy Если какие-либо тесты не пройдены, код завершения процесса устанавливается в 1.
Вложенные тесты
Метод test() контекста теста позволяет создавать вложенные тесты. Он позволяет структурировать тесты иерархически, создавая вложенные тесты внутри более крупного теста. Этот метод работает так же, как функция верхнего уровня test(). В следующем примере показано создание теста верхнего уровня с двумя вложенными тестами.
test('top level test', async (t) => {
await t.test('subtest 1', (t) => {
assert.strictEqual(1, 1);
});
await t.test('subtest 2', (t) => {
assert.strictEqual(2, 2);
});
}); copy Примечание: хуки
beforeEachиafterEachвыполняются между запусками каждого вложенного теста.
В этом примере используется await, чтобы убедиться, что оба вложенных теста завершились. Это необходимо, поскольку тесты не ожидают завершения своих вложенных тестов, в отличие от тестов, созданных в наборах тестов. Все вложенные тесты, которые еще выполняются после завершения родительского теста, отменяются и считаются не пройденными. Если вложенный тест не пройден, родительский тест также считается не пройденным.
Пропуск тестов
Отдельные тесты можно пропустить, передав тесту параметр skip или вызвав метод skip() контекста теста, как показано в следующем примере.
// The skip option is used, but no message is provided.
test('skip option', { skip: true }, (t) => {
// This code is never executed.
});
// The skip option is used, and a message is provided.
test('skip option with message', { skip: 'this is skipped' }, (t) => {
// This code is never executed.
});
test('skip() method', (t) => {
// Make sure to return here as well if the test contains additional logic.
t.skip();
});
test('skip() method with message', (t) => {
// Make sure to return here as well if the test contains additional logic.
t.skip('this is skipped');
}); copy Тесты TODO
Отдельные тесты можно пометить как нестабильные или незавершенные, передав тесту параметр todo или вызвав метод todo() контекста теста, как показано в следующем примере. Такие тесты обозначают ожидающую реализации функциональность или ошибку, которую необходимо исправить. Тесты TODO выполняются, но не считаются не пройденными и поэтому не влияют на код завершения процесса. Если тест одновременно помечен как TODO и пропущенный, параметр TODO игнорируется.
// The todo option is used, but no message is provided.
test('todo option', { todo: true }, (t) => {
// This code is executed, but not treated as a failure.
throw new Error('this does not fail the test');
});
// The todo option is used, and a message is provided.
test('todo option with message', { todo: 'this is a todo test' }, (t) => {
// This code is executed.
});
test('todo() method', (t) => {
t.todo();
});
test('todo() method with message', (t) => {
t.todo('this is a todo test and is not treated as a failure');
throw new Error('this does not fail the test');
}); copy
Псевдонимы describe() и it()
Наборы тестов и тесты также можно описывать с помощью функций describe() и it(). describe() — это псевдоним для suite(), а it() — это псевдоним для test().
describe('A thing', () => {
it('should work', () => {
assert.strictEqual(1, 1);
});
it('should be ok', () => {
assert.strictEqual(2, 2);
});
describe('a nested thing', () => {
it('should work', () => {
assert.strictEqual(3, 3);
});
});
}); copy describe() и it() импортируются из модуля node:test.
Модули JavaScript
import { describe, it } from 'node:test';CommonJS
const { describe, it } = require('node:test');
Тесты only
Если Node.js запущен с параметром командной строки --test-only, можно пропустить все тесты верхнего уровня, кроме выбранного подмножества, передав параметр only тестам, которые необходимо запустить. При запуске теста с заданным параметром only запускаются также все его вложенные тесты. Для реализации такого же поведения на уровне вложенных тестов можно использовать метод runOnly() контекста теста.
// Assume Node.js is run with the --test-only command-line option.
// The 'only' option is set, so this test is run.
test('this test is run', { only: true }, async (t) => {
// Within this test, all subtests are run by default.
await t.test('running subtest');
// The test context can be updated to run subtests with the 'only' option.
t.runOnly(true);
await t.test('this subtest is now skipped');
await t.test('this subtest is run', { only: true });
// Switch the context back to execute all tests.
t.runOnly(false);
await t.test('this subtest is now run');
// Explicitly do not run these tests.
await t.test('skipped subtest 3', { only: false });
await t.test('skipped subtest 4', { skip: true });
});
// The 'only' option is not set, so this test is skipped.
test('this test is not run', () => {
// This code is not run.
throw new Error('fail');
}); copy Фильтрация тестов по имени
Параметр командной строки --test-name-pattern позволяет запускать только тесты, имена которых соответствуют заданному шаблону. Шаблоны имен тестов интерпретируются как регулярные выражения JavaScript. Параметр --test-name-pattern можно указывать несколько раз, чтобы запускать вложенные тесты. Для каждого запущенного теста также выполняются соответствующие хуки теста, например beforeEach().
Для следующего тестового файла запуск Node.js с параметром --test-name-pattern="test [1-3]" приведет к запуску тестов test 1, test 2 и test 3. Если test 1 не соответствует шаблону имени теста, его вложенные тесты не будут запущены, даже если они соответствуют шаблону. Тот же набор тестов можно запустить, указав --test-name-pattern несколько раз (например, --test-name-pattern="test 1", --test-name-pattern="test 2" и т. д.).
test('test 1', async (t) => {
await t.test('test 2');
await t.test('test 3');
});
test('Test 4', async (t) => {
await t.test('Test 5');
await t.test('test 6');
}); copy Шаблоны имен тестов также можно задавать с помощью литералов регулярных выражений. Это позволяет использовать флаги регулярных выражений. В предыдущем примере запуск Node.js с параметром --test-name-pattern="/test [4-5]/i" позволит выбрать Test 4 и Test 5, поскольку шаблон не учитывает регистр.
Шаблоны имен тестов не изменяют набор файлов, запускаемых средством запуска тестов.
Посторонняя асинхронная активность
После завершения выполнения тестовой функции результаты выводятся как можно быстрее, сохраняя порядок тестов. Однако тестовая функция может создавать асинхронную активность, которая продолжается после завершения самого теста. Средство запуска тестов обрабатывает такую активность, но не задерживает вывод результатов теста, чтобы дождаться ее завершения.
В следующем примере тест завершается, когда еще выполняются две операции setImmediate(). Первая операция setImmediate() пытается создать новый вложенный тест. Поскольку родительский тест уже завершился и его результаты выведены, новый вложенный тест немедленно помечается как не пройденный, а затем выводится в <TestsStream>.
Вторая операция setImmediate() создает событие uncaughtException. События uncaughtException и unhandledRejection, исходящие от завершенного теста, модуль test помечает как не пройденные, а <TestsStream> выводит их на верхнем уровне в виде диагностических предупреждений.
test('a test that creates asynchronous activity', (t) => {
setImmediate(() => {
t.test('subtest that is created too late', (t) => {
throw new Error('error1');
});
});
setImmediate(() => {
throw new Error('error2');
});
// The test finishes after this line.
}); copy Режим наблюдения
Средство запуска тестов Node.js поддерживает запуск в режиме наблюдения с помощью флага --watch:
node --test --watch copy
В режиме наблюдения средство запуска тестов отслеживает изменения в тестовых файлах и их зависимостях. При обнаружении изменений оно повторно запускает тесты, на которые повлияли эти изменения. Средство запуска тестов продолжает работу, пока процесс не будет завершен.
Запуск тестов из командной строки
Средство запуска тестов Node.js можно вызвать из командной строки, передав флаг --test:
node --test copy
По умолчанию Node.js рекурсивно ищет в текущем каталоге исходные файлы JavaScript, соответствующие определенному соглашению об именовании. Найденные файлы выполняются как тестовые. Дополнительные сведения о соглашении об именовании тестовых файлов и их поведении см. в разделе модель выполнения средства запуска тестов.
В качестве альтернативы в конце команды Node.js можно указать один или несколько путей, как показано ниже.
node --test test1.js test2.mjs custom_test_dir/ copy
В этом примере средство запуска тестов выполнит файлы test1.js и test2.mjs. Кроме того, оно рекурсивно выполнит поиск тестовых файлов в каталоге custom_test_dir/.
Модель выполнения средства запуска тестов
При поиске тестовых файлов средство запуска тестов работает следующим образом:
- Выполняются все файлы, явно указанные пользователем.
- Если пользователь явно не указал пути, текущий рабочий каталог рекурсивно просматривается в поисках файлов согласно следующим шагам.
-
Каталоги
node_modulesпропускаются, если только пользователь не указал их явно. - Если обнаружен каталог с именем
test, средство запуска тестов рекурсивно ищет в нем все файлы.js,.cjsи.mjs. Все эти файлы считаются тестовыми, и им не обязательно соответствовать приведенному ниже соглашению об именовании. Это позволяет учитывать проекты, в которых все тесты находятся в одном каталогеtest. - Во всех остальных каталогах тестовыми считаются файлы
.js,.cjsи.mjs, соответствующие следующим шаблонам:-
^test$- файлы, базовое имя которых — строка'test'. Примеры:test.js,test.cjs,test.mjs. -
^test-.+- файлы, базовое имя которых начинается со строки'test-', за которой следует один или несколько символов. Примеры:test-example.js,test-another-example.mjs. -
.+[\.\-\_]test$- файлы, базовое имя которых заканчивается на.test,-testили_test, перед которыми стоит один или несколько символов. Примеры:example.test.js,example-test.cjs,example_test.mjs. - Файлы других типов, поддерживаемых Node.js, например
.nodeи.json, не запускаются средством запуска тестов автоматически, но поддерживаются, если явно указаны в командной строке.
-
Каждый подходящий тестовый файл выполняется в отдельном дочернем процессе. Максимальное число одновременно работающих дочерних процессов определяется флагом --test-concurrency. Если дочерний процесс завершился с кодом выхода 0, тест считается пройденным. В противном случае тест считается не пройденным. Тестовые файлы должны запускаться в Node.js, но им не обязательно использовать внутри себя модуль node:test.
Каждый тестовый файл выполняется как обычный скрипт. То есть если сам тестовый файл использует node:test для определения тестов, все эти тесты будут выполнены в одном потоке приложения независимо от значения параметра concurrency функции test().
Сбор данных о покрытии кода
Если Node.js запущен с флагом командной строки --experimental-test-coverage, собираются данные о покрытии кода, а статистика выводится после завершения всех тестов. Если для указания каталога покрытия кода используется переменная окружения NODE_V8_COVERAGE, созданные файлы покрытия V8 записываются в этот каталог. По умолчанию модули ядра Node.js и файлы в каталогах node_modules/ не включаются в отчет о покрытии. Однако их можно явно включить с помощью флага --test-coverage-include. Если сбор данных о покрытии включен, отчет передается всем средствам формирования отчетов о тестировании через событие 'test:coverage'.
Сбор данных о покрытии можно отключить для ряда строк с помощью следующего синтаксиса комментария:
/* node:coverage disable */
if (anAlwaysFalseCondition) {
// Code in this branch will never be executed, but the lines are ignored for
// coverage purposes. All lines following the 'disable' comment are ignored
// until a corresponding 'enable' comment is encountered.
console.log('this is never executed');
}
/* node:coverage enable */ copy Сбор данных о покрытии также можно отключить для заданного числа строк. После указанного количества строк сбор автоматически возобновится. Если количество строк явно не указано, игнорируется одна строка.
/* node:coverage ignore next */
if (anAlwaysFalseCondition) { console.log('this is never executed'); }
/* node:coverage ignore next 3 */
if (anAlwaysFalseCondition) {
console.log('this is never executed');
} copy Средства формирования отчетов о покрытии
Средства формирования отчетов tap и spec выводят сводку статистики покрытия. Также доступно средство формирования отчетов lcov, которое создает файл lcov для подробного анализа покрытия.
node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info copy
- Это средство формирования отчетов не выводит результаты тестов.
- В идеале это средство следует использовать вместе с другим средством формирования отчетов.
Ограничения
Функция сбора данных о покрытии кода средства запуска тестов не поддерживает исключение отдельных файлов или каталогов из отчета о покрытии.
Создание имитаций
Модуль node:test поддерживает создание имитаций во время тестирования с помощью объекта верхнего уровня mock. В следующем примере создаётся шпион для функции, которая складывает два числа. Затем шпион используется для проверки того, что функция была вызвана ожидаемым образом.
Модули JavaScript
import assert from 'node:assert';
import { mock, test } from 'node:test';
test('spies on a function', () => {
const sum = mock.fn((a, b) => {
return a + b;
});
assert.strictEqual(sum.mock.callCount(), 0);
assert.strictEqual(sum(3, 4), 7);
assert.strictEqual(sum.mock.callCount(), 1);
const call = sum.mock.calls[0];
assert.deepStrictEqual(call.arguments, [3, 4]);
assert.strictEqual(call.result, 7);
assert.strictEqual(call.error, undefined);
// Reset the globally tracked mocks.
mock.reset();
});CommonJS
'use strict';
const assert = require('node:assert');
const { mock, test } = require('node:test');
test('spies on a function', () => {
const sum = mock.fn((a, b) => {
return a + b;
});
assert.strictEqual(sum.mock.callCount(), 0);
assert.strictEqual(sum(3, 4), 7);
assert.strictEqual(sum.mock.callCount(), 1);
const call = sum.mock.calls[0];
assert.deepStrictEqual(call.arguments, [3, 4]);
assert.strictEqual(call.result, 7);
assert.strictEqual(call.error, undefined);
// Reset the globally tracked mocks.
mock.reset();
});Та же функциональность создания имитаций также доступна в объекте TestContext каждого теста. В следующем примере с помощью API, доступного в TestContext, создаётся шпион для метода объекта. Преимущество создания имитаций через контекст теста заключается в том, что средство запуска тестов автоматически восстановит всю имитированную функциональность после завершения теста.
test('spies on an object method', (t) => {
const number = {
value: 5,
add(a) {
return this.value + a;
},
};
t.mock.method(number, 'add');
assert.strictEqual(number.add.mock.callCount(), 0);
assert.strictEqual(number.add(3), 8);
assert.strictEqual(number.add.mock.callCount(), 1);
const call = number.add.mock.calls[0];
assert.deepStrictEqual(call.arguments, [3]);
assert.strictEqual(call.result, 8);
assert.strictEqual(call.target, undefined);
assert.strictEqual(call.this, number);
}); copy Таймеры
Имитация таймеров — метод, широко используемый при тестировании программного обеспечения для симуляции и управления поведением таймеров, таких как setInterval и setTimeout, без фактического ожидания заданных интервалов времени.
Полный список методов и возможностей см. в классе MockTimers.
Это позволяет разработчикам писать более надёжные и предсказуемые тесты для функциональности, зависящей от времени.
В примере ниже показано, как имитировать setTimeout. С помощью .enable({ apis: ['setTimeout'] }); будут имитироваться функции setTimeout в модулях node:timers и node:timers/promises, а также в глобальном контексте Node.js.
Примечание: Деструктуризация функций, например import { setTimeout } from 'node:timers', в настоящее время не поддерживается этим API.
Модули JavaScript
import assert from 'node:assert';
import { mock, test } from 'node:test';
test('mocks setTimeout to be executed synchronously without having to actually wait for it', () => {
const fn = mock.fn();
// Optionally choose what to mock
mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Advance in time
mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
// Reset the globally tracked mocks.
mock.timers.reset();
// If you call reset mock instance, it will also reset timers instance
mock.reset();
});CommonJS
const assert = require('node:assert');
const { mock, test } = require('node:test');
test('mocks setTimeout to be executed synchronously without having to actually wait for it', () => {
const fn = mock.fn();
// Optionally choose what to mock
mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Advance in time
mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
// Reset the globally tracked mocks.
mock.timers.reset();
// If you call reset mock instance, it will also reset timers instance
mock.reset();
});Та же функциональность создания имитаций также доступна в свойстве mock объекта TestContext каждого теста. Преимущество создания имитаций через контекст теста заключается в том, что средство запуска тестов автоматически восстановит всю функциональность имитации таймеров после завершения теста.
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
const fn = context.mock.fn();
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Advance in time
context.mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
const fn = context.mock.fn();
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Advance in time
context.mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
});Даты
API имитации таймеров также позволяет имитировать объект Date. Эта возможность полезна для тестирования функциональности, зависящей от времени, или симуляции внутренних календарных функций, таких как Date.now().
Реализация имитации дат также входит в класс MockTimers. Полный список методов и возможностей см. в его описании.
Примечание: При совместной имитации даты и таймеры зависят друг от друга. Это означает, что если имитированы и Date, и setTimeout, то при перемещении времени вперёд имитированная дата также будет перемещаться вперёд, поскольку они используют одни внутренние часы.
В примере ниже показано, как имитировать объект Date и получить текущее значение Date.now().
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('mocks the Date object', (context) => {
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['Date'] });
// If not specified, the initial date will be based on 0 in the UNIX epoch
assert.strictEqual(Date.now(), 0);
// Advance in time will also advance the date
context.mock.timers.tick(9999);
assert.strictEqual(Date.now(), 9999);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('mocks the Date object', (context) => {
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['Date'] });
// If not specified, the initial date will be based on 0 in the UNIX epoch
assert.strictEqual(Date.now(), 0);
// Advance in time will also advance the date
context.mock.timers.tick(9999);
assert.strictEqual(Date.now(), 9999);
});Если начальная эпоха не задана, начальная дата будет соответствовать значению 0 эпохи Unix. Это 1 января 1970 года, 00:00:00 UTC. Вы можете задать начальную дату, передав свойство now методу .enable(). Это значение будет использоваться в качестве начальной даты для имитированного объекта Date. Оно может быть положительным целым числом или другим объектом Date.
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('mocks the Date object with initial time', (context) => {
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['Date'], now: 100 });
assert.strictEqual(Date.now(), 100);
// Advance in time will also advance the date
context.mock.timers.tick(200);
assert.strictEqual(Date.now(), 300);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('mocks the Date object with initial time', (context) => {
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['Date'], now: 100 });
assert.strictEqual(Date.now(), 100);
// Advance in time will also advance the date
context.mock.timers.tick(200);
assert.strictEqual(Date.now(), 300);
});Метод .setTime() можно использовать, чтобы вручную переместить имитированную дату на другое время. Этот метод принимает только положительное целое число.
Примечание: Этот метод выполнит все имитированные таймеры, время срабатывания которых наступило до нового времени.
В примере ниже мы задаём новое время для имитированной даты.
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('sets the time of a date object', (context) => {
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['Date'], now: 100 });
assert.strictEqual(Date.now(), 100);
// Advance in time will also advance the date
context.mock.timers.setTime(1000);
context.mock.timers.tick(200);
assert.strictEqual(Date.now(), 1200);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('sets the time of a date object', (context) => {
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['Date'], now: 100 });
assert.strictEqual(Date.now(), 100);
// Advance in time will also advance the date
context.mock.timers.setTime(1000);
context.mock.timers.tick(200);
assert.strictEqual(Date.now(), 1200);
});Если у вас есть таймер, заданный на время в прошлом, он будет выполнен так, как если бы был вызван метод .tick(). Это полезно, если вы хотите протестировать функциональность, зависящую от времени, которая уже относится к прошлому.
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('runs timers as setTime passes ticks', (context) => {
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
const fn = context.mock.fn();
setTimeout(fn, 1000);
context.mock.timers.setTime(800);
// Timer is not executed as the time is not yet reached
assert.strictEqual(fn.mock.callCount(), 0);
assert.strictEqual(Date.now(), 800);
context.mock.timers.setTime(1200);
// Timer is executed as the time is now reached
assert.strictEqual(fn.mock.callCount(), 1);
assert.strictEqual(Date.now(), 1200);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('runs timers as setTime passes ticks', (context) => {
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
const fn = context.mock.fn();
setTimeout(fn, 1000);
context.mock.timers.setTime(800);
// Timer is not executed as the time is not yet reached
assert.strictEqual(fn.mock.callCount(), 0);
assert.strictEqual(Date.now(), 800);
context.mock.timers.setTime(1200);
// Timer is executed as the time is now reached
assert.strictEqual(fn.mock.callCount(), 1);
assert.strictEqual(Date.now(), 1200);
});Вызов .runAll() выполнит все таймеры, находящиеся в очереди. При этом имитированная дата также переместится к моменту выполнения последнего таймера, как если бы время прошло.
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('runs timers as setTime passes ticks', (context) => {
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
const fn = context.mock.fn();
setTimeout(fn, 1000);
setTimeout(fn, 2000);
setTimeout(fn, 3000);
context.mock.timers.runAll();
// All timers are executed as the time is now reached
assert.strictEqual(fn.mock.callCount(), 3);
assert.strictEqual(Date.now(), 3000);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('runs timers as setTime passes ticks', (context) => {
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
const fn = context.mock.fn();
setTimeout(fn, 1000);
setTimeout(fn, 2000);
setTimeout(fn, 3000);
context.mock.timers.runAll();
// All timers are executed as the time is now reached
assert.strictEqual(fn.mock.callCount(), 3);
assert.strictEqual(Date.now(), 3000);
});Репортёры тестов
Модуль node:test поддерживает передачу флагов --test-reporter, позволяющих указать репортёр для средства запуска тестов.
Поддерживаются следующие встроенные репортёры:
-
tapРепортёрtapвыводит результаты тестов в формате TAP. -
specРепортёрspecвыводит результаты тестов в удобочитаемом формате. -
dotРепортёрdotвыводит результаты тестов в компактном формате: каждый успешно пройденный тест обозначается символом., а каждый не пройденный тест — символомX. -
junitРепортёр junit выводит результаты тестов в формате jUnit XML. -
lcovРепортёрlcovвыводит данные о покрытии тестами при использовании с флагом--experimental-test-coverage.
Если stdout является TTY, по умолчанию используется репортёр spec. В противном случае по умолчанию используется репортёр tap.
Точный формат вывода этих репортёров может меняться в разных версиях Node.js, поэтому не следует полагаться на него программно. Если требуется программный доступ к выводу средства запуска тестов, используйте события, генерируемые объектом <TestsStream>.
Репортёры доступны через модуль node:test/reporters:
Модули JavaScript
import { tap, spec, dot, junit, lcov } from 'node:test/reporters';CommonJS
const { tap, spec, dot, junit, lcov } = require('node:test/reporters');Пользовательские репортёры
Флаг --test-reporter можно использовать, чтобы указать путь к пользовательскому репортёру. Пользовательский репортёр — это модуль, экспортирующий значение, принимаемое функцией stream.compose. Репортёры должны преобразовывать события, генерируемые объектом <TestsStream>.
Пример пользовательского репортёра с использованием <stream.Transform>:
Модули JavaScript
import { Transform } from 'node:stream';
const customReporter = new Transform({
writableObjectMode: true,
transform(event, encoding, callback) {
switch (event.type) {
case 'test:dequeue':
callback(null, `test ${event.data.name} dequeued`);
break;
case 'test:enqueue':
callback(null, `test ${event.data.name} enqueued`);
break;
case 'test:watch:drained':
callback(null, 'test watch queue drained');
break;
case 'test:start':
callback(null, `test ${event.data.name} started`);
break;
case 'test:pass':
callback(null, `test ${event.data.name} passed`);
break;
case 'test:fail':
callback(null, `test ${event.data.name} failed`);
break;
case 'test:plan':
callback(null, 'test plan');
break;
case 'test:diagnostic':
case 'test:stderr':
case 'test:stdout':
callback(null, event.data.message);
break;
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals;
callback(null, `total line count: ${totalLineCount}\n`);
break;
}
}
},
});
export default customReporter;CommonJS
const { Transform } = require('node:stream');
const customReporter = new Transform({
writableObjectMode: true,
transform(event, encoding, callback) {
switch (event.type) {
case 'test:dequeue':
callback(null, `test ${event.data.name} dequeued`);
break;
case 'test:enqueue':
callback(null, `test ${event.data.name} enqueued`);
break;
case 'test:watch:drained':
callback(null, 'test watch queue drained');
break;
case 'test:start':
callback(null, `test ${event.data.name} started`);
break;
case 'test:pass':
callback(null, `test ${event.data.name} passed`);
break;
case 'test:fail':
callback(null, `test ${event.data.name} failed`);
break;
case 'test:plan':
callback(null, 'test plan');
break;
case 'test:diagnostic':
case 'test:stderr':
case 'test:stdout':
callback(null, event.data.message);
break;
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals;
callback(null, `total line count: ${totalLineCount}\n`);
break;
}
}
},
});
module.exports = customReporter;Пример пользовательского репортёра с использованием функции-генератора:
Модули JavaScript
export default async function * customReporter(source) {
for await (const event of source) {
switch (event.type) {
case 'test:dequeue':
yield `test ${event.data.name} dequeued\n`;
break;
case 'test:enqueue':
yield `test ${event.data.name} enqueued\n`;
break;
case 'test:watch:drained':
yield 'test watch queue drained\n';
break;
case 'test:start':
yield `test ${event.data.name} started\n`;
break;
case 'test:pass':
yield `test ${event.data.name} passed\n`;
break;
case 'test:fail':
yield `test ${event.data.name} failed\n`;
break;
case 'test:plan':
yield 'test plan\n';
break;
case 'test:diagnostic':
case 'test:stderr':
case 'test:stdout':
yield `${event.data.message}\n`;
break;
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals;
yield `total line count: ${totalLineCount}\n`;
break;
}
}
}
}CommonJS
module.exports = async function * customReporter(source) {
for await (const event of source) {
switch (event.type) {
case 'test:dequeue':
yield `test ${event.data.name} dequeued\n`;
break;
case 'test:enqueue':
yield `test ${event.data.name} enqueued\n`;
break;
case 'test:watch:drained':
yield 'test watch queue drained\n';
break;
case 'test:start':
yield `test ${event.data.name} started\n`;
break;
case 'test:pass':
yield `test ${event.data.name} passed\n`;
break;
case 'test:fail':
yield `test ${event.data.name} failed\n`;
break;
case 'test:plan':
yield 'test plan\n';
break;
case 'test:diagnostic':
case 'test:stderr':
case 'test:stdout':
yield `${event.data.message}\n`;
break;
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals;
yield `total line count: ${totalLineCount}\n`;
break;
}
}
}
};Значение, передаваемое в --test-reporter, должно быть строкой, подобной той, что используется в import() в коде JavaScript, либо значением, указанным для --import.
Несколько репортёров
Флаг --test-reporter можно указать несколько раз, чтобы выводить результаты тестов в нескольких форматах. В этом случае необходимо указать место назначения для каждого репортёра с помощью флага --test-reporter-destination. Местом назначения может быть stdout, stderr или путь к файлу. Репортёры и места назначения сопоставляются в порядке их указания.
В следующем примере репортёр spec выводит данные в stdout, а репортёр dot — в file.txt:
node --test-reporter=spec --test-reporter=dot --test-reporter-destination=stdout --test-reporter-destination=file.txt copy
Если указан только один репортёр, местом назначения по умолчанию будет stdout, если оно не задано явно.
run([options])
-
options<Object> Параметры конфигурации для запуска тестов. Поддерживаются следующие свойства:-
concurrency<number> | <boolean> Если указано число, параллельно будет запущено соответствующее количество процессов тестирования, каждый из которых обрабатывает один файл с тестами. Еслиtrue, параллельно будут запускатьсяos.availableParallelism() - 1файлов с тестами. Еслиfalse, одновременно будет запускаться только один файл с тестами. По умолчанию:false. -
files: <Array> Массив со списком файлов для запуска. По умолчанию: файлы, соответствующие модели выполнения тестового средства запуска. -
forceExit: <boolean> Настраивает тестовое средство запуска так, чтобы оно завершало процесс после выполнения всех известных тестов, даже если в противном случае цикл событий оставался бы активным. По умолчанию:false. -
inspectPort<number> | <Function> Задает порт инспектора дочернего процесса тестирования. Это может быть число или функция без аргументов, возвращающая число. Если указано nullish-значение, каждому процессу назначается собственный порт, начиная сprocess.debugPortосновного процесса. По умолчанию:undefined. -
only: <boolean> Если значение истинно, контекст тестирования будет запускать только тесты, для которых задана опцияonly -
setup<Function> Функция, принимающая экземплярTestsStreamи позволяющая настроить прослушиватели событий до запуска тестов. По умолчанию:undefined. -
signal<AbortSignal> Позволяет прервать выполняющийся тест. -
testNamePatterns<string> | <RegExp> | <Array> Строка, RegExp или массив RegExp, позволяющие запускать только тесты, имена которых соответствуют заданному шаблону. Шаблоны имен тестов интерпретируются как регулярные выражения JavaScript. Для каждого выполняемого теста также запускаются соответствующие обработчики тестов, напримерbeforeEach(). По умолчанию:undefined. -
testSkipPatterns<string> | <RegExp> | <Array> Строка, RegExp или массив RegExp, позволяющие исключить из запуска тесты, имена которых соответствуют заданному шаблону. Шаблоны имен тестов интерпретируются как регулярные выражения JavaScript. Для каждого выполняемого теста также запускаются соответствующие обработчики тестов, напримерbeforeEach(). По умолчанию:undefined. -
timeout<number> Количество миллисекунд, по истечении которых выполнение теста завершится ошибкой. Если значение не задано, вложенные тесты наследуют его от родительского теста. По умолчанию:Infinity. -
watch<boolean> Определяет, следует ли запускать тесты в режиме наблюдения. По умолчанию:false. -
shard<Object> Запуск тестов в указанном шарде. По умолчанию:undefined.
-
- Возвращает: <TestsStream>
Примечание: shard используется для горизонтального распараллеливания запуска тестов на нескольких машинах или процессах и идеально подходит для масштабного выполнения в различных средах. Эта функция несовместима с режимом watch, предназначенным для быстрой итерации при разработке кода за счет автоматического повторного запуска тестов при изменении файлов.
Модули JavaScript
import { tap } from 'node:test/reporters';
import { run } from 'node:test';
import process from 'node:process';
import path from 'node:path';
run({ files: [path.resolve('./tests/test.js')] })
.on('test:fail', () => {
process.exitCode = 1;
})
.compose(tap)
.pipe(process.stdout);CommonJS
const { tap } = require('node:test/reporters');
const { run } = require('node:test');
const path = require('node:path');
run({ files: [path.resolve('./tests/test.js')] })
.on('test:fail', () => {
process.exitCode = 1;
})
.compose(tap)
.pipe(process.stdout);
suite([name][, options][, fn])
-
name<string> Имя набора тестов, отображаемое при выводе результатов тестирования. По умолчанию: свойствоnameобъектаfnили'<anonymous>', если уfnнет имени. -
options<Object> Необязательные параметры конфигурации для набора тестов. Поддерживаются те же параметры, что и вtest([name][, options][, fn]). -
fn<Function> | <AsyncFunction> Функция набора тестов, объявляющая вложенные тесты и наборы тестов. Первый аргумент этой функции — объектSuiteContext. По умолчанию: пустая функция. - Возвращает: <Promise> Немедленно выполняется с результатом
undefined.
Функция suite() импортируется из модуля node:test.
suite.skip([name][, options][, fn])
Сокращенная запись для пропуска набора тестов. Это то же самое, что и suite([name], { skip: true }[, fn]).
suite.todo([name][, options][, fn])
Сокращенная запись для пометки набора тестов как TODO. Это то же самое, что и suite([name], { todo: true }[, fn]).
suite.only([name][, options][, fn])
Сокращенная запись для пометки набора тестов как only. Это то же самое, что и suite([name], { only: true }[, fn]).
test([name][, options][, fn])
-
name<string> Имя теста, отображаемое при выводе результатов тестирования. По умолчанию: свойствоnameобъектаfnили'<anonymous>', если уfnнет имени. -
options<Object> Параметры конфигурации теста. Поддерживаются следующие свойства:-
concurrency<number> | <boolean> Если указано число, в потоке приложения параллельно выполняется соответствующее количество тестов. Если указаноtrue, все запланированные асинхронные тесты выполняются в потоке одновременно. Если указаноfalse, за раз выполняется только один тест. Если значение не указано, вложенные тесты наследуют его от родительского теста. По умолчанию:false. -
only<boolean> Если значение истинно и контекст теста настроен на выполнение тестовonly, этот тест будет выполнен. В противном случае тест пропускается. По умолчанию:false. -
signal<AbortSignal> Позволяет прервать выполняющийся тест. -
skip<boolean> | <string> Если значение истинно, тест пропускается. Если указана строка, она отображается в результатах тестирования как причина пропуска теста. По умолчанию:false. -
todo<boolean> | <string> Если значение истинно, тест помечается какTODO. Если указана строка, она отображается в результатах тестирования как причина, по которой тестTODO. По умолчанию:false. -
timeout<number> Время в миллисекундах, по истечении которого тест завершится с ошибкой. Если значение не указано, вложенные тесты наследуют его от родительского теста. По умолчанию:Infinity. -
plan<number> Количество проверок и вложенных тестов, которые должны быть выполнены в тесте. Если количество выполненных проверок не совпадает с числом, указанным в плане, тест завершится с ошибкой. По умолчанию:undefined.
-
-
fn<Function> | <AsyncFunction> Функция, тестируемая в рамках теста. Первый аргумент этой функции — объектTestContext. Если в тесте используются обратные вызовы, функция обратного вызова передаётся в качестве второго аргумента. По умолчанию: пустая функция. - Возвращает: <Promise> Выполняется со значением
undefinedпосле завершения теста или немедленно, если тест выполняется внутри набора.
Функция test() — это значение, импортируемое из модуля test. Каждый вызов этой функции приводит к передаче сведений о тесте в <TestsStream>.
Объект TestContext, передаваемый аргументу fn, можно использовать для выполнения действий, связанных с текущим тестом. Например, для пропуска теста, добавления дополнительных диагностических сведений или создания вложенных тестов.
Функция test() возвращает Promise, который выполняется после завершения теста. Если test() вызывается внутри набора, он выполняется немедленно. Возвращаемое значение обычно можно не использовать для тестов верхнего уровня. Однако возвращаемое значение вложенных тестов следует использовать, чтобы родительский тест не завершился раньше и не отменил вложенный тест, как показано в следующем примере.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
}); copy Параметр timeout можно использовать, чтобы завершить тест с ошибкой, если для его выполнения требуется больше timeout миллисекунд. Однако это ненадёжный способ отмены тестов, поскольку выполняющийся тест может заблокировать поток приложения и тем самым помешать запланированной отмене.
test.skip([name][, options][, fn])
Сокращённая форма для пропуска теста, эквивалентная test([name], { skip: true }[, fn]).
test.todo([name][, options][, fn])
Сокращённая форма для пометки теста как TODO, эквивалентная test([name], { todo: true }[, fn]).
test.only([name][, options][, fn])
Сокращённая форма для пометки теста как only, эквивалентная test([name], { only: true }[, fn]).
describe([name][, options][, fn])
Псевдоним для suite().
Функция describe() импортируется из модуля node:test.
describe.skip([name][, options][, fn])
Сокращённая форма для пропуска набора. Эквивалентна describe([name], { skip: true }[, fn]).
describe.todo([name][, options][, fn])
Сокращённая форма для пометки набора как TODO. Эквивалентна describe([name], { todo: true }[, fn]).
describe.only([name][, options][, fn])
Сокращённая форма для пометки набора как only. Эквивалентна describe([name], { only: true }[, fn]).
it([name][, options][, fn])
Псевдоним для test().
Функция it() импортируется из модуля node:test.
it.skip([name][, options][, fn])
Сокращённая форма для пропуска теста, эквивалентная it([name], { skip: true }[, fn]).
it.todo([name][, options][, fn])
Сокращённая форма для пометки теста как TODO, эквивалентная it([name], { todo: true }[, fn]).
it.only([name][, options][, fn])
Сокращённая форма для пометки теста как only, эквивалентная it([name], { only: true }[, fn]).
before([fn][, options])
-
fn<Function> | <AsyncFunction> Функция обработчика. Если в обработчике используются обратные вызовы, функция обратного вызова передаётся в качестве второго аргумента. По умолчанию: пустая функция. -
options<Object> Параметры конфигурации обработчика. Поддерживаются следующие свойства:-
signal<AbortSignal> Позволяет прервать выполняющийся обработчик. -
timeout<number> Время в миллисекундах, по истечении которого обработчик завершится с ошибкой. Если значение не указано, вложенные тесты наследуют его от родительского теста. По умолчанию:Infinity.
-
Эта функция создаёт обработчик, который выполняется перед запуском набора.
describe('tests', async () => {
before(() => console.log('about to run some test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
}); copy
after([fn][, options])
-
fn<Function> | <AsyncFunction> Функция обработчика. Если в обработчике используются обратные вызовы, функция обратного вызова передаётся в качестве второго аргумента. По умолчанию: пустая функция. -
options<Object> Параметры конфигурации обработчика. Поддерживаются следующие свойства:-
signal<AbortSignal> Позволяет прервать выполняющийся обработчик. -
timeout<number> Время в миллисекундах, по истечении которого обработчик завершится с ошибкой. Если значение не указано, вложенные тесты наследуют его от родительского теста. По умолчанию:Infinity.
-
Эта функция создаёт обработчик, который выполняется после запуска набора.
describe('tests', async () => {
after(() => console.log('finished running tests'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
}); copy Примечание: гарантируется, что обработчик after будет выполнен, даже если тесты в наборе завершатся с ошибкой.
beforeEach([fn][, options])
-
fn<Function> | <AsyncFunction> Функция обработчика. Если в обработчике используются обратные вызовы, функция обратного вызова передаётся в качестве второго аргумента. По умолчанию: пустая функция. -
options<Object> Параметры конфигурации обработчика. Поддерживаются следующие свойства:-
signal<AbortSignal> Позволяет прервать выполняющийся обработчик. -
timeout<number> Время в миллисекундах, по истечении которого обработчик завершится с ошибкой. Если значение не указано, вложенные тесты наследуют его от родительского теста. По умолчанию:Infinity.
-
Эта функция создаёт обработчик, который выполняется перед каждым тестом в текущем наборе.
describe('tests', async () => {
beforeEach(() => console.log('about to run a test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
}); copy
afterEach([fn][, options])
-
fn<Function> | <AsyncFunction> Функция обработчика. Если в обработчике используются обратные вызовы, функция обратного вызова передаётся в качестве второго аргумента. По умолчанию: пустая функция. -
options<Object> Параметры конфигурации обработчика. Поддерживаются следующие свойства:-
signal<AbortSignal> Позволяет прервать выполняющийся обработчик. -
timeout<number> Время в миллисекундах, по истечении которого обработчик завершится с ошибкой. Если значение не указано, вложенные тесты наследуют его от родительского теста. По умолчанию:Infinity.
-
Эта функция создаёт обработчик, который выполняется после каждого теста в текущем наборе. Обработчик afterEach() запускается, даже если тест завершится с ошибкой.
describe('tests', async () => {
afterEach(() => console.log('finished running a test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
}); copy Класс: MockFunctionContext
Класс MockFunctionContext используется для проверки или изменения поведения моков, созданных с помощью API MockTracker.
ctx.calls
Геттер, возвращающий копию внутреннего массива, используемого для отслеживания вызовов мока. Каждая запись в массиве — это объект со следующими свойствами.
-
arguments<Array> Массив аргументов, переданных функции-моку. -
error<any> Если функция-мок выбросила исключение, это свойство содержит выброшенное значение. По умолчанию:undefined. -
result<any> Значение, возвращённое функцией-моком. -
stack<Error> ОбъектError, стек которого можно использовать для определения места вызова функции-мока. -
target<Function> | <undefined> Если функция-мок является конструктором, это поле содержит создаваемый класс. В противном случае здесь будетundefined. -
this<any> Значениеthisфункции-мока.
ctx.callCount()
- Возвращает: <integer> Количество вызовов этого мока.
Эта функция возвращает количество вызовов этого мока. Она эффективнее, чем проверка ctx.calls.length, поскольку ctx.calls — это геттер, создающий копию внутреннего массива отслеживания вызовов.
ctx.mockImplementation(implementation)
-
implementation<Function> | <AsyncFunction> Функция, которая будет использоваться в качестве новой реализации мока.
Эта функция используется для изменения поведения существующего мока.
В следующем примере создаётся функция-мок с помощью t.mock.fn(), вызывается функция-мок, а затем реализация мока заменяется другой функцией.
test('changes a mock behavior', (t) => {
let cnt = 0;
function addOne() {
cnt++;
return cnt;
}
function addTwo() {
cnt += 2;
return cnt;
}
const fn = t.mock.fn(addOne);
assert.strictEqual(fn(), 1);
fn.mock.mockImplementation(addTwo);
assert.strictEqual(fn(), 3);
assert.strictEqual(fn(), 5);
}); copy
ctx.mockImplementationOnce(implementation[, onCall])
-
implementation<Function> | <AsyncFunction> Функция, которая будет использоваться в качестве реализации мока для номера вызова, указанного вonCall. -
onCall<integer> Номер вызова, для которого будет использоватьсяimplementation. Если указанный вызов уже произошёл, будет выброшено исключение. По умолчанию: номер следующего вызова.
Эта функция используется для изменения поведения существующего мока при одном вызове. После вызова onCall мок вернётся к поведению, которое использовалось бы, если бы не был вызван mockImplementationOnce().
В следующем примере создаётся функция-мок с помощью t.mock.fn(), вызывается функция-мок, реализация мока заменяется другой функцией для следующего вызова, после чего возобновляется прежнее поведение.
test('changes a mock behavior once', (t) => {
let cnt = 0;
function addOne() {
cnt++;
return cnt;
}
function addTwo() {
cnt += 2;
return cnt;
}
const fn = t.mock.fn(addOne);
assert.strictEqual(fn(), 1);
fn.mock.mockImplementationOnce(addTwo);
assert.strictEqual(fn(), 3);
assert.strictEqual(fn(), 4);
}); copy
ctx.resetCalls()
Сбрасывает историю вызовов функции-мока.
ctx.restore()
Восстанавливает исходное поведение функции-мока. Мок можно использовать и после вызова этой функции.
Класс: MockModuleContext
Класс MockModuleContext используется для изменения поведения моков модулей, созданных с помощью API MockTracker.
ctx.restore()
Сбрасывает реализацию модуля-мока.
Class: MockTracker
Класс MockTracker используется для управления функциональностью имитации. Модуль запуска тестов предоставляет экспорт верхнего уровня mock, который является экземпляром MockTracker. Каждый тест также предоставляет собственный экземпляр MockTracker через свойство mock контекста теста.
mock.fn([original[, implementation]][, options])
-
original<Function> | <AsyncFunction> Необязательная функция, для которой создаётся имитация. По умолчанию: функция, ничего не выполняющая. -
implementation<Function> | <AsyncFunction> Необязательная функция, используемая в качестве реализации имитации дляoriginal. Это удобно для создания имитаций, которые демонстрируют одно поведение заданное число вызовов, а затем восстанавливают поведениеoriginal. По умолчанию: функция, заданная параметромoriginal. -
options<Object> Необязательные параметры конфигурации функции-имитации. Поддерживаются следующие свойства:-
times<integer> Число вызовов, в течение которых имитация будет использовать поведениеimplementation. После того как функция-имитация будет вызванаtimesраз, она автоматически восстановит поведениеoriginal. Это значение должно быть целым числом больше нуля. По умолчанию:Infinity.
-
- Возвращает: <Proxy> Функцию-имитацию. Функция-имитация содержит специальное свойство
mock, являющееся экземпляромMockFunctionContext; оно позволяет проверять и изменять поведение функции-имитации.
Эта функция используется для создания функции-имитации.
В следующем примере создаётся функция-имитация, которая при каждом вызове увеличивает счётчик на единицу. Параметр times используется для изменения поведения имитации: при первых двух вызовах счётчик увеличивается на два, а не на один.
test('mocks a counting function', (t) => {
let cnt = 0;
function addOne() {
cnt++;
return cnt;
}
function addTwo() {
cnt += 2;
return cnt;
}
const fn = t.mock.fn(addOne, addTwo, { times: 2 });
assert.strictEqual(fn(), 2);
assert.strictEqual(fn(), 4);
assert.strictEqual(fn(), 5);
assert.strictEqual(fn(), 6);
}); copy
mock.getter(object, methodName[, implementation][, options])
Эта функция является синтаксическим сокращением для MockTracker.method, где для options.getter задано значение true.
mock.method(object, methodName[, implementation][, options])
-
object<Object> Объект, метод которого имитируется. -
methodName<string> | <symbol> Идентификатор метода объектаobject, для которого создаётся имитация. Еслиobject[methodName]не является функцией, возникает ошибка. -
implementation<Function> | <AsyncFunction> Необязательная функция, используемая в качестве реализации имитации дляobject[methodName]. По умолчанию: исходный метод, заданный параметромobject[methodName]. -
options<Object> Необязательные параметры конфигурации метода-имитации. Поддерживаются следующие свойства:-
getter<boolean> Если значениеtrueравно true,object[methodName]обрабатывается как геттер. Этот параметр нельзя использовать вместе с параметромsetter. По умолчанию: false. -
setter<boolean> Если значениеtrueравно true,object[methodName]обрабатывается как сеттер. Этот параметр нельзя использовать вместе с параметромgetter. По умолчанию: false. -
times<integer> Число вызовов, в течение которых имитация будет использовать поведениеimplementation. После того как имитируемый метод будет вызванtimesраз, он автоматически восстановит исходное поведение. Это значение должно быть целым числом больше нуля. По умолчанию:Infinity.
-
- Возвращает: <Proxy> Имитируемый метод. Имитируемый метод содержит специальное свойство
mock, являющееся экземпляромMockFunctionContext; оно позволяет проверять и изменять поведение имитируемого метода.
Эта функция используется для создания имитации метода существующего объекта. В следующем примере показано, как создать имитацию метода существующего объекта.
test('spies on an object method', (t) => {
const number = {
value: 5,
subtract(a) {
return this.value - a;
},
};
t.mock.method(number, 'subtract');
assert.strictEqual(number.subtract.mock.callCount(), 0);
assert.strictEqual(number.subtract(3), 2);
assert.strictEqual(number.subtract.mock.callCount(), 1);
const call = number.subtract.mock.calls[0];
assert.deepStrictEqual(call.arguments, [3]);
assert.strictEqual(call.result, 2);
assert.strictEqual(call.error, undefined);
assert.strictEqual(call.target, undefined);
assert.strictEqual(call.this, number);
}); copy
mock.module(specifier[, options])
-
specifier<string> Строка, идентифицирующая модуль, для которого создаётся имитация. -
options<Object> Необязательные параметры конфигурации модуля-имитации. Поддерживаются следующие свойства:-
cache<boolean> Если значениеfalseравно true, каждый вызовrequire()илиimport()создаёт новый модуль-имитацию. Если значениеtrueравно false, последующие вызовы возвращают ту же имитацию модуля, которая помещается в кэш CommonJS. По умолчанию: false. -
defaultExport<any> Необязательное значение, используемое в качестве экспорта по умолчанию имитируемого модуля. Если это значение не задано, имитации ESM не содержат экспорта по умолчанию. Если имитация представляет собой модуль CommonJS или встроенный модуль, этот параметр используется в качестве значенияmodule.exports. Если это значение не задано, в имитациях CJS и встроенных модулей в качестве значенияmodule.exportsиспользуется пустой объект. -
namedExports<Object> Необязательный объект, ключи и значения которого используются для создания именованных экспортов имитируемого модуля. Если имитация представляет собой модуль CommonJS или встроенный модуль, эти значения копируются вmodule.exports. Поэтому при создании имитации с именованными экспортами и экспортом по умолчанию, не являющимся объектом, при использовании имитации как модуля CJS или встроенного модуля возникает исключение.
-
- Возвращает: <MockModuleContext> Объект, используемый для управления имитацией.
Эта функция используется для имитации экспортов модулей ECMAScript, модулей CommonJS и встроенных модулей Node.js. Ссылки на исходный модуль, полученные до создания имитации, не затрагиваются. В следующем примере показано, как создать имитацию модуля.
test('mocks a builtin module in both module systems', async (t) => {
// Create a mock of 'node:readline' with a named export named 'fn', which
// does not exist in the original 'node:readline' module.
const mock = t.mock.module('node:readline', {
namedExports: { fn() { return 42; } },
});
let esmImpl = await import('node:readline');
let cjsImpl = require('node:readline');
// cursorTo() is an export of the original 'node:readline' module.
assert.strictEqual(esmImpl.cursorTo, undefined);
assert.strictEqual(cjsImpl.cursorTo, undefined);
assert.strictEqual(esmImpl.fn(), 42);
assert.strictEqual(cjsImpl.fn(), 42);
mock.restore();
// The mock is restored, so the original builtin module is returned.
esmImpl = await import('node:readline');
cjsImpl = require('node:readline');
assert.strictEqual(typeof esmImpl.cursorTo, 'function');
assert.strictEqual(typeof cjsImpl.cursorTo, 'function');
assert.strictEqual(esmImpl.fn, undefined);
assert.strictEqual(cjsImpl.fn, undefined);
}); copy
mock.reset()
Эта функция восстанавливает поведение по умолчанию всех имитаций, ранее созданных этим экземпляром MockTracker, и отсоединяет имитации от экземпляра MockTracker. После отсоединения имитации можно по-прежнему использовать, но экземпляр MockTracker больше нельзя использовать для сброса их поведения или иного взаимодействия с ними.
После завершения каждого теста эта функция вызывается для объекта MockTracker контекста теста. Если глобальный объект MockTracker используется активно, рекомендуется вызывать эту функцию вручную.
mock.restoreAll()
Эта функция восстанавливает поведение по умолчанию всех имитаций, ранее созданных этим экземпляром MockTracker. В отличие от mock.reset(), функция mock.restoreAll() не отсоединяет имитации от экземпляра MockTracker.
mock.setter(object, methodName[, implementation][, options])
Эта функция является синтаксическим сокращением для MockTracker.method, где для options.setter задано значение true.
Класс: MockTimers
Имитация таймеров — это метод, широко используемый при тестировании программного обеспечения для моделирования и управления поведением таймеров, таких как setInterval и setTimeout, без фактического ожидания указанных временных интервалов.
MockTimers также может имитировать объект Date.
MockTracker предоставляет экспорт timers верхнего уровня, который является экземпляром MockTimers.
timers.enable([enableOptions])
Включает имитацию указанных таймеров.
-
enableOptions<Object> Необязательные параметры конфигурации для включения имитации таймеров. Поддерживаются следующие свойства:-
apis<Array> Необязательный массив с таймерами, имитацию которых нужно включить. В настоящее время поддерживаются следующие значения таймеров:'setInterval','setTimeout','setImmediate'и'Date'. По умолчанию:['setInterval', 'setTimeout', 'setImmediate', 'Date']. Если массив не указан, по умолчанию имитируются все связанные со временем API ('setInterval','clearInterval','setTimeout','clearTimeout','setImmediate','clearImmediate'и'Date'). -
now<number> | <Date> Необязательное число или объект Date, представляющий начальное время (в миллисекундах), которое будет использоваться в качестве значения дляDate.now(). По умолчанию:0.
-
Примечание: При включении имитации конкретного таймера связанная с ним функция очистки также будет неявно имитироваться.
Примечание: Имитация Date повлияет на поведение имитируемых таймеров, поскольку они используют одни и те же внутренние часы.
Пример использования без установки начального времени:
Модули JavaScript
import { mock } from 'node:test';
mock.timers.enable({ apis: ['setInterval'] });CommonJS
const { mock } = require('node:test');
mock.timers.enable({ apis: ['setInterval'] });В приведенном выше примере включается имитация таймера setInterval и неявно имитируется функция clearInterval. Будут имитироваться только функции setInterval и clearInterval из node:timers, node:timers/promises и globalThis.
Пример использования с установленным начальным временем
Модули JavaScript
import { mock } from 'node:test';
mock.timers.enable({ apis: ['Date'], now: 1000 });CommonJS
const { mock } = require('node:test');
mock.timers.enable({ apis: ['Date'], now: 1000 });Пример использования с начальным значением времени в виде объекта Date
Модули JavaScript
import { mock } from 'node:test';
mock.timers.enable({ apis: ['Date'], now: new Date() });CommonJS
const { mock } = require('node:test');
mock.timers.enable({ apis: ['Date'], now: new Date() });Кроме того, если вызвать mock.timers.enable() без параметров:
Будут имитироваться все таймеры ('setInterval', 'clearInterval', 'setTimeout', 'clearTimeout', 'setImmediate' и 'clearImmediate'). Будут имитироваться функции setInterval, clearInterval, setTimeout, clearTimeout, setImmediate и clearImmediate из node:timers, node:timers/promises и globalThis. Также будет имитироваться глобальный объект Date.
timers.reset()
Эта функция восстанавливает поведение по умолчанию для всех имитаций, ранее созданных этим экземпляром MockTimers, и отсоединяет имитации от экземпляра MockTracker.
Примечание: После завершения каждого теста эта функция вызывается для MockTracker контекста теста.
Модули JavaScript
import { mock } from 'node:test';
mock.timers.reset();CommonJS
const { mock } = require('node:test');
mock.timers.reset();
timers[Symbol.dispose]()
Вызывает timers.reset().
timers.tick([milliseconds])
Переводит время вперед для всех имитируемых таймеров.
-
milliseconds<number> Время в миллисекундах, на которое нужно перевести таймеры вперед. По умолчанию:1.
Примечание: Это отличается от поведения setTimeout в Node.js: принимаются только положительные числа. В Node.js использование setTimeout с отрицательными числами поддерживается только для совместимости с веб-платформой.
В следующем примере имитируется функция setTimeout, а с помощью .tick время переводится вперед, что приводит к срабатыванию всех ожидающих таймеров.
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
const fn = context.mock.fn();
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Advance in time
context.mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
const fn = context.mock.fn();
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Advance in time
context.mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
});Также функцию .tick можно вызывать много раз
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
const fn = context.mock.fn();
context.mock.timers.enable({ apis: ['setTimeout'] });
const nineSecs = 9000;
setTimeout(fn, nineSecs);
const threeSeconds = 3000;
context.mock.timers.tick(threeSeconds);
context.mock.timers.tick(threeSeconds);
context.mock.timers.tick(threeSeconds);
assert.strictEqual(fn.mock.callCount(), 1);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
const fn = context.mock.fn();
context.mock.timers.enable({ apis: ['setTimeout'] });
const nineSecs = 9000;
setTimeout(fn, nineSecs);
const threeSeconds = 3000;
context.mock.timers.tick(threeSeconds);
context.mock.timers.tick(threeSeconds);
context.mock.timers.tick(threeSeconds);
assert.strictEqual(fn.mock.callCount(), 1);
});Перевод времени вперед с помощью .tick также приведет к переводу времени вперед для любого объекта Date, созданного после включения имитации (если для Date также была включена имитация).
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
const fn = context.mock.fn();
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
assert.strictEqual(Date.now(), 0);
// Advance in time
context.mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
assert.strictEqual(Date.now(), 9999);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
const fn = context.mock.fn();
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
assert.strictEqual(Date.now(), 0);
// Advance in time
context.mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
assert.strictEqual(Date.now(), 9999);
});Использование функций очистки
Как упоминалось выше, все функции очистки таймеров (clearTimeout, clearInterval и clearImmediate) неявно имитируются. Рассмотрим этот пример с использованием setTimeout:
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
const fn = context.mock.fn();
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['setTimeout'] });
const id = setTimeout(fn, 9999);
// Implicitly mocked as well
clearTimeout(id);
context.mock.timers.tick(9999);
// As that setTimeout was cleared the mock function will never be called
assert.strictEqual(fn.mock.callCount(), 0);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
const fn = context.mock.fn();
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['setTimeout'] });
const id = setTimeout(fn, 9999);
// Implicitly mocked as well
clearTimeout(id);
context.mock.timers.tick(9999);
// As that setTimeout was cleared the mock function will never be called
assert.strictEqual(fn.mock.callCount(), 0);
});Работа с модулями таймеров Node.js
После включения имитации таймеров становятся доступны модули node:timers, node:timers/promises, а также таймеры из глобального контекста Node.js:
Примечание: Этот API в настоящее время не поддерживает деструктуризацию функций, например import { setTimeout } from 'node:timers'.
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
import nodeTimers from 'node:timers';
import nodeTimersPromises from 'node:timers/promises';
test('mocks setTimeout to be executed synchronously without having to actually wait for it', async (context) => {
const globalTimeoutObjectSpy = context.mock.fn();
const nodeTimerSpy = context.mock.fn();
const nodeTimerPromiseSpy = context.mock.fn();
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(globalTimeoutObjectSpy, 9999);
nodeTimers.setTimeout(nodeTimerSpy, 9999);
const promise = nodeTimersPromises.setTimeout(9999).then(nodeTimerPromiseSpy);
// Advance in time
context.mock.timers.tick(9999);
assert.strictEqual(globalTimeoutObjectSpy.mock.callCount(), 1);
assert.strictEqual(nodeTimerSpy.mock.callCount(), 1);
await promise;
assert.strictEqual(nodeTimerPromiseSpy.mock.callCount(), 1);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
const nodeTimers = require('node:timers');
const nodeTimersPromises = require('node:timers/promises');
test('mocks setTimeout to be executed synchronously without having to actually wait for it', async (context) => {
const globalTimeoutObjectSpy = context.mock.fn();
const nodeTimerSpy = context.mock.fn();
const nodeTimerPromiseSpy = context.mock.fn();
// Optionally choose what to mock
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(globalTimeoutObjectSpy, 9999);
nodeTimers.setTimeout(nodeTimerSpy, 9999);
const promise = nodeTimersPromises.setTimeout(9999).then(nodeTimerPromiseSpy);
// Advance in time
context.mock.timers.tick(9999);
assert.strictEqual(globalTimeoutObjectSpy.mock.callCount(), 1);
assert.strictEqual(nodeTimerSpy.mock.callCount(), 1);
await promise;
assert.strictEqual(nodeTimerPromiseSpy.mock.callCount(), 1);
});В Node.js функция setInterval из node:timers/promises является AsyncGenerator и также поддерживается этим API:
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
import nodeTimersPromises from 'node:timers/promises';
test('should tick five times testing a real use case', async (context) => {
context.mock.timers.enable({ apis: ['setInterval'] });
const expectedIterations = 3;
const interval = 1000;
const startedAt = Date.now();
async function run() {
const times = [];
for await (const time of nodeTimersPromises.setInterval(interval, startedAt)) {
times.push(time);
if (times.length === expectedIterations) break;
}
return times;
}
const r = run();
context.mock.timers.tick(interval);
context.mock.timers.tick(interval);
context.mock.timers.tick(interval);
const timeResults = await r;
assert.strictEqual(timeResults.length, expectedIterations);
for (let it = 1; it < expectedIterations; it++) {
assert.strictEqual(timeResults[it - 1], startedAt + (interval * it));
}
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
const nodeTimersPromises = require('node:timers/promises');
test('should tick five times testing a real use case', async (context) => {
context.mock.timers.enable({ apis: ['setInterval'] });
const expectedIterations = 3;
const interval = 1000;
const startedAt = Date.now();
async function run() {
const times = [];
for await (const time of nodeTimersPromises.setInterval(interval, startedAt)) {
times.push(time);
if (times.length === expectedIterations) break;
}
return times;
}
const r = run();
context.mock.timers.tick(interval);
context.mock.timers.tick(interval);
context.mock.timers.tick(interval);
const timeResults = await r;
assert.strictEqual(timeResults.length, expectedIterations);
for (let it = 1; it < expectedIterations; it++) {
assert.strictEqual(timeResults[it - 1], startedAt + (interval * it));
}
});
timers.runAll()
Немедленно запускает все ожидающие имитируемые таймеры. Если объект Date также имитируется, время в объекте Date также будет переведено к моменту срабатывания самого позднего таймера.
Приведенный ниже пример немедленно запускает все ожидающие таймеры, заставляя их выполниться без задержки.
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('runAll functions following the given order', (context) => {
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
const results = [];
setTimeout(() => results.push(1), 9999);
// Notice that if both timers have the same timeout,
// the order of execution is guaranteed
setTimeout(() => results.push(3), 8888);
setTimeout(() => results.push(2), 8888);
assert.deepStrictEqual(results, []);
context.mock.timers.runAll();
assert.deepStrictEqual(results, [3, 2, 1]);
// The Date object is also advanced to the furthest timer's time
assert.strictEqual(Date.now(), 9999);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('runAll functions following the given order', (context) => {
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
const results = [];
setTimeout(() => results.push(1), 9999);
// Notice that if both timers have the same timeout,
// the order of execution is guaranteed
setTimeout(() => results.push(3), 8888);
setTimeout(() => results.push(2), 8888);
assert.deepStrictEqual(results, []);
context.mock.timers.runAll();
assert.deepStrictEqual(results, [3, 2, 1]);
// The Date object is also advanced to the furthest timer's time
assert.strictEqual(Date.now(), 9999);
});Примечание: Функция runAll() предназначена специально для запуска таймеров в контексте имитации таймеров. Она не влияет на системные часы реального времени или настоящие таймеры за пределами среды имитации.
timers.setTime(milliseconds)
Устанавливает текущую временную метку Unix, которая будет использоваться как точка отсчета для любых имитируемых объектов Date.
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('runAll functions following the given order', (context) => {
const now = Date.now();
const setTime = 1000;
// Date.now is not mocked
assert.deepStrictEqual(Date.now(), now);
context.mock.timers.enable({ apis: ['Date'] });
context.mock.timers.setTime(setTime);
// Date.now is now 1000
assert.strictEqual(Date.now(), setTime);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('setTime replaces current time', (context) => {
const now = Date.now();
const setTime = 1000;
// Date.now is not mocked
assert.deepStrictEqual(Date.now(), now);
context.mock.timers.enable({ apis: ['Date'] });
context.mock.timers.setTime(setTime);
// Date.now is now 1000
assert.strictEqual(Date.now(), setTime);
});Совместная работа дат и таймеров
Объекты Date и таймеры зависят друг от друга. Если использовать setTime() для передачи текущего времени имитируемому объекту Date, установленные таймеры с помощью setTimeout и setInterval не изменятся.
Однако метод tick будет переводить вперед время имитируемого объекта Date.
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('runAll functions following the given order', (context) => {
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
const results = [];
setTimeout(() => results.push(1), 9999);
assert.deepStrictEqual(results, []);
context.mock.timers.setTime(12000);
assert.deepStrictEqual(results, []);
// The date is advanced but the timers don't tick
assert.strictEqual(Date.now(), 12000);
});CommonJS
const assert = require('node:assert');
const { test } = require('node:test');
test('runAll functions following the given order', (context) => {
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
const results = [];
setTimeout(() => results.push(1), 9999);
assert.deepStrictEqual(results, []);
context.mock.timers.setTime(12000);
assert.deepStrictEqual(results, []);
// The date is advanced but the timers don't tick
assert.strictEqual(Date.now(), 12000);
});Класс: TestsStream
- Наследует <Readable>
Успешный вызов метода run() возвращает новый объект <TestsStream>, который передает поток событий, представляющих выполнение тестов. TestsStream генерирует события в порядке определения тестов
Для некоторых событий гарантированно соблюдается тот же порядок, в котором определены тесты, тогда как другие генерируются в порядке выполнения тестов.
Событие: 'test:coverage'
-
data<Object>-
summary<Object> Объект, содержащий отчет о покрытии кода.-
files<Array> Массив отчетов о покрытии кода для отдельных файлов. Каждый отчет представляет собой объект со следующей структурой:-
path<string> Абсолютный путь к файлу. -
totalLineCount<number> Общее количество строк. -
totalBranchCount<number> Общее количество ветвей. -
totalFunctionCount<number> Общее количество функций. -
coveredLineCount<number> Количество строк, покрытых тестами. -
coveredBranchCount<number> Количество ветвей, покрытых тестами. -
coveredFunctionCount<number> Количество функций, покрытых тестами. -
coveredLinePercent<number> Процент строк, покрытых тестами. -
coveredBranchPercent<number> Процент ветвей, покрытых тестами. -
coveredFunctionPercent<number> Процент функций, покрытых тестами. -
functions<Array> Массив функций, представляющий покрытие функций. -
branches<Array> Массив ветвей, представляющий покрытие ветвей. -
lines<Array> Массив строк, представляющий номера строк и количество их покрытий тестами.
-
-
totals<Object> Объект со сводными данными о покрытии кода для всех файлов.-
totalLineCount<number> Общее количество строк. -
totalBranchCount<number> Общее количество ветвей. -
totalFunctionCount<number> Общее количество функций. -
coveredLineCount<number> Количество строк, покрытых тестами. -
coveredBranchCount<number> Количество ветвей, покрытых тестами. -
coveredFunctionCount<number> Количество функций, покрытых тестами. -
coveredLinePercent<number> Процент строк, покрытых тестами. -
coveredBranchPercent<number> Процент ветвей, покрытых тестами. -
coveredFunctionPercent<number> Процент функций, покрытых тестами.
-
-
workingDirectory<string> Рабочий каталог на момент начала сбора данных о покрытии кода. Это полезно для отображения относительных путей, если тесты изменили рабочий каталог процесса Node.js.
-
-
nesting<number> Уровень вложенности теста.
-
Генерируется, когда включен сбор данных о покрытии кода и все тесты завершены.
Событие: 'test:complete'
-
data<Object>-
column<number> | <undefined> Номер столбца, в котором определен тест, илиundefined, если тест был запущен через REPL. -
details<Object> Дополнительные метаданные выполнения.-
passed<boolean> Указывает, пройден ли тест. -
duration_ms<number> Длительность теста в миллисекундах. -
error<Error> | <undefined> Ошибка, оборачивающая ошибку, выброшенную тестом, если он не был пройден.-
cause<Error> Фактическая ошибка, выброшенная тестом.
-
-
type<string> | <undefined> Тип теста, указывающий, является ли он набором тестов.
-
-
file<string> | <undefined> Путь к файлу теста;undefined, если тест был запущен через REPL. -
line<number> | <undefined> Номер строки, в которой определен тест, илиundefined, если тест был запущен через REPL. -
name<string> Имя теста. -
nesting<number> Уровень вложенности теста. -
testNumber<number> Порядковый номер теста. -
todo<string> | <boolean> | <undefined> Присутствует, если вызван методcontext.todo -
skip<string> | <boolean> | <undefined> Присутствует, если вызван методcontext.skip
-
Генерируется при завершении выполнения теста. Это событие генерируется не в том же порядке, в котором определены тесты. Соответствующие события, упорядоченные по порядку объявления: 'test:pass' и 'test:fail'.
Событие: 'test:dequeue'
-
data<Object>-
column<number> | <undefined> Номер столбца, в котором определен тест, илиundefined, если тест был запущен через REPL. -
file<string> | <undefined> Путь к файлу теста;undefined, если тест был запущен через REPL. -
line<number> | <undefined> Номер строки, в которой определен тест, илиundefined, если тест был запущен через REPL. -
name<string> Имя теста. -
nesting<number> Уровень вложенности теста.
-
Генерируется при извлечении теста из очереди непосредственно перед его выполнением. Это событие не обязательно генерируется в том же порядке, в котором определены тесты. Соответствующее событие, упорядоченное по порядку объявления: 'test:start'.
Событие: 'test:diagnostic'
-
data<Object>-
column<number> | <undefined> Номер столбца, в котором определён тест, илиundefined, если тест был запущен через REPL. -
file<string> | <undefined> Путь к файлу теста,undefined, если тест был запущен через REPL. -
line<number> | <undefined> Номер строки, в которой определён тест, илиundefined, если тест был запущен через REPL. -
message<string> Диагностическое сообщение. -
nesting<number> Уровень вложенности теста.
-
Генерируется при вызове context.diagnostic. Гарантируется, что это событие будет сгенерировано в том же порядке, в котором определены тесты.
Событие: 'test:enqueue'
-
data<Object>-
column<number> | <undefined> Номер столбца, в котором определён тест, илиundefined, если тест был запущен через REPL. -
file<string> | <undefined> Путь к файлу теста,undefined, если тест был запущен через REPL. -
line<number> | <undefined> Номер строки, в которой определён тест, илиundefined, если тест был запущен через REPL. -
name<string> Имя теста. -
nesting<number> Уровень вложенности теста.
-
Генерируется, когда тест ставится в очередь на выполнение.
Событие: 'test:fail'
-
data<Object>-
column<number> | <undefined> Номер столбца, в котором определён тест, илиundefined, если тест был запущен через REPL. -
details<Object> Дополнительные метаданные выполнения.-
duration_ms<number> Длительность теста в миллисекундах. -
error<Error> Ошибка-обёртка, содержащая ошибку, выброшенную тестом.-
cause<Error> Фактическая ошибка, выброшенная тестом.
-
-
type<string> | <undefined> Тип теста, указывающий, является ли он набором тестов.
-
-
file<string> | <undefined> Путь к файлу теста,undefined, если тест был запущен через REPL. -
line<number> | <undefined> Номер строки, в которой определён тест, илиundefined, если тест был запущен через REPL. -
name<string> Имя теста. -
nesting<number> Уровень вложенности теста. -
testNumber<number> Порядковый номер теста. -
todo<string> | <boolean> | <undefined> Присутствует, если вызванcontext.todo -
skip<string> | <boolean> | <undefined> Присутствует, если вызванcontext.skip
-
Генерируется, когда тест завершается с ошибкой. Гарантируется, что это событие будет сгенерировано в том же порядке, в котором определены тесты. Соответствующее событие, упорядоченное по выполнению, — 'test:complete'.
Событие: 'test:pass'
-
data<Object>-
column<number> | <undefined> Номер столбца, в котором определён тест, илиundefined, если тест был запущен через REPL. -
details<Object> Дополнительные метаданные выполнения.-
duration_ms<number> Длительность теста в миллисекундах. -
type<string> | <undefined> Тип теста, указывающий, является ли он набором тестов.
-
-
file<string> | <undefined> Путь к файлу теста,undefined, если тест был запущен через REPL. -
line<number> | <undefined> Номер строки, в которой определён тест, илиundefined, если тест был запущен через REPL. -
name<string> Имя теста. -
nesting<number> Уровень вложенности теста. -
testNumber<number> Порядковый номер теста. -
todo<string> | <boolean> | <undefined> Присутствует, если вызванcontext.todo -
skip<string> | <boolean> | <undefined> Присутствует, если вызванcontext.skip
-
Генерируется, когда тест проходит успешно. Гарантируется, что это событие будет сгенерировано в том же порядке, в котором определены тесты. Соответствующее событие, упорядоченное по выполнению, — 'test:complete'.
Событие: 'test:plan'
-
data<Object>-
column<number> | <undefined> Номер столбца, в котором определён тест, илиundefined, если тест был запущен через REPL. -
file<string> | <undefined> Путь к файлу теста,undefined, если тест был запущен через REPL. -
line<number> | <undefined> Номер строки, в которой определён тест, илиundefined, если тест был запущен через REPL. -
nesting<number> Уровень вложенности теста. -
count<number> Количество выполненных подтестов.
-
Генерируется, когда все подтесты для заданного теста завершены. Гарантируется, что это событие будет сгенерировано в том же порядке, в котором определены тесты.
Событие: 'test:start'
-
data<Object>-
column<number> | <undefined> Номер столбца, в котором определён тест, илиundefined, если тест был запущен через REPL. -
file<string> | <undefined> Путь к файлу теста,undefined, если тест был запущен через REPL. -
line<number> | <undefined> Номер строки, в которой определён тест, илиundefined, если тест был запущен через REPL. -
name<string> Имя теста. -
nesting<number> Уровень вложенности теста.
-
Вызывается, когда тест начинает сообщать о своём состоянии и состоянии своих подтестов. Гарантируется, что это событие будет вызвано в том же порядке, в котором определены тесты. Соответствующее событие, упорядоченное по времени выполнения, — 'test:dequeue'.
Событие: 'test:stderr'
Вызывается, когда выполняющийся тест записывает данные в stderr. Это событие вызывается только при передаче флага --test. Не гарантируется, что это событие будет вызвано в том же порядке, в котором определены тесты.
Событие: 'test:stdout'
Вызывается, когда выполняющийся тест записывает данные в stdout. Это событие вызывается только при передаче флага --test. Не гарантируется, что это событие будет вызвано в том же порядке, в котором определены тесты.
Событие: 'test:watch:drained'
Вызывается, когда в режиме наблюдения в очереди больше не остаётся тестов для выполнения.
Класс: TestContext
Экземпляр TestContext передается каждой тестовой функции, чтобы взаимодействовать с тестовым раннером. Однако конструктор TestContext не предоставляется как часть API.
context.before([fn][, options])
-
fn<Function> | <AsyncFunction> Функция хука. Первый аргумент этой функции — объектTestContext. Если хук использует обратные вызовы, функция обратного вызова передается в качестве второго аргумента. По умолчанию: Функция-заглушка. -
options<Object> Параметры конфигурации хука. Поддерживаются следующие свойства:-
signal<AbortSignal> Позволяет прервать выполняющийся хук. -
timeout<number> Количество миллисекунд, по истечении которых хук завершится с ошибкой. Если значение не указано, под-тесты наследуют его от родительского теста. По умолчанию:Infinity.
-
Эта функция используется для создания хука, выполняемого перед под-тестами текущего теста.
context.beforeEach([fn][, options])
-
fn<Function> | <AsyncFunction> Функция хука. Первый аргумент этой функции — объектTestContext. Если хук использует обратные вызовы, функция обратного вызова передается в качестве второго аргумента. По умолчанию: Функция-заглушка. -
options<Object> Параметры конфигурации хука. Поддерживаются следующие свойства:-
signal<AbortSignal> Позволяет прервать выполняющийся хук. -
timeout<number> Количество миллисекунд, по истечении которых хук завершится с ошибкой. Если значение не указано, под-тесты наследуют его от родительского теста. По умолчанию:Infinity.
-
Эта функция используется для создания хука, выполняемого перед каждым под-тестом текущего теста.
test('top level test', async (t) => {
t.beforeEach((t) => t.diagnostic(`about to run ${t.name}`));
await t.test(
'This is a subtest',
(t) => {
assert.ok('some relevant assertion here');
},
);
}); copy
context.after([fn][, options])
-
fn<Function> | <AsyncFunction> Функция хука. Первый аргумент этой функции — объектTestContext. Если хук использует обратные вызовы, функция обратного вызова передается в качестве второго аргумента. По умолчанию: Функция-заглушка. -
options<Object> Параметры конфигурации хука. Поддерживаются следующие свойства:-
signal<AbortSignal> Позволяет прервать выполняющийся хук. -
timeout<number> Количество миллисекунд, по истечении которых хук завершится с ошибкой. Если значение не указано, под-тесты наследуют его от родительского теста. По умолчанию:Infinity.
-
Эта функция используется для создания хука, выполняемого после завершения текущего теста.
test('top level test', async (t) => {
t.after((t) => t.diagnostic(`finished running ${t.name}`));
assert.ok('some relevant assertion here');
}); copy
context.afterEach([fn][, options])
-
fn<Function> | <AsyncFunction> Функция хука. Первый аргумент этой функции — объектTestContext. Если хук использует обратные вызовы, функция обратного вызова передается в качестве второго аргумента. По умолчанию: Функция-заглушка. -
options<Object> Параметры конфигурации хука. Поддерживаются следующие свойства:-
signal<AbortSignal> Позволяет прервать выполняющийся хук. -
timeout<number> Количество миллисекунд, по истечении которых хук завершится с ошибкой. Если значение не указано, под-тесты наследуют его от родительского теста. По умолчанию:Infinity.
-
Эта функция используется для создания хука, выполняемого после каждого под-теста текущего теста.
test('top level test', async (t) => {
t.afterEach((t) => t.diagnostic(`finished running ${t.name}`));
await t.test(
'This is a subtest',
(t) => {
assert.ok('some relevant assertion here');
},
);
}); copy
context.assert
Объект, содержащий методы проверки утверждений, привязанные к context. Здесь доступны функции верхнего уровня из модуля node:assert для создания планов тестирования.
test('test', (t) => {
t.plan(1);
t.assert.strictEqual(true, true);
}); copy
context.diagnostic(message)
-
message<string> Сообщение для вывода.
Эта функция используется для вывода диагностических данных. Любая диагностическая информация включается в конец результатов теста. Эта функция не возвращает значение.
test('top level test', (t) => {
t.diagnostic('A diagnostic message');
}); copy
context.fullName
Имя теста и каждого из его предков, разделенные >.
context.name
Имя теста.
context.plan(count)
-
count<number> Количество проверок утверждений и под-тестов, которые должны быть выполнены.
Эта функция используется для указания количества проверок утверждений и под-тестов, которые должны быть выполнены в рамках теста. Если количество выполненных проверок утверждений и под-тестов не совпадает с ожидаемым, тест завершится с ошибкой.
Примечание: Чтобы обеспечить отслеживание проверок утверждений, вместо прямого вызова
assertнеобходимо использоватьt.assert.
test('top level test', (t) => {
t.plan(2);
t.assert.ok('some relevant assertion here');
t.test('subtest', () => {});
}); copy При работе с асинхронным кодом функцию plan можно использовать, чтобы убедиться, что выполнено правильное количество проверок утверждений:
test('planning with streams', (t, done) => {
function* generate() {
yield 'a';
yield 'b';
yield 'c';
}
const expected = ['a', 'b', 'c'];
t.plan(expected.length);
const stream = Readable.from(generate());
stream.on('data', (chunk) => {
t.assert.strictEqual(chunk, expected.shift());
});
stream.on('end', () => {
done();
});
}); copy
context.runOnly(shouldRunOnlyTests)
-
shouldRunOnlyTests<boolean> Следует ли запускать тестыonly.
Если значение shouldRunOnlyTests истинно, контекст теста будет запускать только тесты, для которых задан параметр only. В противном случае запускаются все тесты. Если Node.js запущен без параметра командной строки --test-only, эта функция ничего не делает.
test('top level test', (t) => {
// The test context can be set to run subtests with the 'only' option.
t.runOnly(true);
return Promise.all([
t.test('this subtest is now skipped'),
t.test('this subtest is run', { only: true }),
]);
}); copy
context.signal
- Тип: <AbortSignal>
Можно использовать для прерывания подзадач теста, если тест был прерван.
test('top level test', async (t) => {
await fetch('some/uri', { signal: t.signal });
}); copy
context.skip([message])
-
message<string> Необязательное сообщение о пропуске.
Эта функция указывает в выводе теста, что тест пропущен. Если указано message, оно включается в вывод. Вызов skip() не прекращает выполнение тестовой функции. Эта функция не возвращает значение.
test('top level test', (t) => {
// Make sure to return here as well if the test contains additional logic.
t.skip('this is skipped');
}); copy
context.todo([message])
-
message<string> Необязательное сообщениеTODO.
Эта функция добавляет директиву TODO в вывод теста. Если указано message, оно включается в вывод. Вызов todo() не прекращает выполнение тестовой функции. Эта функция не возвращает значение.
test('top level test', (t) => {
// This test is marked as `TODO`
t.todo('this is a todo');
}); copy
context.test([name][, options][, fn])
-
name<string> Имя подтеста, отображаемое при выводе результатов тестирования. По умолчанию: свойствоnameобъектаfnили'<anonymous>', если уfnнет имени. -
options<Object> Параметры конфигурации подтеста. Поддерживаются следующие свойства:-
concurrency<number> | <boolean> | <null> Если указано число, такое количество тестов будет выполняться параллельно в потоке приложения. Если значение равноtrue, все подтесты будут выполняться параллельно. Если значение равноfalse, за раз будет выполняться только один тест. Если значение не указано, подтесты наследуют его от родительского теста. По умолчанию:null. -
only<boolean> Если значение истинно и контекст теста настроен на выполнение тестовonly, этот тест будет запущен. В противном случае тест пропускается. По умолчанию:false. -
signal<AbortSignal> Позволяет прервать выполняющийся тест. -
skip<boolean> | <string> Если значение истинно, тест пропускается. Если указана строка, она отображается в результатах тестирования как причина пропуска теста. По умолчанию:false. -
todo<boolean> | <string> Если значение истинно, тест помечается какTODO. Если указана строка, она отображается в результатах тестирования как причина, по которой тестTODO. По умолчанию:false. -
timeout<number> Время в миллисекундах, по истечении которого тест завершится с ошибкой. Если значение не указано, подтесты наследуют его от родительского теста. По умолчанию:Infinity. -
plan<number> Ожидаемое количество проверок и подтестов, которые должны быть выполнены в тесте. Если количество выполненных проверок не совпадает с числом, указанным в плане, тест завершится с ошибкой. По умолчанию:undefined.
-
-
fn<Function> | <AsyncFunction> Проверяемая функция. Первый аргумент этой функции — объектTestContext. Если в тесте используются обратные вызовы, функция обратного вызова передаётся вторым аргументом. По умолчанию: пустая функция. - Возвращает: <Promise> Выполняется со значением
undefinedпосле завершения теста.
Эта функция используется для создания подтестов в рамках текущего теста. Она работает так же, как функция верхнего уровня test().
test('top level test', async (t) => {
await t.test(
'This is a subtest',
{ only: false, skip: false, concurrency: 1, todo: false, plan: 1 },
(t) => {
t.assert.ok('some relevant assertion here');
},
);
}); copy Класс: SuiteContext
Экземпляр SuiteContext передаётся каждой функции набора тестов для взаимодействия с исполнительной средой тестов. Однако конструктор SuiteContext не предоставляется как часть API.
context.name
Имя набора тестов.
context.signal
- Тип: <AbortSignal>
Можно использовать для прерывания подзадач теста, если тест был прерван.
© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v20.x/docs/api/test.html