Skip to content

Запуск тестов

[История]

ВерсияИзменения
v20.0.0Запуск тестов теперь стабилен.
v18.0.0, v16.17.0Добавлено в: v18.0.0, v16.17.0

[Стабильность: 2 - Стабильно]

Стабильность: 2 Стабильность: 2 - Стабильно

Исходный код: lib/test.js

Модуль node:test упрощает создание тестов JavaScript. Чтобы получить к нему доступ:

js
import test from 'node:test';
js
const test = require('node:test');

Этот модуль доступен только по схеме node:.

Тесты, созданные с помощью модуля test, состоят из одной функции, которая обрабатывается одним из трех способов:

В следующем примере показано, как пишутся тесты с использованием модуля test.

js
test('синхронный проходящий тест', (t) => {
  // Этот тест проходит, потому что он не выбрасывает исключение.
  assert.strictEqual(1, 1);
});

test('синхронный непроходящий тест', (t) => {
  // Этот тест не проходит, потому что он выбрасывает исключение.
  assert.strictEqual(1, 2);
});

test('асинхронный проходящий тест', async (t) => {
  // Этот тест проходит, потому что Promise, возвращенный асинхронной
  // функцией, выполнен и не отклонен.
  assert.strictEqual(1, 1);
});

test('асинхронный непроходящий тест', async (t) => {
  // Этот тест не проходит, потому что Promise, возвращенный асинхронной
  // функцией, отклонен.
  assert.strictEqual(1, 2);
});

test('непроходящий тест с использованием Promises', (t) => {
  // Promises также можно использовать напрямую.
  return new Promise((resolve, reject) => {
    setImmediate(() => {
      reject(new Error('это приведет к сбою теста'));
    });
  });
});

test('проходящий тест с обратным вызовом', (t, done) => {
  // done() - это функция обратного вызова. Когда выполняется setImmediate(), он вызывает
  // done() без аргументов.
  setImmediate(done);
});

test('непроходящий тест с обратным вызовом', (t, done) => {
  // Когда выполняется setImmediate(), done() вызывается с объектом Error и
  // тест не проходит.
  setImmediate(() => {
    done(new Error('сбой обратного вызова'));
  });
});

Если какие-либо тесты не пройдены, коду выхода процесса присваивается значение 1.

Подтесты

Метод test() контекста теста позволяет создавать подтесты. Он позволяет структурировать ваши тесты иерархически, где вы можете создавать вложенные тесты внутри большего теста. Этот метод ведет себя идентично функции test() верхнего уровня. Следующий пример демонстрирует создание теста верхнего уровня с двумя подтестами.

js
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);
  });
});

В этом примере await используется для обеспечения завершения обоих подтестов. Это необходимо, потому что тесты не ждут завершения своих подтестов, в отличие от тестов, созданных внутри наборов. Любые незавершенные подтесты при завершении их родительского элемента отменяются и рассматриваются как сбои. Любые сбои подтестов приводят к сбою родительского теста.

Пропуск тестов

Отдельные тесты можно пропустить, передав параметр skip в тест или вызвав метод skip() контекста теста, как показано в следующем примере.

js
// Используется параметр skip, но сообщение не предоставлено.
test('skip option', { skip: true }, (t) => {
  // Этот код никогда не выполняется.
});

// Используется параметр skip, и предоставлено сообщение.
test('skip option with message', { skip: 'this is skipped' }, (t) => {
  // Этот код никогда не выполняется.
});

test('skip() method', (t) => {
  // Обязательно вернитесь сюда, если тест содержит дополнительную логику.
  t.skip();
});

test('skip() method with message', (t) => {
  // Обязательно вернитесь сюда, если тест содержит дополнительную логику.
  t.skip('this is skipped');
});

Тесты TODO

Отдельные тесты можно пометить как нестабильные или неполные, передав параметр todo в тест или вызвав метод todo() контекста теста, как показано в следующем примере. Эти тесты представляют собой ожидающую реализацию или ошибку, которую необходимо исправить. Тесты TODO выполняются, но не рассматриваются как сбои тестов и, следовательно, не влияют на код завершения процесса. Если тест помечен как TODO и пропущен, параметр TODO игнорируется.

js
// Используется параметр todo, но сообщение не предоставлено.
test('todo option', { todo: true }, (t) => {
  // Этот код выполняется, но не рассматривается как сбой.
  throw new Error('this does not fail the test');
});

// Используется параметр todo, и предоставлено сообщение.
test('todo option with message', { todo: 'this is a todo test' }, (t) => {
  // Этот код выполняется.
});

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');
});

Псевдонимы describe() и it()

Наборы и тесты также можно писать с помощью функций describe() и it(). describe() является псевдонимом для suite(), а it() является псевдонимом для test().

js
describe('Что-то', () => {
  it('должно работать', () => {
    assert.strictEqual(1, 1);
  });

  it('должно быть хорошо', () => {
    assert.strictEqual(2, 2);
  });

  describe('вложенная штука', () => {
    it('должно работать', () => {
      assert.strictEqual(3, 3);
    });
  });
});

describe() и it() импортируются из модуля node:test.

js
import { describe, it } from 'node:test';
js
const { describe, it } = require('node:test');

only тесты

Если Node.js запускается с опцией командной строки --test-only или изоляция тестов отключена, можно пропустить все тесты, за исключением выбранного подмножества, передав опцию only тестам, которые должны быть запущены. Когда для теста установлена опция only, все подтесты также запускаются. Если для набора установлена опция only, все тесты в наборе запускаются, если только у него нет потомков с установленной опцией only, в этом случае запускаются только эти тесты.

При использовании подтестов внутри test()/it() необходимо пометить все родительские тесты опцией only, чтобы запустить только выбранное подмножество тестов.

Метод runOnly() контекста теста можно использовать для реализации того же поведения на уровне подтестов. Тесты, которые не выполняются, исключаются из выходных данных средства запуска тестов.

js
// Предположим, что Node.js запущен с опцией командной строки --test-only.
// Установлена опция 'only' набора, поэтому эти тесты запускаются.
test('этот тест выполняется', { only: true }, async (t) => {
  // Внутри этого теста все подтесты выполняются по умолчанию.
  await t.test('запуск подтеста');

  // Контекст теста можно обновить, чтобы запускать подтесты с опцией 'only'.
  t.runOnly(true);
  await t.test('этот подтест теперь пропущен');
  await t.test('этот подтест выполняется', { only: true });

  // Переключите контекст обратно для выполнения всех тестов.
  t.runOnly(false);
  await t.test('этот подтест теперь выполняется');

  // Явно не запускайте эти тесты.
  await t.test('пропущенный подтест 3', { only: false });
  await t.test('пропущенный подтест 4', { skip: true });
});

// Опция 'only' не установлена, поэтому этот тест пропускается.
test('этот тест не выполняется', () => {
  // Этот код не выполняется.
  throw new Error('fail');
});

describe('набор', () => {
  // Установлена опция 'only', поэтому этот тест выполняется.
  it('этот тест выполняется', { only: true }, () => {
    // Этот код выполняется.
  });

  it('этот тест не выполняется', () => {
    // Этот код не выполняется.
    throw new Error('fail');
  });
});

describe.only('набор', () => {
  // Установлена опция 'only', поэтому этот тест выполняется.
  it('этот тест выполняется', () => {
    // Этот код выполняется.
  });

  it('этот тест выполняется', () => {
    // Этот код выполняется.
  });
});

Фильтрация тестов по имени

Опция командной строки --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" и т.д.).

js
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');
});

Шаблоны имен тестов также могут быть указаны с использованием литералов регулярных выражений. Это позволяет использовать флаги регулярных выражений. В предыдущем примере запуск Node.js с --test-name-pattern="/test [4-5]/i" (или --test-skip-pattern="/test [4-5]/i") будет соответствовать Test 4 и Test 5, потому что шаблон нечувствителен к регистру.

Чтобы сопоставить один тест с шаблоном, вы можете добавить к нему префикс в виде всех имен его родительских тестов, разделенных пробелом, чтобы обеспечить его уникальность. Например, учитывая следующий файл тестов:

js
describe('test 1', (t) => {
  it('some test');
});

describe('test 2', (t) => {
  it('some test');
});

Запуск 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>.

js
test('тест, создающий асинхронную активность', (t) => {
  setImmediate(() => {
    t.test('подтест, который был создан слишком поздно', (t) => {
      throw new Error('error1');
    });
  });

  setImmediate(() => {
    throw new Error('error2');
  });

  // Тест завершается после этой строки.
});

Режим наблюдения

Добавлено в: v19.2.0, v18.13.0

[Stable: 1 - Experimental]

Stable: 1 Стабильность: 1 - Экспериментально

Тестовый исполнитель Node.js поддерживает запуск в режиме наблюдения, передавая флаг --watch:

bash
node --test --watch

В режиме наблюдения тестовый исполнитель будет отслеживать изменения в тестовых файлах и их зависимостях. При обнаружении изменения тестовый исполнитель перезапустит тесты, затронутые этим изменением. Тестовый исполнитель будет продолжать работать до завершения процесса.

Запуск тестов из командной строки

Тестовый исполнитель Node.js можно вызвать из командной строки, передав флаг --test:

bash
node --test

По умолчанию 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}

При предоставлении --experimental-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}

В качестве альтернативы, один или несколько шаблонов glob могут быть предоставлены в качестве последнего аргумента(ов) команде Node.js, как показано ниже. Шаблоны Glob следуют поведению glob(7). Шаблоны glob должны быть заключены в двойные кавычки в командной строке, чтобы предотвратить расширение оболочки, что может снизить переносимость между системами.

bash
node --test "**/*.test.js" "**/*.spec.js"

Соответствующие файлы выполняются как тестовые файлы. Дополнительную информацию о выполнении тестовых файлов можно найти в разделе модель выполнения тестового исполнителя.

Модель выполнения тестового запуска

Когда включена изоляция тестов на уровне процесса, каждый подходящий тестовый файл выполняется в отдельном дочернем процессе. Максимальное количество дочерних процессов, работающих одновременно, контролируется флагом --test-concurrency. Если дочерний процесс завершается с кодом выхода 0, тест считается пройденным. В противном случае тест считается неудачным. Тестовые файлы должны быть исполняемыми Node.js, но не обязаны использовать модуль node:test внутри.

Каждый тестовый файл выполняется как обычный скрипт. То есть, если сам тестовый файл использует node:test для определения тестов, все эти тесты будут выполнены в одном потоке приложения, независимо от значения параметра concurrency функции test().

Когда изоляция тестов на уровне процесса отключена, каждый подходящий тестовый файл импортируется в процесс тестового запуска. После загрузки всех тестовых файлов тесты верхнего уровня выполняются с параллельностью, равной единице. Поскольку все тестовые файлы запускаются в одном контексте, тесты могут взаимодействовать друг с другом способами, которые невозможны при включенной изоляции. Например, если тест зависит от глобального состояния, это состояние может быть изменено тестом, происходящим из другого файла.

Сбор покрытия кода

[Stable: 1 - Experimental]

Stable: 1 Стабильность: 1 - Экспериментальная

Когда Node.js запускается с флагом командной строки --experimental-test-coverage, собирается покрытие кода и статистика сообщается после завершения всех тестов. Если переменная окружения NODE_V8_COVERAGE используется для указания каталога покрытия кода, сгенерированные файлы покрытия V8 записываются в этот каталог. Модули ядра Node.js и файлы в каталогах node_modules/ по умолчанию не включаются в отчет о покрытии. Однако их можно явно включить с помощью флага --test-coverage-include. По умолчанию все подходящие тестовые файлы исключаются из отчета о покрытии. Исключения можно переопределить с помощью флага --test-coverage-exclude. Если покрытие включено, отчет о покрытии отправляется любым репортерам тестов через событие 'test:coverage'.

Покрытие можно отключить на серии строк, используя следующий синтаксис комментариев:

js
/* node:coverage disable */
if (anAlwaysFalseCondition) {
  // Код в этой ветви никогда не будет выполнен, но строки игнорируются для
  // целей покрытия. Все строки после комментария 'disable' игнорируются
  // до тех пор, пока не встретится соответствующий комментарий 'enable'.
  console.log('this is never executed');
}
/* node:coverage enable */

Покрытие также можно отключить для указанного количества строк. После указанного количества строк покрытие будет автоматически включено повторно. Если количество строк явно не указано, игнорируется одна строка.

js
/* 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');
}

Репортеры покрытия

Репортеры tap и spec будут печатать сводку статистики покрытия. Существует также репортер lcov, который будет генерировать файл lcov, который можно использовать в качестве подробного отчета о покрытии.

bash
node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info
  • Этот репортер не сообщает о результатах тестов.
  • Этот репортер в идеале следует использовать вместе с другим репортером.

Мокирование

Модуль node:test поддерживает мокирование во время тестирования через объект верхнего уровня mock. В следующем примере создается шпион за функцией, которая складывает два числа. Затем шпион используется для подтверждения того, что функция была вызвана должным образом.

js
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();
});
js
'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. Преимущество мокирования через контекст теста заключается в том, что средство запуска тестов автоматически восстановит всю мокированную функциональность после завершения теста.

js
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);
});

Таймеры

Имитация таймеров - это метод, обычно используемый в тестировании программного обеспечения для имитации и управления поведением таймеров, таких как setInterval и setTimeout, без фактического ожидания указанных временных интервалов.

Полный список методов и функций см. в классе MockTimers.

Это позволяет разработчикам писать более надежные и предсказуемые тесты для функциональности, зависящей от времени.

В приведенном ниже примере показано, как имитировать setTimeout. Использование .enable({ apis: ['setTimeout'] }); позволит имитировать функции setTimeout в модулях node:timers и node:timers/promises, а также из глобального контекста Node.js.

Примечание: Деструктурирование функций, таких как import { setTimeout } from 'node:timers', в настоящее время не поддерживается этим API.

js
import assert from 'node:assert';
import { mock, test } from 'node:test';

test('имитирует setTimeout для синхронного выполнения без необходимости фактического ожидания', () => {
  const fn = mock.fn();

  // При необходимости выберите, что имитировать
  mock.timers.enable({ apis: ['setTimeout'] });
  setTimeout(fn, 9999);
  assert.strictEqual(fn.mock.callCount(), 0);

  // Продвинуться во времени
  mock.timers.tick(9999);
  assert.strictEqual(fn.mock.callCount(), 1);

  // Сбросить глобально отслеживаемые моки.
  mock.timers.reset();

  // Если вы вызываете reset mock instance, он также сбросит timers instance
  mock.reset();
});
js
const assert = require('node:assert');
const { mock, test } = require('node:test');

test('имитирует setTimeout для синхронного выполнения без необходимости фактического ожидания', () => {
  const fn = mock.fn();

  // При необходимости выберите, что имитировать
  mock.timers.enable({ apis: ['setTimeout'] });
  setTimeout(fn, 9999);
  assert.strictEqual(fn.mock.callCount(), 0);

  // Продвинуться во времени
  mock.timers.tick(9999);
  assert.strictEqual(fn.mock.callCount(), 1);

  // Сбросить глобально отслеживаемые моки.
  mock.timers.reset();

  // Если вы вызываете reset mock instance, он также сбросит timers instance
  mock.reset();
});

Та же функциональность имитации также предоставляется в свойстве mock объекта TestContext каждого теста. Преимущество имитации через контекст теста заключается в том, что средство запуска тестов автоматически восстановит всю функциональность имитируемых таймеров после завершения теста.

js
import assert from 'node:assert';
import { test } from 'node:test';

test('имитирует setTimeout для синхронного выполнения без необходимости фактического ожидания', (context) => {
  const fn = context.mock.fn();

  // При необходимости выберите, что имитировать
  context.mock.timers.enable({ apis: ['setTimeout'] });
  setTimeout(fn, 9999);
  assert.strictEqual(fn.mock.callCount(), 0);

  // Продвинуться во времени
  context.mock.timers.tick(9999);
  assert.strictEqual(fn.mock.callCount(), 1);
});
js
const assert = require('node:assert');
const { test } = require('node:test');

test('имитирует setTimeout для синхронного выполнения без необходимости фактического ожидания', (context) => {
  const fn = context.mock.fn();

  // При необходимости выберите, что имитировать
  context.mock.timers.enable({ apis: ['setTimeout'] });
  setTimeout(fn, 9999);
  assert.strictEqual(fn.mock.callCount(), 0);

  // Продвинуться во времени
  context.mock.timers.tick(9999);
  assert.strictEqual(fn.mock.callCount(), 1);
});

Даты

API mock-таймеров также позволяет мокать объект Date. Это полезная функция для тестирования функциональности, зависящей от времени, или для имитации внутренних календарных функций, таких как Date.now().

Реализация дат также является частью класса MockTimers. Обратитесь к нему для получения полного списка методов и функций.

Примечание: Даты и таймеры зависимы, когда мокаются вместе. Это означает, что если у вас замоканы и Date, и setTimeout, продвижение времени также продвинет и замоканную дату, поскольку они имитируют единые внутренние часы.

В приведенном ниже примере показано, как замокать объект Date и получить текущее значение Date.now().

js
import assert from 'node:assert';
import { test } from 'node:test';

test('мокает объект Date', (context) => {
  // Опционально выберите, что мокать
  context.mock.timers.enable({ apis: ['Date'] });
  // Если не указано, начальная дата будет основана на 0 в эпохе UNIX
  assert.strictEqual(Date.now(), 0);

  // Продвижение во времени также продвинет дату
  context.mock.timers.tick(9999);
  assert.strictEqual(Date.now(), 9999);
});
js
const assert = require('node:assert');
const { test } = require('node:test');

test('мокает объект Date', (context) => {
  // Опционально выберите, что мокать
  context.mock.timers.enable({ apis: ['Date'] });
  // Если не указано, начальная дата будет основана на 0 в эпохе UNIX
  assert.strictEqual(Date.now(), 0);

  // Продвижение во времени также продвинет дату
  context.mock.timers.tick(9999);
  assert.strictEqual(Date.now(), 9999);
});

Если начальная эпоха не установлена, начальная дата будет основана на 0 в эпохе Unix. Это 1 января 1970 года, 00:00:00 UTC. Вы можете установить начальную дату, передав свойство now методу .enable(). Это значение будет использоваться в качестве начальной даты для замоканного объекта Date. Оно может быть как положительным целым числом, так и другим объектом Date.

js
import assert from 'node:assert';
import { test } from 'node:test';

test('мокает объект Date с начальным временем', (context) => {
  // Опционально выберите, что мокать
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Продвижение во времени также продвинет дату
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 300);
});
js
const assert = require('node:assert');
const { test } = require('node:test');

test('мокает объект Date с начальным временем', (context) => {
  // Опционально выберите, что мокать
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Продвижение во времени также продвинет дату
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 300);
});

Вы можете использовать метод .setTime() для ручного перемещения замоканной даты на другое время. Этот метод принимает только положительное целое число.

Примечание: Этот метод выполнит любые замоканные таймеры, которые были в прошлом относительно нового времени.

В приведенном ниже примере мы устанавливаем новое время для замоканной даты.

js
import assert from 'node:assert';
import { test } from 'node:test';

test('устанавливает время объекта Date', (context) => {
  // Опционально выберите, что мокать
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Продвижение во времени также продвинет дату
  context.mock.timers.setTime(1000);
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 1200);
});
js
const assert = require('node:assert');
const { test } = require('node:test');

test('устанавливает время объекта Date', (context) => {
  // Опционально выберите, что мокать
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Продвижение во времени также продвинет дату
  context.mock.timers.setTime(1000);
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 1200);
});

Если у вас есть какой-либо таймер, настроенный на запуск в прошлом, он будет выполнен, как если бы был вызван метод .tick(). Это полезно, если вы хотите протестировать функциональность, зависящую от времени, которая уже в прошлом.

js
import assert from 'node:assert';
import { test } from 'node:test';

test('запускает таймеры, когда setTime проходит тики', (context) => {
  // Опционально выберите, что мокать
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const fn = context.mock.fn();
  setTimeout(fn, 1000);

  context.mock.timers.setTime(800);
  // Таймер не выполняется, так как время еще не достигнуто
  assert.strictEqual(fn.mock.callCount(), 0);
  assert.strictEqual(Date.now(), 800);

  context.mock.timers.setTime(1200);
  // Таймер выполняется, так как время теперь достигнуто
  assert.strictEqual(fn.mock.callCount(), 1);
  assert.strictEqual(Date.now(), 1200);
});
js
const assert = require('node:assert');
const { test } = require('node:test');

test('запускает таймеры, когда setTime проходит тики', (context) => {
  // Опционально выберите, что мокать
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const fn = context.mock.fn();
  setTimeout(fn, 1000);

  context.mock.timers.setTime(800);
  // Таймер не выполняется, так как время еще не достигнуто
  assert.strictEqual(fn.mock.callCount(), 0);
  assert.strictEqual(Date.now(), 800);

  context.mock.timers.setTime(1200);
  // Таймер выполняется, так как время теперь достигнуто
  assert.strictEqual(fn.mock.callCount(), 1);
  assert.strictEqual(Date.now(), 1200);
});

Использование .runAll() выполнит все таймеры, которые в данный момент находятся в очереди. Это также продвинет замоканную дату до времени последнего выполненного таймера, как если бы время прошло.

js
import assert from 'node:assert';
import { test } from 'node:test';

test('запускает таймеры, когда setTime проходит тики', (context) => {
  // Опционально выберите, что мокать
  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();
  // Все таймеры выполняются, так как время теперь достигнуто
  assert.strictEqual(fn.mock.callCount(), 3);
  assert.strictEqual(Date.now(), 3000);
});
js
const assert = require('node:assert');
const { test } = require('node:test');

test('запускает таймеры, когда setTime проходит тики', (context) => {
  // Опционально выберите, что мокать
  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();
  // Все таймеры выполняются, так как время теперь достигнуто
  assert.strictEqual(fn.mock.callCount(), 3);
  assert.strictEqual(Date.now(), 3000);
});

Snapshot testing

[Stable: 1 - Experimental]

Stable: 1 Stability: 1.0 - Ранняя разработка

Снапшот-тесты позволяют сериализовать произвольные значения в строковые значения и сравнивать их с набором известных хороших значений. Известные хорошие значения называются снапшотами и хранятся в файле снапшотов. Файлы снапшотов управляются тестовым исполнителем, но разработаны таким образом, чтобы быть читаемыми человеком, чтобы помочь в отладке. Рекомендуется сохранять файлы снапшотов в системе контроля версий вместе с вашими тестовыми файлами.

Файлы снапшотов генерируются путем запуска Node.js с флагом командной строки --test-update-snapshots. Для каждого тестового файла генерируется отдельный файл снапшотов. По умолчанию файл снапшотов имеет то же имя, что и тестовый файл, с расширением .snapshot. Это поведение можно настроить с помощью функции snapshot.setResolveSnapshotPath(). Каждое утверждение снапшота соответствует экспорту в файле снапшотов.

Пример снапшот-теста показан ниже. При первом выполнении этого теста он завершится неудачей, потому что соответствующий файл снапшотов не существует.

js
// test.js
suite('suite of snapshot tests', () => {
  test('snapshot test', (t) => {
    t.assert.snapshot({ value1: 1, value2: 2 });
    t.assert.snapshot(5);
  });
});

Сгенерируйте файл снапшотов, запустив тестовый файл с --test-update-snapshots. Тест должен пройти, и в том же каталоге, что и тестовый файл, будет создан файл с именем test.js.snapshot. Содержимое файла снапшотов показано ниже. Каждый снапшот идентифицируется полным именем теста и счетчиком для различения снапшотов в одном и том же тесте.

js
exports[`suite of snapshot tests > snapshot test 1`] = `
{
  "value1": 1,
  "value2": 2
}
`;

exports[`suite of snapshot tests > snapshot test 2`] = `
5
`;

После создания файла снапшотов запустите тесты снова без флага --test-update-snapshots. Теперь тесты должны пройти.

Test reporters

[История]

ВерсияИзменения
v19.9.0, v18.17.0Репортёры теперь доступны в node:test/reporters.
v19.6.0, v18.15.0Добавлено в: v19.6.0, v18.15.0

Модуль 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:

js
import { tap, spec, dot, junit, lcov } from 'node:test/reporters';
js
const { tap, spec, dot, junit, lcov } = require('node:test/reporters');

Пользовательские репортёры

--test-reporter можно использовать для указания пути к пользовательскому репортёру. Пользовательский репортёр — это модуль, который экспортирует значение, принимаемое stream.compose. Репортёры должны преобразовывать события, генерируемые <TestsStream>.

Пример пользовательского репортёра, использующего <stream.Transform>:

js
import { Transform } from 'node:stream';

const customReporter = new Transform({
  writableObjectMode: true,
  transform(event, encoding, callback) {
    switch (event.type) {
      case 'test:dequeue':
        callback(null, `test ${event.data.name} dequeued`);
        break;
      case 'test:enqueue':
        callback(null, `test ${event.data.name} enqueued`);
        break;
      case 'test:watch:drained':
        callback(null, 'test watch queue drained');
        break;
      case 'test:start':
        callback(null, `test ${event.data.name} started`);
        break;
      case 'test:pass':
        callback(null, `test ${event.data.name} passed`);
        break;
      case 'test:fail':
        callback(null, `test ${event.data.name} failed`);
        break;
      case 'test:plan':
        callback(null, 'test plan');
        break;
      case 'test:diagnostic':
      case 'test:stderr':
      case 'test:stdout':
        callback(null, event.data.message);
        break;
      case 'test:coverage': {
        const { totalLineCount } = event.data.summary.totals;
        callback(null, `total line count: ${totalLineCount}\n`);
        break;
      }
    }
  },
});

export default customReporter;
js
const { Transform } = require('node:stream');

const customReporter = new Transform({
  writableObjectMode: true,
  transform(event, encoding, callback) {
    switch (event.type) {
      case 'test:dequeue':
        callback(null, `test ${event.data.name} dequeued`);
        break;
      case 'test:enqueue':
        callback(null, `test ${event.data.name} enqueued`);
        break;
      case 'test:watch:drained':
        callback(null, 'test watch queue drained');
        break;
      case 'test:start':
        callback(null, `test ${event.data.name} started`);
        break;
      case 'test:pass':
        callback(null, `test ${event.data.name} passed`);
        break;
      case 'test:fail':
        callback(null, `test ${event.data.name} failed`);
        break;
      case 'test:plan':
        callback(null, 'test plan');
        break;
      case 'test:diagnostic':
      case 'test:stderr':
      case 'test:stdout':
        callback(null, event.data.message);
        break;
      case 'test:coverage': {
        const { totalLineCount } = event.data.summary.totals;
        callback(null, `total line count: ${totalLineCount}\n`);
        break;
      }
    }
  },
});

module.exports = customReporter;

Пример пользовательского репортёра, использующего функцию-генератор:

js
export default async function * customReporter(source) {
  for await (const event of source) {
    switch (event.type) {
      case 'test:dequeue':
        yield `test ${event.data.name} dequeued\n`;
        break;
      case 'test:enqueue':
        yield `test ${event.data.name} enqueued\n`;
        break;
      case 'test:watch:drained':
        yield 'test watch queue drained\n';
        break;
      case 'test:start':
        yield `test ${event.data.name} started\n`;
        break;
      case 'test:pass':
        yield `test ${event.data.name} passed\n`;
        break;
      case 'test:fail':
        yield `test ${event.data.name} failed\n`;
        break;
      case 'test:plan':
        yield 'test plan\n';
        break;
      case 'test:diagnostic':
      case 'test:stderr':
      case 'test:stdout':
        yield `${event.data.message}\n`;
        break;
      case 'test:coverage': {
        const { totalLineCount } = event.data.summary.totals;
        yield `total line count: ${totalLineCount}\n`;
        break;
      }
    }
  }
}
js
module.exports = async function * customReporter(source) {
  for await (const event of source) {
    switch (event.type) {
      case 'test:dequeue':
        yield `test ${event.data.name} dequeued\n`;
        break;
      case 'test:enqueue':
        yield `test ${event.data.name} enqueued\n`;
        break;
      case 'test:watch:drained':
        yield 'test watch queue drained\n';
        break;
      case 'test:start':
        yield `test ${event.data.name} started\n`;
        break;
      case 'test:pass':
        yield `test ${event.data.name} passed\n`;
        break;
      case 'test:fail':
        yield `test ${event.data.name} failed\n`;
        break;
      case 'test:plan':
        yield 'test plan\n';
        break;
      case 'test:diagnostic':
      case 'test:stderr':
      case 'test:stdout':
        yield `${event.data.message}\n`;
        break;
      case 'test:coverage': {
        const { totalLineCount } = event.data.summary.totals;
        yield `total line count: ${totalLineCount}\n`;
        break;
      }
    }
  }
};

Значение, предоставленное --test-reporter, должно быть строкой, похожей на используемую в import() в коде JavaScript, или значением, предоставленным для --import.

Несколько репортеров

Флаг --test-reporter можно указать несколько раз для вывода результатов тестов в нескольких форматах. В этом случае необходимо указать место назначения для каждого репортера с помощью --test-reporter-destination. Местом назначения может быть stdout, stderr или путь к файлу. Репортеры и места назначения сопоставляются в соответствии с порядком их указания.

В следующем примере репортер spec будет выводить данные в stdout, а репортер dot - в file.txt:

bash
node --test-reporter=spec --test-reporter=dot --test-reporter-destination=stdout --test-reporter-destination=file.txt

Если указан один репортер, место назначения по умолчанию будет stdout, если явно не указано другое место назначения.

run([options])

[История]

ВерсияИзменения
v23.0.0Добавлен параметр cwd.
v23.0.0Добавлены параметры покрытия кода.
v22.8.0Добавлен параметр isolation.
v22.6.0Добавлен параметр globPatterns.
v22.0.0, v20.14.0Добавлен параметр forceExit.
v20.1.0, v18.17.0Добавлен параметр testNamePatterns.
v18.9.0, v16.19.0Добавлено в: v18.9.0, v16.19.0
  • 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> Устанавливает порт инспектора дочернего тестового процесса. Это может быть число или функция, которая не принимает аргументов и возвращает число. Если указано значение null, каждый процесс получает свой собственный порт, увеличивающийся от основного process.debugPort. Этот параметр игнорируется, если для параметра isolation установлено значение 'none', поскольку дочерние процессы не создаются. По умолчанию: undefined.

    • isolation <string> Конфигурирует тип изоляции тестов. Если установлено значение 'process', каждый тестовый файл запускается в отдельном дочернем процессе. Если установлено значение 'none', все тестовые файлы запускаются в текущем процессе. По умолчанию: 'process'.

    • only: <boolean> Если истинно, контекст теста будет запускать только тесты, у которых установлен параметр only

    • setup <Function> Функция, которая принимает экземпляр TestsStream и может использоваться для настройки прослушивателей до запуска каких-либо тестов. По умолчанию: undefined.

    • execArgv <Array> Массив флагов CLI для передачи исполняемому файлу node при создании подпроцессов. Этот параметр не действует, если isolation имеет значение 'none'. По умолчанию: []

    • argv <Array> Массив флагов CLI для передачи каждому тестовому файлу при создании подпроцессов. Этот параметр не действует, если 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.

      • index <number> - это положительное целое число от 1 до \<total\>, указывающее индекс осколка для запуска. Этот параметр обязателен.
      • total <number> - это положительное целое число, указывающее общее количество осколков, на которые нужно разделить тестовые файлы. Этот параметр обязателен.
    • 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.

  • Возвращает: <TestsStream>

Примечание: shard используется для горизонтальной параллелизации запуска тестов на нескольких машинах или в процессах, что идеально подходит для крупномасштабных выполнений в различных средах. Он несовместим с режимом watch, предназначенным для быстрой итерации кода путем автоматического повторного запуска тестов при изменении файлов.

js
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);
js
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])

Добавлено в: v22.0.0, v20.13.0

  • 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])

Добавлено в: v22.0.0, v20.13.0

Сокращенная запись для пропуска набора тестов. Это то же самое, что и suite([name], { skip: true }[, fn]).

suite.todo([name][, options][, fn])

Добавлено в: v22.0.0, v20.13.0

Сокращенная запись для пометки набора тестов как TODO. Это то же самое, что и suite([name], { todo: true }[, fn]).

suite.only([name][, options][, fn])

Добавлено в: v22.0.0, v20.13.0

Сокращенная запись для пометки набора тестов как only. Это то же самое, что и suite([name], { only: true }[, fn]).

test([name][, options][, fn])

[История]

ВерсияИзменения
v20.2.0, v18.17.0Добавлены сокращенные записи skip, todo и only.
v18.8.0, v16.18.0Добавлен параметр signal.
v18.7.0, v16.17.0Добавлен параметр timeout.
v18.0.0, v16.17.0Добавлено в: v18.0.0, v16.17.0
  • 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() вызывается внутри набора тестов, он выполняется немедленно. Возвращаемое значение обычно можно отбросить для тестов верхнего уровня. Однако возвращаемое значение из подтестов следует использовать, чтобы предотвратить завершение родительского теста первым и отмену подтеста, как показано в следующем примере.

js
test('top level test', async (t) => {
  // setTimeout() в следующем подтесте приведет к тому, что он переживет свой
  // родительский тест, если удалить 'await' в следующей строке. После завершения родительского теста
  // он отменит любые незавершенные подтесты.
  await t.test('longer running subtest', async (t) => {
    return new Promise((resolve, reject) => {
      setTimeout(resolve, 1000);
    });
  });
});

Параметр 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])

Добавлено в: v19.8.0, v18.15.0

Сокращенная запись для пометки набора тестов как only. Это то же самое, что и describe([name], { only: true }[, fn]).

it([name][, options][, fn])

[История]

ВерсияИзменения
v19.8.0, v18.16.0Вызов it() теперь эквивалентен вызову test().
v18.6.0, v16.17.0Добавлено в: v18.6.0, v16.17.0

Псевдоним для 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])

Добавлено в: v19.8.0, v18.15.0

Сокращенная запись для пометки теста как only, то же самое, что и it([name], { only: true }[, fn]).

before([fn][, options])

Добавлено в: v18.8.0, v16.18.0

  • fn <Function> | <AsyncFunction> Функция-хук. Если хук использует колбэки, функция колбэка передается в качестве второго аргумента. По умолчанию: Функция-пустышка.
  • options <Object> Параметры конфигурации для хука. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполняющийся хук.
    • timeout <number> Количество миллисекунд, по истечении которого хук завершится с ошибкой. Если не указано, подтесты наследуют это значение от родительского элемента. По умолчанию: Infinity.

Эта функция создает хук, который выполняется перед выполнением набора тестов.

js
describe('tests', async () => {
  before(() => console.log('about to run some test'));
  it('is a subtest', () => {
    assert.ok('some relevant assertion here');
  });
});

after([fn][, options])

Добавлено в: v18.8.0, v16.18.0

  • fn <Function> | <AsyncFunction> Функция-хук. Если хук использует колбэки, функция колбэка передается в качестве второго аргумента. По умолчанию: Функция-пустышка.
  • options <Object> Параметры конфигурации для хука. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполняющийся хук.
    • timeout <number> Количество миллисекунд, по истечении которого хук завершится с ошибкой. Если не указано, подтесты наследуют это значение от родительского элемента. По умолчанию: Infinity.

Эта функция создает хук, который выполняется после выполнения набора тестов.

js
describe('tests', async () => {
  after(() => console.log('finished running tests'));
  it('is a subtest', () => {
    assert.ok('some relevant assertion here');
  });
});

Примечание: Хук after гарантированно запустится, даже если тесты внутри набора завершатся с ошибкой.

beforeEach([fn][, options])

Добавлено в: v18.8.0, v16.18.0

  • fn <Function> | <AsyncFunction> Функция хука. Если хук использует коллбэки, функция коллбэка передается в качестве второго аргумента. По умолчанию: функция-пустышка.
  • options <Object> Параметры конфигурации для хука. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполняющийся хук.
    • timeout <number> Количество миллисекунд, после которого хук завершится с ошибкой. Если не указано, подтесты наследуют это значение от своего родителя. По умолчанию: Infinity.

Эта функция создает хук, который выполняется перед каждым тестом в текущем наборе тестов.

js
describe('tests', async () => {
  beforeEach(() => console.log('about to run a test'));
  it('is a subtest', () => {
    assert.ok('some relevant assertion here');
  });
});

afterEach([fn][, options])

Добавлено в: v18.8.0, v16.18.0

  • fn <Function> | <AsyncFunction> Функция хука. Если хук использует коллбэки, функция коллбэка передается в качестве второго аргумента. По умолчанию: функция-пустышка.
  • options <Object> Параметры конфигурации для хука. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполняющийся хук.
    • timeout <number> Количество миллисекунд, после которого хук завершится с ошибкой. Если не указано, подтесты наследуют это значение от своего родителя. По умолчанию: Infinity.

Эта функция создает хук, который выполняется после каждого теста в текущем наборе тестов. Хук afterEach() выполняется, даже если тест завершается неудачей.

js
describe('tests', async () => {
  afterEach(() => console.log('finished running a test'));
  it('is a subtest', () => {
    assert.ok('some relevant assertion here');
  });
});

snapshot

Добавлено в: v22.3.0

[Стабильность: 1 - Экспериментальная]

Стабильность: 1 Стабильность: 1.0 - Ранняя разработка

Объект, чьи методы используются для настройки параметров снимков по умолчанию в текущем процессе. Можно применить одну и ту же конфигурацию ко всем файлам, поместив общий код конфигурации в модуль, предварительно загруженный с помощью --require или --import.

snapshot.setDefaultSnapshotSerializers(serializers)

Добавлено в: v22.3.0

[Стабильность: 1 - Экспериментальная]

Стабильность: 1 Стабильность: 1.0 - Ранняя разработка

  • serializers <Array> Массив синхронных функций, используемых в качестве сериализаторов по умолчанию для снапшот-тестов.

Эта функция используется для настройки механизма сериализации по умолчанию, используемого средством запуска тестов. По умолчанию средство запуска тестов выполняет сериализацию, вызывая JSON.stringify(value, null, 2) для предоставленного значения. JSON.stringify() имеет ограничения в отношении циклических структур и поддерживаемых типов данных. Если требуется более надежный механизм сериализации, следует использовать эту функцию.

snapshot.setResolveSnapshotPath(fn)

Добавлено в: v22.3.0

[Стабильность: 1 - Экспериментальная]

Стабильность: 1 Стабильность: 1.0 - Ранняя разработка

  • fn <Function> Функция, используемая для вычисления местоположения файла снимка. Функция получает путь к файлу теста в качестве единственного аргумента. Если тест не связан с файлом (например, в REPL), входные данные не определены. fn() должна возвращать строку, указывающую местоположение файла снимка.

Эта функция используется для настройки местоположения файла снимка, используемого для снапшот-тестирования. По умолчанию имя файла снимка совпадает с именем файла точки входа с расширением .snapshot.

Класс: MockFunctionContext

Добавлено в: v19.1.0, v18.13.0

Класс MockFunctionContext используется для проверки или управления поведением моков, созданных с помощью API MockTracker.

ctx.calls

Добавлено в: v19.1.0, v18.13.0

Геттер, возвращающий копию внутреннего массива, используемого для отслеживания вызовов мока. Каждая запись в массиве является объектом со следующими свойствами.

  • arguments <Array> Массив аргументов, переданных в мок-функцию.
  • error <any> Если мокированная функция вызвала исключение, то это свойство содержит выброшенное значение. По умолчанию: undefined.
  • result <any> Значение, возвращенное мокированной функцией.
  • stack <Error> Объект Error, чей стек можно использовать для определения места вызова мокированной функции.
  • target <Function> | <undefined> Если мокированная функция является конструктором, это поле содержит создаваемый класс. В противном случае будет undefined.
  • this <any> Значение this мокированной функции.

ctx.callCount()

Добавлено в: v19.1.0, v18.13.0

  • Возвращает: <integer> Количество вызовов этого мока.

Эта функция возвращает количество вызовов этого мока. Эта функция более эффективна, чем проверка ctx.calls.length, потому что ctx.calls является геттером, который создает копию внутреннего массива отслеживания вызовов.

ctx.mockImplementation(implementation)

Добавлено в: v19.1.0, v18.13.0

  • implementation <Function> | <AsyncFunction> Функция, которая будет использоваться в качестве новой реализации мока.

Эта функция используется для изменения поведения существующего мока.

В следующем примере создается функция-мок с использованием t.mock.fn(), вызывается функция-мок, а затем реализация мока изменяется на другую функцию.

js
test('изменяет поведение мока', (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);
});

ctx.mockImplementationOnce(implementation[, onCall])

Добавлено в: v19.1.0, v18.13.0

  • implementation <Function> | <AsyncFunction> Функция, которая будет использоваться в качестве реализации мока для номера вызова, указанного в onCall.
  • onCall <integer> Номер вызова, который будет использовать implementation. Если указанный вызов уже произошел, будет выброшено исключение. По умолчанию: Номер следующего вызова.

Эта функция используется для изменения поведения существующего мока для одного вызова. После того, как произошел вызов onCall, мок вернется к тому поведению, которое он использовал бы, если бы mockImplementationOnce() не вызывался.

В следующем примере создается функция-мок с использованием t.mock.fn(), вызывается функция-мок, изменяется реализация мока на другую функцию для следующего вызова, а затем возобновляется его предыдущее поведение.

js
test('изменяет поведение мока один раз', (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);
});

ctx.resetCalls()

Добавлено в: v19.3.0, v18.13.0

Сбрасывает историю вызовов фиктивной функции.

ctx.restore()

Добавлено в: v19.1.0, v18.13.0

Восстанавливает исходную реализацию фиктивной функции. После вызова этой функции фиктивная функция по-прежнему может использоваться.

Класс: MockModuleContext

Добавлено в: v22.3.0, v20.18.0

[Стабильность: 1 - Экспериментальная]

Стабильность: 1 Стабильность: 1.0 - Ранняя стадия разработки

Класс MockModuleContext используется для управления поведением фиктивных модулей, созданных с помощью API MockTracker.

ctx.restore()

Добавлено в: v22.3.0, v20.18.0

Восстанавливает реализацию фиктивного модуля.

Класс: MockTracker

Добавлено в: v19.1.0, v18.13.0

Класс MockTracker используется для управления функциональностью имитации. Модуль запуска тестов предоставляет экспорт верхнего уровня mock, который является экземпляром MockTracker. Каждый тест также предоставляет свой собственный экземпляр MockTracker через свойство mock контекста теста.

mock.fn([original[, implementation]][, options])

Добавлено в: v19.1.0, v18.13.0

  • original <Function> | <AsyncFunction> Необязательная функция, для которой создается фиктивная функция. По умолчанию: Функция-пустышка.

  • implementation <Function> | <AsyncFunction> Необязательная функция, используемая в качестве фиктивной реализации для original. Это полезно для создания фиктивных функций, которые демонстрируют одно поведение для указанного количества вызовов, а затем восстанавливают поведение original. По умолчанию: Функция, указанная в original.

  • options <Object> Необязательные параметры конфигурации для фиктивной функции. Поддерживаются следующие свойства:

    • times <integer> Количество раз, когда фиктивная функция будет использовать поведение implementation. Как только фиктивная функция будет вызвана times раз, она автоматически восстановит поведение original. Это значение должно быть целым числом больше нуля. По умолчанию: Infinity.
  • Возвращает: <Proxy> Фиктивная функция. Фиктивная функция содержит специальное свойство mock, которое является экземпляром MockFunctionContext, и может использоваться для проверки и изменения поведения фиктивной функции.

Эта функция используется для создания фиктивной функции.

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

js
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);
});

mock.getter(object, methodName[, implementation][, options])

Добавлено в версии: v19.3.0, v18.13.0

Эта функция является синтаксическим сахаром для MockTracker.method с options.getter, установленным в true.

mock.method(object, methodName[, implementation][, options])

Добавлено в версии: v19.1.0, v18.13.0

  • 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 и может использоваться для проверки и изменения поведения имитируемого метода.

Эта функция используется для создания имитации метода существующего объекта. В следующем примере показано, как создается имитация метода существующего объекта.

js
test('следит за методом объекта', (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);
});

mock.module(specifier[, options])

Добавлено в версии: v22.3.0, v20.18.0

[Стабильность: 1 - Экспериментальная]

Стабильность: 1 Стабильность: 1.0 - Ранняя разработка

  • 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 и встроенных модулей Node.js. Любые ссылки на оригинальный модуль до подмены не затрагиваются. Чтобы включить подмену модулей, Node.js необходимо запустить с флагом командной строки --experimental-test-module-mocks.

В следующем примере показано, как создается заглушка для модуля.

js
test('подменяет встроенный модуль в обеих системах модулей', async (t) => {
  // Создайте заглушку 'node:readline' с именованным экспортом с именем 'fn', который
  // не существует в оригинальном модуле 'node:readline'.
  const mock = t.mock.module('node:readline', {
    namedExports: { fn() { return 42; } },
  });

  let esmImpl = await import('node:readline');
  let cjsImpl = require('node:readline');

  // cursorTo() — это экспорт оригинального модуля 'node:readline'.
  assert.strictEqual(esmImpl.cursorTo, undefined);
  assert.strictEqual(cjsImpl.cursorTo, undefined);
  assert.strictEqual(esmImpl.fn(), 42);
  assert.strictEqual(cjsImpl.fn(), 42);

  mock.restore();

  // Заглушка восстановлена, поэтому возвращается оригинальный встроенный модуль.
  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);
});

mock.reset()

Добавлено в версии: v19.1.0, v18.13.0

Эта функция восстанавливает поведение по умолчанию для всех макетов, которые были ранее созданы этим MockTracker, и разъединяет макеты от экземпляра MockTracker. После разъединения макеты все еще можно использовать, но экземпляр MockTracker больше нельзя использовать для сброса их поведения или иного взаимодействия с ними.

После завершения каждого теста эта функция вызывается в MockTracker контекста теста. Если глобальный MockTracker используется в значительной степени, рекомендуется вызывать эту функцию вручную.

mock.restoreAll()

Добавлено в версии: v19.1.0, v18.13.0

Эта функция восстанавливает поведение по умолчанию для всех макетов, которые были ранее созданы этим MockTracker. В отличие от mock.reset(), mock.restoreAll() не разъединяет макеты от экземпляра MockTracker.

mock.setter(object, methodName[, implementation][, options])

Добавлено в версии: v19.3.0, v18.13.0

Эта функция является синтаксическим сахаром для MockTracker.method с options.setter, установленным в true.

Класс: MockTimers

[История]

ВерсияИзменения
v23.1.0Mock Timers теперь стабильны.
v20.4.0, v18.19.0Добавлено в версии: v20.4.0, v18.19.0

[Стабильно: 2 - Стабильно]

Стабильно: 2 Стабильность: 2 - Стабильно

Макеты таймеров - это техника, обычно используемая при тестировании программного обеспечения для имитации и контроля поведения таймеров, таких как setInterval и setTimeout, без фактического ожидания указанных временных интервалов.

MockTimers также может имитировать объект Date.

MockTracker предоставляет экспорт timers верхнего уровня, который является экземпляром MockTimers.

timers.enable([enableOptions])

[История]

ВерсияИзменения
v21.2.0, v20.11.0Обновлены параметры, чтобы быть объектом опций с доступными API и начальной эпохой по умолчанию.
v20.4.0, v18.19.0Добавлено в версии: v20.4.0, v18.19.0

Включает макет таймеров для указанных таймеров.

  • 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 повлияет на поведение смоделированных таймеров, поскольку они используют одни и те же внутренние часы.

Пример использования без установки начального времени:

js
import { mock } from 'node:test';
mock.timers.enable({ apis: ['setInterval'] });
js
const { mock } = require('node:test');
mock.timers.enable({ apis: ['setInterval'] });

Приведенный выше пример включает макет для таймера setInterval и неявно имитирует функцию clearInterval. Только функции setInterval и clearInterval из node:timers, node:timers/promises и globalThis будут смоделированы.

Пример использования с установленным начальным временем

js
import { mock } from 'node:test';
mock.timers.enable({ apis: ['Date'], now: 1000 });
js
const { mock } = require('node:test');
mock.timers.enable({ apis: ['Date'], now: 1000 });

Пример использования с начальным объектом Date в качестве установленного времени

js
import { mock } from 'node:test';
mock.timers.enable({ apis: ['Date'], now: new Date() });
js
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()

Добавлено в: v20.4.0, v18.19.0

Эта функция восстанавливает поведение по умолчанию для всех макетов, которые были ранее созданы этим экземпляром MockTimers, и отвязывает макеты от экземпляра MockTracker.

Примечание: После завершения каждого теста эта функция вызывается в MockTracker контекста теста.

js
import { mock } from 'node:test';
mock.timers.reset();
js
const { mock } = require('node:test');
mock.timers.reset();

timers[Symbol.dispose]()

Вызывает timers.reset().

timers.tick([milliseconds])

Добавлено в: v20.4.0, v18.19.0

Продвигает время для всех макетированных таймеров.

  • milliseconds <number> Количество времени в миллисекундах, на которое следует продвинуть таймеры. По умолчанию: 1.

Примечание: Это отличается от того, как setTimeout ведет себя в Node.js, и принимает только положительные числа. В Node.js setTimeout с отрицательными числами поддерживается только из соображений совместимости с вебом.

В следующем примере создается макет функции setTimeout, и с помощью .tick продвигается время, запуская все ожидающие таймеры.

js
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);
});
js
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 можно вызвать много раз.

js
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);
});
js
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).

js
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);
});
js
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);
});

Использование функций clear

Как упоминалось, все функции clear из таймеров (clearTimeout, clearInterval и clearImmediate) неявно маскируются. Взгляните на этот пример с использованием setTimeout:

js
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);
});
js
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 включаются:

Примечание: Деструктуризация функций, таких как import { setTimeout } from 'node:timers', в настоящее время не поддерживается этим API.

js
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);
});
js
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:

js
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));
  }
});
js
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()

Добавлено в: v20.4.0, v18.19.0

Немедленно запускает все ожидающие фиктивные таймеры. Если объект Date также является фиктивным, он также продвинет объект Date до времени самого дальнего таймера.

Пример ниже немедленно запускает все ожидающие таймеры, заставляя их выполняться без задержки.

js
import assert from 'node:assert';
import { test } from 'node:test';

test('runAll выполняет функции в заданном порядке', (context) => {
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const results = [];
  setTimeout(() => results.push(1), 9999);

  // Обратите внимание, что если оба таймера имеют одинаковый таймаут,
  // порядок выполнения гарантируется
  setTimeout(() => results.push(3), 8888);
  setTimeout(() => results.push(2), 8888);

  assert.deepStrictEqual(results, []);

  context.mock.timers.runAll();
  assert.deepStrictEqual(results, [3, 2, 1]);
  // Объект Date также продвигается до времени самого дальнего таймера
  assert.strictEqual(Date.now(), 9999);
});
js
const assert = require('node:assert');
const { test } = require('node:test');

test('runAll выполняет функции в заданном порядке', (context) => {
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const results = [];
  setTimeout(() => results.push(1), 9999);

  // Обратите внимание, что если оба таймера имеют одинаковый таймаут,
  // порядок выполнения гарантируется
  setTimeout(() => results.push(3), 8888);
  setTimeout(() => results.push(2), 8888);

  assert.deepStrictEqual(results, []);

  context.mock.timers.runAll();
  assert.deepStrictEqual(results, [3, 2, 1]);
  // Объект Date также продвигается до времени самого дальнего таймера
  assert.strictEqual(Date.now(), 9999);
});

Примечание: Функция runAll() специально разработана для запуска таймеров в контексте фиктивного тайминга. Она не оказывает никакого влияния на системные часы реального времени или фактические таймеры за пределами среды фиктивного тайминга.

timers.setTime(milliseconds)

Добавлено в: v21.2.0, v20.11.0

Устанавливает текущую метку времени Unix, которая будет использоваться в качестве ссылки для любых фиктивных объектов Date.

js
import assert from 'node:assert';
import { test } from 'node:test';

test('runAll выполняет функции в заданном порядке', (context) => {
  const now = Date.now();
  const setTime = 1000;
  // Date.now не является фиктивным
  assert.deepStrictEqual(Date.now(), now);

  context.mock.timers.enable({ apis: ['Date'] });
  context.mock.timers.setTime(setTime);
  // Date.now теперь 1000
  assert.strictEqual(Date.now(), setTime);
});
js
const assert = require('node:assert');
const { test } = require('node:test');

test('setTime заменяет текущее время', (context) => {
  const now = Date.now();
  const setTime = 1000;
  // Date.now не является фиктивным
  assert.deepStrictEqual(Date.now(), now);

  context.mock.timers.enable({ apis: ['Date'] });
  context.mock.timers.setTime(setTime);
  // Date.now теперь 1000
  assert.strictEqual(Date.now(), setTime);
});

Взаимодействие Date и Timer

Объекты Date и timer зависят друг от друга. Если вы используете setTime() для передачи текущего времени смоделированному объекту Date, установленные таймеры с помощью setTimeout и setInterval не будут затронуты.

Однако метод tick будет продвигать смоделированный объект Date.

js
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);
});
js
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

[История]

ВерсияИзменения
v20.0.0, v19.9.0, v18.17.0добавлено type в события test:pass и test:fail, когда тест является набором тестов.
v18.9.0, v16.19.0Добавлено в: v18.9.0, v16.19.0

Успешный вызов метода 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> Массив функций, представляющий покрытие функций.

    • name <string> Имя функции.

    • line <number> Номер строки, где определена функция.

    • count <number> Количество вызовов функции.

    • branches <Array> Массив ветвлений, представляющий покрытие ветвлений.

    • line <number> Номер строки, где определено ветвление.

    • count <number> Количество прохождений ветвления.

    • lines <Array> Массив строк, представляющий номера строк и количество раз, когда они были покрыты.

    • line <number> Номер строки.

    • count <number> Количество раз, когда строка была покрыта.

    • thresholds <Object> Объект, содержащий информацию о том, превышено ли пороговое значение покрытия для каждого типа покрытия.

    • function <number> Пороговое значение покрытия функций.

    • branch <number> Пороговое значение покрытия ветвлений.

    • line <number> Пороговое значение покрытия строк.

    • 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> Тип теста, используемый для обозначения того, является ли это набором тестов (suite).

    • file <string> | <undefined> Путь к файлу теста, undefined, если тест был запущен через REPL.

    • line <number> | <undefined> Номер строки, где определен тест, или undefined, если тест был запущен через REPL.

    • name <string> Имя теста.

    • nesting <number> Уровень вложенности теста.

    • testNumber <number> Порядковый номер теста.

    • todo <string> | <boolean> | <undefined> Присутствует, если вызван context.todo

    • skip <string> | <boolean> | <undefined> Присутствует, если вызван context.skip

Срабатывает, когда тест завершает свое выполнение. Это событие не генерируется в том же порядке, в котором определены тесты. Соответствующие события, упорядоченные по декларации, это 'test:pass' и 'test:fail'.

Событие: 'test:dequeue'

  • data <Object>
    • column <number> | <undefined> Номер столбца, где определен тест, или undefined, если тест был запущен через REPL.
    • file <string> | <undefined> Путь к файлу теста, undefined, если тест был запущен через REPL.
    • line <number> | <undefined> Номер строки, где определен тест, или undefined, если тест был запущен через REPL.
    • name <string> Имя теста.
    • nesting <number> Уровень вложенности теста.

Выдается, когда тест извлекается из очереди, непосредственно перед его выполнением. Не гарантируется, что это событие будет выдано в том же порядке, в котором определены тесты. Соответствующим событием, упорядоченным по объявлению, является 'test:start'.

Событие: 'test:diagnostic'

  • data <Object>
    • column <number> | <undefined> Номер столбца, где определен тест, или undefined, если тест был запущен через REPL.
    • file <string> | <undefined> Путь к файлу теста, undefined, если тест был запущен через REPL.
    • line <number> | <undefined> Номер строки, где определен тест, или undefined, если тест был запущен через REPL.
    • message <string> Диагностическое сообщение.
    • nesting <number> Уровень вложенности теста.

Выдается, когда вызывается context.diagnostic. Гарантируется, что это событие будет выдано в том же порядке, в котором определены тесты.

Событие: 'test:enqueue'

  • data <Object>
    • column <number> | <undefined> Номер столбца, в котором определен тест, или undefined, если тест был запущен через REPL.
    • file <string> | <undefined> Путь к файлу теста, undefined, если тест был запущен через REPL.
    • line <number> | <undefined> Номер строки, в которой определен тест, или undefined, если тест был запущен через REPL.
    • name <string> Имя теста.
    • nesting <number> Уровень вложенности теста.

Выбрасывается, когда тест помещается в очередь для выполнения.

Событие: 'test:fail'

  • data <Object>
    • column <number> | <undefined> Номер столбца, в котором определен тест, или undefined, если тест был запущен через REPL.

    • details <Object> Дополнительные метаданные выполнения.

    • duration_ms <number> Продолжительность теста в миллисекундах.

    • error <Error> Ошибка, оборачивающая ошибку, выброшенную тестом.

    • cause <Error> Фактическая ошибка, выброшенная тестом.

    • type <string> | <undefined> Тип теста, используется для обозначения, является ли это набором тестов.

    • file <string> | <undefined> Путь к файлу теста, undefined, если тест был запущен через REPL.

    • line <number> | <undefined> Номер строки, в которой определен тест, или undefined, если тест был запущен через REPL.

    • name <string> Имя теста.

    • nesting <number> Уровень вложенности теста.

    • testNumber <number> Порядковый номер теста.

    • todo <string> | <boolean> | <undefined> Присутствует, если вызван context.todo

    • skip <string> | <boolean> | <undefined> Присутствует, если вызван context.skip

Выбрасывается, когда тест завершается неудачей. Это событие гарантированно выбрасывается в том же порядке, в котором определены тесты. Соответствующим событием в порядке выполнения является 'test:complete'.

Событие: 'test:pass'

  • data <Object>
    • column <number> | <undefined> Номер столбца, где определен тест, или undefined, если тест был запущен через REPL.

    • details <Object> Дополнительные метаданные выполнения.

    • duration_ms <number> Продолжительность теста в миллисекундах.

    • type <string> | <undefined> Тип теста, используется для обозначения, является ли это набором тестов.

    • file <string> | <undefined> Путь к файлу теста, undefined, если тест был запущен через REPL.

    • line <number> | <undefined> Номер строки, где определен тест, или undefined, если тест был запущен через REPL.

    • name <string> Имя теста.

    • nesting <number> Уровень вложенности теста.

    • testNumber <number> Порядковый номер теста.

    • todo <string> | <boolean> | <undefined> Присутствует, если вызван context.todo

    • skip <string> | <boolean> | <undefined> Присутствует, если вызван context.skip

Сгенерировано, когда тест пройден. Это событие гарантированно генерируется в том же порядке, в котором определены тесты. Соответствующее упорядоченное по выполнению событие - 'test:complete'.

Event: 'test:plan'

  • data <Object>
    • column <number> | <undefined> Номер столбца, где определен тест, или undefined, если тест был запущен через REPL.
    • file <string> | <undefined> Путь к файлу теста, undefined, если тест был запущен через REPL.
    • line <number> | <undefined> Номер строки, где определен тест, или undefined, если тест был запущен через REPL.
    • nesting <number> Уровень вложенности теста.
    • count <number> Количество запущенных подтестов.

Срабатывает, когда все подтесты завершены для данного теста. Гарантируется, что это событие будет сгенерировано в том же порядке, в котором определены тесты.

Event: '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'

  • data <Object>
    • file <string> Путь к файлу теста.
    • message <string> Сообщение, записанное в stderr.

Срабатывает, когда запущенный тест записывает в stderr. Это событие срабатывает только в том случае, если передан флаг --test. Не гарантируется, что это событие будет срабатывать в том же порядке, в котором определены тесты.

Событие: 'test:stdout'

  • data <Object>
    • file <string> Путь к файлу теста.
    • message <string> Сообщение, записанное в stdout.

Срабатывает, когда запущенный тест записывает в stdout. Это событие срабатывает только в том случае, если передан флаг --test. Не гарантируется, что это событие будет срабатывать в том же порядке, в котором определены тесты.

Событие: 'test:summary'

  • data <Object>
    • counts <Object> Объект, содержащий счетчики различных результатов тестов.

    • cancelled <number> Общее количество отмененных тестов.

    • failed <number> Общее количество проваленных тестов.

    • passed <number> Общее количество пройденных тестов.

    • skipped <number> Общее количество пропущенных тестов.

    • suites <number> Общее количество запущенных наборов тестов (suites).

    • tests <number> Общее количество запущенных тестов, исключая наборы тестов (suites).

    • todo <number> Общее количество тестов TODO.

    • topLevel <number> Общее количество тестов и наборов тестов верхнего уровня.

    • duration_ms <number> Продолжительность выполнения тестов в миллисекундах.

    • file <string> | <undefined> Путь к файлу теста, который сгенерировал сводку. Если сводка соответствует нескольким файлам, это значение будет undefined.

    • success <boolean> Указывает, считается ли запуск тестов успешным или нет. Если возникает какое-либо условие ошибки, такое как сбой теста или невыполненный порог покрытия, это значение будет установлено в false.

Срабатывает при завершении выполнения тестов. Это событие содержит метрики, относящиеся к завершенному выполнению тестов, и полезно для определения того, пройден или не пройден запуск тестов. Если используется изоляция тестов на уровне процесса, событие 'test:summary' генерируется для каждого файла теста в дополнение к итоговой совокупной сводке.

Событие: 'test:watch:drained'

Вызывается, когда в режиме наблюдения больше нет тестов, поставленных в очередь для выполнения.

Класс: TestContext

[История]

ВерсияИзменения
v20.1.0, v18.17.0Функция before была добавлена в TestContext.
v18.0.0, v16.17.0Добавлено в: v18.0.0, v16.17.0

Экземпляр TestContext передается каждой тестовой функции для взаимодействия с тестовым раннером. Однако конструктор TestContext не предоставляется как часть API.

context.before([fn][, options])

Добавлено в: v20.1.0, v18.17.0

  • fn <Function> | <AsyncFunction> Функция-хук. Первым аргументом этой функции является объект TestContext. Если хук использует колбэки, функция колбэка передается в качестве второго аргумента. По умолчанию: Функция бездействия.
  • options <Object> Параметры конфигурации для хука. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполняющийся хук.
    • timeout <number> Количество миллисекунд, по истечении которого хук завершится с ошибкой. Если не указано, подтесты наследуют это значение от своего родителя. По умолчанию: Infinity.

Эта функция используется для создания хука, выполняющегося перед подтестом текущего теста.

context.beforeEach([fn][, options])

Добавлено в: v18.8.0, v16.18.0

  • fn <Function> | <AsyncFunction> Функция-хук. Первым аргументом этой функции является объект TestContext. Если хук использует колбэки, функция колбэка передается в качестве второго аргумента. По умолчанию: Функция бездействия.
  • options <Object> Параметры конфигурации для хука. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполняющийся хук.
    • timeout <number> Количество миллисекунд, по истечении которого хук завершится с ошибкой. Если не указано, подтесты наследуют это значение от своего родителя. По умолчанию: Infinity.

Эта функция используется для создания хука, выполняющегося перед каждым подтестом текущего теста.

js
test('top level test', async (t) => {
  t.beforeEach((t) => t.diagnostic(`about to run ${t.name}`));
  await t.test(
    'This is a subtest',
    (t) => {
      assert.ok('some relevant assertion here');
    },
  );
});

context.after([fn][, options])

Добавлено в версии: v19.3.0, v18.13.0

  • fn <Function> | <AsyncFunction> Функция-хук. Первым аргументом этой функции является объект TestContext. Если хук использует обратные вызовы, функция обратного вызова передается в качестве второго аргумента. По умолчанию: Функция без операций.
  • options <Object> Параметры конфигурации для хука. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполняющийся хук.
    • timeout <number> Количество миллисекунд, после которого хук завершится с ошибкой. Если не указано, подтесты наследуют это значение от родительского элемента. По умолчанию: Infinity.

Эта функция используется для создания хука, который выполняется после завершения текущего теста.

js
test('top level test', async (t) => {
  t.after((t) => t.diagnostic(`finished running ${t.name}`));
  assert.ok('some relevant assertion here');
});

context.afterEach([fn][, options])

Добавлено в версии: v18.8.0, v16.18.0

  • fn <Function> | <AsyncFunction> Функция-хук. Первым аргументом этой функции является объект TestContext. Если хук использует обратные вызовы, функция обратного вызова передается в качестве второго аргумента. По умолчанию: Функция без операций.
  • options <Object> Параметры конфигурации для хука. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполняющийся хук.
    • timeout <number> Количество миллисекунд, после которого хук завершится с ошибкой. Если не указано, подтесты наследуют это значение от родительского элемента. По умолчанию: Infinity.

Эта функция используется для создания хука, выполняющегося после каждого подтеста текущего теста.

js
test('top level test', async (t) => {
  t.afterEach((t) => t.diagnostic(`finished running ${t.name}`));
  await t.test(
    'This is a subtest',
    (t) => {
      assert.ok('some relevant assertion here');
    },
  );
});

context.assert

Added in: v22.2.0, v20.15.0

Объект, содержащий методы утверждений, привязанные к context. Функции верхнего уровня из модуля node:assert представлены здесь для создания планов тестирования.

js
test('test', (t) => {
  t.plan(1);
  t.assert.strictEqual(true, true);
});

context.assert.snapshot(value[, options])

Added in: v22.3.0

[Stable: 1 - Experimental]

Stable: 1 Stability: 1.0 - Ранняя разработка

  • value <any> Значение для сериализации в строку. Если Node.js был запущен с флагом --test-update-snapshots, сериализованное значение записывается в файл снимка. В противном случае сериализованное значение сравнивается с соответствующим значением в существующем файле снимка.
  • options <Object> Дополнительные параметры конфигурации. Поддерживаются следующие свойства:
    • serializers <Array> Массив синхронных функций, используемых для сериализации value в строку. value передается в качестве единственного аргумента первой функции сериализатора. Возвращаемое значение каждого сериализатора передается в качестве входных данных следующему сериализатору. После того, как все сериализаторы были запущены, результирующее значение приводится к строке. Default: Если сериализаторы не предоставлены, используются сериализаторы по умолчанию для средства запуска тестов.

Эта функция реализует утверждения для тестирования снимков.

js
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)],
  });
});

context.diagnostic(message)

Добавлено в: v18.0.0, v16.17.0

  • message <string> Сообщение для отчета.

Эта функция используется для записи диагностических данных в вывод. Любая диагностическая информация включается в конце результатов теста. Эта функция не возвращает значение.

js
test('top level test', (t) => {
  t.diagnostic('A diagnostic message');
});

context.filePath

Добавлено в: v22.6.0, v20.16.0

Абсолютный путь к файлу теста, который создал текущий тест. Если файл теста импортирует дополнительные модули, генерирующие тесты, импортированные тесты будут возвращать путь к корневому файлу теста.

context.fullName

Добавлено в: v22.3.0

Имя теста и каждого из его предков, разделенных символом \>.

context.name

Добавлено в: v18.8.0, v16.18.0

Имя теста.

context.plan(count)

[История]

ВерсияИзменения
v23.4.0Эта функция больше не является экспериментальной.
v22.2.0, v20.15.0Добавлено в: v22.2.0, v20.15.0
  • count <number> Количество утверждений и подтестов, которые должны быть выполнены.

Эта функция используется для установки количества утверждений и подтестов, которые должны быть выполнены в тесте. Если количество выполненных утверждений и подтестов не соответствует ожидаемому количеству, тест завершится неудачей.

js
test('top level test', (t) => {
  t.plan(2);
  t.assert.ok('some relevant assertion here');
  t.test('subtest', () => {});
});

При работе с асинхронным кодом функцию plan можно использовать для обеспечения выполнения правильного количества утверждений:

js
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();
  });
});

context.runOnly(shouldRunOnlyTests)

Добавлено в версии: v18.0.0, v16.17.0

  • shouldRunOnlyTests <boolean> Указывает, следует ли запускать только тесты с флагом only.

Если shouldRunOnlyTests имеет значение true, тестовый контекст будет запускать только тесты, у которых установлен параметр only. В противном случае будут запущены все тесты. Если Node.js не был запущен с опцией командной строки --test-only, эта функция не выполняет никаких действий.

js
test('top level test', (t) => {
  // Контекст теста можно настроить для запуска подтестов с опцией 'only'.
  t.runOnly(true);
  return Promise.all([
    t.test('this subtest is now skipped'),
    t.test('this subtest is run', { only: true }),
  ]);
});

context.signal

Добавлено в версии: v18.7.0, v16.17.0

Может использоваться для прерывания подзадач теста, когда тест был прерван.

js
test('top level test', async (t) => {
  await fetch('some/uri', { signal: t.signal });
});

context.skip([message])

Добавлено в версии: v18.0.0, v16.17.0

  • message <string> Необязательное сообщение о пропуске.

Эта функция указывает в выводе теста, что тест был пропущен. Если указано message, оно включается в вывод. Вызов skip() не прерывает выполнение тестовой функции. Эта функция не возвращает значение.

js
test('top level test', (t) => {
  // Обязательно вернитесь здесь, если тест содержит дополнительную логику.
  t.skip('this is skipped');
});

context.todo([message])

Добавлено в версии: v18.0.0, v16.17.0

  • message <string> Необязательное сообщение TODO.

Эта функция добавляет директиву TODO в вывод теста. Если указано message, оно включается в вывод. Вызов todo() не прерывает выполнение тестовой функции. Эта функция не возвращает значение.

js
test('top level test', (t) => {
  // Этот тест помечен как `TODO`
  t.todo('this is a todo');
});

context.test([name][, options][, fn])

[История]

ВерсияИзменения
v18.8.0, v16.18.0Добавлена опция signal.
v18.7.0, v16.17.0Добавлена опция timeout.
v18.0.0, v16.17.0Добавлено в: v18.0.0, v16.17.0
  • 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().

js
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');
    },
  );
});

Класс: SuiteContext

Добавлено в: v18.7.0, v16.17.0

Экземпляр SuiteContext передается каждой функции набора тестов для взаимодействия с исполнителем тестов. Однако конструктор SuiteContext не предоставляется как часть API.

context.filePath

Добавлено в: v22.6.0

Абсолютный путь к файлу теста, который создал текущий набор. Если файл теста импортирует дополнительные модули, которые генерируют наборы, импортированные наборы будут возвращать путь к корневому файлу теста.

context.name

Добавлено в: v18.8.0, v16.18.0

Имя набора тестов.

context.signal

Добавлено в: v18.7.0, v16.17.0

Может быть использован для прерывания подзадач теста, когда тест был прерван.