Spec-Zone.ru › Node.js 20 LTS

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

История
Версия Изменения
v20.0.0

Запуск тестов теперь стабилен.

v18.0.0, v16.17.0

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

Уровень стабильности: 2 - Стабильно

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

Модуль node:test облегчает создание тестов JavaScript. Для доступа к нему:

Модули MJS

import test from 'node:test';

Модули CJS

const test = require('node:test');

Этот модуль доступен только по схеме node:. Следующее не будет работать:

Модули MJS

import test from 'test';

Модули CJS

const test = require('test');

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

  1. Синхронная функция, которая считается проваленной, если она выбрасывает исключение, и проходит в противном случае.
  2. Функция, которая возвращает Promise, которая считается проваленной, если Promise отклоняется, и считается успешной, если Promise выполняется.
  3. Функция, которая получает функцию обратного вызова. Если функция обратного вызова получает любое истинное значение в качестве своего первого аргумента, тест считается проваленным. Если в качестве первого аргумента функции обратного вызова передано ложное значение, тест считается пройденным. Если функция теста получает функцию обратного вызова и также возвращает Promise, тест завершится неудачей.

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

test('synchronous passing test', (t) => {
  // This test passes because it does not throw an exception.
  assert.strictEqual(1, 1);
});

test('synchronous failing test', (t) => {
  // This test fails because it throws an exception.
  assert.strictEqual(1, 2);
});

test('asynchronous passing test', async (t) => {
  // This test passes because the Promise returned by the async
  // function is settled and not rejected.
  assert.strictEqual(1, 1);
});

test('asynchronous failing test', async (t) => {
  // This test fails because the Promise returned by the async
  // function is rejected.
  assert.strictEqual(1, 2);
});

test('failing test using Promises', (t) => {
  // Promises can be used directly as well.
  return new Promise((resolve, reject) => {
    setImmediate(() => {
      reject(new Error('this will cause the test to fail'));
    });
  });
});

test('callback passing test', (t, done) => {
  // done() is the callback function. When the setImmediate() runs, it invokes
  // done() with no arguments.
  setImmediate(done);
});

test('callback failing test', (t, done) => {
  // When the setImmediate() runs, done() is invoked with an Error object and
  // the test fails.
  setImmediate(() => {
    done(new Error('callback failure'));
  });
}); copy

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

Подтесты

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

test('top level test', async (t) => {
  await t.test('subtest 1', (t) => {
    assert.strictEqual(1, 1);
  });

  await t.test('subtest 2', (t) => {
    assert.strictEqual(2, 2);
  });
}); copy

Примечание: beforeEach и afterEach хуки запускаются между каждой выполнением подтеста.

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

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

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

// The skip option is used, but no message is provided.
test('skip option', { skip: true }, (t) => {
  // This code is never executed.
});

// The skip option is used, and a message is provided.
test('skip option with message', { skip: 'this is skipped' }, (t) => {
  // This code is never executed.
});

test('skip() method', (t) => {
  // Make sure to return here as well if the test contains additional logic.
  t.skip();
});

test('skip() method with message', (t) => {
  // Make sure to return here as well if the test contains additional logic.
  t.skip('this is skipped');
}); copy

Тесты TODO

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

// The todo option is used, but no message is provided.
test('todo option', { todo: true }, (t) => {
  // This code is executed, but not treated as a failure.
  throw new Error('this does not fail the test');
});

// The todo option is used, and a message is provided.
test('todo option with message', { todo: 'this is a todo test' }, (t) => {
  // This code is executed.
});

test('todo() method', (t) => {
  t.todo();
});

test('todo() method with message', (t) => {
  t.todo('this is a todo test and is not treated as a failure');
  throw new Error('this does not fail the test');
}); copy

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

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

describe('A thing', () => {
  it('should work', () => {
    assert.strictEqual(1, 1);
  });

  it('should be ok', () => {
    assert.strictEqual(2, 2);
  });

  describe('a nested thing', () => {
    it('should work', () => {
      assert.strictEqual(3, 3);
    });
  });
}); copy

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

Модули MJS

import { describe, it } from 'node:test';

Модули CJS

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

only тесты

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

// Assume Node.js is run with the --test-only command-line option.
// The 'only' option is set, so this test is run.
test('this test is run', { only: true }, async (t) => {
  // Within this test, all subtests are run by default.
  await t.test('running subtest');

  // The test context can be updated to run subtests with the 'only' option.
  t.runOnly(true);
  await t.test('this subtest is now skipped');
  await t.test('this subtest is run', { only: true });

  // Switch the context back to execute all tests.
  t.runOnly(false);
  await t.test('this subtest is now run');

  // Explicitly do not run these tests.
  await t.test('skipped subtest 3', { only: false });
  await t.test('skipped subtest 4', { skip: true });
});

// The 'only' option is not set, so this test is skipped.
test('this test is not run', () => {
  // This code is not run.
  throw new Error('fail');
}); copy

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

Опция командной строки --test-name-pattern может быть использована для запуска только тестов, имя которых соответствует заданному шаблону. Шаблоны имён тестов интерпретируются как JavaScript регулярные выражения. Опция --test-name-pattern может быть указана несколько раз для запуска вложенных тестов. Для каждого выполняемого теста также запускаются соответствующие хуки теста, такие как beforeEach().

В данном файле теста, запуск Node.js с опцией --test-name-pattern="test [1-3]" заставит запустить test 1, test 2, и test 3. Если test 1 не соответствовало шаблону имени теста, то его подтесты не будут выполняться, несмотря на соответствие шаблону. Тот же набор тестов можно также запустить, передавая --test-name-pattern несколько раз (например, --test-name-pattern="test 1", --test-name-pattern="test 2", и т. д.).

test('test 1', async (t) => {
  await t.test('test 2');
  await t.test('test 3');
});

test('Test 4', async (t) => {
  await t.test('Test 5');
  await t.test('test 6');
}); copy

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

Шаблоны имён тестов не изменяют набор файлов, которые выполняет запускатель тестов.

Внезапная асинхронная активность

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

В следующем примере тест завершается с двумя ещё не завершёнными операциями setImmediate(). Первый setImmediate() пытается создать новый подтест. Поскольку родительский тест уже завершен и вывел свои результаты, новый подтест немедленно помечается как проваленный и сообщается позже в <Поток тестов>.

Второй setImmediate() создаёт событие uncaughtException. События uncaughtException и unhandledRejection, исходящие от завершённого теста, помечаются как проваленные модулем test и сообщаются как диагностические предупреждения на верхнем уровне <Потоком тестов>.

test('a test that creates asynchronous activity', (t) => {
  setImmediate(() => {
    t.test('subtest that is created too late', (t) => {
      throw new Error('error1');
    });
  });

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

  // The test finishes after this line.
}); copy

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

Добавлен в: v19.2.0, v18.13.0
Уровень стабильности: 1 - Экспериментально

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

node --test --watch copy

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

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

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

node --test copy

По умолчанию Node.js рекурсивно ищет файлы JavaScript в текущей директории, соответствующие определённой схеме именования. Соответствующие файлы выполняются как тестовые файлы. Дополнительная информация о требуемой схеме именования тестовых файлов и поведении представлена в разделе модель выполнения тестового исполнителя.

В качестве альтернативы можно указать один или несколько путей в качестве конечных аргументов команды Node.js, как показано ниже.

node --test test1.js test2.mjs custom_test_dir/ copy

В этом примере тестовый исполняемый файл выполнит файлы test1.js и test2.mjs. Тестовый исполняемый файл также рекурсивно найдёт тестовые файлы в директории custom_test_dir/.

Модель выполнения тестового исполнителя

При поиске тестовых файлов для выполнения тестовый исполняемый файл ведёт себя следующим образом:

  • Все файлы, явно указанные пользователем, выполняются.
  • Если пользователь не указал никаких путей, текущая рабочая директория рекурсивно просматривается на файлы, как указано в следующих шагах.
  • node_modules каталоги пропускаются, если они не указаны пользователем явно.
  • Если встречается каталог с именем test, тестовый исполняемый файл рекурсивно ищет все файлы .js, .cjs, и .mjs. Все эти файлы обрабатываются как тестовые файлы и не должны соответствовать специфической схеме именования, описанной ниже. Это сделано для поддержки проектов, помещающих все тесты в один каталог test.
  • Во всех других каталогах файлы .js, .cjs, и .mjs, соответствующие следующим шаблонам, обрабатываются как тестовые файлы:
    • ^test$ - Файлы, чьё имя файла является строкой 'test'. Примеры: test.js, test.cjs, test.mjs.
    • ^test-.+ - Файлы, чьё имя файла начинается со строки 'test-', за которой следуют один или более символов. Примеры: test-example.js, test-another-example.mjs.
    • .+[\.\-\_]test$ - Файлы, чьё имя файла заканчивается на .test, -test, или _test, перед которыми стоят один или более символов. Примеры: example.test.js, example-test.cjs, example_test.mjs.
    • Другие типы файлов, понятные Node.js, такие как .node и .json не автоматически выполняются тестовым исполнителем, но поддерживаются, если они явно указаны в командной строке.

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

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

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

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

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

Покрытие кода может быть отключено на ряде строк с помощью следующего синтаксиса комментария:

/* node:coverage disable */
if (anAlwaysFalseCondition) {
  // Code in this branch will never be executed, but the lines are ignored for
  // coverage purposes. All lines following the 'disable' comment are ignored
  // until a corresponding 'enable' comment is encountered.
  console.log('this is never executed');
}
/* node:coverage enable */ copy

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

/* node:coverage ignore next */
if (anAlwaysFalseCondition) { console.log('this is never executed'); }

/* node:coverage ignore next 3 */
if (anAlwaysFalseCondition) {
  console.log('this is never executed');
} copy

Отчётчики покрытия

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

node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info copy

Ограничения

Функциональность тестового исполнителя по сбору покрытия кода не поддерживает исключение определённых файлов или каталогов из отчёта о покрытии.

Мокирование

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

Модули MJS

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.calls.length, 0);
  assert.strictEqual(sum(3, 4), 7);
  assert.strictEqual(sum.mock.calls.length, 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();
});

Модули CJS

'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.calls.length, 0);
  assert.strictEqual(sum(3, 4), 7);
  assert.strictEqual(sum.mock.calls.length, 1);

  const call = sum.mock.calls[0];
  assert.deepStrictEqual(call.arguments, [3, 4]);
  assert.strictEqual(call.result, 7);
  assert.strictEqual(call.error, undefined);

  // Reset the globally tracked mocks.
  mock.reset();
});

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

test('spies on an object method', (t) => {
  const number = {
    value: 5,
    add(a) {
      return this.value + a;
    },
  };

  t.mock.method(number, 'add');
  assert.strictEqual(number.add.mock.calls.length, 0);
  assert.strictEqual(number.add(3), 8);
  assert.strictEqual(number.add.mock.calls.length, 1);

  const call = number.add.mock.calls[0];

  assert.deepStrictEqual(call.arguments, [3]);
  assert.strictEqual(call.result, 8);
  assert.strictEqual(call.target, undefined);
  assert.strictEqual(call.this, number);
}); copy

Таймеры

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

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

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

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

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

Модули MJS

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

test('mocks setTimeout to be executed synchronously without having to actually wait for it', () => {
  const fn = mock.fn();

  // Optionally choose what to mock
  mock.timers.enable({ apis: ['setTimeout'] });
  setTimeout(fn, 9999);
  assert.strictEqual(fn.mock.callCount(), 0);

  // Advance in time
  mock.timers.tick(9999);
  assert.strictEqual(fn.mock.callCount(), 1);

  // Reset the globally tracked mocks.
  mock.timers.reset();

  // If you call reset mock instance, it will also reset timers instance
  mock.reset();
});

Модули CJS

const assert = require('node:assert');
const { mock, test } = require('node:test');

test('mocks setTimeout to be executed synchronously without having to actually wait for it', () => {
  const fn = mock.fn();

  // Optionally choose what to mock
  mock.timers.enable({ apis: ['setTimeout'] });
  setTimeout(fn, 9999);
  assert.strictEqual(fn.mock.callCount(), 0);

  // Advance in time
  mock.timers.tick(9999);
  assert.strictEqual(fn.mock.callCount(), 1);

  // Reset the globally tracked mocks.
  mock.timers.reset();

  // If you call reset mock instance, it will also reset timers instance
  mock.reset();
});

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

Модули MJS

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

test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
  const fn = context.mock.fn();

  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['setTimeout'] });
  setTimeout(fn, 9999);
  assert.strictEqual(fn.mock.callCount(), 0);

  // Advance in time
  context.mock.timers.tick(9999);
  assert.strictEqual(fn.mock.callCount(), 1);
});

Модули CJS

const assert = require('node:assert');
const { test } = require('node:test');

test('mocks setTimeout to be executed synchronously without having to actually wait for it', (context) => {
  const fn = context.mock.fn();

  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['setTimeout'] });
  setTimeout(fn, 9999);
  assert.strictEqual(fn.mock.callCount(), 0);

  // Advance in time
  context.mock.timers.tick(9999);
  assert.strictEqual(fn.mock.callCount(), 1);
});

Даты

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

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

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

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

Модули MJS

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

test('mocks the Date object', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'] });
  // If not specified, the initial date will be based on 0 in the UNIX epoch
  assert.strictEqual(Date.now(), 0);

  // Advance in time will also advance the date
  context.mock.timers.tick(9999);
  assert.strictEqual(Date.now(), 9999);
});

Модули CJS

const assert = require('node:assert');
const { test } = require('node:test');

test('mocks the Date object', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'] });
  // If not specified, the initial date will be based on 0 in the UNIX epoch
  assert.strictEqual(Date.now(), 0);

  // Advance in time will also advance the date
  context.mock.timers.tick(9999);
  assert.strictEqual(Date.now(), 9999);
});

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

Модули MJS

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

test('mocks the Date object with initial time', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Advance in time will also advance the date
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 300);
});

Модули CJS

const assert = require('node:assert');
const { test } = require('node:test');

test('mocks the Date object with initial time', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Advance in time will also advance the date
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 300);
});

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

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

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

Модули MJS

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

test('sets the time of a date object', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Advance in time will also advance the date
  context.mock.timers.setTime(1000);
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 1200);
});

Модули CJS

const assert = require('node:assert');
const { test } = require('node:test');

test('sets the time of a date object', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['Date'], now: 100 });
  assert.strictEqual(Date.now(), 100);

  // Advance in time will also advance the date
  context.mock.timers.setTime(1000);
  context.mock.timers.tick(200);
  assert.strictEqual(Date.now(), 1200);
});

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

Модули MJS

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

test('runs timers as setTime passes ticks', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const fn = context.mock.fn();
  setTimeout(fn, 1000);

  context.mock.timers.setTime(800);
  // Timer is not executed as the time is not yet reached
  assert.strictEqual(fn.mock.callCount(), 0);
  assert.strictEqual(Date.now(), 800);

  context.mock.timers.setTime(1200);
  // Timer is executed as the time is now reached
  assert.strictEqual(fn.mock.callCount(), 1);
  assert.strictEqual(Date.now(), 1200);
});

Модули CJS

const assert = require('node:assert');
const { test } = require('node:test');

test('runs timers as setTime passes ticks', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const fn = context.mock.fn();
  setTimeout(fn, 1000);

  context.mock.timers.setTime(800);
  // Timer is not executed as the time is not yet reached
  assert.strictEqual(fn.mock.callCount(), 0);
  assert.strictEqual(Date.now(), 800);

  context.mock.timers.setTime(1200);
  // Timer is executed as the time is now reached
  assert.strictEqual(fn.mock.callCount(), 1);
  assert.strictEqual(Date.now(), 1200);
});

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

Модули MJS

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

test('runs timers as setTime passes ticks', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const fn = context.mock.fn();
  setTimeout(fn, 1000);
  setTimeout(fn, 2000);
  setTimeout(fn, 3000);

  context.mock.timers.runAll();
  // All timers are executed as the time is now reached
  assert.strictEqual(fn.mock.callCount(), 3);
  assert.strictEqual(Date.now(), 3000);
});

Модули CJS

const assert = require('node:assert');
const { test } = require('node:test');

test('runs timers as setTime passes ticks', (context) => {
  // Optionally choose what to mock
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const fn = context.mock.fn();
  setTimeout(fn, 1000);
  setTimeout(fn, 2000);
  setTimeout(fn, 3000);

  context.mock.timers.runAll();
  // All timers are executed as the time is now reached
  assert.strictEqual(fn.mock.callCount(), 3);
  assert.strictEqual(Date.now(), 3000);
});

Отчётчики о тестах

История
Версия Изменения
v19.9.0

Отчётчики теперь доступны в node:test/reporters.

v19.6.0, v18.15.0

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

Модуль node:test поддерживает передачу флагов --test-reporter для тестового исполнителя, чтобы использовать определённый отчётчик.

Поддерживаются следующие встроенные отчётчики:

  • tap Отчётчик tap выводит результаты тестов в формате TAP.

  • spec Отчётчик spec выводит результаты тестов в удобочитаемом формате.

  • dot Отчётчик dot выводит результаты тестов в компактном формате, где каждый прошедший тест представлен ., а каждый неудачный тест — X.

  • junit Отчётчик junit выводит результаты тестов в формате jUnit XML.

  • lcov Отчётчик lcov выводит охват кода при использовании флага --experimental-test-coverage.

Если stdout является TTY, по умолчанию используется отчётчик spec . В противном случае, по умолчанию используется отчётчик tap.

Точный вывод этих отчётчиков может изменяться между версиями Node.js и не должен использоваться в программировании. Если требуется программный доступ к выводу тестового исполнителя, используйте события, испускаемые <TestsStream>.

Отчётчики доступны через модуль node:test/reporters:

Модули MJS

import { tap, spec, dot, junit, lcov } from 'node:test/reporters';

Модули CJS

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

Пользовательские отчётчики

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

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

Модули MJS

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;

Модули CJS

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;

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

Модули MJS

export default async function * customReporter(source) {
  for await (const event of source) {
    switch (event.type) {
      case 'test:dequeue':
        yield `test ${event.data.name} dequeued`;
        break;
      case 'test:enqueue':
        yield `test ${event.data.name} enqueued`;
        break;
      case 'test:watch:drained':
        yield 'test watch queue drained';
        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';
        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;
      }
    }
  }
}

Модули CJS

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

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

Несколько отчётчиков

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

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

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

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

run([options])

История
Версия Изменения
v20.14.0

Добавлен параметр forceExit.

v20.1.0, v18.17.0

Добавлен параметр testNamePatterns.

v18.9.0, v16.19.0

Добавлен в: v18.9.0, v16.19.0

  • options <Объект> Параметры конфигурации для запуска тестов. Поддерживаются следующие свойства:
    • concurrency <число> | <булево> Если указано число, столько процессов тестов будет запущено параллельно, где каждый процесс соответствует одному файлу тестов. Если true, то os.availableParallelism() - 1 файлов тестов будут запущены параллельно. Если false, то будет запускаться только один файл тестов за раз. По умолчанию: false.
    • files: <Массив> Массив, содержащий список файлов для запуска. По умолчанию соответствие файлам из модели выполнения тестового исполнителя.
    • forceExit: <булево> Настраивает тестовый исполнитель на выход из процесса после завершения выполнения всех известных тестов, даже если цикл событий в противном случае останется активным. По умолчанию: false.
    • inspectPort <число> | <Функция> Устанавливает порт инспектора тестового дочернего процесса. Это может быть число или функция, которая не принимает аргументов и возвращает число. Если предоставлено пустое значение, каждый процесс получает свой собственный порт, увеличивающийся с порта основного процесса на process.debugPort. По умолчанию: undefined.
    • only: <булево> Если истинно, контекст теста будет запускать только тесты, у которых установлен параметр only.
    • setup <Функция> Функция, которая принимает экземпляр TestsStream и может использоваться для настройки слушателей до запуска любых тестов. По умолчанию: undefined.
    • signal <AbortSignal> Позволяет прервать выполнение теста.
    • testNamePatterns <строка> | <RegExp> | <Массив> Строка, RegExp или массив RegExp, которые могут использоваться для запуска только тестов, имена которых соответствуют предоставленному шаблону. Шаблоны имён тестов интерпретируются как регулярные выражения JavaScript. Для каждого выполняемого теста также выполняются любые соответствующие тестовые хуки, такие как beforeEach(). По умолчанию: undefined.
    • timeout <число> Количество миллисекунд, после которого выполнение теста завершится с ошибкой. Если не указано, подтесты наследуют это значение от родительского теста. По умолчанию: Infinity.
    • watch <булево> Выполнять ли в режиме слежения.
    • shard <Объект> Выполнение тестов в определённом фрагменте. По умолчанию: undefined.
      • index <число> — положительное целое число от 1 до <total>, которое определяет индекс фрагмента для выполнения. Этот параметр обязателен.
      • total <число> — положительное целое число, которое определяет общее количество фрагментов для разделения файлов тестов. Этот параметр обязателен.
  • Возвращает: <TestsStream>

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

Модули MJS

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

Модули CJS

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

Добавлен в: v20.13.0
  • name <строка> Название набора, отображаемое при сообщении о результатах тестирования. По умолчанию: свойство name объекта fn, или '<anonymous>', если у fn нет имени.
  • options <Объект> Необязательные параметры конфигурации набора. Поддерживает те же параметры, что и test([name][, options][, fn]).
  • fn <Функция> | <Асинхронная функция> Функция набора, объявляющая вложенные тесты и наборы. Первым аргументом этой функции является объект SuiteContext. По умолчанию: функция-пустышка.
  • Возвращает: <Promise> Немедленно выполняется с undefined.

Функция suite() импортируется из модуля node:test.

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

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

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

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

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

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

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

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

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

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

История
Версия Изменения
v20.2.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 <строка> Название теста, отображаемое при сообщении о результатах. По умолчанию: свойство name объекта fn, или '<anonymous>', если у fn нет имени.
  • options <Объект> Параметры конфигурации теста. Поддерживаются следующие свойства:
    • concurrency <число> | <логическое> Если указано число, столько тестов будет выполняться параллельно в потоке приложения. Если true, все запланированные асинхронные тесты выполняются одновременно в потоке. Если false, только один тест выполняется за раз. Если не указано, подтесты наследуют это значение от родительского теста. По умолчанию: false.
    • only <логическое> Если истинно, и контекст теста настроен на запуск only тестов, этот тест будет запущен. В противном случае тест пропускается. По умолчанию: false.
    • signal <AbortSignal> Разрешает прерывание текущего теста.
    • skip <логическое> | <строка> Если истинно, тест пропускается. Если указана строка, эта строка отображается в результатах теста как причина пропуска. По умолчанию: false.
    • todo <логическое> | <строка> Если истинно, тест помечен как TODO. Если указана строка, эта строка отображается в результатах теста как причина, по которой тест помечен как TODO. По умолчанию: false.
    • timeout <число> Количество миллисекунд, после которого тест будет посчитан как проваленный. Если не указано, подтесты наследуют это значение от родительского теста. По умолчанию: Infinity.
    • plan <число> Количество ожидаемых утверждений и подтестов в тесте. Если количество выполненных утверждений в тесте не соответствует указанному в плане, тест будет провален. По умолчанию: undefined.
  • fn <Функция> | <Асинхронная функция> Функция, подлежащая тестированию. Первым аргументом этой функции является объект TestContext. Если тест использует обратные вызовы, функция обратного вызова передаётся как второй аргумент. По умолчанию: функция-пустышка.
  • Возвращает: <Promise> Выполняется с undefined после завершения теста или немедленно, если тест выполняется в рамках набора.

Функция test() — значение, импортированное из модуля test.

Каждый вызов этой функции приводит к сообщению о тесте в <Поток тестов>.

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

Функция test() возвращает Promise объект, который выполняется после завершения теста. Если test() вызывается в пределах набора, выполняется немедленно. Значение возврата обычно можно отбросить для тестов верхнего уровня. Однако возвращаемое значение из подтестов должно быть использовано для предотвращения завершения родительского теста в первую очередь и отмены подтеста, как показано в следующем примере.

test('top level test', async (t) => {
  // The setTimeout() in the following subtest would cause it to outlive its
  // parent test if 'await' is removed on the next line. Once the parent test
  // completes, it will cancel any outstanding subtests.
  await t.test('longer running subtest', async (t) => {
    return new Promise((resolve, reject) => {
      setTimeout(resolve, 1000);
    });
  });
}); copy

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

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

Сокращённая запись для пропуска теста, аналогично test([name], { skip: true }[, fn]).

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

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

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

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

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

Псевдоним для suite().

Функция describe() импортируется из модуля node:test.

describe.skip([name][, options][, fn])

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

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

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

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

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

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

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

История
Версия Изменения
v19.8.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]).

END_OF_DOCUMENT_MARKER

before([fn][, options])

Added in: v18.8.0, v16.18.0
  • fn <Функция> | <AsyncФункция> Функция-обработчик. Если обработчик использует колбэки, то функция-колбэк передаётся в качестве второго аргумента. По умолчанию: функция-пустышка.
  • options <Объект> Параметры конфигурации обработчика. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполнение обработчика.
    • options <число> Количество миллисекунд, после которого обработчик завершит работу с ошибкой. Если не указано, подтесты унаследуют это значение от родительского теста. По умолчанию: Infinity.

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

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

after([fn][, options])

Added in: v18.8.0, v16.18.0
  • fn <Функция> | <AsyncФункция> Функция-обработчик. Если обработчик использует колбэки, то функция-колбэк передаётся в качестве второго аргумента. По умолчанию: функция-пустышка.
  • options <Объект> Параметры конфигурации обработчика. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполнение обработчика.
    • timeout <число> Количество миллисекунд, после которого обработчик завершит работу с ошибкой. Если не указано, подтесты унаследуют это значение от родительского теста. По умолчанию: Infinity.

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

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

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

beforeEach([fn][, options])

Added in: v18.8.0, v16.18.0
  • fn <Функция> | <AsyncФункция> Функция-обработчик. Если обработчик использует колбэки, то функция-колбэк передаётся в качестве второго аргумента. По умолчанию: функция-пустышка.
  • options <Объект> Параметры конфигурации обработчика. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполнение обработчика.
    • timeout <число> Количество миллисекунд, после которого обработчик завершит работу с ошибкой. Если не указано, подтесты унаследуют это значение от родительского теста. По умолчанию: Infinity.

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

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

afterEach([fn][, options])

Added in: v18.8.0, v16.18.0
  • fn <Функция> | <AsyncФункция> Функция-обработчик. Если обработчик использует колбэки, то функция-колбэк передаётся в качестве второго аргумента. По умолчанию: функция-пустышка.
  • options <Объект> Параметры конфигурации обработчика. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполнение обработчика.
    • timeout <число> Количество миллисекунд, после которого обработчик завершит работу с ошибкой. Если не указано, подтесты унаследуют это значение от родительского теста. По умолчанию: Infinity.

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

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

Class: MockFunctionContext

Added in: v19.1.0, v18.13.0

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

ctx.calls

Added in: v19.1.0, v18.13.0
  • <Массив>

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

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

ctx.callCount()

Added in: v19.1.0, v18.13.0
  • Возвращает: <целое число> Количество вызовов мока.

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

ctx.mockImplementation(implementation)

Added in: v19.1.0, v18.13.0
  • implementation <Функция> | <AsyncФункция> Функция, которая будет использоваться в качестве новой реализации мока.

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

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

test('changes a mock behavior', (t) => {
  let cnt = 0;

  function addOne() {
    cnt++;
    return cnt;
  }

  function addTwo() {
    cnt += 2;
    return cnt;
  }

  const fn = t.mock.fn(addOne);

  assert.strictEqual(fn(), 1);
  fn.mock.mockImplementation(addTwo);
  assert.strictEqual(fn(), 3);
  assert.strictEqual(fn(), 5);
}); copy

ctx.mockImplementationOnce(implementation[, onCall])

Added in: v19.1.0, v18.13.0
  • implementation <Функция> | <AsyncФункция> Функция, которая будет использоваться в качестве реализации мока для вызова с номером, указанным в onCall.
  • onCall <целое число> Номер вызова, для которого будет использоваться implementation. Если указанный вызов уже произошёл, то выбрасывается исключение. По умолчанию: номер следующего вызова.

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

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

test('changes a mock behavior once', (t) => {
  let cnt = 0;

  function addOne() {
    cnt++;
    return cnt;
  }

  function addTwo() {
    cnt += 2;
    return cnt;
  }

  const fn = t.mock.fn(addOne);

  assert.strictEqual(fn(), 1);
  fn.mock.mockImplementationOnce(addTwo);
  assert.strictEqual(fn(), 3);
  assert.strictEqual(fn(), 4);
}); copy

ctx.resetCalls()

Added in: v19.3.0, v18.13.0

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

ctx.restore()

Added in: v19.1.0, v18.13.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 <Функция> | <Асинхронная функция> Необязательная функция для создания подмены. По умолчанию: функция без действий.
  • implementation <Функция> | <Асинхронная функция> Необязательная функция, используемая в качестве реализации подмены для original. Это полезно для создания подмен, которые демонстрируют одно поведение для определённого числа вызовов, а затем восстанавливают поведение original. По умолчанию: функция, указанная original.
  • options <Объект> Необязательные параметры конфигурации для функции подмены. Поддерживаются следующие свойства:
    • times <целое число> Количество раз, когда подмена будет использовать поведение implementation. После того, как функция подмены будет вызвана times раз, она автоматически восстановит поведение original. Это значение должно быть целым числом, большим нуля. По умолчанию: Infinity.
  • Возвращает: <Прокси> Функция подмены. Функция подмены содержит специальное свойство mock, которое является экземпляром MockFunctionContext и может использоваться для проверки и изменения поведения функции подмены.

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

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

test('mocks a counting function', (t) => {
  let cnt = 0;

  function addOne() {
    cnt++;
    return cnt;
  }

  function addTwo() {
    cnt += 2;
    return cnt;
  }

  const fn = t.mock.fn(addOne, addTwo, { times: 2 });

  assert.strictEqual(fn(), 2);
  assert.strictEqual(fn(), 4);
  assert.strictEqual(fn(), 5);
  assert.strictEqual(fn(), 6);
}); copy

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

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

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

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

Добавлен в: v19.1.0, v18.13.0
  • object <Объект> Объект, метод которого подменяется.
  • methodName <строка> | <символ> Идентификатор метода на object для подмены. Если object[methodName] не является функцией, выбрасывается ошибка.
  • implementation <Функция> | <Асинхронная функция> Необязательная функция, используемая в качестве реализации подмены для object[methodName]. По умолчанию: исходный метод, указанный object[methodName].
  • options <Объект> Необязательные параметры конфигурации для метода подмены. Поддерживаются следующие свойства:
    • getter <логическое значение> Если true, object[methodName] обрабатывается как геттер. Эта опция не может использоваться с опцией setter. По умолчанию: false.
    • setter <логическое значение> Если true, object[methodName] обрабатывается как сеттер. Эта опция не может использоваться с опцией getter. По умолчанию: false.
    • times <целое число> Количество раз, когда подмена будет использовать поведение implementation. После того, как подменяемый метод был вызван times раз, он автоматически восстановит исходное поведение. Это значение должно быть целым числом, большим нуля. По умолчанию: Infinity.
  • Возвращает: <Прокси> Подменяемый метод. Подменяемый метод содержит специальное свойство mock, которое является экземпляром MockFunctionContext и может использоваться для проверки и изменения поведения подменяемого метода.

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

test('spies on an object method', (t) => {
  const number = {
    value: 5,
    subtract(a) {
      return this.value - a;
    },
  };

  t.mock.method(number, 'subtract');
  assert.strictEqual(number.subtract.mock.calls.length, 0);
  assert.strictEqual(number.subtract(3), 2);
  assert.strictEqual(number.subtract.mock.calls.length, 1);

  const call = number.subtract.mock.calls[0];

  assert.deepStrictEqual(call.arguments, [3]);
  assert.strictEqual(call.result, 2);
  assert.strictEqual(call.error, undefined);
  assert.strictEqual(call.target, undefined);
  assert.strictEqual(call.this, number);
}); copy

mock.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

Добавлен в: v20.4.0
Устойчивость: 1 - Экспериментальный

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

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

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

timers.enable([enableOptions])

История
Версия Изменения
v20.11.0

Обновлены параметры на объект опций с доступными API и начальной эпохой по умолчанию.

v20.4.0

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

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

  • enableOptions <Объект> Дополнительные параметры конфигурации для включения моделирования таймеров. Поддерживаются следующие свойства:
    • apis <Массив> Необязательный массив, содержащий таймеры для моделирования. В настоящее время поддерживаются значения таймеров 'setInterval', 'setTimeout', 'setImmediate', и 'Date'. По умолчанию: ['setInterval', 'setTimeout', 'setImmediate', 'Date']. Если массив не предоставлен, все API, связанные со временем ('setInterval', 'clearInterval', 'setTimeout', 'clearTimeout', и 'Date') будут смоделированы по умолчанию.
    • now <число> | <Дата> Необязательное число или объект Date, представляющее начальное время (в миллисекундах) для использования в качестве значения для Date.now(). По умолчанию: 0.

Примечание: При включении моделирования для конкретного таймера его связанная функция clear также будет неявно смоделирована.

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

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

Модули MJS

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

Модули CJS

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

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

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

Модули MJS

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

Модули CJS

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

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

Модули MJS

import { mock } from 'node:test';
mock.timers.enable({ apis: ['Date'], now: new Date() });

Модули CJS

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

В качестве альтернативы, если вы вызываете mock.timers.enable() без параметров:

Все таймеры ('setInterval', 'clearInterval', 'setTimeout', и 'clearTimeout') будут смоделированы. Функции setInterval, clearInterval, setTimeout, и clearTimeout из node:timers, node:timers/promises, и globalThis также будут смоделированы. А также глобальный объект Date.

timers.reset()

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

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

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

Модули MJS

import { mock } from 'node:test';
mock.timers.reset();

Модули CJS

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

timers[Symbol.dispose]()

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

timers.tick(milliseconds)

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

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

  • milliseconds <число> Количество времени в миллисекундах для продвижения таймеров.

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

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

Модули MJS

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

Модули CJS

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 может вызываться многократно

Модули MJS

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 twoSeconds = 3000;
  context.mock.timers.tick(twoSeconds);
  context.mock.timers.tick(twoSeconds);
  context.mock.timers.tick(twoSeconds);

  assert.strictEqual(fn.mock.callCount(), 1);
});

Модули CJS

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 twoSeconds = 3000;
  context.mock.timers.tick(twoSeconds);
  context.mock.timers.tick(twoSeconds);
  context.mock.timers.tick(twoSeconds);

  assert.strictEqual(fn.mock.callCount(), 1);
});

Перемещение времени с помощью .tick также переместит время для любого объекта Date, созданного после включения мока (если Date также был установлен для моделирования).

Модули MJS

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

Модули CJS

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) неявно смоделированы. Посмотрите на этот пример с использованием setTimeout:

Модули MJS

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

  // Implicity 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);
});

Модули CJS

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

  // Implicity 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.

Модули MJS

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

Модули CJS

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:

Модули MJS

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

Модули CJS

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

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

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

Модули MJS

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

test('runAll functions following the given order', (context) => {
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const results = [];
  setTimeout(() => results.push(1), 9999);

  // Notice that if both timers have the same timeout,
  // the order of execution is guaranteed
  setTimeout(() => results.push(3), 8888);
  setTimeout(() => results.push(2), 8888);

  assert.deepStrictEqual(results, []);

  context.mock.timers.runAll();
  assert.deepStrictEqual(results, [3, 2, 1]);
  // The Date object is also advanced to the furthest timer's time
  assert.strictEqual(Date.now(), 9999);
});

Модули CJS

const assert = require('node:assert');
const { test } = require('node:test');

test('runAll functions following the given order', (context) => {
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
  const results = [];
  setTimeout(() => results.push(1), 9999);

  // Notice that if both timers have the same timeout,
  // the order of execution is guaranteed
  setTimeout(() => results.push(3), 8888);
  setTimeout(() => results.push(2), 8888);

  assert.deepStrictEqual(results, []);

  context.mock.timers.runAll();
  assert.deepStrictEqual(results, [3, 2, 1]);
  // The Date object is also advanced to the furthest timer's time
  assert.strictEqual(Date.now(), 9999);
});

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

timers.setTime(milliseconds)

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

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

Модули MJS

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

test('runAll functions following the given order', (context) => {
  const now = Date.now();
  const setTime = 1000;
  // Date.now is not mocked
  assert.deepStrictEqual(Date.now(), now);

  context.mock.timers.enable({ apis: ['Date'] });
  context.mock.timers.setTime(setTime);
  // Date.now is now 1000
  assert.strictEqual(Date.now(), setTime);
});

Модули CJS

const assert = require('node:assert');
const { test } = require('node:test');

test('setTime replaces current time', (context) => {
  const now = Date.now();
  const setTime = 1000;
  // Date.now is not mocked
  assert.deepStrictEqual(Date.now(), now);

  context.mock.timers.enable({ apis: ['Date'] });
  context.mock.timers.setTime(setTime);
  // Date.now is now 1000
  assert.strictEqual(Date.now(), setTime);
});
Работа дат и таймеров вместе

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

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

Модули MJS

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

Модули CJS

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

Добавлен тип для событий test:pass и test:fail, когда тест является набором тестов.

v18.9.0, v16.19.0

Добавлен в: v18.9.0, v16.19.0

  • Расширяет <Readable>

Успешное вызов метода run() вернет новый объект <TestsStream>, который транслирует серию событий, представляющих выполнение тестов. TestsStream будет излучать события в порядке определения тестов.

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

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

  • data <Объект>
    • summary <Объект> Объект, содержащий отчет о покрытии кода.
      • files <Массив> Массив отчетов о покрытии для отдельных файлов. Каждый отчет — это объект со следующей схемой:
        • path <строка> Абсолютный путь к файлу.
        • totalLineCount <число> Общее количество строк.
        • totalBranchCount <число> Общее количество ветвей.
        • totalFunctionCount <число> Общее количество функций.
        • coveredLineCount <число> Количество покрытых строк.
        • coveredBranchCount <число> Количество покрытых ветвей.
        • coveredFunctionCount <число> Количество покрытых функций.
        • coveredLinePercent <число> Процент покрытых строк.
        • coveredBranchPercent <число> Процент покрытых ветвей.
        • coveredFunctionPercent <число> Процент покрытых функций.
        • functions <Массив> Массив функций, представляющих покрытие функций.
          • name <строка> Имя функции.
          • line <число> Номер строки, где определена функция.
          • count <число> Количество вызовов функции.
        • branches <Массив> Массив ветвей, представляющих покрытие ветвей.
          • line <число> Номер строки, где определена ветвь.
          • count <число> Количество пройденных ветвей.
        • lines <Массив> Массив строк, представляющий номера строк и количество их покрытий.
          • line <число> Номер строки.
          • count <число> Количество покрытий строки.
      • totals <Объект> Объект, содержащий сводку покрытия для всех файлов.
        • totalLineCount <число> Общее количество строк.
        • totalBranchCount <число> Общее количество ветвей.
        • totalFunctionCount <число> Общее количество функций.
        • coveredLineCount <число> Количество покрытых строк.
        • coveredBranchCount <число> Количество покрытых ветвей.
        • coveredFunctionCount <число> Количество покрытых функций.
        • coveredLinePercent <число> Процент покрытых строк.
        • coveredBranchPercent <число> Процент покрытых ветвей.
        • coveredFunctionPercent <число> Процент покрытых функций.
      • workingDirectory <строка> Рабочая директория в момент начала сбора статистики покрытия кода. Это полезно для отображения относительных путей в случае, если тесты изменили рабочую директорию процесса Node.js.
    • nesting <число> Уровень вложенности теста.

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

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

  • data <Object>
    • column <number> | <undefined> Номер столбца, в котором определён тест, или undefined , если тест был запущен через REPL.
    • details <Object> Дополнительные метаданные выполнения.
      • passed <boolean> Прошёл ли тест успешно.
      • duration_ms <number> Длительность теста в миллисекундах.
      • error <Error> | <undefined> Ошибка, обертывающая ошибку, выброшенную тестом, если он не прошёл.
        • cause <Error> Фактическая ошибка, выброшенная тестом.
      • type <string> | <undefined> Тип теста, используемый для обозначения набора тестов.
    • file <string> | <undefined> Путь к файлу с тестом, undefined если тест был запущен через REPL.
    • line <number> | <undefined> Номер строки, в которой определён тест, или undefined , если тест был запущен через REPL.
    • name <string> Название теста.
    • nesting <number> Уровень вложенности теста.
    • testNumber <number> Порядковый номер теста.
    • todo <string> | <boolean> | <undefined> Присутствует, если вызвана функция context.todo
    • skip <string> | <boolean> | <undefined> Присутствует, если вызвана функция context.skip

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

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

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

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

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

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

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

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

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

Имеет место при добавлении теста в очередь на выполнение.

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

  • data <Объект>
    • column <число> | <неопределено> Номер столбца, в котором определён тест, или undefined , если тест был запущен через REPL.
    • details <Объект> Дополнительные метаданные выполнения.
      • duration_ms <число> Продолжительность теста в миллисекундах.
      • error <Ошибка> Ошибка, обертывающая ошибку, брошенную тестом.
        • cause <Ошибка> Фактическая ошибка, брошенная тестом.
      • type <строка> | <неопределено> Тип теста, используемый для обозначения, является ли это набором тестов.
    • file <строка> | <неопределено> Путь к файлу с тестом, undefined , если тест был запущен через REPL.
    • line <число> | <неопределено> Номер строки, в которой определён тест, или undefined , если тест был запущен через REPL.
    • name <строка> Название теста.
    • nesting <число> Уровень вложенности теста.
    • testNumber <число> Порядковый номер теста.
    • todo <строка> | <логическое> | <неопределено> Присутствует, если вызвана context.todo
    • skip <строка> | <логическое> | <неопределено> Присутствует, если вызвана context.skip

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

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

  • data <Объект>
    • column <число> | <неопределено> Номер столбца, в котором определён тест, или undefined , если тест был запущен через REPL.
    • details <Объект> Дополнительные метаданные выполнения.
      • duration_ms <число> Продолжительность теста в миллисекундах.
      • type <строка> | <неопределено> Тип теста, используемый для обозначения, является ли это набором тестов.
    • file <строка> | <неопределено> Путь к файлу с тестом, undefined , если тест был запущен через REPL.
    • line <число> | <неопределено> Номер строки, в которой определён тест, или undefined , если тест был запущен через REPL.
    • name <строка> Название теста.
    • nesting <число> Уровень вложенности теста.
    • testNumber <число> Порядковый номер теста.
    • todo <строка> | <логическое> | <неопределено> Присутствует, если вызвана context.todo
    • skip <строка> | <логическое> | <неопределено> Присутствует, если вызвана context.skip

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

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

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

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

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

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

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

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

  • data <Объект>
    • column <число> | <неопределено> Номер столбца, в котором определён тест, или undefined , если тест был запущен через REPL.
    • file <строка> Путь к файлу теста.
    • line <число> | <неопределено> Номер строки, в которой определён тест, или undefined , если тест был запущен через REPL.
    • message <строка> Сообщение, выведенное в stderr.

Выдаётся, когда работающий тест пишет в stderr. Это событие выводится только если --test флаг передан. Это событие не гарантируется, что будет выведено в том же порядке, что и определение тестов.

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

  • data <Объект>
    • column <число> | <неопределено> Номер столбца, в котором определён тест, или undefined , если тест был запущен через REPL.
    • file <строка> Путь к файлу теста.
    • line <число> | <неопределено> Номер строки, в которой определён тест, или undefined , если тест был запущен через REPL.
    • message <строка> Сообщение, выведенное в stdout.

Выдаётся, когда работающий тест пишет в stdout. Это событие выводится только если --test флаг передан. Это событие не гарантируется, что будет выведено в том же порядке, что и определение тестов.

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

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

Класс: TestContext

История
Версия Изменения
v20.1.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
  • fn <Функция> | <Асинхронная функция> Функция-обработчик. Первым аргументом этой функции является объект TestContext. Если обработчик использует колбэки, функция колбэка передается в качестве второго аргумента. По умолчанию: функция-пустышка.
  • options <Объект> Параметры конфигурации для обработчика. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполнение обработчика.
    • timeout <число> Число миллисекунд, после которого обработчик завершит работу с ошибкой. Если не указано, подтесты унаследуют это значение от родительского теста. По умолчанию: Infinity.

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

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

Добавлена в: v18.8.0, v16.18.0
  • fn <Функция> | <Асинхронная функция> Функция-обработчик. Первым аргументом этой функции является объект TestContext. Если обработчик использует колбэки, функция колбэка передается в качестве второго аргумента. По умолчанию: функция-пустышка.
  • options <Объект> Параметры конфигурации для обработчика. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполнение обработчика.
    • timeout <число> Число миллисекунд, после которого обработчик завершит работу с ошибкой. Если не указано, подтесты унаследуют это значение от родительского теста. По умолчанию: Infinity.

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

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

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

Добавлена в: v19.3.0, v18.13.0
  • fn <Функция> | <Асинхронная функция> Функция-обработчик. Первым аргументом этой функции является объект TestContext. Если обработчик использует колбэки, функция колбэка передается в качестве второго аргумента. По умолчанию: функция-пустышка.
  • options <Объект> Параметры конфигурации для обработчика. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполнение обработчика.
    • timeout <число> Число миллисекунд, после которого обработчик завершит работу с ошибкой. Если не указано, подтесты унаследуют это значение от родительского теста. По умолчанию: Infinity.

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

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

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

Добавлена в: v18.8.0, v16.18.0
  • fn <Функция> | <Асинхронная функция> Функция-обработчик. Первым аргументом этой функции является объект TestContext. Если обработчик использует колбэки, функция колбэка передается в качестве второго аргумента. По умолчанию: функция-пустышка.
  • options <Объект> Параметры конфигурации для обработчика. Поддерживаются следующие свойства:
    • signal <AbortSignal> Позволяет прервать выполнение обработчика.
    • timeout <число> Число миллисекунд, после которого обработчик завершит работу с ошибкой. Если не указано, подтесты унаследуют это значение от родительского теста. По умолчанию: Infinity.

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

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

context.diagnostic(message)

Добавлена в: v18.0.0, v16.17.0
  • message <строка> Сообщение для отчета.

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

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

context.name

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

Имя теста.

context.plan(count)

Добавлена в: v20.15.0
Уровень стабильности: 1 - Экспериментальная
  • count <число> Количество ожидаемых утверждений и подтестов.

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

Примечание: Чтобы отслеживать утверждения, необходимо использовать t.assert, а не assert напрямую.

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

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

test('planning with streams', (t, done) => {
  function* generate() {
    yield 'a';
    yield 'b';
    yield 'c';
  }
  const expected = ['a', 'b', 'c'];
  t.plan(expected.length);
  const stream = Readable.from(generate());
  stream.on('data', (chunk) => {
    t.assert.strictEqual(chunk, expected.shift());
  });

  stream.on('end', () => {
    done();
  });
}); copy

context.runOnly(shouldRunOnlyTests)

Добавлена в: v18.0.0, v16.17.0
  • shouldRunOnlyTests <логическое значение> Указывает, нужно ли выполнять тесты only.

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

test('top level test', (t) => {
  // The test context can be set to run subtests with the 'only' option.
  t.runOnly(true);
  return Promise.all([
    t.test('this subtest is now skipped'),
    t.test('this subtest is run', { only: true }),
  ]);
}); copy

context.signal

Добавлена в: v18.7.0, v16.17.0
  • Тип: <AbortSignal>

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

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

context.skip([message])

Добавлена в: v18.0.0, v16.17.0
  • message <строка> Необязательное сообщение о пропуске.

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

test('top level test', (t) => {
  // Make sure to return here as well if the test contains additional logic.
  t.skip('this is skipped');
}); copy

context.todo([message])

Добавлена в: v18.0.0, v16.17.0
  • message <строка> Необязательное TODO сообщение.

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

test('top level test', (t) => {
  // This test is marked as `TODO`
  t.todo('this is a todo');
}); copy

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

История
Версия Изменения
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().

test('top level test', async (t) => {
  await t.test(
    'This is a subtest',
    { only: false, skip: false, concurrency: 1, todo: false, plan: 4 },
    (t) => {
      assert.ok('some relevant assertion here');
    },
  );
}); copy

Класс: SuiteContext

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

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

context.name

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

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

context.signal

Добавлен в: v18.7.0, v16.17.0
  • Тип: <AbortSignal>

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

© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v20.x/docs/api/test.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API