Средство запуска тестов
Исходный код: lib/test.js
Модуль node:test упрощает создание тестов JavaScript. Чтобы получить к нему доступ:
Модули JavaScript
import test from 'node:test';
CommonJS
const test = require('node:test');Этот модуль доступен только при использовании схемы node:.
Тесты, созданные с помощью модуля 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 Повторный запуск тестов, завершившихся неудачно
Средство запуска тестов поддерживает сохранение состояния запуска в файл, что позволяет повторно запускать тесты, завершившиеся неудачно, не запуская весь набор тестов заново. Используйте параметр командной строки --test-rerun-failures, чтобы указать путь к файлу, в котором будет сохранено состояние запуска. Если файл состояния не существует, средство запуска тестов создаст его. Файл состояния представляет собой JSON-файл, содержащий массив попыток запуска. Каждая попытка запуска — это объект, сопоставляющий успешно завершившиеся тесты с номером попытки, в которой они завершились успешно. Ключом, идентифицирующим тест в этой карте, служит путь к файлу теста с номером строки и столбца, в которых определен тест. Если тест, определенный в конкретном месте, запускается несколько раз, например внутри функции или цикла, к ключу добавляется счетчик, позволяющий различать запуски теста. Обратите внимание: изменение порядка выполнения тестов или местоположения теста может привести к тому, что средство запуска тестов посчитает тесты успешно завершившимися в предыдущей попытке. Поэтому --test-rerun-failures следует использовать, если тесты запускаются в детерминированном порядке.
Пример файла состояния:
[
{
"test.js:10:5": { "passed_on_attempt": 0, "name": "test 1" }
},
{
"test.js:10:5": { "passed_on_attempt": 0, "name": "test 1" },
"test.js:20:5": { "passed_on_attempt": 1, "name": "test 2" }
}
] copy В этом примере представлены две попытки запуска и два теста, определенные в test.js: первый тест успешно завершился с первой попытки, а второй — со второй.
Если используется параметр --test-rerun-failures, средство запуска тестов запускает только те тесты, которые еще не завершились успешно.
node --test-rerun-failures /path/to/state/file 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 Ожидание неудачного завершения тестов
Это меняет местами результаты успешного и неудачного завершения для конкретного теста или набора тестов: помеченный тест/тестовый пример должен выбросить исключение, чтобы «завершиться успешно»; тест/тестовый пример, который не выбрасывает исключение, завершается неудачно.
В следующем примере doTheThing() возвращает текущее false (false не равно true, что приводит к выбросу исключения в strictEqual, поэтому тестовый пример завершается успешно).
it.expectFailure('should do the thing', () => {
assert.strictEqual(doTheThing(), true);
});
it('should do the thing', { expectFailure: true }, () => {
assert.strictEqual(doTheThing(), true);
}); copy Параметры skip и/или todo несовместимы с expectFailure. Если применены оба параметра, «победит» skip или todo (skip имеет приоритет над обоими, а todo — над expectFailure).
Эти тесты будут пропущены (и не запущены):
it.expectFailure('should do the thing', { skip: true }, () => {
assert.strictEqual(doTheThing(), true);
});
it.skip('should do the thing', { expectFailure: true }, () => {
assert.strictEqual(doTheThing(), true);
}); copy Эти тесты будут помечены как «todo» (ошибки будут подавлены):
it.expectFailure('should do the thing', { todo: true }, () => {
assert.strictEqual(doTheThing(), true);
});
it.todo('should do the thing', { expectFailure: true }, () => {
assert.strictEqual(doTheThing(), true);
}); 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, запускаются также все его подтесты. Если для набора тестов задан параметр only, запускаются все тесты в этом наборе, кроме случая, когда в нем есть дочерние элементы с заданным параметром only: тогда запускаются только эти тесты.
При использовании подтестов внутри test()/it() для запуска только выбранного подмножества тестов необходимо пометить параметром only все родительские тесты.
Метод runOnly() контекста теста можно использовать для реализации того же поведения на уровне подтестов. Не выполненные тесты не отображаются в выводе средства запуска тестов.
// Assume Node.js is run with the --test-only command-line option.
// The suite's 'only' option is set, so these tests are 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');
});
describe('a suite', () => {
// The 'only' option is set, so this test is run.
it('this test is run', { only: true }, () => {
// This code is run.
});
it('this test is not run', () => {
// This code is not run.
throw new Error('fail');
});
});
describe.only('a suite', () => {
// The 'only' option is set, so this test is run.
it('this test is run', () => {
// This code is run.
});
it('this test is run', () => {
// This code is run.
});
}); copy Фильтрация тестов по имени
Параметр командной строки --test-name-pattern позволяет запускать только тесты, имена которых соответствуют заданному шаблону, а параметр --test-skip-pattern позволяет пропускать тесты, имена которых соответствуют заданному шаблону. Шаблоны имен тестов интерпретируются как регулярные выражения JavaScript. Параметры --test-name-pattern и --test-skip-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-skip-pattern="/test [4-5]/i") соответствует Test 4 и Test 5, поскольку шаблон не учитывает регистр.
Чтобы сопоставить один тест с шаблоном, можно добавить перед ним имена всех его родительских тестов, разделенные пробелами, чтобы шаблон был уникальным. Например, при наличии следующего файла тестов:
describe('test 1', (t) => {
it('some test');
});
describe('test 2', (t) => {
it('some test');
}); copy Запуск Node.js с --test-name-pattern="test 1 some test" позволит выбрать только some test в test 1.
Шаблоны имен тестов не меняют набор файлов, которые выполняет средство запуска тестов.
Если указаны и --test-name-pattern, и --test-skip-pattern, для выполнения тесты должны соответствовать обоим требованиям.
Посторонняя асинхронная активность
После завершения выполнения тестовой функции результаты сообщаются как можно быстрее, при этом сохраняется порядок тестов. Однако тестовая функция может создавать асинхронную активность, которая продолжается после завершения самого теста. Средство запуска тестов обрабатывает такую активность, но не откладывает сообщение результатов теста, чтобы дождаться ее завершения.
В следующем примере тест завершается, хотя еще не выполнены две операции 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
В режиме наблюдения средство запуска тестов отслеживает изменения в файлах тестов и их зависимостях. При обнаружении изменений оно повторно запускает тесты, на которые эти изменения повлияли. Средство запуска тестов продолжает работу, пока процесс не будет завершен.
Глобальная настройка и очистка
Средство запуска тестов поддерживает указание модуля, который будет выполнен перед запуском всех тестов и может использоваться для настройки глобального состояния или тестовых фикстур. Это удобно для подготовки ресурсов или настройки общего состояния, необходимого нескольким тестам.
Этот модуль может экспортировать любую из следующих функций:
- Функция
globalSetup, которая выполняется один раз перед запуском всех тестов - Функция
globalTeardown, которая выполняется один раз после завершения всех тестов
Модуль указывается с помощью флага --test-global-setup при запуске тестов из командной строки.
CommonJS
// setup-module.js
async function globalSetup() {
// Setup shared resources, state, or environment
console.log('Global setup executed');
// Run servers, create files, prepare databases, etc.
}
async function globalTeardown() {
// Clean up resources, state, or environment
console.log('Global teardown executed');
// Close servers, remove files, disconnect from databases, etc.
}
module.exports = { globalSetup, globalTeardown };Модули JavaScript
// setup-module.mjs
export async function globalSetup() {
// Setup shared resources, state, or environment
console.log('Global setup executed');
// Run servers, create files, prepare databases, etc.
}
export async function globalTeardown() {
// Clean up resources, state, or environment
console.log('Global teardown executed');
// Close servers, remove files, disconnect from databases, etc.
}Если функция глобальной настройки выбрасывает ошибку, тесты не запускаются, а процесс завершается с ненулевым кодом. В этом случае функция глобальной очистки вызвана не будет.
Запуск тестов из командной строки
Средство запуска тестов Node.js можно вызвать из командной строки, передав флаг --test:
node --test copy
По умолчанию Node.js запустит все файлы, соответствующие следующим шаблонам:
**/*.test.{cjs,mjs,js}**/*-test.{cjs,mjs,js}**/*_test.{cjs,mjs,js}**/test-*.{cjs,mjs,js}**/test.{cjs,mjs,js}**/test/**/*.{cjs,mjs,js}
Если не указан флаг --no-strip-types, также будут сопоставлены следующие дополнительные шаблоны:
**/*.test.{cts,mts,ts}**/*-test.{cts,mts,ts}**/*_test.{cts,mts,ts}**/test-*.{cts,mts,ts}**/test.{cts,mts,ts}**/test/**/*.{cts,mts,ts}
В качестве альтернативы в качестве последнего аргумента (или аргументов) команды Node.js можно передать один или несколько шаблонов glob, как показано ниже. Шаблоны glob работают согласно правилам glob(7). Чтобы предотвратить раскрытие шаблонов оболочкой, в командной строке их следует заключать в двойные кавычки; это повышает переносимость между системами.
node --test "**/*.test.js" "**/*.spec.js" copy
Соответствующие файлы выполняются как тестовые файлы. Дополнительные сведения о выполнении тестовых файлов приведены в разделе модель выполнения средства запуска тестов.
Модель выполнения средства запуска тестов
Если включена изоляция на уровне процессов, каждый соответствующий тестовый файл выполняется в отдельном дочернем процессе. Максимальное количество одновременно работающих дочерних процессов задаётся флагом --test-concurrency. Если дочерний процесс завершается с кодом выхода 0, тест считается пройденным. В противном случае тест считается не пройденным. Тестовые файлы должны выполняться в Node.js, но не обязаны использовать внутри модуль node:test.
Каждый тестовый файл выполняется как обычный скрипт. То есть если сам тестовый файл использует node:test для определения тестов, все эти тесты будут выполняться в одном потоке приложения независимо от значения параметра concurrency у test().
Если изоляция на уровне процессов отключена, каждый соответствующий тестовый файл импортируется в процесс средства запуска тестов. После загрузки всех тестовых файлов тесты верхнего уровня выполняются с параллелизмом, равным единице. Поскольку все тестовые файлы выполняются в одном контексте, тесты могут взаимодействовать друг с другом способами, невозможными при включённой изоляции. Например, если тест зависит от глобального состояния, тест из другого файла может изменить это состояние.
Наследование параметров дочерними процессами
При запуске тестов в режиме изоляции процессов (режим по умолчанию) порождённые дочерние процессы наследуют параметры Node.js от родительского процесса, включая параметры, указанные в файлах конфигурации. Однако некоторые флаги отфильтровываются, чтобы обеспечить корректную работу средства запуска тестов:
-
--test— отключён во избежание рекурсивного запуска тестов -
--experimental-test-coverage— обрабатывается средством запуска тестов -
--watch— режим наблюдения обрабатывается на уровне родительского процесса -
--experimental-default-config-file— загрузка файла конфигурации обрабатывается родительским процессом -
--test-reporter— создание отчётов управляется родительским процессом -
--test-reporter-destination— места вывода контролируются родительским процессом -
--experimental-config-file— пути к файлам конфигурации управляются родительским процессом
Все остальные параметры Node.js из аргументов командной строки, переменных среды и файлов конфигурации наследуются дочерними процессами.
Сбор данных о покрытии кода
Если Node.js запущен с флагом командной строки --experimental-test-coverage, собираются данные о покрытии кода и выводится статистика после завершения всех тестов. Если для указания каталога для данных о покрытии кода используется переменная среды NODE_V8_COVERAGE, созданные файлы покрытия V8 записываются в этот каталог. По умолчанию модули ядра Node.js и файлы в каталогах node_modules/ не включаются в отчёт о покрытии. Однако их можно явно включить с помощью флага --test-coverage-include. По умолчанию все соответствующие тестовые файлы исключаются из отчёта о покрытии. Изменить список исключений можно с помощью флага --test-coverage-exclude. Если сбор данных о покрытии включён, отчёт о покрытии передаётся всем средствам формирования отчётов о тестах через событие '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.
Примечание: Этот API пока не поддерживает деструктуризацию функций, таких как import { setTimeout } from 'node:timers'.
Модули 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);
});Таймеры, запланированные на момент времени в прошлом, не сработают при вызове setTime(). Чтобы выполнить эти таймеры, можно использовать метод .tick(), чтобы перевести время вперёд от нового момента.
Модули JavaScript
import assert from 'node:assert';
import { test } from 'node:test';
test('setTime does not execute timers', (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 still not executed
assert.strictEqual(fn.mock.callCount(), 0);
// Advance in time to execute the timer
context.mock.timers.tick(0);
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.js с флагом командной строки --test-update-snapshots. Для каждого тестового файла создаётся отдельный файл снимков. По умолчанию файл снимков имеет то же имя, что и тестовый файл, но с расширением .snapshot. Это поведение можно настроить с помощью функции snapshot.setResolveSnapshotPath(). Каждое утверждение о снимке соответствует экспорту в файле снимков.
Пример теста со снимками приведён ниже. При первом запуске этот тест завершится ошибкой, поскольку соответствующий файл снимков ещё не существует.
// test.js
suite('suite of snapshot tests', () => {
test('snapshot test', (t) => {
t.assert.snapshot({ value1: 1, value2: 2 });
t.assert.snapshot(5);
});
}); copy Создайте файл снимков, запустив тестовый файл с --test-update-snapshots. Тест должен пройти, а в том же каталоге, что и тестовый файл, будет создан файл с именем test.js.snapshot. Ниже показано содержимое файла снимков. Каждый снимок идентифицируется полным именем теста и счётчиком, позволяющим различать снимки в рамках одного теста.
exports[`suite of snapshot tests > snapshot test 1`] = `
{
"value1": 1,
"value2": 2
}
`;
exports[`suite of snapshot tests > snapshot test 2`] = `
5
`; copy После создания файла снимков запустите тесты ещё раз без флага --test-update-snapshots. Теперь тесты должны пройти.
Средства формирования отчетов о тестах
Модуль node:test поддерживает передачу флагов --test-reporter, чтобы средство запуска тестов использовало определенное средство формирования отчетов.
Поддерживаются следующие встроенные средства формирования отчетов:
-
specСредство формирования отчетовspecвыводит результаты тестов в удобном для чтения формате. Это средство используется по умолчанию. -
tapСредство формирования отчетовtapвыводит результаты тестов в формате TAP. -
dotСредство формирования отчетовdotвыводит результаты тестов в компактном формате: каждый пройденный тест обозначается., а каждый не пройденный —X. -
junitСредство формирования отчетов junit выводит результаты тестов в формате jUnit XML -
lcovСредство формирования отчетовlcovвыводит данные о покрытии тестами при использовании флага--experimental-test-coverage.
Точный формат вывода этих средств формирования отчетов может меняться между версиями 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:watch:restarted':
callback(null, 'test watch restarted due to file change');
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:watch:restarted':
callback(null, 'test watch restarted due to file change');
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:watch:restarted':
yield 'test watch restarted due to file change\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:watch:restarted':
yield 'test watch restarted due to file change\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. -
cwd<string> Задает текущий рабочий каталог для использования тестовым исполнителем. Служит базовым путем для разрешения файлов, как если бы запуск тестов из командной строки выполнялся из этого каталога. По умолчанию:process.cwd(). -
files<Array> Массив со списком файлов для запуска. По умолчанию: как при запуске тестов из командной строки. -
forceExit<boolean> Настраивает тестовый исполнитель на завершение процесса после выполнения всех известных тестов, даже если в противном случае цикл событий оставался бы активным. По умолчанию:false. -
globPatterns<Array> Массив шаблонов glob для поиска файлов тестов. Эту опцию нельзя использовать вместе сfiles. По умолчанию: как при запуске тестов из командной строки. -
inspectPort<number> | <Function> Задает порт инспектора дочернего процесса тестов. Это может быть число или функция без аргументов, возвращающая число. Если указано nullish-значение, каждому процессу назначается собственный порт, начиная сprocess.debugPortосновного процесса и далее по возрастанию. Эта опция игнорируется, если для опцииisolationзадано значение'none', поскольку дочерние процессы не создаются. По умолчанию:undefined. -
isolation<string> Настраивает тип изоляции тестов. Если задано значение'process', каждый файл тестов запускается в отдельном дочернем процессе. Если задано значение'none', все файлы тестов запускаются в текущем процессе. По умолчанию:'process'. -
only<boolean> Если значение истинно, контекст тестирования запускает только тесты, для которых задана опцияonly -
setup<Function> Функция, принимающая экземплярTestsStreamи позволяющая настроить обработчики событий до запуска тестов. По умолчанию:undefined. -
execArgv<Array> Массив флагов командной строки, передаваемых исполняемому файлуnodeпри создании дочерних процессов. Эта опция не действует, еслиisolationимеет значение'none'. По умолчанию:[] -
argv<Array> Массив флагов командной строки, передаваемых каждому файлу тестов при создании дочерних процессов. Эта опция не действует, еслиisolationимеет значение'none'. По умолчанию:[]. -
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. -
rerunFailuresFilePath<string> Путь к файлу, в котором тестовый исполнитель будет хранить состояние тестов, чтобы при следующем запуске можно было повторно выполнить только неудачные тесты. Дополнительные сведения см. в разделе [Повторный запуск неудачных тестов][]. По умолчанию:undefined. -
coverage<boolean> Включает сбор покрытия кода. По умолчанию:false. -
coverageExcludeGlobs<string> | <Array> Исключает определенные файлы из отчета о покрытии кода с помощью шаблона glob, который может соответствовать как абсолютным, так и относительным путям к файлам. Это свойство применимо только в том случае, если дляcoverageзадано значениеtrue. Если заданы иcoverageExcludeGlobs, иcoverageIncludeGlobs, файлы должны соответствовать обоим критериям, чтобы попасть в отчет о покрытии. По умолчанию:undefined. -
coverageIncludeGlobs<string> | <Array> Включает определенные файлы в отчет о покрытии кода с помощью шаблона glob, который может соответствовать как абсолютным, так и относительным путям к файлам. Это свойство применимо только в том случае, если дляcoverageзадано значениеtrue. Если заданы иcoverageExcludeGlobs, иcoverageIncludeGlobs, файлы должны соответствовать обоим критериям, чтобы попасть в отчет о покрытии. По умолчанию:undefined. -
lineCoverage<number> Задает минимальный процент покрытых строк. Если покрытие кода не достигнет указанного порога, процесс завершится с кодом1. По умолчанию:0. -
branchCoverage<number> Задает минимальный процент покрытых ветвей. Если покрытие кода не достигнет указанного порога, процесс завершится с кодом1. По умолчанию:0. -
functionCoverage<number> Задает минимальный процент покрытых функций. Если покрытие кода не достигнет указанного порога, процесс завершится с кодом1. По умолчанию:0. -
env<Object> Задает переменные окружения, передаваемые процессу тестирования. Этот параметр несовместим сisolation='none'. Эти переменные переопределяют переменные основного процесса и не объединяются сprocess.env. По умолчанию:process.env.
-
- Возвращает: <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', () => {
// Some relevant assertions 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', () => {
// 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', () => {
// 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', () => {
// Some relevant assertion here
});
}); copy
assert
Объект, методы которого используются для настройки доступных проверок для объектов TestContext в текущем процессе. Методы из node:assert и функции тестирования снимков доступны по умолчанию.
Можно применить одну и ту же конфигурацию ко всем файлам, поместив общий код конфигурации в модуль, предварительно загруженный с помощью --require или --import.
assert.register(name, fn)
Определяет новую функцию проверки с указанными именем и функцией. Если функция проверки с таким именем уже существует, она перезаписывается.
snapshot
Объект, методы которого используются для настройки параметров снимков по умолчанию в текущем процессе. Можно применить одну и ту же конфигурацию ко всем файлам, поместив общий код конфигурации в модуль, предварительно загруженный с помощью --require или --import.
snapshot.setDefaultSnapshotSerializers(serializers)
-
serializers<Array> Массив синхронных функций, используемых в качестве сериализаторов по умолчанию для тестов снимков.
Эта функция используется для настройки механизма сериализации по умолчанию, применяемого средством запуска тестов. По умолчанию средство запуска тестов выполняет сериализацию, вызывая JSON.stringify(value, null, 2) для переданного значения. У JSON.stringify() есть ограничения, связанные с циклическими структурами и поддерживаемыми типами данных. Если требуется более надежный механизм сериализации, следует использовать эту функцию.
snapshot.setResolveSnapshotPath(fn)
-
fn<Function> Функция, используемая для определения расположения файла снимка. Функция получает путь к файлу теста в качестве единственного аргумента. Если тест не связан с файлом (например, в REPL), входное значение равно undefined.fn()должна возвращать строку, указывающую расположение файла снимка.
Эта функция используется для настройки расположения файла снимка, применяемого при тестировании снимков. По умолчанию имя файла снимка совпадает с именем файла точки входа, но имеет расширение файла .snapshot.
Класс: MockFunctionContext
Класс MockFunctionContext используется для проверки или изменения поведения моков, созданных с помощью API MockTracker.
ctx.calls
- Тип: <Array>
Геттер, возвращающий копию внутреннего массива, используемого для отслеживания вызовов мока. Каждая запись в массиве — это объект со следующими свойствами.
-
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()
Восстанавливает исходную реализацию модуля-мока.
Класс: MockPropertyContext
Класс MockPropertyContext используется для проверки или изменения поведения моков свойств, созданных с помощью API MockTracker.
ctx.accesses
- Тип: <Array>
Геттер, возвращающий копию внутреннего массива, используемого для отслеживания обращений (чтения/записи) к свойству-моку. Каждая запись в массиве — это объект со следующими свойствами:
ctx.accessCount()
- Возвращает: <integer> Количество обращений к свойству (чтений или записей).
Эта функция возвращает количество обращений к свойству. Она работает эффективнее, чем проверка ctx.accesses.length, поскольку ctx.accesses — это геттер, создающий копию внутреннего массива отслеживания обращений.
ctx.mockImplementation(value)
-
value<any> Новое значение, которое будет установлено в качестве значения свойства-мока.
Эта функция используется для изменения значения, возвращаемого геттером свойства-мока.
ctx.mockImplementationOnce(value[, onAccess])
-
value<any> Значение, которое будет использоваться в качестве реализации мока для номера обращения, указанного вonAccess. -
onAccess<integer> Номер обращения, для которого будет использоватьсяvalue. Если указанное обращение уже состоялось, выбрасывается исключение. По умолчанию: номер следующего обращения.
Эта функция используется для изменения поведения существующего мока при одном обращении. После обращения onAccess мок вернется к поведению, которое использовалось бы, если бы mockImplementationOnce() не вызывалась.
В следующем примере создается функция-мок с помощью t.mock.property(), выполняется обращение к свойству-моку, реализация мока для следующего обращения заменяется другим значением, а затем восстанавливается предыдущее поведение.
test('changes a mock behavior once', (t) => {
const obj = { foo: 1 };
const prop = t.mock.property(obj, 'foo', 5);
assert.strictEqual(obj.foo, 5);
prop.mock.mockImplementationOnce(25);
assert.strictEqual(obj.foo, 25);
assert.strictEqual(obj.foo, 5);
}); copy Предостережение
Для согласованности с остальной частью API моков эта функция считает обращениями как чтение, так и запись свойства. Если запись в свойство происходит с тем же индексом обращения, значение «once» будет использовано операцией записи, а значение свойства-мока изменится на это значение «once». Это может привести к неожиданному поведению, если предполагается использовать значение «once» только для операции чтения.
ctx.resetAccesses()
Сбрасывает историю обращений к свойству-моку.
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,object[methodName]рассматривается как геттер. Этот параметр нельзя использовать вместе с параметромsetter. По умолчанию: false. -
setter<boolean> Если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> | <URL> Строка, идентифицирующая модуль для имитации. -
options<Object> Необязательные параметры конфигурации модуля-имитации. Поддерживаются следующие свойства:-
cache<boolean> Еслиfalse, каждый вызовrequire()илиimport()создаёт новый модуль-имитацию. Еслиtrue, последующие вызовы возвращают ту же имитацию модуля, которая помещается в кэш CommonJS. По умолчанию: false. -
defaultExport<any> Необязательное значение, используемое в качестве экспорта по умолчанию имитируемого модуля. Если это значение не указано, имитации ESM не содержат экспорта по умолчанию. Если имитируется модуль CommonJS или встроенный модуль, это значение используется как значениеmodule.exports. Если это значение не указано, в имитациях CJS и встроенных модулей в качестве значенияmodule.exportsиспользуется пустой объект. -
namedExports<Object> Необязательный объект, ключи и значения которого используются для создания именованных экспортов имитируемого модуля. Если имитируется модуль CommonJS или встроенный модуль, эти значения копируются вmodule.exports. Поэтому, если имитация создана с именованными экспортами и экспортом по умолчанию, не являющимся объектом, при использовании её как модуля CJS или встроенного модуля будет выброшено исключение.
-
- Возвращает: <MockModuleContext> Объект, который можно использовать для управления имитацией.
Эта функция используется для имитации экспортов модулей ECMAScript, модулей CommonJS, модулей JSON и встроенных модулей Node.js. Ссылки на исходный модуль, полученные до создания имитации, не затрагиваются. Чтобы включить имитацию модулей, Node.js необходимо запустить с флагом командной строки --experimental-test-module-mocks.
В следующем примере показано, как создаётся имитация модуля.
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.property(object, propertyName[, value])
-
object<Object> Объект, значение свойства которого имитируется. -
propertyName<string> | <symbol> Идентификатор имитируемого свойства объектаobject. -
value<any> Необязательное значение, используемое в качестве имитируемого значения дляobject[propertyName]. По умолчанию: исходное значение свойства. - Возвращает: <Proxy> Прокси для имитируемого объекта. Имитируемый объект содержит специальное свойство
mock, являющееся экземпляромMockPropertyContext, которое можно использовать для проверки и изменения поведения имитируемого свойства.
Создаёт имитацию значения свойства объекта. Это позволяет отслеживать и контролировать доступ к определённому свойству, в том числе количество его чтений (геттер) и записей (сеттер), а также восстанавливать исходное значение после имитации.
test('mocks a property value', (t) => {
const obj = { foo: 42 };
const prop = t.mock.property(obj, 'foo', 100);
assert.strictEqual(obj.foo, 100);
assert.strictEqual(prop.mock.accessCount(), 1);
assert.strictEqual(prop.mock.accesses[0].type, 'get');
assert.strictEqual(prop.mock.accesses[0].value, 100);
obj.foo = 200;
assert.strictEqual(prop.mock.accessCount(), 2);
assert.strictEqual(prop.mock.accesses[1].type, 'set');
assert.strictEqual(prop.mock.accesses[1].value, 200);
prop.mock.restore();
assert.strictEqual(obj.foo, 42);
}); 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);
});Совместная работа дат и таймеров
Объекты дат и таймеров зависят друг от друга. Если использовать 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> Массив строк с номерами строк и количеством случаев их покрытия.
-
-
thresholds<Object> Объект, содержащий сведения о том, достигнут ли порог для каждого типа покрытия. -
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> Уровень вложенности теста. -
type<string> Тип теста. Это либо'suite', либо'test'.
-
Событие генерируется, когда тест извлекается из очереди, непосредственно перед его выполнением. Не гарантируется, что это событие будет сгенерировано в том же порядке, в котором определены тесты. Соответствующее событие, упорядоченное по объявлению, — '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> Уровень вложенности теста. -
level<string> Уровень серьёзности диагностического сообщения. Возможные значения:-
'info': информационные сообщения. -
'warn': предупреждения. -
'error': ошибки.
-
-
Событие генерируется при вызове 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> Уровень вложенности теста. -
type<string> Тип теста. Это либо'suite', либо'test'.
-
Событие генерируется, когда тест ставится в очередь на выполнение.
Событие: 'test:fail'
-
data<Object>-
column<number> | <undefined> Номер столбца, в котором определён тест, илиundefined, если тест был запущен через REPL. -
details<Object> Дополнительные метаданные выполнения.-
duration_ms<number> Продолжительность теста в миллисекундах. -
error<Error> Ошибка, оборачивающая ошибку, выброшенную тестом.-
cause<Error> Фактическая ошибка, выброшенная тестом.
-
-
type<string> | <undefined> Тип теста, указывающий, является ли он набором тестов. -
attempt<number> | <undefined> Номер попытки запуска теста; присутствует только при использовании флага--test-rerun-failures.
-
-
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> Тип теста, указывающий, является ли он набором тестов. -
attempt<number> | <undefined> Номер попытки запуска теста; присутствует только при использовании флага--test-rerun-failures. -
passed_on_attempt<number> | <undefined> Номер попытки, в которой тест завершился успешно; присутствует только при использовании флага--test-rerun-failures.
-
-
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:summary'
-
data<Object>-
counts<Object> Объект, содержащий количество тестов с различными результатами.-
cancelled<number> Общее количество отменённых тестов. -
failed<number> Общее количество не пройденных тестов. -
passed<number> Общее количество успешно пройденных тестов. -
skipped<number> Общее количество пропущенных тестов. -
suites<number> Общее количество запущенных наборов тестов. -
tests<number> Общее количество запущенных тестов, без учёта наборов тестов. -
todo<number> Общее количество тестов TODO. -
topLevel<number> Общее количество тестов и наборов тестов верхнего уровня.
-
-
duration_ms<number> Длительность запуска тестов в миллисекундах. -
file<string> | <undefined> Путь к файлу теста, для которого создана сводка. Если сводка относится к нескольким файлам, значение равноundefined. -
success<boolean> Указывает, считается ли запуск тестов успешным. Если возникает ошибка, например тест не пройден или пороговое значение покрытия не достигнуто, этому значению присваиваетсяfalse.
-
Создаётся по завершении запуска тестов. Это событие содержит показатели завершённого запуска тестов и позволяет определить, завершился ли запуск успешно. Если используется изоляция тестов на уровне процесса, для каждого файла теста создаётся событие 'test:summary', а также итоговая сводка.
Событие: 'test:watch:drained'
Создаётся, когда в режиме наблюдения больше не осталось тестов в очереди на выполнение.
Событие: 'test:watch:restarted'
Создаётся, когда в режиме наблюдения один или несколько тестов перезапускаются из-за изменения файла.
Class: 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) => {
// 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}`));
// 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) => {
// Some relevant assertion here
},
);
}); copy
context.assert
Объект, содержащий методы проверки утверждений, привязанные к context. Здесь доступны функции верхнего уровня из модуля node:assert для создания планов тестирования.
test('test', (t) => {
t.plan(1);
t.assert.strictEqual(true, true);
}); copy
context.assert.fileSnapshot(value, path[, options])
-
value<any> Значение для сериализации в строку. Если Node.js запущен с флагом--test-update-snapshots, сериализованное значение записывается вpath. В противном случае сериализованное значение сравнивается с содержимым существующего файла снимка. -
path<string> Файл, в который записывается сериализованное значениеvalue. -
options<Object> Необязательные параметры конфигурации. Поддерживаются следующие свойства:-
serializers<Array> Массив синхронных функций, используемых для сериализацииvalueв строку.valueпередаётся в качестве единственного аргумента первой функции-сериализатора. Возвращаемое значение каждого сериализатора передаётся следующему сериализатору в качестве входных данных. После выполнения всех сериализаторов полученное значение преобразуется в строку. По умолчанию: если сериализаторы не указаны, используются сериализаторы средства запуска тестов по умолчанию.
-
Эта функция сериализует value и записывает его в файл, указанный в path.
test('snapshot test with default serialization', (t) => {
t.assert.fileSnapshot({ value1: 1, value2: 2 }, './snapshots/snapshot.json');
}); copy Эта функция отличается от context.assert.snapshot() следующим:
- Путь к файлу снимка явно задаётся пользователем.
- Каждый файл снимка содержит только одно значение снимка.
- Средство запуска тестов не выполняет дополнительное экранирование.
Эти различия позволяют лучше поддерживать в файлах снимков такие возможности, как подсветка синтаксиса.
context.assert.snapshot(value[, options])
-
value<any> Значение для сериализации в строку. Если Node.js запущен с флагом--test-update-snapshots, сериализованное значение записывается в файл снимка. В противном случае сериализованное значение сравнивается с соответствующим значением в существующем файле снимка. -
options<Object> Необязательные параметры конфигурации. Поддерживаются следующие свойства:-
serializers<Array> Массив синхронных функций, используемых для сериализацииvalueв строку.valueпередаётся в качестве единственного аргумента первой функции-сериализатора. Возвращаемое значение каждого сериализатора передаётся следующему сериализатору в качестве входных данных. После выполнения всех сериализаторов полученное значение преобразуется в строку. По умолчанию: если сериализаторы не указаны, используются сериализаторы средства запуска тестов по умолчанию.
-
Эта функция реализует проверки для тестирования снимков.
test('snapshot test with default serialization', (t) => {
t.assert.snapshot({ value1: 1, value2: 2 });
});
test('snapshot test with custom serialization', (t) => {
t.assert.snapshot({ value3: 3, value4: 4 }, {
serializers: [(value) => JSON.stringify(value)],
});
}); copy
context.diagnostic(message)
-
message<string> Сообщение для вывода.
Эта функция используется для вывода диагностических данных. Любая диагностическая информация включается в конец результатов теста. Эта функция не возвращает значение.
test('top level test', (t) => {
t.diagnostic('A diagnostic message');
}); copy
context.filePath
Абсолютный путь к файлу теста, создавшему текущий тест. Если файл теста импортирует дополнительные модули, создающие тесты, импортированные тесты будут возвращать путь к корневому файлу теста.
context.fullName
Имя теста и каждого из его предков, разделённые >.
context.name
Имя теста.
context.passed
- Тип: <boolean>
falseдо выполнения теста, например в хукеbeforeEach.
Указывает, успешно ли выполнен тест.
context.error
Причина сбоя теста/варианта; обёрнута и доступна через context.error.cause.
context.plan(count[,options])
-
count<number> Количество проверок и под-тестов, которые должны быть запущены. -
options<Object> Дополнительные параметры плана.-
wait<boolean> | <number> Время ожидания плана:- Если
true, план будет бесконечно ждать выполнения всех проверок и под-тестов. - Если
false, план немедленно выполняет проверку после завершения тестовой функции, не дожидаясь выполнения ожидающих проверок или под-тестов. Проверки или под-тесты, завершившиеся после этой проверки, не будут учтены в плане. - Если указано число, оно задаёт максимальное время ожидания в миллисекундах, по истечении которого ожидание сопоставления ожидаемых проверок и под-тестов завершается по тайм-ауту. Если время ожидания истечёт, тест завершится с ошибкой. По умолчанию:
false.
- Если
-
Эта функция используется для задания количества проверок и под-тестов, которые должны быть запущены в тесте. Если количество запущенных проверок и под-тестов не совпадает с ожидаемым, тест завершится с ошибкой.
Примечание: чтобы проверки отслеживались, необходимо использовать
t.assertвместо непосредственного вызова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 При использовании параметра wait можно управлять временем ожидания тестом ожидаемых проверок. Например, если задать максимальное время ожидания, тест будет ждать завершения асинхронных проверок в течение указанного периода:
test('plan with wait: 2000 waits for async assertions', (t) => {
t.plan(1, { wait: 2000 }); // Waits for up to 2 seconds for the assertion to complete.
const asyncActivity = () => {
setTimeout(() => {
t.assert.ok(true, 'Async assertion completed within the wait time');
}, 1000); // Completes after 1 second, within the 2-second wait time.
};
asyncActivity(); // The test will pass because the assertion is completed in time.
}); copy Примечание: если задан тайм-аут wait, его отсчёт начинается только после завершения выполнения тестовой функции.
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
context.waitFor(condition[, options])
-
condition<Function> | <AsyncFunction> Функция проверки, которая периодически вызывается до успешного завершения или истечения заданного тайм-аута опроса. Завершение считается успешным, если функция не выбрасывает исключение и не отклоняет промис. Эта функция не принимает аргументов и может возвращать любое значение. -
options<Object> Необязательный объект конфигурации операции опроса. Поддерживаются следующие свойства: - Возвращает: <Promise> Выполняется со значением, возвращённым
condition.
Этот метод опрашивает функцию condition до тех пор, пока она не завершится успешно или не истечёт время ожидания операции.
Класс: SuiteContext
Экземпляр SuiteContext передаётся каждой функции набора тестов для взаимодействия с программой запуска тестов. Однако конструктор SuiteContext не является частью API.
context.filePath
Абсолютный путь к файлу теста, создавшему текущий набор тестов. Если файл теста импортирует дополнительные модули, создающие наборы тестов, импортированные наборы будут возвращать путь к корневому файлу теста.
context.fullName
Имя набора тестов и каждого из его предков, разделённые >.
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-v24.x/docs/api/test.html