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