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