toThrowMatchers.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = exports.createMatcher = void 0;
  6. var _jestMatcherUtils = require('jest-matcher-utils');
  7. var _jestMessageUtil = require('jest-message-util');
  8. var _print = require('./print');
  9. var _utils = require('./utils');
  10. /**
  11. * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  12. *
  13. * This source code is licensed under the MIT license found in the
  14. * LICENSE file in the root directory of this source tree.
  15. *
  16. */
  17. /* eslint-disable local/ban-types-eventually */
  18. const DID_NOT_THROW = 'Received function did not throw';
  19. const getThrown = e => {
  20. const hasMessage =
  21. e !== null && e !== undefined && typeof e.message === 'string';
  22. if (hasMessage && typeof e.name === 'string' && typeof e.stack === 'string') {
  23. return {
  24. hasMessage,
  25. isError: true,
  26. message: e.message,
  27. value: e
  28. };
  29. }
  30. return {
  31. hasMessage,
  32. isError: false,
  33. message: hasMessage ? e.message : String(e),
  34. value: e
  35. };
  36. };
  37. const createMatcher = (matcherName, fromPromise) =>
  38. function (received, expected) {
  39. const options = {
  40. isNot: this.isNot,
  41. promise: this.promise
  42. };
  43. let thrown = null;
  44. if (fromPromise && (0, _utils.isError)(received)) {
  45. thrown = getThrown(received);
  46. } else {
  47. if (typeof received !== 'function') {
  48. if (!fromPromise) {
  49. const placeholder = expected === undefined ? '' : 'expected';
  50. throw new Error(
  51. (0, _jestMatcherUtils.matcherErrorMessage)(
  52. (0, _jestMatcherUtils.matcherHint)(
  53. matcherName,
  54. undefined,
  55. placeholder,
  56. options
  57. ),
  58. `${(0, _jestMatcherUtils.RECEIVED_COLOR)(
  59. 'received'
  60. )} value must be a function`,
  61. (0, _jestMatcherUtils.printWithType)(
  62. 'Received',
  63. received,
  64. _jestMatcherUtils.printReceived
  65. )
  66. )
  67. );
  68. }
  69. } else {
  70. try {
  71. received();
  72. } catch (e) {
  73. thrown = getThrown(e);
  74. }
  75. }
  76. }
  77. if (expected === undefined) {
  78. return toThrow(matcherName, options, thrown);
  79. } else if (typeof expected === 'function') {
  80. return toThrowExpectedClass(matcherName, options, thrown, expected);
  81. } else if (typeof expected === 'string') {
  82. return toThrowExpectedString(matcherName, options, thrown, expected);
  83. } else if (expected !== null && typeof expected.test === 'function') {
  84. return toThrowExpectedRegExp(matcherName, options, thrown, expected);
  85. } else if (
  86. expected !== null &&
  87. typeof expected.asymmetricMatch === 'function'
  88. ) {
  89. return toThrowExpectedAsymmetric(matcherName, options, thrown, expected);
  90. } else if (expected !== null && typeof expected === 'object') {
  91. return toThrowExpectedObject(matcherName, options, thrown, expected);
  92. } else {
  93. throw new Error(
  94. (0, _jestMatcherUtils.matcherErrorMessage)(
  95. (0, _jestMatcherUtils.matcherHint)(
  96. matcherName,
  97. undefined,
  98. undefined,
  99. options
  100. ),
  101. `${(0, _jestMatcherUtils.EXPECTED_COLOR)(
  102. 'expected'
  103. )} value must be a string or regular expression or class or error`,
  104. (0, _jestMatcherUtils.printWithType)(
  105. 'Expected',
  106. expected,
  107. _jestMatcherUtils.printExpected
  108. )
  109. )
  110. );
  111. }
  112. };
  113. exports.createMatcher = createMatcher;
  114. const matchers = {
  115. toThrow: createMatcher('toThrow'),
  116. toThrowError: createMatcher('toThrowError')
  117. };
  118. const toThrowExpectedRegExp = (matcherName, options, thrown, expected) => {
  119. const pass = thrown !== null && expected.test(thrown.message);
  120. const message = pass
  121. ? () =>
  122. (0, _jestMatcherUtils.matcherHint)(
  123. matcherName,
  124. undefined,
  125. undefined,
  126. options
  127. ) +
  128. '\n\n' +
  129. formatExpected('Expected pattern: not ', expected) +
  130. (thrown !== null && thrown.hasMessage
  131. ? formatReceived(
  132. 'Received message: ',
  133. thrown,
  134. 'message',
  135. expected
  136. ) + formatStack(thrown)
  137. : formatReceived('Received value: ', thrown, 'value'))
  138. : () =>
  139. (0, _jestMatcherUtils.matcherHint)(
  140. matcherName,
  141. undefined,
  142. undefined,
  143. options
  144. ) +
  145. '\n\n' +
  146. formatExpected('Expected pattern: ', expected) +
  147. (thrown === null
  148. ? '\n' + DID_NOT_THROW
  149. : thrown.hasMessage
  150. ? formatReceived('Received message: ', thrown, 'message') +
  151. formatStack(thrown)
  152. : formatReceived('Received value: ', thrown, 'value'));
  153. return {
  154. message,
  155. pass
  156. };
  157. };
  158. const toThrowExpectedAsymmetric = (matcherName, options, thrown, expected) => {
  159. const pass = thrown !== null && expected.asymmetricMatch(thrown.value);
  160. const message = pass
  161. ? () =>
  162. (0, _jestMatcherUtils.matcherHint)(
  163. matcherName,
  164. undefined,
  165. undefined,
  166. options
  167. ) +
  168. '\n\n' +
  169. formatExpected('Expected asymmetric matcher: not ', expected) +
  170. '\n' +
  171. (thrown !== null && thrown.hasMessage
  172. ? formatReceived('Received name: ', thrown, 'name') +
  173. formatReceived('Received message: ', thrown, 'message') +
  174. formatStack(thrown)
  175. : formatReceived('Thrown value: ', thrown, 'value'))
  176. : () =>
  177. (0, _jestMatcherUtils.matcherHint)(
  178. matcherName,
  179. undefined,
  180. undefined,
  181. options
  182. ) +
  183. '\n\n' +
  184. formatExpected('Expected asymmetric matcher: ', expected) +
  185. '\n' +
  186. (thrown === null
  187. ? DID_NOT_THROW
  188. : thrown.hasMessage
  189. ? formatReceived('Received name: ', thrown, 'name') +
  190. formatReceived('Received message: ', thrown, 'message') +
  191. formatStack(thrown)
  192. : formatReceived('Thrown value: ', thrown, 'value'));
  193. return {
  194. message,
  195. pass
  196. };
  197. };
  198. const toThrowExpectedObject = (matcherName, options, thrown, expected) => {
  199. const pass = thrown !== null && thrown.message === expected.message;
  200. const message = pass
  201. ? () =>
  202. (0, _jestMatcherUtils.matcherHint)(
  203. matcherName,
  204. undefined,
  205. undefined,
  206. options
  207. ) +
  208. '\n\n' +
  209. formatExpected('Expected message: not ', expected.message) +
  210. (thrown !== null && thrown.hasMessage
  211. ? formatStack(thrown)
  212. : formatReceived('Received value: ', thrown, 'value'))
  213. : () =>
  214. (0, _jestMatcherUtils.matcherHint)(
  215. matcherName,
  216. undefined,
  217. undefined,
  218. options
  219. ) +
  220. '\n\n' +
  221. (thrown === null
  222. ? formatExpected('Expected message: ', expected.message) +
  223. '\n' +
  224. DID_NOT_THROW
  225. : thrown.hasMessage
  226. ? (0, _jestMatcherUtils.printDiffOrStringify)(
  227. expected.message,
  228. thrown.message,
  229. 'Expected message',
  230. 'Received message',
  231. true
  232. ) +
  233. '\n' +
  234. formatStack(thrown)
  235. : formatExpected('Expected message: ', expected.message) +
  236. formatReceived('Received value: ', thrown, 'value'));
  237. return {
  238. message,
  239. pass
  240. };
  241. };
  242. const toThrowExpectedClass = (matcherName, options, thrown, expected) => {
  243. const pass = thrown !== null && thrown.value instanceof expected;
  244. const message = pass
  245. ? () =>
  246. (0, _jestMatcherUtils.matcherHint)(
  247. matcherName,
  248. undefined,
  249. undefined,
  250. options
  251. ) +
  252. '\n\n' +
  253. (0, _print.printExpectedConstructorNameNot)(
  254. 'Expected constructor',
  255. expected
  256. ) +
  257. (thrown !== null &&
  258. thrown.value != null &&
  259. typeof thrown.value.constructor === 'function' &&
  260. thrown.value.constructor !== expected
  261. ? (0, _print.printReceivedConstructorNameNot)(
  262. 'Received constructor',
  263. thrown.value.constructor,
  264. expected
  265. )
  266. : '') +
  267. '\n' +
  268. (thrown !== null && thrown.hasMessage
  269. ? formatReceived('Received message: ', thrown, 'message') +
  270. formatStack(thrown)
  271. : formatReceived('Received value: ', thrown, 'value'))
  272. : () =>
  273. (0, _jestMatcherUtils.matcherHint)(
  274. matcherName,
  275. undefined,
  276. undefined,
  277. options
  278. ) +
  279. '\n\n' +
  280. (0, _print.printExpectedConstructorName)(
  281. 'Expected constructor',
  282. expected
  283. ) +
  284. (thrown === null
  285. ? '\n' + DID_NOT_THROW
  286. : (thrown.value != null &&
  287. typeof thrown.value.constructor === 'function'
  288. ? (0, _print.printReceivedConstructorName)(
  289. 'Received constructor',
  290. thrown.value.constructor
  291. )
  292. : '') +
  293. '\n' +
  294. (thrown.hasMessage
  295. ? formatReceived('Received message: ', thrown, 'message') +
  296. formatStack(thrown)
  297. : formatReceived('Received value: ', thrown, 'value')));
  298. return {
  299. message,
  300. pass
  301. };
  302. };
  303. const toThrowExpectedString = (matcherName, options, thrown, expected) => {
  304. const pass = thrown !== null && thrown.message.includes(expected);
  305. const message = pass
  306. ? () =>
  307. (0, _jestMatcherUtils.matcherHint)(
  308. matcherName,
  309. undefined,
  310. undefined,
  311. options
  312. ) +
  313. '\n\n' +
  314. formatExpected('Expected substring: not ', expected) +
  315. (thrown !== null && thrown.hasMessage
  316. ? formatReceived(
  317. 'Received message: ',
  318. thrown,
  319. 'message',
  320. expected
  321. ) + formatStack(thrown)
  322. : formatReceived('Received value: ', thrown, 'value'))
  323. : () =>
  324. (0, _jestMatcherUtils.matcherHint)(
  325. matcherName,
  326. undefined,
  327. undefined,
  328. options
  329. ) +
  330. '\n\n' +
  331. formatExpected('Expected substring: ', expected) +
  332. (thrown === null
  333. ? '\n' + DID_NOT_THROW
  334. : thrown.hasMessage
  335. ? formatReceived('Received message: ', thrown, 'message') +
  336. formatStack(thrown)
  337. : formatReceived('Received value: ', thrown, 'value'));
  338. return {
  339. message,
  340. pass
  341. };
  342. };
  343. const toThrow = (matcherName, options, thrown) => {
  344. const pass = thrown !== null;
  345. const message = pass
  346. ? () =>
  347. (0, _jestMatcherUtils.matcherHint)(
  348. matcherName,
  349. undefined,
  350. '',
  351. options
  352. ) +
  353. '\n\n' +
  354. (thrown !== null && thrown.hasMessage
  355. ? formatReceived('Error name: ', thrown, 'name') +
  356. formatReceived('Error message: ', thrown, 'message') +
  357. formatStack(thrown)
  358. : formatReceived('Thrown value: ', thrown, 'value'))
  359. : () =>
  360. (0, _jestMatcherUtils.matcherHint)(
  361. matcherName,
  362. undefined,
  363. '',
  364. options
  365. ) +
  366. '\n\n' +
  367. DID_NOT_THROW;
  368. return {
  369. message,
  370. pass
  371. };
  372. };
  373. const formatExpected = (label, expected) =>
  374. label + (0, _jestMatcherUtils.printExpected)(expected) + '\n';
  375. const formatReceived = (label, thrown, key, expected) => {
  376. if (thrown === null) {
  377. return '';
  378. }
  379. if (key === 'message') {
  380. const message = thrown.message;
  381. if (typeof expected === 'string') {
  382. const index = message.indexOf(expected);
  383. if (index !== -1) {
  384. return (
  385. label +
  386. (0, _print.printReceivedStringContainExpectedSubstring)(
  387. message,
  388. index,
  389. expected.length
  390. ) +
  391. '\n'
  392. );
  393. }
  394. } else if (expected instanceof RegExp) {
  395. return (
  396. label +
  397. (0, _print.printReceivedStringContainExpectedResult)(
  398. message,
  399. typeof expected.exec === 'function' ? expected.exec(message) : null
  400. ) +
  401. '\n'
  402. );
  403. }
  404. return label + (0, _jestMatcherUtils.printReceived)(message) + '\n';
  405. }
  406. if (key === 'name') {
  407. return thrown.isError
  408. ? label + (0, _jestMatcherUtils.printReceived)(thrown.value.name) + '\n'
  409. : '';
  410. }
  411. if (key === 'value') {
  412. return thrown.isError
  413. ? ''
  414. : label + (0, _jestMatcherUtils.printReceived)(thrown.value) + '\n';
  415. }
  416. return '';
  417. };
  418. const formatStack = thrown =>
  419. thrown === null || !thrown.isError
  420. ? ''
  421. : (0, _jestMessageUtil.formatStackTrace)(
  422. (0, _jestMessageUtil.separateMessageFromStack)(thrown.value.stack)
  423. .stack,
  424. {
  425. rootDir: process.cwd(),
  426. testMatch: []
  427. },
  428. {
  429. noStackTrace: false
  430. }
  431. );
  432. var _default = matchers;
  433. exports.default = _default;