Перейти к содержанию

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

latest

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

АПИ является удовлетворительным. Совместимость с NPM имеет высший приоритет и не будет нарушена кроме случаев явной необходимости.

Модуль node:assert предоставляет набор функций утверждения для проверки инвариантов.

Режим строгого утверждения

В режиме строгого утверждения нестрогие методы ведут себя как соответствующие им строгие методы. Например, assert.deepEqual() будет вести себя как assert.deepStrictEqual().

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

Семантика параметра message

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

  • string: Используется как есть. Если после строки message указаны дополнительные аргументы, они обрабатываются как подстановки в стиле printf (см. util.format()).
  • Error: Если в качестве message передан экземпляр Error, выбрасывается именно эта ошибка, а не AssertionError.
  • function: Функция вида (actual, expected) => string. Вызывается только при провале утверждения и должна вернуть строку, которая будет использована как сообщение об ошибке. Нестроковые возвращаемые значения игнорируются, вместо них используется сообщение по умолчанию.

Если вместе с message в виде Error или функции переданы дополнительные аргументы, вызов отклоняется с ERR_AMBIGUOUS_ARGUMENT.

Если первый аргумент не является строкой, Error или функцией, выбрасывается ERR_INVALID_ARG_TYPE.

Чтобы использовать режим строгого утверждения:

1
import { strict as assert } from 'node:assert';
1
const assert = require('node:assert').strict;

1
import assert from 'node:assert/strict';
1
const assert = require('node:assert/strict');

Пример diff в сообщении об ошибке:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import { strict as assert } from 'node:assert';

assert.deepEqual(
    [[[1, 2, 3]], 4, 5],
    [[[1, 2, '3']], 4, 5]
);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
//   [
//     [
// ...
//       2,
// +     3
// -     '3'
//     ],
// ...
//     5
//   ]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
const assert = require('node:assert/strict');

assert.deepEqual(
    [[[1, 2, 3]], 4, 5],
    [[[1, 2, '3']], 4, 5]
);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
//   [
//     [
// ...
//       2,
// +     3
// -     '3'
//     ],
// ...
//     5
//   ]

Чтобы отключить цвета, используйте переменные окружения NO_COLOR или NODE_DISABLE_COLORS. Это также отключит цвета в REPL. Подробнее о поддержке цветов в терминальных средах см. документацию по tty getColorDepth().

Устаревший режим утверждения

Устаревший режим утверждения использует оператор == в:

Чтобы использовать устаревший режим утверждения:

1
import assert from 'node:assert';
1
const assert = require('node:assert');

Устаревший режим утверждения может давать неожиданные результаты, особенно при использовании assert.deepEqual():

1
2
3
// ВНИМАНИЕ: в устаревшем режиме утверждения
// это не вызывает AssertionError!
assert.deepEqual(/a/gi, new Date());

Класс: assert.AssertionError

Указывает на неудачу утверждения. Все ошибки, выбрасываемые модулем node:assert, являются экземплярами класса AssertionError.

new assert.AssertionError(options)

  • options <Object>
    • message <string> Если указано, сообщение об ошибке устанавливается в это значение.
    • actual <any> Свойство actual у экземпляра ошибки.
    • expected <any> Свойство expected у экземпляра ошибки.
    • operator <string> Свойство operator у экземпляра ошибки.
    • stackStartFn <Function> Если задано, сгенерированная трассировка стека не включает кадры выше этой функции.
    • diff <string> При значении 'full' в ошибках утверждения показывается полный diff. По умолчанию 'simple'. Допустимые значения: 'simple', 'full'.

Подкласс Error, указывающий на неудачу утверждения.

Все экземпляры содержат встроенные свойства Error (message и name) и:

  • actual <any> Устанавливается в аргумент actual для таких методов, как assert.strictEqual().
  • expected <any> Устанавливается в ожидаемое значение для таких методов, как assert.strictEqual().
  • generatedMessage <boolean> Показывает, было ли сообщение сгенерировано автоматически (true) или нет.
  • code <string> Значение всегда ERR_ASSERTION, чтобы указать, что это ошибка утверждения.
  • operator <string> Устанавливается в переданное значение оператора.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import assert from 'node:assert';

// Создаём AssertionError для последующего сравнения сообщения об ошибке:
const { message } = new assert.AssertionError({
    actual: 1,
    expected: 2,
    operator: 'strictEqual',
});

// Проверяем вывод ошибки:
try {
    assert.strictEqual(1, 2);
} catch (err) {
    assert(err instanceof assert.AssertionError);
    assert.strictEqual(err.message, message);
    assert.strictEqual(err.name, 'AssertionError');
    assert.strictEqual(err.actual, 1);
    assert.strictEqual(err.expected, 2);
    assert.strictEqual(err.code, 'ERR_ASSERTION');
    assert.strictEqual(err.operator, 'strictEqual');
    assert.strictEqual(err.generatedMessage, true);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
const assert = require('node:assert');

// Создаём AssertionError для последующего сравнения сообщения об ошибке:
const { message } = new assert.AssertionError({
    actual: 1,
    expected: 2,
    operator: 'strictEqual',
});

// Проверяем вывод ошибки:
try {
    assert.strictEqual(1, 2);
} catch (err) {
    assert(err instanceof assert.AssertionError);
    assert.strictEqual(err.message, message);
    assert.strictEqual(err.name, 'AssertionError');
    assert.strictEqual(err.actual, 1);
    assert.strictEqual(err.expected, 2);
    assert.strictEqual(err.code, 'ERR_ASSERTION');
    assert.strictEqual(err.operator, 'strictEqual');
    assert.strictEqual(err.generatedMessage, true);
}

Класс: assert.Assert

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

new assert.Assert([options])

  • options <Object>
    • diff <string> При значении 'full' в ошибках утверждения показывается полный diff. По умолчанию 'simple'. Допустимые значения: 'simple', 'full'.
    • strict <boolean> При true нестрогие методы ведут себя как соответствующие строгие. По умолчанию true.
    • skipPrototype <boolean> При true при глубоком сравнении на равенство не сравниваются прототип и конструктор. По умолчанию false.

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

1
2
3
4
const { Assert } = require('node:assert');
const assertInstance = new Assert({ diff: 'full' });
assertInstance.deepStrictEqual({ a: 1 }, { a: 2 });
// В сообщении об ошибке показывается полный diff.

Важно: при деструктуризации методов утверждений из экземпляра Assert они теряют связь с параметрами конфигурации экземпляра (такими как diff, strict и skipPrototype). У деструктурированных методов используется поведение по умолчанию.

1
2
3
4
5
6
7
8
const myAssert = new Assert({ diff: 'full' });

// Работает как ожидается - используется полный diff
myAssert.strictEqual({ a: 1 }, { b: { c: 1 } });

// Здесь теряется настройка полного diff - используется значение по умолчанию `simple`
const { strictEqual } = myAssert;
strictEqual({ a: 1 }, { b: { c: 1 } });

Параметр skipPrototype влияет на все методы глубокого сравнения:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Foo {
    constructor(a) {
        this.a = a;
    }
}

class Bar {
    constructor(a) {
        this.a = a;
    }
}

const foo = new Foo(1);
const bar = new Bar(1);

// Поведение по умолчанию - ошибка из-за разных конструкторов
const assert1 = new Assert();
assert1.deepStrictEqual(foo, bar); // AssertionError

// Без сравнения прототипа - проходит, если свойства равны
const assert2 = new Assert({ skipPrototype: true });
assert2.deepStrictEqual(foo, bar); // OK

При деструктуризации методы теряют доступ к контексту this экземпляра и возвращаются к поведению утверждений по умолчанию (diff: 'simple', нестрогий режим). Чтобы сохранить пользовательские параметры при использовании деструктурированных методов, не применяйте деструктуризацию и вызывайте методы напрямую у экземпляра.

assert(value[, message])

Псевдоним assert.ok().

assert.deepEqual(actual, expected[, message])

Режим строгих утверждений (strict assertion mode)

Псевдоним assert.deepStrictEqual().

Режим унаследованных утверждений (legacy assertion mode)

Стабильность: 3 - Legacy: вместо этого используйте assert.deepStrictEqual().

Проверяет глубокое равенство между параметрами actual и expected. Предпочтительно использовать assert.deepStrictEqual() - у assert.deepEqual() результат может быть неожиданным.

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

Детали сравнения

  • Примитивы сравниваются оператором ==, за исключением {NaN}: если с обеих сторон {NaN}, они считаются совпадающими.
  • Теги типов объектов должны совпадать.
  • Учитываются только перечислимые собственные свойства.
  • Обёртки над примитивами сравниваются и как объекты, и как развёрнутые значения.
  • Реализация не проверяет [[Prototype]] объектов.
  • Свойства Symbol не сравниваются.
  • Экземпляры WeakMap, WeakSet и Promise не сравниваются структурно: они равны только если ссылаются на один и тот же объект. Любое сравнение разных экземпляров WeakMap, WeakSet или Promise даёт неравенство, даже при одинаковом содержимом.
  • У RegExp всегда сравниваются lastIndex, флаги и source, даже если это не перечислимые свойства.

Следующий пример не выбрасывает AssertionError, потому что примитивы сравниваются оператором ==.

1
2
3
4
import assert from 'node:assert';
// ВНИМАНИЕ: AssertionError при этом не возникает!

assert.deepEqual('+00000000', false);
1
2
3
4
const assert = require('node:assert');
// ВНИМАНИЕ: AssertionError при этом не возникает!

assert.deepEqual('+00000000', false);

«Глубокое» равенство означает, что перечислимые собственные свойства вложенных объектов также учитываются:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import assert from 'node:assert';

const obj1 = {
    a: {
        b: 1,
    },
};
const obj2 = {
    a: {
        b: 2,
    },
};
const obj3 = {
    a: {
        b: 1,
    },
};
const obj4 = { __proto__: obj1 };

assert.deepEqual(obj1, obj1);
// OK

// Значения b различаются:
assert.deepEqual(obj1, obj2);
// AssertionError: { a: { b: 1 } } deepEqual { a: { b: 2 } }

assert.deepEqual(obj1, obj3);
// OK

// Прототипы игнорируются:
assert.deepEqual(obj1, obj4);
// AssertionError: { a: { b: 1 } } deepEqual {}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const assert = require('node:assert');

const obj1 = {
    a: {
        b: 1,
    },
};
const obj2 = {
    a: {
        b: 2,
    },
};
const obj3 = {
    a: {
        b: 1,
    },
};
const obj4 = { __proto__: obj1 };

assert.deepEqual(obj1, obj1);
// OK

// Значения b различаются:
assert.deepEqual(obj1, obj2);
// AssertionError: { a: { b: 1 } } deepEqual { a: { b: 2 } }

assert.deepEqual(obj1, obj3);
// OK

// Прототипы игнорируются:
assert.deepEqual(obj1, obj4);
// AssertionError: { a: { b: 1 } } deepEqual {}

Если значения не равны, выбрасывается AssertionError: свойство message равно значению параметра message. Если message не передан, подставляется сообщение по умолчанию. Если message является экземпляром Error, выбрасывается он, а не AssertionError.

assert.deepStrictEqual(actual, expected[, message])

Проверяет глубокое равенство между параметрами actual и expected. «Глубокое» равенство означает, что перечислимые собственные свойства вложенных объектов также рекурсивно оцениваются по следующим правилам.

Детали сравнения

  • Примитивы сравниваются через Object.is().
  • Теги типов объектов должны совпадать.
  • [[Prototype]] объектов сравнивается оператором ===.
  • Учитываются только перечислимые собственные свойства.
  • Обёртки над примитивами сравниваются и как объекты, и как развёрнутые значения.
  • Свойства объектов Object сравниваются без учёта порядка.
  • Ключи Map и элементы Set сравниваются без учёта порядка.
  • Рекурсия останавливается, когда значения различаются или когда одна из сторон натыкается на циклическую ссылку.
  • Экземпляры WeakMap, WeakSet и Promise не сравниваются структурно: они равны только если ссылаются на один и тот же объект. Любое сравнение разных экземпляров WeakMap, WeakSet или Promise даёт неравенство, даже при одинаковом содержимом.
  • У RegExp всегда сравниваются lastIndex, флаги и source, даже если это не перечислимые свойства.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
import assert from 'node:assert/strict';

// Не проходит, так как 1 !== '1'.
assert.deepStrictEqual({ a: 1 }, { a: '1' });
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
//   {
// +   a: 1
// -   a: '1'
//   }

// У следующих объектов нет собственных свойств
const date = new Date();
const object = {};
const fakeDate = {};
Object.setPrototypeOf(fakeDate, Date.prototype);

// Разный [[Prototype]]:
assert.deepStrictEqual(object, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + {}
// - Date {}

// Разные теги типов:
assert.deepStrictEqual(date, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 2018-04-26T00:49:08.604Z
// - Date {}

assert.deepStrictEqual(NaN, NaN);
// OK: Object.is(NaN, NaN) === true.

// Разные развёрнутые числа:
assert.deepStrictEqual(new Number(1), new Number(2));
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + [Number: 1]
// - [Number: 2]

assert.deepStrictEqual(new String('foo'), Object('foo'));
// OK: объект и строка совпадают после развёртывания.

assert.deepStrictEqual(-0, -0);
// OK

// Разные нули:
assert.deepStrictEqual(0, -0);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 0
// - -0

const symbol1 = Symbol();
const symbol2 = Symbol();
assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol1]: 1 });
// OK: в обоих объектах используется один и тот же символ.

assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol2]: 1 });
// AssertionError [ERR_ASSERTION]: Inputs identical but not reference equal:
//
// {
//   Symbol(): 1
// }

const weakMap1 = new WeakMap();
const weakMap2 = new WeakMap();
const obj = {};

weakMap1.set(obj, 'value');
weakMap2.set(obj, 'value');

// Сравнение разных экземпляров не проходит, даже при одинаковом содержимом
assert.deepStrictEqual(weakMap1, weakMap2);
// AssertionError: Values have same structure but are not reference-equal:
//
// WeakMap {
//   <items unknown>
// }

// Сравнение экземпляра с самим собой проходит
assert.deepStrictEqual(weakMap1, weakMap1);
// OK

const weakSet1 = new WeakSet();
const weakSet2 = new WeakSet();
weakSet1.add(obj);
weakSet2.add(obj);

// Сравнение разных экземпляров не проходит, даже при одинаковом содержимом
assert.deepStrictEqual(weakSet1, weakSet2);
// AssertionError: Values have same structure but are not reference-equal:
// + actual - expected
//
// WeakSet {
//   <items unknown>
// }

// Сравнение экземпляра с самим собой проходит
assert.deepStrictEqual(weakSet1, weakSet1);
// OK
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
const assert = require('node:assert/strict');

// Не проходит, так как 1 !== '1'.
assert.deepStrictEqual({ a: 1 }, { a: '1' });
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
//   {
// +   a: 1
// -   a: '1'
//   }

// У следующих объектов нет собственных свойств
const date = new Date();
const object = {};
const fakeDate = {};
Object.setPrototypeOf(fakeDate, Date.prototype);

// Разный [[Prototype]]:
assert.deepStrictEqual(object, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + {}
// - Date {}

// Разные теги типов:
assert.deepStrictEqual(date, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 2018-04-26T00:49:08.604Z
// - Date {}

assert.deepStrictEqual(NaN, NaN);
// OK: Object.is(NaN, NaN) === true.

// Разные развёрнутые числа:
assert.deepStrictEqual(new Number(1), new Number(2));
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + [Number: 1]
// - [Number: 2]

assert.deepStrictEqual(new String('foo'), Object('foo'));
// OK: объект и строка совпадают после развёртывания.

assert.deepStrictEqual(-0, -0);
// OK

// Разные нули:
assert.deepStrictEqual(0, -0);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 0
// - -0

const symbol1 = Symbol();
const symbol2 = Symbol();
assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol1]: 1 });
// OK: в обоих объектах используется один и тот же символ.

assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol2]: 1 });
// AssertionError [ERR_ASSERTION]: Inputs identical but not reference equal:
//
// {
//   Symbol(): 1
// }

const weakMap1 = new WeakMap();
const weakMap2 = new WeakMap();
const obj = {};

weakMap1.set(obj, 'value');
weakMap2.set(obj, 'value');

// Сравнение разных экземпляров не проходит, даже при одинаковом содержимом
assert.deepStrictEqual(weakMap1, weakMap2);
// AssertionError: Values have same structure but are not reference-equal:
//
// WeakMap {
//   <items unknown>
// }

// Сравнение экземпляра с самим собой проходит
assert.deepStrictEqual(weakMap1, weakMap1);
// OK

const weakSet1 = new WeakSet();
const weakSet2 = new WeakSet();
weakSet1.add(obj);
weakSet2.add(obj);

// Сравнение разных экземпляров не проходит, даже при одинаковом содержимом
assert.deepStrictEqual(weakSet1, weakSet2);
// AssertionError: Values have same structure but are not reference-equal:
// + actual - expected
//
// WeakSet {
//   <items unknown>
// }

// Сравнение экземпляра с самим собой проходит
assert.deepStrictEqual(weakSet1, weakSet1);
// OK

Если значения не равны, выбрасывается AssertionError: свойство message равно значению параметра message. Если message не передан, подставляется сообщение по умолчанию. Если message является экземпляром Error, выбрасывается он, а не AssertionError.

assert.doesNotMatch(string, regexp[, message])

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import assert from 'node:assert/strict';

assert.doesNotMatch('I will fail', /fail/);
// AssertionError [ERR_ASSERTION]: The input was expected to not match the ...

assert.doesNotMatch(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.

assert.doesNotMatch('I will pass', /different/);
// OK
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const assert = require('node:assert/strict');

assert.doesNotMatch('I will fail', /fail/);
// AssertionError [ERR_ASSERTION]: The input was expected to not match the ...

assert.doesNotMatch(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.

assert.doesNotMatch('I will pass', /different/);
// OK

Если строка совпадает с шаблоном или аргумент string имеет тип, отличный от string, выбрасывается AssertionError: свойство message равно значению параметра message. Если message не передан, подставляется сообщение по умолчанию. Если message является экземпляром Error, выбрасывается он, а не AssertionError.

assert.doesNotReject(asyncFn[, error][, message])

Ожидает завершения промиса asyncFn или, если asyncFn - функция, сразу вызывает её и ожидает промис из возвращаемого значения. Затем проверяется, что промис не был отклонён.

Если asyncFn - функция и она синхронно выбрасывает ошибку, assert.doesNotReject() вернёт отклонённый Promise с этой ошибкой. Если функция не возвращает промис, assert.doesNotReject() вернёт отклонённый Promise с ошибкой ERR_INVALID_RETURN_VALUE. В обоих случаях обработчик ошибки из проверки типа не используется.

На практике assert.doesNotReject() почти не полезен: мало смысла перехватывать отклонение и снова отклонять промис. Лучше оставить комментарий у участка кода, который не должен завершаться отклонением, и формулировать сообщения об ошибках максимально ясно.

При необходимости параметр error может быть Class, RegExp или функцией проверки. Подробнее - в assert.throws().

Поведение после ожидания завершения совпадает с assert.doesNotThrow(), кроме асинхронности.

1
2
3
4
5
import assert from 'node:assert/strict';

await assert.doesNotReject(async () => {
    throw new TypeError('Wrong value');
}, SyntaxError);
1
2
3
4
5
6
7
const assert = require('node:assert/strict');

(async () => {
    await assert.doesNotReject(async () => {
        throw new TypeError('Wrong value');
    }, SyntaxError);
})();

1
2
3
4
5
6
7
8
9
import assert from 'node:assert/strict';

assert
    .doesNotReject(
        Promise.reject(new TypeError('Wrong value'))
    )
    .then(() => {
        // ...
    });
1
2
3
4
5
6
7
8
9
const assert = require('node:assert/strict');

assert
    .doesNotReject(
        Promise.reject(new TypeError('Wrong value'))
    )
    .then(() => {
        // ...
    });

assert.doesNotThrow(fn[, error][, message])

Утверждает, что функция fn не выбрасывает ошибку.

На практике assert.doesNotThrow() почти не полезен: мало смысла перехватывать ошибку и тут же пробрасывать её снова. Лучше оставить комментарий у участка кода, который не должен выбрасывать ошибку, и формулировать сообщения максимально ясно.

При вызове assert.doesNotThrow() функция fn выполняется сразу.

Если ошибка выброшена и её тип совпадает с типом, заданным параметром error, выбрасывается AssertionError. Если тип другой или параметр error не задан, ошибка пробрасывается вызывающему коду.

При необходимости error может быть Class, RegExp или функцией проверки. Подробнее - в assert.throws().

В следующем примере будет выброшен TypeError, потому что в утверждении нет подходящего типа ошибки:

1
2
3
4
5
import assert from 'node:assert/strict';

assert.doesNotThrow(() => {
    throw new TypeError('Wrong value');
}, SyntaxError);
1
2
3
4
5
const assert = require('node:assert/strict');

assert.doesNotThrow(() => {
    throw new TypeError('Wrong value');
}, SyntaxError);

Следующий пример приводит к AssertionError с сообщением «Got unwanted exception...»:

1
2
3
4
5
import assert from 'node:assert/strict';

assert.doesNotThrow(() => {
    throw new TypeError('Wrong value');
}, TypeError);
1
2
3
4
5
const assert = require('node:assert/strict');

assert.doesNotThrow(() => {
    throw new TypeError('Wrong value');
}, TypeError);

Если выброшена AssertionError и для параметра message задано значение, оно дописывается к сообщению AssertionError:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import assert from 'node:assert/strict';

assert.doesNotThrow(
    () => {
        throw new TypeError('Wrong value');
    },
    /Wrong value/,
    'Whoops'
);
// Throws: AssertionError: Got unwanted exception: Whoops
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const assert = require('node:assert/strict');

assert.doesNotThrow(
    () => {
        throw new TypeError('Wrong value');
    },
    /Wrong value/,
    'Whoops'
);
// Throws: AssertionError: Got unwanted exception: Whoops

assert.equal(actual, expected[, message])

Режим строгих утверждений (strict assertion mode)

Псевдоним assert.strictEqual().

Режим унаследованных утверждений (legacy assertion mode)

Стабильность: 3 - Legacy: вместо этого используйте assert.strictEqual().

Проверяет неглубокое равенство с приведением типов между actual и expected с помощью оператора ==. NaN обрабатывается особым образом: считается совпадающим, если NaN с обеих сторон.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import assert from 'node:assert';

assert.equal(1, 1);
// OK, 1 == 1
assert.equal(1, '1');
// OK, 1 == '1'
assert.equal(NaN, NaN);
// OK

assert.equal(1, 2);
// AssertionError: 1 == 2
assert.equal({ a: { b: 1 } }, { a: { b: 1 } });
// AssertionError: { a: { b: 1 } } == { a: { b: 1 } }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const assert = require('node:assert');

assert.equal(1, 1);
// OK, 1 == 1
assert.equal(1, '1');
// OK, 1 == '1'
assert.equal(NaN, NaN);
// OK

assert.equal(1, 2);
// AssertionError: 1 == 2
assert.equal({ a: { b: 1 } }, { a: { b: 1 } });
// AssertionError: { a: { b: 1 } } == { a: { b: 1 } }

Если значения не равны, выбрасывается AssertionError: свойство message равно значению параметра message. Если message не передан, подставляется сообщение по умолчанию. Если message является экземпляром Error, выбрасывается он, а не AssertionError.

assert.fail([message])

Выбрасывает AssertionError с указанным сообщением или сообщением по умолчанию. Если message является экземпляром Error, выбрасывается он, а не AssertionError.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import assert from 'node:assert/strict';

assert.fail();
// AssertionError [ERR_ASSERTION]: Failed

assert.fail('boom');
// AssertionError [ERR_ASSERTION]: boom

assert.fail(new TypeError('need array'));
// TypeError: need array
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const assert = require('node:assert/strict');

assert.fail();
// AssertionError [ERR_ASSERTION]: Failed

assert.fail('boom');
// AssertionError [ERR_ASSERTION]: boom

assert.fail(new TypeError('need array'));
// TypeError: need array

assert.ifError(value)

Выбрасывает value, если оно не undefined и не null. Удобно при проверке аргумента error в колбэках. В трассировку стека входят все кадры из переданной в ifError() ошибки, включая возможные новые кадры для самой ifError().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import assert from 'node:assert/strict';

assert.ifError(null);
// OK
assert.ifError(0);
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 0
assert.ifError('error');
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 'error'
assert.ifError(new Error());
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: Error

// Несколько произвольных кадров стека ошибки.
let err;
(function errorFrame() {
    err = new Error('test error');
})();

(function ifErrorFrame() {
    assert.ifError(err);
})();
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: test error
//     at ifErrorFrame
//     at errorFrame
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const assert = require('node:assert/strict');

assert.ifError(null);
// OK
assert.ifError(0);
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 0
assert.ifError('error');
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 'error'
assert.ifError(new Error());
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: Error

// Несколько произвольных кадров стека ошибки.
let err;
(function errorFrame() {
    err = new Error('test error');
})();

(function ifErrorFrame() {
    assert.ifError(err);
})();
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: test error
//     at ifErrorFrame
//     at errorFrame

assert.match(string, regexp[, message])

Ожидается, что строка string соответствует регулярному выражению.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import assert from 'node:assert/strict';

assert.match('I will fail', /pass/);
// AssertionError [ERR_ASSERTION]: The input did not match the regular ...

assert.match(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.

assert.match('I will pass', /pass/);
// OK
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const assert = require('node:assert/strict');

assert.match('I will fail', /pass/);
// AssertionError [ERR_ASSERTION]: The input did not match the regular ...

assert.match(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.

assert.match('I will pass', /pass/);
// OK

Если строка не совпадает с шаблоном или аргумент string имеет тип, отличный от string, выбрасывается AssertionError: свойство message равно значению параметра message. Если message не передан, подставляется сообщение по умолчанию. Если message является экземпляром Error, выбрасывается он, а не AssertionError.

assert.notDeepEqual(actual, expected[, message])

Строгий режим утверждения

Псевдоним assert.notDeepStrictEqual().

Режим утверждения Legacy

Стабильность: 3 - Legacy: вместо этого используйте assert.notDeepStrictEqual().

Проверяет произвольное глубокое неравенство. Противоположность assert.deepEqual().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import assert from 'node:assert';

const obj1 = {
    a: {
        b: 1,
    },
};
const obj2 = {
    a: {
        b: 2,
    },
};
const obj3 = {
    a: {
        b: 1,
    },
};
const obj4 = { __proto__: obj1 };

assert.notDeepEqual(obj1, obj1);
// AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }

assert.notDeepEqual(obj1, obj2);
// OK

assert.notDeepEqual(obj1, obj3);
// AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }

assert.notDeepEqual(obj1, obj4);
// OK
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const assert = require('node:assert');

const obj1 = {
    a: {
        b: 1,
    },
};
const obj2 = {
    a: {
        b: 2,
    },
};
const obj3 = {
    a: {
        b: 1,
    },
};
const obj4 = { __proto__: obj1 };

assert.notDeepEqual(obj1, obj1);
// AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }

assert.notDeepEqual(obj1, obj2);
// OK

assert.notDeepEqual(obj1, obj3);
// AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }

assert.notDeepEqual(obj1, obj4);
// OK

Если значения глубоко равны, выбрасывается AssertionError со свойством message, равным значению параметра message. Если параметр message имеет значение undefined, подставляется сообщение об ошибке по умолчанию. Если параметр message является экземпляром Error, он будет выброшен вместо AssertionError.

assert.notDeepStrictEqual(actual, expected[, message])

Проверяет глубокое строгое неравенство. Противоположность assert.deepStrictEqual().

1
2
3
4
import assert from 'node:assert/strict';

assert.notDeepStrictEqual({ a: 1 }, { a: '1' });
// OK
1
2
3
4
const assert = require('node:assert/strict');

assert.notDeepStrictEqual({ a: 1 }, { a: '1' });
// OK

Если значения глубоко и строго равны, выбрасывается AssertionError со свойством message, равным значению параметра message. Если параметр message имеет значение undefined, подставляется сообщение об ошибке по умолчанию. Если параметр message является экземпляром Error, он будет выброшен вместо AssertionError.

assert.notEqual(actual, expected[, message])

Строгий режим утверждения

Псевдоним assert.notStrictEqual().

Режим утверждения Legacy

Стабильность: 3 - Legacy: вместо этого используйте assert.notStrictEqual().

Проверяет неглубокое принудительное неравенство с помощью !=. NaN обрабатывается особым образом и считается совпадающим, если обе стороны - NaN.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import assert from 'node:assert';

assert.notEqual(1, 2);
// OK

assert.notEqual(1, 1);
// AssertionError: 1 != 1

assert.notEqual(1, '1');
// AssertionError: 1 != '1'
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const assert = require('node:assert');

assert.notEqual(1, 2);
// OK

assert.notEqual(1, 1);
// AssertionError: 1 != 1

assert.notEqual(1, '1');
// AssertionError: 1 != '1'

Если значения равны, выбрасывается AssertionError со свойством message, равным значению параметра message. Если параметр message имеет значение undefined, подставляется сообщение об ошибке по умолчанию. Если параметр message является экземпляром Error, он будет выброшен вместо AssertionError.

assert.notStrictEqual(actual, expected[, message])

Проверяет строгое неравенство между параметрами actual и expected, определяемое Object.is().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import assert from 'node:assert/strict';

assert.notStrictEqual(1, 2);
// OK

assert.notStrictEqual(1, 1);
// AssertionError [ERR_ASSERTION]: Expected "actual" to be strictly unequal to:
//
// 1

assert.notStrictEqual(1, '1');
// OK
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const assert = require('node:assert/strict');

assert.notStrictEqual(1, 2);
// OK

assert.notStrictEqual(1, 1);
// AssertionError [ERR_ASSERTION]: Expected "actual" to be strictly unequal to:
//
// 1

assert.notStrictEqual(1, '1');
// OK

Если значения строго равны, выбрасывается AssertionError со свойством message, равным значению параметра message. Если параметр message имеет значение undefined, подставляется сообщение об ошибке по умолчанию. Если параметр message является экземпляром Error, он будет выброшен вместо AssertionError.

assert.ok(value[, message])

Проверяет, является ли value истинным (truthy). Эквивалентно assert.equal(!!value, true, message).

Если value ложно (falsy), выбрасывается AssertionError со свойством message, равным значению параметра message. Если параметр message имеет значение undefined, подставляется сообщение об ошибке по умолчанию. Если параметр message является экземпляром Error, он будет выброшен вместо AssertionError. Если аргументы не переданы вообще, message будет установлена в строку 'No value argument passed to `assert.ok()`'.

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import assert from 'node:assert/strict';

assert.ok(true);
// OK
assert.ok(1);
// OK

assert.ok();
// AssertionError: No value argument passed to `assert.ok()`

assert.ok(false, "it's false");
// AssertionError: it's false

// В REPL:
assert.ok(typeof 123 === 'string');
// AssertionError: false == true

// В файле (например, test.js):
assert.ok(typeof 123 === 'string');
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(typeof 123 === 'string')

assert.ok(false);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(false)

assert.ok(0);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(0)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const assert = require('node:assert/strict');

assert.ok(true);
// OK
assert.ok(1);
// OK

assert.ok();
// AssertionError: No value argument passed to `assert.ok()`

assert.ok(false, "it's false");
// AssertionError: it's false

// В REPL:
assert.ok(typeof 123 === 'string');
// AssertionError: false == true

// В файле (например, test.js):
assert.ok(typeof 123 === 'string');
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(typeof 123 === 'string')

assert.ok(false);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(false)

assert.ok(0);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(0)

1
2
3
4
5
6
7
import assert from 'node:assert/strict';

// Вызов `assert()` ведёт себя так же:
assert(2 + 2 > 5);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert(2 + 2 > 5)
1
2
3
4
5
6
7
const assert = require('node:assert');

// Вызов `assert()` ведёт себя так же:
assert(2 + 2 > 5);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert(2 + 2 > 5)

assert.rejects(asyncFn[, error][, message])

Ожидает промис asyncFn или, если asyncFn - функция, сразу вызывает её и ожидает завершения возвращённого промиса. Затем проверяется, что промис отклонён.

Если asyncFn - функция и она синхронно выбрасывает ошибку, assert.rejects() вернёт отклонённый Promise с этой ошибкой. Если функция не возвращает промис, assert.rejects() вернёт отклонённый Promise с ошибкой ERR_INVALID_RETURN_VALUE. В обоих случаях обработчик ошибки пропускается.

Помимо асинхронного ожидания завершения поведение совпадает с assert.throws().

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

Если указано, message будет сообщением, которое передаёт AssertionError, если asyncFn не отклонится.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import assert from 'node:assert/strict';

await assert.rejects(
    async () => {
        throw new TypeError('Wrong value');
    },
    {
        name: 'TypeError',
        message: 'Wrong value',
    }
);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const assert = require('node:assert/strict');

(async () => {
    await assert.rejects(
        async () => {
            throw new TypeError('Wrong value');
        },
        {
            name: 'TypeError',
            message: 'Wrong value',
        }
    );
})();

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import assert from 'node:assert/strict';

await assert.rejects(
    async () => {
        throw new TypeError('Wrong value');
    },
    (err) => {
        assert.strictEqual(err.name, 'TypeError');
        assert.strictEqual(err.message, 'Wrong value');
        return true;
    }
);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const assert = require('node:assert/strict');

(async () => {
    await assert.rejects(
        async () => {
            throw new TypeError('Wrong value');
        },
        (err) => {
            assert.strictEqual(err.name, 'TypeError');
            assert.strictEqual(err.message, 'Wrong value');
            return true;
        }
    );
})();

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import assert from 'node:assert/strict';

assert
    .rejects(
        Promise.reject(new Error('Wrong value')),
        Error
    )
    .then(() => {
        // ...
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const assert = require('node:assert/strict');

assert
    .rejects(
        Promise.reject(new Error('Wrong value')),
        Error
    )
    .then(() => {
        // ...
    });

error не может быть строкой. Если вторым аргументом передана строка, считается, что error опущен, и строка используется как message. Это легко даёт незаметные ошибки. Внимательно прочитайте пример в assert.throws(), если рассматриваете передачу строки вторым аргументом.

assert.strictEqual(actual, expected[, message])

  • actual <any>
  • expected <any>
  • message <string> | <Error> | <Function> Постфиксные аргументы в стиле printf, если message используется как строка формата. Если message - функция, она вызывается при несовпадении сравнения. Функция получает аргументы actual и expected и должна вернуть строку, которая будет использована как сообщение об ошибке. Строки формата в стиле printf и функции удобны для производительности, когда аргументы пробрасываются дальше. Кроме того, так проще получить аккуратное форматирование.

Проверяет строгое равенство между параметрами actual и expected так, как определяет Object.is().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import assert from 'node:assert/strict';

assert.strictEqual(1, 2);
// AssertionError [ERR_ASSERTION]: Ожидается, что входные значения строго равны:
//
// 1 !== 2

assert.strictEqual(1, 1);
// OK

assert.strictEqual('Hello foobar', 'Hello World!');
// AssertionError [ERR_ASSERTION]: Ожидается, что входные значения строго равны:
// + фактическое - ожидаемое
//
// + 'Hello foobar'
// - 'Hello World!'
//          ^

const apples = 1;
const oranges = 2;
assert.strictEqual(
    apples,
    oranges,
    `apples ${apples} !== oranges ${oranges}`
);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2

assert.strictEqual(
    apples,
    oranges,
    'apples %s !== oranges %s',
    apples,
    oranges
);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2

assert.strictEqual(
    1,
    '1',
    new TypeError('Inputs are not identical')
);
// TypeError: Inputs are not identical

assert.strictEqual(apples, oranges, (actual, expected) => {
    // «Тяжёлые» вычисления
    return `I expected ${expected} but I got ${actual}`;
});
// AssertionError [ERR_ASSERTION]: I expected oranges but I got apples
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const assert = require('node:assert/strict');

assert.strictEqual(1, 2);
// AssertionError [ERR_ASSERTION]: Ожидается, что входные значения строго равны:
//
// 1 !== 2

assert.strictEqual(1, 1);
// OK

assert.strictEqual('Hello foobar', 'Hello World!');
// AssertionError [ERR_ASSERTION]: Ожидается, что входные значения строго равны:
// + фактическое - ожидаемое
//
// + 'Hello foobar'
// - 'Hello World!'
//          ^

const apples = 1;
const oranges = 2;
assert.strictEqual(
    apples,
    oranges,
    `apples ${apples} !== oranges ${oranges}`
);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2

assert.strictEqual(
    apples,
    oranges,
    'apples %s !== oranges %s',
    apples,
    oranges
);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2

assert.strictEqual(
    1,
    '1',
    new TypeError('Inputs are not identical')
);
// TypeError: Inputs are not identical

assert.strictEqual(apples, oranges, (actual, expected) => {
    // «Тяжёлые» вычисления
    return `I expected ${expected} but I got ${actual}`;
});
// AssertionError [ERR_ASSERTION]: I expected oranges but I got apples

Если значения не строго равны, выбрасывается AssertionError со свойством message, равным значению параметра message. Если параметр message равен undefined, подставляется сообщение об ошибке по умолчанию. Если параметр message является экземпляром Error, выбрасывается он, а не AssertionError.

assert.throws(fn[, error][, message])

Ожидает, что функция fn выбросит ошибку.

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

Если указано, message дополняет сообщение, которое даёт AssertionError, если вызов fn не привёл к выбросу или если проверка ошибки не прошла.

Пользовательский объект проверки / экземпляр ошибки:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import assert from 'node:assert/strict';

const err = new TypeError('Wrong value');
err.code = 404;
err.foo = 'bar';
err.info = {
    nested: true,
    baz: 'text',
};
err.reg = /abc/i;

assert.throws(
    () => {
        throw err;
    },
    {
        name: 'TypeError',
        message: 'Wrong value',
        info: {
            nested: true,
            baz: 'text',
        },
        // Проверяются только свойства объекта проверки.
        // Для вложенных объектов должны присутствовать все свойства, иначе
        // проверка не пройдёт.
    }
);

// Регулярные выражения для проверки свойств ошибки:
assert.throws(
    () => {
        throw err;
    },
    {
        // Свойства `name` и `message` - строки; для них регулярные выражения
        // сопоставляются со строкой. При неудаче выбрасывается ошибка.
        name: /^TypeError$/,
        message: /Wrong/,
        foo: 'bar',
        info: {
            nested: true,
            // Для вложенных свойств нельзя использовать регулярные выражения!
            baz: 'text',
        },
        // Свойство `reg` содержит регулярное выражение; проверка пройдёт только
        // если в объекте проверки то же самое регулярное выражение.
        reg: /abc/i,
    }
);

// Не проходит из-за разных свойств `message` и `name`:
assert.throws(
    () => {
        const otherErr = new Error('Not found');
        // Копируем все перечислимые свойства из `err` в `otherErr`.
        for (const [key, value] of Object.entries(err)) {
            otherErr[key] = value;
        }
        throw otherErr;
    },
    // Свойства `message` и `name` ошибки также проверяются, если ошибка
    // используется как объект проверки.
    err
);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
const assert = require('node:assert/strict');

const err = new TypeError('Wrong value');
err.code = 404;
err.foo = 'bar';
err.info = {
    nested: true,
    baz: 'text',
};
err.reg = /abc/i;

assert.throws(
    () => {
        throw err;
    },
    {
        name: 'TypeError',
        message: 'Wrong value',
        info: {
            nested: true,
            baz: 'text',
        },
        // Проверяются только свойства объекта проверки.
        // Для вложенных объектов должны присутствовать все свойства, иначе
        // проверка не пройдёт.
    }
);

// Регулярные выражения для проверки свойств ошибки:
assert.throws(
    () => {
        throw err;
    },
    {
        // Свойства `name` и `message` - строки; для них регулярные выражения
        // сопоставляются со строкой. При неудаче выбрасывается ошибка.
        name: /^TypeError$/,
        message: /Wrong/,
        foo: 'bar',
        info: {
            nested: true,
            // Для вложенных свойств нельзя использовать регулярные выражения!
            baz: 'text',
        },
        // Свойство `reg` содержит регулярное выражение; проверка пройдёт только
        // если в объекте проверки то же самое регулярное выражение.
        reg: /abc/i,
    }
);

// Не проходит из-за разных свойств `message` и `name`:
assert.throws(
    () => {
        const otherErr = new Error('Not found');
        // Копируем все перечислимые свойства из `err` в `otherErr`.
        for (const [key, value] of Object.entries(err)) {
            otherErr[key] = value;
        }
        throw otherErr;
    },
    // Свойства `message` и `name` ошибки также проверяются, если ошибка
    // используется как объект проверки.
    err
);

Проверка instanceof через конструктор:

1
2
3
4
5
import assert from 'node:assert/strict';

assert.throws(() => {
    throw new Error('Wrong value');
}, Error);
1
2
3
4
5
const assert = require('node:assert/strict');

assert.throws(() => {
    throw new Error('Wrong value');
}, Error);

Проверка сообщения об ошибке с помощью RegExp:

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

1
2
3
4
5
import assert from 'node:assert/strict';

assert.throws(() => {
    throw new Error('Wrong value');
}, /^Error: Wrong value$/);
1
2
3
4
5
const assert = require('node:assert/strict');

assert.throws(() => {
    throw new Error('Wrong value');
}, /^Error: Wrong value$/);

Пользовательская проверка ошибки:

Функция должна вернуть true, чтобы показать, что все внутренние проверки прошли. Иначе проверка завершится с AssertionError.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import assert from 'node:assert/strict';

assert.throws(
    () => {
        throw new Error('Wrong value');
    },
    (err) => {
        assert(err instanceof Error);
        assert(/value/.test(err));
        // Не возвращайте из функций проверки ничего, кроме `true`.
        // Иначе непонятно, какая часть проверки не прошла. Вместо этого
        // выбросьте ошибку о конкретной неудавшейся проверке (как в этом
        // примере) и добавьте в неё как можно больше полезной отладочной информации.
        return true;
    },
    'unexpected error'
);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const assert = require('node:assert/strict');

assert.throws(
    () => {
        throw new Error('Wrong value');
    },
    (err) => {
        assert(err instanceof Error);
        assert(/value/.test(err));
        // Не возвращайте из функций проверки ничего, кроме `true`.
        // Иначе непонятно, какая часть проверки не прошла. Вместо этого
        // выбросьте ошибку о конкретной неудавшейся проверке (как в этом
        // примере) и добавьте в неё как можно больше полезной отладочной информации.
        return true;
    },
    'unexpected error'
);

error не может быть строкой. Если вторым аргументом передана строка, считается, что error опущен, и строка используется как message. Это легко даёт незаметные ошибки. Если сообщение совпадает с текстом выброшенной ошибки, возникнет ошибка ERR_AMBIGUOUS_ARGUMENT. Внимательно прочитайте пример ниже, если рассматриваете передачу строки вторым аргументом:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import assert from 'node:assert/strict';

function throwingFirst() {
    throw new Error('First');
}

function throwingSecond() {
    throw new Error('Second');
}

function notThrowing() {}

// Второй аргумент - строка, а входная функция выбросила Error.
// Первый случай не выбросит ошибку, так как не совпадает с сообщением
// ошибки из входной функции!
assert.throws(throwingFirst, 'Second');
// В следующем примере сообщение не добавляет ничего к сообщению из
// ошибки, и неясно, хотел ли пользователь сопоставлять именно текст ошибки,
// поэтому Node.js выбрасывает ошибку `ERR_AMBIGUOUS_ARGUMENT`.
assert.throws(throwingSecond, 'Second');
// TypeError [ERR_AMBIGUOUS_ARGUMENT]

// Строка используется (как message) только если функция не выбросила ошибку:
assert.throws(notThrowing, 'Second');
// AssertionError [ERR_ASSERTION]: Missing expected exception: Second

// Если нужно сопоставлять сообщение об ошибке, сделайте так:
// Ошибка не выбрасывается, так как сообщения совпадают.
assert.throws(throwingSecond, /Second$/);

// Если сообщение не совпадает, выбрасывается AssertionError.
assert.throws(throwingFirst, /Second$/);
// AssertionError [ERR_ASSERTION]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const assert = require('node:assert/strict');

function throwingFirst() {
    throw new Error('First');
}

function throwingSecond() {
    throw new Error('Second');
}

function notThrowing() {}

// Второй аргумент - строка, а входная функция выбросила Error.
// Первый случай не выбросит ошибку, так как не совпадает с сообщением
// ошибки из входной функции!
assert.throws(throwingFirst, 'Second');
// В следующем примере сообщение не добавляет ничего к сообщению из
// ошибки, и неясно, хотел ли пользователь сопоставлять именно текст ошибки,
// поэтому Node.js выбрасывает ошибку `ERR_AMBIGUOUS_ARGUMENT`.
assert.throws(throwingSecond, 'Second');
// TypeError [ERR_AMBIGUOUS_ARGUMENT]

// Строка используется (как message) только если функция не выбросила ошибку:
assert.throws(notThrowing, 'Second');
// AssertionError [ERR_ASSERTION]: Missing expected exception: Second

// Если нужно сопоставлять сообщение об ошибке, сделайте так:
// Ошибка не выбрасывается, так как сообщения совпадают.
assert.throws(throwingSecond, /Second$/);

// Если сообщение не совпадает, выбрасывается AssertionError.
assert.throws(throwingFirst, /Second$/);
// AssertionError [ERR_ASSERTION]

Из-за запутанной и подверженной ошибкам записи не используйте строку вторым аргументом.

assert.partialDeepStrictEqual(actual, expected[, message])

Проверяет частичное глубокое равенство между параметрами actual и expected. «Глубокое» равенство означает, что перечислимые собственные свойства дочерних объектов рекурсивно оцениваются по правилам ниже. «Частичное» равенство означает, что сравниваются только свойства, присутствующие в параметре expected.

Этот метод всегда проходит те же проверки, что и assert.deepStrictEqual(), и ведёт себя как надмножество этой функции.

Детали сравнения

  • Примитивы сравниваются через Object.is().
  • Теги типов объектов должны совпадать.
  • [[Prototype]] объектов не сравниваются.
  • Учитываются только перечислимые собственные свойства.
  • Обёртки объектов сравниваются и как объекты, и как развёрнутые значения.
  • Свойства Object сравниваются без учёта порядка.
  • Ключи Map и элементы Set сравниваются без учёта порядка.
  • Рекурсия останавливается, когда обе стороны различаются или обе доходят до циклической ссылки.
  • Экземпляры WeakMap, WeakSet и Promise не сравниваются структурно. Они равны только если ссылаются на один и тот же объект. Любое сравнение разных экземпляров WeakMap, WeakSet или Promise даст неравенство, даже при одинаковом содержимом.
  • У RegExp всегда сравниваются lastIndex, флаги и source, даже если это неперечислимые свойства.
  • Дыры в разреженных массивах игнорируются.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import assert from 'node:assert';

assert.partialDeepStrictEqual(
    { a: { b: { c: 1 } } },
    { a: { b: { c: 1 } } }
);
// OK

assert.partialDeepStrictEqual(
    { a: 1, b: 2, c: 3 },
    { b: 2 }
);
// OK

assert.partialDeepStrictEqual(
    [1, 2, 3, 4, 5, 6, 7, 8, 9],
    [4, 5, 8]
);
// OK

assert.partialDeepStrictEqual(
    new Set([{ a: 1 }, { b: 1 }]),
    new Set([{ a: 1 }])
);
// OK

assert.partialDeepStrictEqual(
    new Map([
        ['key1', 'value1'],
        ['key2', 'value2'],
    ]),
    new Map([['key2', 'value2']])
);
// OK

assert.partialDeepStrictEqual(123n, 123n);
// OK

assert.partialDeepStrictEqual(
    [1, 2, 3, 4, 5, 6, 7, 8, 9],
    [5, 4, 8]
);
// AssertionError

assert.partialDeepStrictEqual({ a: 1 }, { a: 1, b: 2 });
// AssertionError

assert.partialDeepStrictEqual(
    { a: { b: 2 } },
    { a: { b: '2' } }
);
// AssertionError
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const assert = require('node:assert');

assert.partialDeepStrictEqual(
    { a: { b: { c: 1 } } },
    { a: { b: { c: 1 } } }
);
// OK

assert.partialDeepStrictEqual(
    { a: 1, b: 2, c: 3 },
    { b: 2 }
);
// OK

assert.partialDeepStrictEqual(
    [1, 2, 3, 4, 5, 6, 7, 8, 9],
    [4, 5, 8]
);
// OK

assert.partialDeepStrictEqual(
    new Set([{ a: 1 }, { b: 1 }]),
    new Set([{ a: 1 }])
);
// OK

assert.partialDeepStrictEqual(
    new Map([
        ['key1', 'value1'],
        ['key2', 'value2'],
    ]),
    new Map([['key2', 'value2']])
);
// OK

assert.partialDeepStrictEqual(123n, 123n);
// OK

assert.partialDeepStrictEqual(
    [1, 2, 3, 4, 5, 6, 7, 8, 9],
    [5, 4, 8]
);
// AssertionError

assert.partialDeepStrictEqual({ a: 1 }, { a: 1, b: 2 });
// AssertionError

assert.partialDeepStrictEqual(
    { a: { b: 2 } },
    { a: { b: '2' } }
);
// AssertionError

Комментарии