Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfeugy <damien.feugas@gmail.com>2018-01-12 02:16:41 +0300
committerMyles Borins <mylesborins@google.com>2018-11-04 15:30:51 +0300
commit3babc5bb533d94e6355d062233fbe05744603115 (patch)
tree37359302d360c32fc34a4b52d735b904f6dc903b
parent7f34c277accdfffe0b87b24f5e2fda889b1ac924 (diff)
assert: add rejects() and doesNotReject()
Implement asynchronous equivalent for assert.throws() and assert.doesNotThrow(). Backport-PR-URL: https://github.com/nodejs/node/pull/24019 PR-URL: https://github.com/nodejs/node/pull/18023 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Shingo Inoue <leko.noor@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
-rw-r--r--doc/api/assert.md80
-rw-r--r--lib/assert.js65
-rw-r--r--test/parallel/test-assert-async.js66
-rw-r--r--test/parallel/test-assert.js11
4 files changed, 207 insertions, 15 deletions
diff --git a/doc/api/assert.md b/doc/api/assert.md
index dbd32096b5c..6cc3cd561eb 100644
--- a/doc/api/assert.md
+++ b/doc/api/assert.md
@@ -242,6 +242,43 @@ If the values are not equal, an `AssertionError` is thrown with a `message`
property set equal to the value of the `message` parameter. If the `message`
parameter is undefined, a default error message is assigned.
+## assert.doesNotReject(block[, error][, message])
+<!-- YAML
+added: REPLACEME
+-->
+* `block` {Function}
+* `error` {RegExp|Function}
+* `message` {any}
+
+Awaits for the promise returned by function `block` to complete and not be
+rejected. See [`assert.rejects()`][] for more details.
+
+When `assert.doesNotReject()` is called, it will immediately call the `block`
+function, and awaits for completion.
+
+Besides the async nature to await the completion behaves identical to
+[`assert.doesNotThrow()`][].
+
+```js
+(async () => {
+ await assert.doesNotReject(
+ async () => {
+ throw new TypeError('Wrong value');
+ },
+ SyntaxError
+ );
+})();
+```
+
+```js
+assert.doesNotReject(
+ () => Promise.reject(new TypeError('Wrong value')),
+ SyntaxError
+).then(() => {
+ // ...
+});
+```
+
## assert.doesNotThrow(block[, error][, message])
<!-- YAML
added: v0.1.21
@@ -631,6 +668,48 @@ If the values are not strictly equal, an `AssertionError` is thrown with a
`message` property set equal to the value of the `message` parameter. If the
`message` parameter is undefined, a default error message is assigned.
+## assert.rejects(block[, error][, message])
+<!-- YAML
+added: REPLACEME
+-->
+* `block` {Function}
+* `error` {RegExp|Function|Object}
+* `message` {any}
+
+Awaits for promise returned by function `block` to be rejected.
+
+When `assert.rejects()` is called, it will immediately call the `block`
+function, and awaits for completion.
+
+Besides the async nature to await the completion behaves identical to
+[`assert.throws()`][].
+
+If specified, `error` can be a constructor, [`RegExp`][], a validation
+function, or an object where each property will be tested for.
+
+If specified, `message` will be the message provided by the `AssertionError` if
+the block fails to reject.
+
+```js
+(async () => {
+ await assert.rejects(
+ async () => {
+ throw new Error('Wrong value');
+ },
+ Error
+ );
+})();
+```
+
+```js
+assert.rejects(
+ () => Promise.reject(new Error('Wrong value')),
+ Error
+).then(() => {
+ // ...
+});
+```
+
## assert.throws(block[, error][, message])
<!-- YAML
added: v0.1.21
@@ -786,6 +865,7 @@ For more information, see
[`assert.ok()`]: #assert_assert_ok_value_message
[`assert.strictEqual()`]: #assert_assert_strictequal_actual_expected_message
[`assert.throws()`]: #assert_assert_throws_block_error_message
+[`assert.rejects()`]: #assert_assert_rejects_block_error_message
[`strict mode`]: #assert_strict_mode
[Abstract Equality Comparison]: https://tc39.github.io/ecma262/#sec-abstract-equality-comparison
[Object.prototype.toString()]: https://tc39.github.io/ecma262/#sec-object.prototype.tostring
diff --git a/lib/assert.js b/lib/assert.js
index ad568547b45..545f76bef4b 100644
--- a/lib/assert.js
+++ b/lib/assert.js
@@ -718,17 +718,27 @@ function getActual(block) {
}
}
-// Expected to throw an error.
-assert.throws = function throws(block, error, message) {
- const actual = getActual(block);
+async function waitForActual(block) {
+ if (typeof block !== 'function') {
+ throw new errors.ERR_INVALID_ARG_TYPE('block', 'Function', block);
+ }
+ try {
+ await block();
+ } catch (e) {
+ return e;
+ }
+ return errors.NO_EXCEPTION_SENTINEL;
+}
+// Expected to throw an error.
+function expectsError(stackStartFn, actual, error, message) {
if (typeof error === 'string') {
- if (arguments.length === 3)
+ if (arguments.length === 4) {
throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
'error',
['Function', 'RegExp'],
error);
-
+ }
message = error;
error = null;
}
@@ -739,21 +749,21 @@ assert.throws = function throws(block, error, message) {
details += ` (${error.name})`;
}
details += message ? `: ${message}` : '.';
+ const fnType = stackStartFn === rejects ? 'rejection' : 'exception';
innerFail({
actual,
expected: error,
- operator: 'throws',
- message: `Missing expected exception${details}`,
- stackStartFn: throws
+ operator: stackStartFn.name,
+ message: `Missing expected ${fnType}${details}`,
+ stackStartFn
});
}
if (error && expectedException(actual, error, message) === false) {
throw actual;
}
-};
+}
-assert.doesNotThrow = function doesNotThrow(block, error, message) {
- const actual = getActual(block);
+function expectsNoError(stackStartFn, actual, error, message) {
if (actual === undefined)
return;
@@ -764,16 +774,41 @@ assert.doesNotThrow = function doesNotThrow(block, error, message) {
if (!error || expectedException(actual, error)) {
const details = message ? `: ${message}` : '.';
+ const fnType = stackStartFn === doesNotReject ? 'rejection' : 'exception';
innerFail({
actual,
expected: error,
- operator: 'doesNotThrow',
- message: `Got unwanted exception${details}\n${actual.message}`,
- stackStartFn: doesNotThrow
+ operator: stackStartFn.name,
+ message: `Got unwanted ${fnType}${details}\n${actual.message}`,
+ stackStartFn
});
}
throw actual;
-};
+}
+
+function throws(block, ...args) {
+ expectsError(throws, getActual(block), ...args);
+}
+
+assert.throws = throws;
+
+async function rejects(block, ...args) {
+ expectsError(rejects, await waitForActual(block), ...args);
+}
+
+assert.rejects = rejects;
+
+function doesNotThrow(block, ...args) {
+ expectsNoError(doesNotThrow, getActual(block), ...args);
+}
+
+assert.doesNotThrow = doesNotThrow;
+
+async function doesNotReject(block, ...args) {
+ expectsNoError(doesNotReject, await waitForActual(block), ...args);
+}
+
+assert.doesNotReject = doesNotReject;
assert.ifError = function ifError(err) { if (err) throw err; };
diff --git a/test/parallel/test-assert-async.js b/test/parallel/test-assert-async.js
new file mode 100644
index 00000000000..9fcde68bd5a
--- /dev/null
+++ b/test/parallel/test-assert-async.js
@@ -0,0 +1,66 @@
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { promisify } = require('util');
+const wait = promisify(setTimeout);
+
+/* eslint-disable prefer-common-expectserror, no-restricted-properties */
+
+// Test assert.rejects() and assert.doesNotReject() by checking their
+// expected output and by verifying that they do not work sync
+
+assert.rejects(
+ () => assert.fail(),
+ common.expectsError({
+ code: 'ERR_ASSERTION',
+ type: assert.AssertionError,
+ message: 'Failed'
+ })
+);
+
+assert.doesNotReject(() => {});
+
+{
+ const promise = assert.rejects(async () => {
+ await wait(1);
+ assert.fail();
+ }, common.expectsError({
+ code: 'ERR_ASSERTION',
+ type: assert.AssertionError,
+ message: 'Failed'
+ }));
+ assert.doesNotReject(() => promise);
+}
+
+{
+ const promise = assert.doesNotReject(async () => {
+ await wait(1);
+ throw new Error();
+ });
+ assert.rejects(() => promise,
+ (err) => {
+ assert(err instanceof assert.AssertionError,
+ `${err.name} is not instance of AssertionError`);
+ assert.strictEqual(err.code, 'ERR_ASSERTION');
+ assert(/^Got unwanted rejection\.\n$/.test(err.message));
+ assert.strictEqual(err.operator, 'doesNotReject');
+ assert.ok(!err.stack.includes('at Function.doesNotReject'));
+ return true;
+ }
+ );
+}
+
+{
+ const promise = assert.rejects(() => {});
+ assert.rejects(() => promise,
+ (err) => {
+ assert(err instanceof assert.AssertionError,
+ `${err.name} is not instance of AssertionError`);
+ assert.strictEqual(err.code, 'ERR_ASSERTION');
+ assert(/^Missing expected rejection\.$/.test(err.message));
+ assert.strictEqual(err.operator, 'rejects');
+ assert.ok(!err.stack.includes('at Function.rejects'));
+ return true;
+ }
+ );
+}
diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js
index 08b81b7c37f..7335982a6c6 100644
--- a/test/parallel/test-assert.js
+++ b/test/parallel/test-assert.js
@@ -443,6 +443,7 @@ assert.throws(makeBlock(thrower, TypeError));
} catch (e) {
threw = true;
assert.ok(e instanceof a.AssertionError);
+ assert.ok(!e.stack.includes('at Function.doesNotThrow'));
}
assert.strictEqual(true, threw,
'a.doesNotThrow is not catching type matching errors');
@@ -544,6 +545,16 @@ a.throws(makeBlock(thrower, TypeError), (err) => {
code: 'ERR_ASSERTION',
message: /^Missing expected exception \(TypeError\): fhqwhgads$/
}));
+
+ let threw = false;
+ try {
+ a.throws(noop);
+ } catch (e) {
+ threw = true;
+ assert.ok(e instanceof a.AssertionError);
+ assert.ok(!e.stack.includes('at Function.throws'));
+ }
+ assert.ok(threw);
}
const circular = { y: 1 };