toThrowMatchers.js 13 KB

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