• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2const common = require('../common');
3const assert = require('assert');
4
5// Run all tests in parallel and check their outcome at the end.
6const promises = [];
7
8// Thenable object without `catch` method,
9// shouldn't be considered as a valid Thenable
10const invalidThenable = {
11  then: (fulfill, reject) => {
12    fulfill();
13  },
14};
15
16// Function that returns a Thenable function,
17// a function with `catch` and `then` methods attached,
18// shouldn't be considered as a valid Thenable.
19const invalidThenableFunc = () => {
20  function f() {}
21
22  f.then = (fulfill, reject) => {
23    fulfill();
24  };
25  f.catch = () => {};
26
27  return f;
28};
29
30// Test assert.rejects() and assert.doesNotReject() by checking their
31// expected output and by verifying that they do not work sync
32
33// Check `assert.rejects`.
34{
35  const rejectingFn = async () => assert.fail();
36  const errObj = {
37    code: 'ERR_ASSERTION',
38    name: 'AssertionError',
39    message: 'Failed'
40  };
41
42  // `assert.rejects` accepts a function or a promise
43  // or a thenable as first argument.
44  promises.push(assert.rejects(rejectingFn, errObj));
45  promises.push(assert.rejects(rejectingFn(), errObj));
46
47  const validRejectingThenable = {
48    then: (fulfill, reject) => {
49      reject({ code: 'FAIL' });
50    },
51    catch: () => {}
52  };
53  promises.push(assert.rejects(validRejectingThenable, { code: 'FAIL' }));
54
55  // `assert.rejects` should not accept thenables that
56  // use a function as `obj` and that have no `catch` handler.
57  promises.push(assert.rejects(
58    assert.rejects(invalidThenable, {}),
59    {
60      code: 'ERR_INVALID_ARG_TYPE'
61    })
62  );
63  promises.push(assert.rejects(
64    assert.rejects(invalidThenableFunc, {}),
65    {
66      code: 'ERR_INVALID_RETURN_VALUE'
67    })
68  );
69
70  const err = new Error('foobar');
71  const validate = () => { return 'baz'; };
72  promises.push(assert.rejects(
73    () => assert.rejects(Promise.reject(err), validate),
74    {
75      message: 'The "validate" validation function is expected to ' +
76               "return \"true\". Received 'baz'\n\nCaught error:\n\n" +
77               'Error: foobar',
78      code: 'ERR_ASSERTION',
79      actual: err,
80      expected: validate,
81      name: 'AssertionError',
82      operator: 'rejects',
83    }
84  ));
85}
86
87{
88  const handler = (err) => {
89    assert(err instanceof assert.AssertionError,
90           `${err.name} is not instance of AssertionError`);
91    assert.strictEqual(err.code, 'ERR_ASSERTION');
92    assert.strictEqual(err.message,
93                       'Missing expected rejection (mustNotCall).');
94    assert.strictEqual(err.operator, 'rejects');
95    assert.ok(!err.stack.includes('at Function.rejects'));
96    return true;
97  };
98
99  let promise = assert.rejects(async () => {}, common.mustNotCall());
100  promises.push(assert.rejects(promise, common.mustCall(handler)));
101
102  promise = assert.rejects(() => {}, common.mustNotCall());
103  promises.push(assert.rejects(promise, {
104    name: 'TypeError',
105    code: 'ERR_INVALID_RETURN_VALUE',
106    message: 'Expected instance of Promise to be returned ' +
107             'from the "promiseFn" function but got type undefined.'
108  }));
109
110  promise = assert.rejects(Promise.resolve(), common.mustNotCall());
111  promises.push(assert.rejects(promise, common.mustCall(handler)));
112}
113
114{
115  const THROWN_ERROR = new Error();
116
117  promises.push(assert.rejects(() => {
118    throw THROWN_ERROR;
119  }, {}).catch(common.mustCall((err) => {
120    assert.strictEqual(err, THROWN_ERROR);
121  })));
122}
123
124promises.push(assert.rejects(
125  assert.rejects('fail', {}),
126  {
127    code: 'ERR_INVALID_ARG_TYPE',
128    message: 'The "promiseFn" argument must be of type function or an ' +
129             "instance of Promise. Received type string ('fail')"
130  }
131));
132
133{
134  const handler = (generated, actual, err) => {
135    assert.strictEqual(err.generatedMessage, generated);
136    assert.strictEqual(err.code, 'ERR_ASSERTION');
137    assert.strictEqual(err.actual, actual);
138    assert.strictEqual(err.operator, 'rejects');
139    assert(/rejects/.test(err.stack));
140    return true;
141  };
142  const err = new Error();
143  promises.push(assert.rejects(
144    assert.rejects(Promise.reject(null), { code: 'FOO' }),
145    handler.bind(null, true, null)
146  ));
147  promises.push(assert.rejects(
148    assert.rejects(Promise.reject(5), { code: 'FOO' }, 'AAAAA'),
149    handler.bind(null, false, 5)
150  ));
151  promises.push(assert.rejects(
152    assert.rejects(Promise.reject(err), { code: 'FOO' }, 'AAAAA'),
153    handler.bind(null, false, err)
154  ));
155}
156
157// Check `assert.doesNotReject`.
158{
159  // `assert.doesNotReject` accepts a function or a promise
160  // or a thenable as first argument.
161  /* eslint-disable no-restricted-syntax */
162  let promise = assert.doesNotReject(() => new Map(), common.mustNotCall());
163  promises.push(assert.rejects(promise, {
164    message: 'Expected instance of Promise to be returned ' +
165             'from the "promiseFn" function but got instance of Map.',
166    code: 'ERR_INVALID_RETURN_VALUE',
167    name: 'TypeError'
168  }));
169  promises.push(assert.doesNotReject(async () => {}));
170  promises.push(assert.doesNotReject(Promise.resolve()));
171
172  // `assert.doesNotReject` should not accept thenables that
173  // use a function as `obj` and that have no `catch` handler.
174  const validFulfillingThenable = {
175    then: (fulfill, reject) => {
176      fulfill();
177    },
178    catch: () => {}
179  };
180  promises.push(assert.doesNotReject(validFulfillingThenable));
181  promises.push(assert.rejects(
182    assert.doesNotReject(invalidThenable),
183    {
184      code: 'ERR_INVALID_ARG_TYPE'
185    })
186  );
187  promises.push(assert.rejects(
188    assert.doesNotReject(invalidThenableFunc),
189    {
190      code: 'ERR_INVALID_RETURN_VALUE'
191    })
192  );
193
194  const handler1 = (err) => {
195    assert(err instanceof assert.AssertionError,
196           `${err.name} is not instance of AssertionError`);
197    assert.strictEqual(err.code, 'ERR_ASSERTION');
198    assert.strictEqual(err.message, 'Failed');
199    return true;
200  };
201  const handler2 = (err) => {
202    assert(err instanceof assert.AssertionError,
203           `${err.name} is not instance of AssertionError`);
204    assert.strictEqual(err.code, 'ERR_ASSERTION');
205    assert.strictEqual(err.message,
206                       'Got unwanted rejection.\nActual message: "Failed"');
207    assert.strictEqual(err.operator, 'doesNotReject');
208    assert.ok(err.stack);
209    assert.ok(!err.stack.includes('at Function.doesNotReject'));
210    return true;
211  };
212
213  const rejectingFn = async () => assert.fail();
214
215  promise = assert.doesNotReject(rejectingFn, common.mustCall(handler1));
216  promises.push(assert.rejects(promise, common.mustCall(handler2)));
217
218  promise = assert.doesNotReject(rejectingFn(), common.mustCall(handler1));
219  promises.push(assert.rejects(promise, common.mustCall(handler2)));
220
221  promise = assert.doesNotReject(() => assert.fail(), common.mustNotCall());
222  promises.push(assert.rejects(promise, common.mustCall(handler1)));
223
224  promises.push(assert.rejects(
225    assert.doesNotReject(123),
226    {
227      code: 'ERR_INVALID_ARG_TYPE',
228      message: 'The "promiseFn" argument must be of type ' +
229               'function or an instance of Promise. Received type number (123)'
230    }
231  ));
232  /* eslint-enable no-restricted-syntax */
233}
234
235// Make sure all async code gets properly executed.
236Promise.all(promises).then(common.mustCall());
237