Skip to content

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

[История]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Подтесты

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

js
test('тест верхнего уровня', async t => {
  await t.test('подтест 1', t => {
    assert.strictEqual(1, 1)
  })

  await t.test('подтест 2', t => {
    assert.strictEqual(2, 2)
  })
})

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

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

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

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

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

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

test('метод skip() с сообщением', t => {
  // Не забудьте вернуть значение здесь, если тест содержит дополнительную логику.
  t.skip('этот тест пропущен')
})

Тесты TODO

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

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

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

test('метод todo()', t => {
  t.todo()
})

test('метод todo() с сообщением', t => {
  t.todo('это тест todo и не обрабатывается как ошибка')
  throw new Error('это не приводит к ошибке теста')
})

Алиасы describe() и it()

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

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

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

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

Тесты only

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

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

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

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

  // Контекст теста может быть обновлен для запуска подтестов с параметром 'only'.
  t.runOnly(true)
  await t.test('this subtest is now skipped')
  await t.test('this subtest is run', { only: true })

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

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

// Параметр 'only' не установлен, поэтому этот тест пропускается.
test('this test is not run', () => {
  // Этот код не выполняется.
  throw new Error('fail')
})

describe('a suite', () => {
  // Параметр 'only' установлен, поэтому этот тест выполняется.
  it('this test is run', { only: true }, () => {
    // Этот код выполняется.
  })

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

describe.only('a suite', () => {
  // Параметр 'only' установлен, поэтому этот тест выполняется.
  it('this test is run', () => {
    // Этот код выполняется.
  })

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

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

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

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

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

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

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

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

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

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

Запуск Node.js с --test-name-pattern="test 1 some test" будет соответствовать только some test в test 1.

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

Если указаны оба параметра --test-name-pattern и --test-skip-pattern, тесты должны удовлетворять обоим требованиям, чтобы быть выполненными.

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

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

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

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

js
test('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.
})

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

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

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

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

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

bash
node --test --watch

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

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

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

bash
node --test

По умолчанию Node.js будет запускать все файлы, соответствующие этим шаблонам:

  • **/*.test.{cjs,mjs,js}
  • **/*-test.{cjs,mjs,js}
  • **/*_test.{cjs,mjs,js}
  • **/test-*.{cjs,mjs,js}
  • **/test.{cjs,mjs,js}
  • **/test/**/*.{cjs,mjs,js}

Когда предоставляется --experimental-strip-types, соответствуют следующие дополнительные шаблоны:

  • **/*.test.{cts,mts,ts}
  • **/*-test.{cts,mts,ts}
  • **/*_test.{cts,mts,ts}
  • **/test-*.{cts,mts,ts}
  • **/test.{cts,mts,ts}
  • **/test/**/*.{cts,mts,ts}

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

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

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

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

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

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

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

Сбор данных о покрытии кода

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

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

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

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

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

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

js
/* node:coverage ignore next */
if (anAlwaysFalseCondition) {
  console.log('это никогда не выполняется')
}

/* node:coverage ignore next 3 */
if (anAlwaysFalseCondition) {
  console.log('это никогда не выполняется')
}

Отчёты о покрытии кода

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

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

Мокирование

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

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

test('spies on a function', () => {
  const sum = mock.fn((a, b) => {
    return a + b
  })

  assert.strictEqual(sum.mock.callCount(), 0)
  assert.strictEqual(sum(3, 4), 7)
  assert.strictEqual(sum.mock.callCount(), 1)

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

  // Сброс глобально отслеживаемых моков.
  mock.reset()
})
js
'use strict'
const assert = require('node:assert')
const { mock, test } = require('node:test')

test('spies on a function', () => {
  const sum = mock.fn((a, b) => {
    return a + b
  })

  assert.strictEqual(sum.mock.callCount(), 0)
  assert.strictEqual(sum(3, 4), 7)
  assert.strictEqual(sum.mock.callCount(), 1)

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

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

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

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

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

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

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

Таймеры

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

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

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

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

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

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

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

  // Необязательно выбирать, что имитировать
  mock.timers.enable({ apis: ['setTimeout'] })
  setTimeout(fn, 9999)
  assert.strictEqual(fn.mock.callCount(), 0)

  // Перемещение во времени
  mock.timers.tick(9999)
  assert.strictEqual(fn.mock.callCount(), 1)

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

  // Если вы вызываете сброс экземпляра имитации, он также сбросит экземпляр таймеров
  mock.reset()
})
js
const assert = require('node:assert')
const { mock, test } = require('node:test')

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

  // Необязательно выбирать, что имитировать
  mock.timers.enable({ apis: ['setTimeout'] })
  setTimeout(fn, 9999)
  assert.strictEqual(fn.mock.callCount(), 0)

  // Перемещение во времени
  mock.timers.tick(9999)
  assert.strictEqual(fn.mock.callCount(), 1)

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

  // Если вы вызываете сброс экземпляра имитации, он также сбросит экземпляр таймеров
  mock.reset()
})

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

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

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

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

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

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

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

  // Перемещение во времени
  context.mock.timers.tick(9999)
  assert.strictEqual(fn.mock.callCount(), 1)
})

Даты

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  context.mock.timers.runAll()
  // Все таймеры выполняются, так как время теперь достигнуто
  assert.strictEqual(fn.mock.callCount(), 3)
  assert.strictEqual(Date.now(), 3000)
})

Тестирование снимков

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

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

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

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

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

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

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

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

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

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

Отчёты тестов

[История]

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

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

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

  • spec Отчётчик spec выводит результаты тестов в удобочитаемом формате. Это отчётчик по умолчанию.
  • tap Отчётчик tap выводит результаты тестов в формате TAP.
  • dot Отчётчик dot выводит результаты тестов в компактном формате, где каждый пройденный тест представлен точкой ., а каждый неудачный тест — буквой X.
  • junit Отчётчик junit выводит результаты тестов в формате jUnit XML
  • lcov Отчётчик lcov выводит покрытие тестами при использовании флага --experimental-test-coverage.

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

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

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

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

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

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

js
import { Transform } from 'node:stream'

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

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

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

module.exports = customReporter

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

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

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

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

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

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

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

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

run([options])

[История]

ВерсияИзменения
v23.0.0Добавлен параметр cwd.
v23.0.0Добавлены параметры покрытия.
v22.8.0Добавлен параметр isolation.
v22.6.0Добавлен параметр globPatterns.
v22.0.0, v20.14.0Добавлен параметр forceExit.
v20.1.0, v18.17.0Добавлен параметр testNamePatterns.
v18.9.0, v16.19.0Добавлено в: v18.9.0, v16.19.0
  • options <Object> Параметры конфигурации для запуска тестов. Поддерживаются следующие свойства:

    • concurrency <number> | <boolean> Если указано число, то будет запущено параллельно столько процессов тестирования, сколько указано числом, где каждый процесс соответствует одному файлу теста. Если true, будет запущено os.availableParallelism() - 1 файлов тестов параллельно. Если false, будет запущен только один файл теста за раз. По умолчанию: false.

    • cwd: <string> Указывает текущий рабочий каталог, который будет использоваться модулем запуска тестов. Служит базовым путем для разрешения файлов в соответствии с моделью выполнения модуля запуска тестов. По умолчанию: process.cwd().

    • files: <Array> Массив, содержащий список файлов для запуска. По умолчанию: соответствующие файлы из модели выполнения модуля запуска тестов.

    • forceExit: <boolean> Настраивает модуль запуска тестов на завершение работы процесса после завершения выполнения всех известных тестов, даже если цикл событий останется активным. По умолчанию: false.

    • globPatterns: <Array> Массив, содержащий список шаблонов glob для сопоставления файлов тестов. Этот параметр не может использоваться вместе с files. По умолчанию: соответствующие файлы из модели выполнения модуля запуска тестов.

    • inspectPort <number> | <Function> Устанавливает порт инспектора дочернего процесса тестирования. Это может быть число или функция, которая не принимает аргументов и возвращает число. Если указано нулевое значение, каждый процесс получает свой собственный порт, увеличиваемый от process.debugPort основного процесса. Этот параметр игнорируется, если параметр isolation установлен в 'none', так как дочерние процессы не создаются. По умолчанию: undefined.

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

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

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

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

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

    • signal <AbortSignal> Позволяет прервать выполнение теста, находящегося в процессе выполнения.

    • testNamePatterns <string> | <RegExp> | <Array> Строка, регулярное выражение или массив регулярных выражений, которые можно использовать для запуска только тех тестов, чьи имена соответствуют предоставленному шаблону. Шаблоны имен тестов интерпретируются как регулярные выражения JavaScript. Для каждого выполняемого теста также выполняются все соответствующие хуки теста, такие как beforeEach(). По умолчанию: undefined.

    • testSkipPatterns <string> | <RegExp> | <Array> Строка, регулярное выражение или массив регулярных выражений, которые можно использовать для исключения запуска тестов, чьи имена соответствуют предоставленному шаблону. Шаблоны имен тестов интерпретируются как регулярные выражения JavaScript. Для каждого выполняемого теста также выполняются все соответствующие хуки теста, такие как beforeEach(). По умолчанию: undefined.

    • timeout <number> Количество миллисекунд, после которого выполнение теста завершится с ошибкой. Если не указано, подтесты наследуют это значение от своего родителя. По умолчанию: Infinity.

    • watch <boolean> Запускать ли в режиме наблюдения или нет. По умолчанию: false.

    • shard <Object> Запуск тестов в определенном фрагменте. По умолчанию: undefined.

    • index <number> является положительным целым числом от 1 до \<total\>, которое указывает индекс фрагмента для запуска. Этот параметр обязателен.

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

    • coverage <boolean> включить сбор покрытия кода. По умолчанию: false.

    • coverageExcludeGlobs <string> | <Array> Исключает определенные файлы из покрытия кода с использованием шаблона glob, который может соответствовать как абсолютным, так и относительным путям к файлам. Это свойство применимо только тогда, когда coverage установлено в true. Если указаны как coverageExcludeGlobs, так и coverageIncludeGlobs, файлы должны соответствовать обоим критериям, чтобы быть включенными в отчет о покрытии. По умолчанию: undefined.

    • coverageIncludeGlobs <string> | <Array> Включает определенные файлы в покрытие кода с использованием шаблона glob, который может соответствовать как абсолютным, так и относительным путям к файлам. Это свойство применимо только тогда, когда coverage установлено в true. Если указаны как coverageExcludeGlobs, так и coverageIncludeGlobs, файлы должны соответствовать обоим критериям, чтобы быть включенными в отчет о покрытии. По умолчанию: undefined.

    • lineCoverage <number> Требуется минимальный процент покрытых строк. Если покрытие кода не достигает указанного порога, процесс завершится с кодом 1. По умолчанию: 0.

    • branchCoverage <number> Требуется минимальный процент покрытых ветвей. Если покрытие кода не достигает указанного порога, процесс завершится с кодом 1. По умолчанию: 0.

    • functionCoverage <number> Требуется минимальный процент покрытых функций. Если покрытие кода не достигает указанного порога, процесс завершится с кодом 1. По умолчанию: 0.

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

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

js
import { tap } from 'node:test/reporters'
import { run } from 'node:test'
import process from 'node:process'
import path from 'node:path'

run({ files: [path.resolve('./tests/test.js')] })
  .on('test:fail', () => {
    process.exitCode = 1
  })
  .compose(tap)
  .pipe(process.stdout)
js
const { tap } = require('node:test/reporters')
const { run } = require('node:test')
const path = require('node:path')

run({ files: [path.resolve('./tests/test.js')] })
  .on('test:fail', () => {
    process.exitCode = 1
  })
  .compose(tap)
  .pipe(process.stdout)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[История]

ВерсияИзменения
v20.2.0, v18.17.0Добавлены сокращения skip, todo и only.
v18.8.0, v16.18.0Добавлен параметр signal.
v18.7.0, v16.17.0Добавлен параметр timeout.
v18.0.0, v16.17.0Добавлено в: v18.0.0, v16.17.0
  • name <string> Имя теста, отображаемое при отчете о результатах тестирования. По умолчанию: Свойство name функции fn или '\<anonymous\>', если fn не имеет имени.

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

    • concurrency <number> | <boolean> Если указано число, то столько тестов будет выполняться параллельно в потоке приложения. Если true, все запланированные асинхронные тесты выполняются одновременно в потоке. Если false, то выполняется только один тест за раз. Если не указано, подтесты наследуют это значение от своего родителя. По умолчанию: false.
    • only <boolean> Если истинно, и контекст теста настроен на запуск тестов only, то этот тест будет выполнен. В противном случае тест пропускается. По умолчанию: false.
    • signal <AbortSignal> Позволяет прервать выполняющийся тест.
    • skip <boolean> | <string> Если истинно, тест пропускается. Если указана строка, эта строка отображается в результатах теста как причина пропуска теста. По умолчанию: false.
    • todo <boolean> | <string> Если истинно, тест помечен как TODO. Если указана строка, эта строка отображается в результатах теста как причина, по которой тест является TODO. По умолчанию: false.
    • timeout <number> Количество миллисекунд, после которого тест завершится с ошибкой. Если не указано, подтесты наследуют это значение от своего родителя. По умолчанию: Infinity.
    • plan <number> Количество утверждений и подтестов, которые должны быть выполнены в тесте. Если количество выполненных в тесте утверждений не совпадает с числом, указанным в плане, тест завершится с ошибкой. По умолчанию: undefined.
  • fn <Function> | <AsyncFunction> Функция, которая тестируется. Первый аргумент этой функции — объект TestContext. Если тест использует обратные вызовы, функция обратного вызова передается в качестве второго аргумента. По умолчанию: Функция без операции.

  • Возвращает: <Promise> Выполняется с undefined после завершения теста или немедленно, если тест выполняется в наборе тестов.

Функция test() — это значение, импортируемое из модуля test. Каждое вызов этой функции приводит к отправке отчета о тесте в <TestsStream>.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[История]

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

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

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

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

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

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

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

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

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

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

before([fn][, options])

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

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

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

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

after([fn][, options])

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

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

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

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

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

beforeEach([fn][, options])

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

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

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

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

afterEach([fn][, options])

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

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

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

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

snapshot

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

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

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

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

snapshot.setDefaultSnapshotSerializers(serializers)

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

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

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

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

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

snapshot.setResolveSnapshotPath(fn)

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

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

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

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

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

Класс: MockFunctionContext

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

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

ctx.calls

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

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

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

ctx.callCount()

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

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

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

ctx.mockImplementation(implementation)

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

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

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

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

js
test('изменяет поведение макета', t => {
  let cnt = 0

  function addOne() {
    cnt++
    return cnt
  }

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

  const fn = t.mock.fn(addOne)

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

ctx.mockImplementationOnce(implementation[, onCall])

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

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

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

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

js
test('изменяет поведение макета один раз', t => {
  let cnt = 0

  function addOne() {
    cnt++
    return cnt
  }

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

  const fn = t.mock.fn(addOne)

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

ctx.resetCalls()

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

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

ctx.restore()

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

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

Класс: MockModuleContext

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

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

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

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

ctx.restore()

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

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

Класс: MockTracker

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

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

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

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

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

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

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

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

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

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

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

  function addOne() {
    cnt++
    return cnt
  }

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

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

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

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

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

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

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

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

  • object <Object> Объект, метод которого имитируется.

  • methodName <string> | <symbol> Идентификатор метода в object, который нужно имитировать. Если object[methodName] не является функцией, будет выброшена ошибка.

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

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

    • getter <boolean> Если true, object[methodName] рассматривается как геттер. Этот параметр не может использоваться с параметром setter. По умолчанию: false.
    • setter <boolean> Если true, object[methodName] рассматривается как сеттер. Этот параметр не может использоваться с параметром getter. По умолчанию: false.
    • times <integer> Количество раз, когда имитация будет использовать поведение implementation. После того, как имитируемый метод будет вызван times раз, он автоматически восстановит исходное поведение. Это значение должно быть целым числом больше нуля. По умолчанию: Infinity.
  • Возвращает: <Proxy> Имитируемый метод. Имитируемый метод содержит специальное свойство mock, которое является экземпляром MockFunctionContext и может использоваться для проверки и изменения поведения имитируемого метода.

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

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

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

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

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

mock.module(specifier[, options])

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

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

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

  • specifier <строка> | <URL> Строка, идентифицирующая модуль для имитации.

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

    • cache <булево> Если false, каждый вызов require() или import() создает новый имитируемый модуль. Если true, последующие вызовы будут возвращать один и тот же имитируемый модуль, и имитируемый модуль будет добавлен в кэш CommonJS. По умолчанию: false.
    • defaultExport <любой> Необязательное значение, используемое в качестве экспорта по умолчанию имитируемого модуля. Если это значение не указано, имитации ESM не включают экспорт по умолчанию. Если имитация является модулем CommonJS или встроенным модулем, это значение используется в качестве значения module.exports. Если это значение не указано, имитации CJS и встроенные имитации используют пустой объект в качестве значения module.exports.
    • namedExports <Объект> Необязательный объект, ключи и значения которого используются для создания именованных экспортов имитируемого модуля. Если имитация является модулем CommonJS или встроенным модулем, эти значения копируются в module.exports. Таким образом, если имитация создается как с именованными экспортами, так и с экспортом по умолчанию, не являющимся объектом, имитация выбросит исключение при использовании в качестве модуля CJS или встроенного модуля.
  • Возвращает: <MockModuleContext> Объект, который можно использовать для управления имитацией.

Эта функция используется для имитации экспорта модулей ECMAScript, модулей CommonJS и встроенных модулей Node.js. Любые ссылки на исходный модуль до имитации не затрагиваются. Для включения имитации модулей Node.js должен быть запущен с флагом командной строки --experimental-test-module-mocks.

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

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

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

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

  mock.restore()

  // Имитация восстановлена, поэтому возвращается исходный встроенный модуль.
  esmImpl = await import('node:readline')
  cjsImpl = require('node:readline')

  assert.strictEqual(typeof esmImpl.cursorTo, 'function')
  assert.strictEqual(typeof cjsImpl.cursorTo, 'function')
  assert.strictEqual(esmImpl.fn, undefined)
  assert.strictEqual(cjsImpl.fn, undefined)
})

mock.reset()

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

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

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

mock.restoreAll()

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

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

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

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

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

Класс: MockTimers

[История]

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

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

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

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

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

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

timers.enable([enableOptions])

[История]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

timers.reset()

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

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

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

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

timers[Symbol.dispose]()

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

timers.tick([milliseconds])

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

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

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

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

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

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

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

  context.mock.timers.enable({ apis: ['setTimeout'] })

  setTimeout(fn, 9999)

  assert.strictEqual(fn.mock.callCount(), 0)

  // Продвижение во времени
  context.mock.timers.tick(9999)

  assert.strictEqual(fn.mock.callCount(), 1)
})
js
const assert = require('node:assert')
const { test } = require('node:test')

test('mocks setTimeout to be executed synchronously without having to actually wait for it', context => {
  const fn = context.mock.fn()
  context.mock.timers.enable({ apis: ['setTimeout'] })

  setTimeout(fn, 9999)
  assert.strictEqual(fn.mock.callCount(), 0)

  // Продвижение во времени
  context.mock.timers.tick(9999)

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

В качестве альтернативы, функцию .tick можно вызывать много раз

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

test('mocks setTimeout to be executed synchronously without having to actually wait for it', context => {
  const fn = context.mock.fn()
  context.mock.timers.enable({ apis: ['setTimeout'] })
  const nineSecs = 9000
  setTimeout(fn, nineSecs)

  const threeSeconds = 3000
  context.mock.timers.tick(threeSeconds)
  context.mock.timers.tick(threeSeconds)
  context.mock.timers.tick(threeSeconds)

  assert.strictEqual(fn.mock.callCount(), 1)
})
js
const assert = require('node:assert')
const { test } = require('node:test')

test('mocks setTimeout to be executed synchronously without having to actually wait for it', context => {
  const fn = context.mock.fn()
  context.mock.timers.enable({ apis: ['setTimeout'] })
  const nineSecs = 9000
  setTimeout(fn, nineSecs)

  const threeSeconds = 3000
  context.mock.timers.tick(threeSeconds)
  context.mock.timers.tick(threeSeconds)
  context.mock.timers.tick(threeSeconds)

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

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

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

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

  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })
  setTimeout(fn, 9999)

  assert.strictEqual(fn.mock.callCount(), 0)
  assert.strictEqual(Date.now(), 0)

  // Продвижение во времени
  context.mock.timers.tick(9999)
  assert.strictEqual(fn.mock.callCount(), 1)
  assert.strictEqual(Date.now(), 9999)
})
js
const assert = require('node:assert')
const { test } = require('node:test')

test('mocks setTimeout to be executed synchronously without having to actually wait for it', context => {
  const fn = context.mock.fn()
  context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })

  setTimeout(fn, 9999)
  assert.strictEqual(fn.mock.callCount(), 0)
  assert.strictEqual(Date.now(), 0)

  // Продвижение во времени
  context.mock.timers.tick(9999)
  assert.strictEqual(fn.mock.callCount(), 1)
  assert.strictEqual(Date.now(), 9999)
})

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

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

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

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

  // Необязательно указывать, что имитировать
  context.mock.timers.enable({ apis: ['setTimeout'] })
  const id = setTimeout(fn, 9999)

  // Неявно имитируется
  clearTimeout(id)
  context.mock.timers.tick(9999)

  // Так как setTimeout был очищен, функция mock никогда не будет вызвана
  assert.strictEqual(fn.mock.callCount(), 0)
})
js
const assert = require('node:assert')
const { test } = require('node:test')

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

  // Необязательно указывать, что имитировать
  context.mock.timers.enable({ apis: ['setTimeout'] })
  const id = setTimeout(fn, 9999)

  // Неявно имитируется
  clearTimeout(id)
  context.mock.timers.tick(9999)

  // Так как setTimeout был очищен, функция mock никогда не будет вызвана
  assert.strictEqual(fn.mock.callCount(), 0)
})

Работа с модулями таймеров Node.js

После включения имитации таймеров, модули node:timers, node:timers/promises и таймеры из глобального контекста Node.js включаются:

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

js
import assert from 'node:assert'
import { test } from 'node:test'
import nodeTimers from 'node:timers'
import nodeTimersPromises from 'node:timers/promises'

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

  // Необязательно указывать, что имитировать
  context.mock.timers.enable({ apis: ['setTimeout'] })
  setTimeout(globalTimeoutObjectSpy, 9999)
  nodeTimers.setTimeout(nodeTimerSpy, 9999)

  const promise = nodeTimersPromises.setTimeout(9999).then(nodeTimerPromiseSpy)

  // Переход во времени
  context.mock.timers.tick(9999)
  assert.strictEqual(globalTimeoutObjectSpy.mock.callCount(), 1)
  assert.strictEqual(nodeTimerSpy.mock.callCount(), 1)
  await promise
  assert.strictEqual(nodeTimerPromiseSpy.mock.callCount(), 1)
})
js
const assert = require('node:assert')
const { test } = require('node:test')
const nodeTimers = require('node:timers')
const nodeTimersPromises = require('node:timers/promises')

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

  // Необязательно указывать, что имитировать
  context.mock.timers.enable({ apis: ['setTimeout'] })
  setTimeout(globalTimeoutObjectSpy, 9999)
  nodeTimers.setTimeout(nodeTimerSpy, 9999)

  const promise = nodeTimersPromises.setTimeout(9999).then(nodeTimerPromiseSpy)

  // Переход во времени
  context.mock.timers.tick(9999)
  assert.strictEqual(globalTimeoutObjectSpy.mock.callCount(), 1)
  assert.strictEqual(nodeTimerSpy.mock.callCount(), 1)
  await promise
  assert.strictEqual(nodeTimerPromiseSpy.mock.callCount(), 1)
})

В Node.js, setInterval из node:timers/promises является AsyncGenerator и также поддерживается этим API:

js
import assert from 'node:assert'
import { test } from 'node:test'
import nodeTimersPromises from 'node:timers/promises'
test('должен тикать пять раз, проверяя реальный сценарий использования', async context => {
  context.mock.timers.enable({ apis: ['setInterval'] })

  const expectedIterations = 3
  const interval = 1000
  const startedAt = Date.now()
  async function run() {
    const times = []
    for await (const time of nodeTimersPromises.setInterval(interval, startedAt)) {
      times.push(time)
      if (times.length === expectedIterations) break
    }
    return times
  }

  const r = run()
  context.mock.timers.tick(interval)
  context.mock.timers.tick(interval)
  context.mock.timers.tick(interval)

  const timeResults = await r
  assert.strictEqual(timeResults.length, expectedIterations)
  for (let it = 1; it < expectedIterations; it++) {
    assert.strictEqual(timeResults[it - 1], startedAt + interval * it)
  }
})
js
const assert = require('node:assert')
const { test } = require('node:test')
const nodeTimersPromises = require('node:timers/promises')
test('должен тикать пять раз, проверяя реальный сценарий использования', async context => {
  context.mock.timers.enable({ apis: ['setInterval'] })

  const expectedIterations = 3
  const interval = 1000
  const startedAt = Date.now()
  async function run() {
    const times = []
    for await (const time of nodeTimersPromises.setInterval(interval, startedAt)) {
      times.push(time)
      if (times.length === expectedIterations) break
    }
    return times
  }

  const r = run()
  context.mock.timers.tick(interval)
  context.mock.timers.tick(interval)
  context.mock.timers.tick(interval)

  const timeResults = await r
  assert.strictEqual(timeResults.length, expectedIterations)
  for (let it = 1; it < expectedIterations; it++) {
    assert.strictEqual(timeResults[it - 1], startedAt + interval * it)
  }
})

timers.runAll()

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

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

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

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

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

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

  assert.deepStrictEqual(results, [])

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

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

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

  assert.deepStrictEqual(results, [])

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

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

timers.setTime(milliseconds)

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

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

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

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

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

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

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

Работа дат и таймеров вместе

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

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

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

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

  assert.deepStrictEqual(results, [])
  context.mock.timers.setTime(12000)
  assert.deepStrictEqual(results, [])
  // Дата продвигается, но таймеры не тикают
  assert.strictEqual(Date.now(), 12000)
})
js
const assert = require('node:assert')
const { test } = require('node:test')

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

  assert.deepStrictEqual(results, [])
  context.mock.timers.setTime(12000)
  assert.deepStrictEqual(results, [])
  // Дата продвигается, но таймеры не тикают
  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

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

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

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

  • data <Object>

    • summary <Object> Объект, содержащий отчет о покрытии кода.

    • files <Array> Массив отчетов о покрытии кода для отдельных файлов. Каждый отчет — это объект со следующей схемой:

    • path <string> Абсолютный путь к файлу.

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

    • totalBranchCount <number> Общее количество ветвлений.

    • totalFunctionCount <number> Общее количество функций.

    • coveredLineCount <number> Количество покрытых строк.

    • coveredBranchCount <number> Количество покрытых ветвлений.

    • coveredFunctionCount <number> Количество покрытых функций.

    • coveredLinePercent <number> Процент покрытых строк.

    • coveredBranchPercent <number> Процент покрытых ветвлений.

    • coveredFunctionPercent <number> Процент покрытых функций.

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

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

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

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

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

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

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

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

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

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

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

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

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

    • line <number> Порог покрытия строк.

    • totals <Object> Объект, содержащий сводку покрытия для всех файлов.

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

    • totalBranchCount <number> Общее количество ветвлений.

    • totalFunctionCount <number> Общее количество функций.

    • coveredLineCount <number> Количество покрытых строк.

    • coveredBranchCount <number> Количество покрытых ветвлений.

    • coveredFunctionCount <number> Количество покрытых функций.

    • coveredLinePercent <number> Процент покрытых строк.

    • coveredBranchPercent <number> Процент покрытых ветвлений.

    • coveredFunctionPercent <number> Процент покрытых функций.

    • workingDirectory <string> Рабочий каталог на момент начала покрытия кода. Это полезно для отображения относительных имен путей, если тесты изменили рабочий каталог процесса Node.js.

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

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

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

  • data <Object>

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

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

    • passed <boolean> Прошел ли тест или нет.

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

    • error <Error> | <undefined> Объект ошибки, обертывающий ошибку, выброшенную тестом, если он не прошел.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • data <Object>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Класс: TestContext

[История]

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

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

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

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

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

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

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

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

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

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

js
test('тест верхнего уровня', async t => {
  t.beforeEach(t => t.diagnostic(`начинаем выполнение ${t.name}`))
  await t.test('Это подтест', t => {
    assert.ok('какое-то релевантное утверждение здесь')
  })
})

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

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

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

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

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

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

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

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

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

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

context.assert

Добавлено в: v22.2.0, v20.15.0

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

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

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

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

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

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

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

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

js
test('snapshot test with default serialization', t => {
  t.assert.snapshot({ value1: 1, value2: 2 })
})

test('snapshot test with custom serialization', t => {
  t.assert.snapshot(
    { value3: 3, value4: 4 },
    {
      serializers: [value => JSON.stringify(value)],
    }
  )
})

context.diagnostic(message)

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

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

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

js
test('top level test', t => {
  t.diagnostic('Диагностическое сообщение')
})

context.filePath

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

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

context.fullName

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

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

context.name

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

Имя теста.

context.plan(count)

[История]

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

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

js
test('top level test', t => {
  t.plan(2)
  t.assert.ok('какое-то релевантное утверждение здесь')
  t.test('подтест', () => {})
})

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

js
test('планирование с потоками', (t, done) => {
  function* generate() {
    yield 'a'
    yield 'b'
    yield 'c'
  }
  const expected = ['a', 'b', 'c']
  t.plan(expected.length)
  const stream = Readable.from(generate())
  stream.on('data', chunk => {
    t.assert.strictEqual(chunk, expected.shift())
  })

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

context.runOnly(shouldRunOnlyTests)

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

  • shouldRunOnlyTests <boolean> Запускать ли только тесты с опцией only.

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

js
test('тест верхнего уровня', t => {
  // Контекст теста может быть установлен для запуска подтестов с опцией 'only'.
  t.runOnly(true)
  return Promise.all([t.test('этот подтест теперь пропущен'), t.test('этот подтест выполняется', { only: true })])
})

context.signal

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

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

js
test('тест верхнего уровня', async t => {
  await fetch('some/uri', { signal: t.signal })
})

context.skip([message])

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

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

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

js
test('тест верхнего уровня', t => {
  // Убедитесь, что здесь также есть возврат, если тест содержит дополнительную логику.
  t.skip('это пропущено')
})

context.todo([message])

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

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

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

js
test('тест верхнего уровня', t => {
  // Этот тест помечен как `TODO`
  t.todo('это задача')
})

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

[История]

ВерсияИзменения
v18.8.0, v16.18.0Добавлен параметр signal.
v18.7.0, v16.17.0Добавлен параметр timeout.
v18.0.0, v16.17.0Добавлено в: v18.0.0, v16.17.0
  • name <строка> Имя подтеста, отображаемое при отчёте о результатах тестирования. По умолчанию: Свойство name функции fn или '\<anonymous\>', если у fn нет имени.

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

    • concurrency <число> | <булево> | <null> Если указано число, то столько тестов будет выполняться параллельно в потоке приложения. Если true, то все подтесты будут выполняться параллельно. Если false, то будет выполняться только один тест за раз. Если не указано, подтесты наследуют это значение от своего родителя. По умолчанию: null.
    • only <булево> Если истинно, и контекст теста настроен на запуск только тестов only, то этот тест будет выполнен. В противном случае тест пропускается. По умолчанию: false.
    • signal <AbortSignal> Позволяет прервать выполняющийся тест.
    • skip <булево> | <строка> Если истинно, тест пропускается. Если указана строка, эта строка отображается в результатах теста как причина пропуска теста. По умолчанию: false.
    • todo <булево> | <строка> Если истинно, тест помечается как TODO. Если указана строка, эта строка отображается в результатах теста как причина, по которой тест является TODO. По умолчанию: false.
    • timeout <число> Количество миллисекунд, после которых тест завершится с ошибкой. Если не указано, подтесты наследуют это значение от своего родителя. По умолчанию: Infinity.
    • plan <число> Количество утверждений и подтестов, которые, как ожидается, будут выполнены в тесте. Если количество выполненных в тесте утверждений не совпадает с указанным в плане, тест завершится с ошибкой. По умолчанию: undefined.
  • fn <Функция> | <AsyncFunction> Тестируемая функция. Первый аргумент этой функции — это объект TestContext. Если тест использует обратные вызовы, функция обратного вызова передаётся в качестве второго аргумента. По умолчанию: Функция без операции.

  • Возвращает: <Promise> Выполняется с undefined после завершения теста.

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

js
test('тест верхнего уровня', async t => {
  await t.test('Это подтест', { only: false, skip: false, concurrency: 1, todo: false, plan: 1 }, t => {
    t.assert.ok('какое-то релевантное утверждение здесь')
  })
})

Класс: SuiteContext

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

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

context.filePath

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

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

context.name

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

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

context.signal

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

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