• 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    // FIXME(JakobJingleheimer): This should match on key words, like /Promise/ and /undefined/.
107    message: 'Expected instance of Promise to be returned ' +
108             'from the "promiseFn" function but got undefined.'
109  }));
110
111  promise = assert.rejects(Promise.resolve(), common.mustNotCall());
112  promises.push(assert.rejects(promise, common.mustCall(handler)));
113}
114
115{
116  const THROWN_ERROR = new Error();
117
118  promises.push(assert.rejects(() => {
119    throw THROWN_ERROR;
120  }, {}).catch(common.mustCall((err) => {
121    assert.strictEqual(err, THROWN_ERROR);
122  })));
123}
124
125promises.push(assert.rejects(
126  assert.rejects('fail', {}),
127  {
128    code: 'ERR_INVALID_ARG_TYPE',
129    message: 'The "promiseFn" argument must be of type function or an ' +
130             "instance of Promise. Received type string ('fail')"
131  }
132));
133
134{
135  const handler = (generated, actual, err) => {
136    assert.strictEqual(err.generatedMessage, generated);
137    assert.strictEqual(err.code, 'ERR_ASSERTION');
138    assert.strictEqual(err.actual, actual);
139    assert.strictEqual(err.operator, 'rejects');
140    assert.match(err.stack, /rejects/);
141    return true;
142  };
143  const err = new Error();
144  promises.push(assert.rejects(
145    assert.rejects(Promise.reject(null), { code: 'FOO' }),
146    handler.bind(null, true, null)
147  ));
148  promises.push(assert.rejects(
149    assert.rejects(Promise.reject(5), { code: 'FOO' }, 'AAAAA'),
150    handler.bind(null, false, 5)
151  ));
152  promises.push(assert.rejects(
153    assert.rejects(Promise.reject(err), { code: 'FOO' }, 'AAAAA'),
154    handler.bind(null, false, err)
155  ));
156}
157
158// Check `assert.doesNotReject`.
159{
160  // `assert.doesNotReject` accepts a function or a promise
161  // or a thenable as first argument.
162  /* eslint-disable no-restricted-syntax */
163  let promise = assert.doesNotReject(() => new Map(), common.mustNotCall());
164  promises.push(assert.rejects(promise, {
165    message: 'Expected instance of Promise to be returned ' +
166             'from the "promiseFn" function but got an instance of Map.',
167    code: 'ERR_INVALID_RETURN_VALUE',
168    name: 'TypeError'
169  }));
170  promises.push(assert.doesNotReject(async () => {}));
171  promises.push(assert.doesNotReject(Promise.resolve()));
172
173  // `assert.doesNotReject` should not accept thenables that
174  // use a function as `obj` and that have no `catch` handler.
175  const validFulfillingThenable = {
176    then: (fulfill, reject) => {
177      fulfill();
178    },
179    catch: () => {}
180  };
181  promises.push(assert.doesNotReject(validFulfillingThenable));
182  promises.push(assert.rejects(
183    assert.doesNotReject(invalidThenable),
184    {
185      code: 'ERR_INVALID_ARG_TYPE'
186    })
187  );
188  promises.push(assert.rejects(
189    assert.doesNotReject(invalidThenableFunc),
190    {
191      code: 'ERR_INVALID_RETURN_VALUE'
192    })
193  );
194
195  const handler1 = (err) => {
196    assert(err instanceof assert.AssertionError,
197           `${err.name} is not instance of AssertionError`);
198    assert.strictEqual(err.code, 'ERR_ASSERTION');
199    assert.strictEqual(err.message, 'Failed');
200    return true;
201  };
202  const handler2 = (err) => {
203    assert(err instanceof assert.AssertionError,
204           `${err.name} is not instance of AssertionError`);
205    assert.strictEqual(err.code, 'ERR_ASSERTION');
206    assert.strictEqual(err.message,
207                       'Got unwanted rejection.\nActual message: "Failed"');
208    assert.strictEqual(err.operator, 'doesNotReject');
209    assert.ok(err.stack);
210    assert.ok(!err.stack.includes('at Function.doesNotReject'));
211    return true;
212  };
213
214  const rejectingFn = async () => assert.fail();
215
216  promise = assert.doesNotReject(rejectingFn, common.mustCall(handler1));
217  promises.push(assert.rejects(promise, common.mustCall(handler2)));
218
219  promise = assert.doesNotReject(rejectingFn(), common.mustCall(handler1));
220  promises.push(assert.rejects(promise, common.mustCall(handler2)));
221
222  promise = assert.doesNotReject(() => assert.fail(), common.mustNotCall());
223  promises.push(assert.rejects(promise, common.mustCall(handler1)));
224
225  promises.push(assert.rejects(
226    assert.doesNotReject(123),
227    {
228      code: 'ERR_INVALID_ARG_TYPE',
229      message: 'The "promiseFn" argument must be of type ' +
230               'function or an instance of Promise. Received type number (123)'
231    }
232  ));
233  /* eslint-enable no-restricted-syntax */
234}
235
236// Make sure all async code gets properly executed.
237Promise.all(promises).then(common.mustCall());
238