index.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. 'use strict';
  2. var matcherUtils = _interopRequireWildcard(require('jest-matcher-utils'));
  3. var _asymmetricMatchers = require('./asymmetricMatchers');
  4. var _extractExpectedAssertionsErrors = _interopRequireDefault(
  5. require('./extractExpectedAssertionsErrors')
  6. );
  7. var _jasmineUtils = require('./jasmineUtils');
  8. var _jestMatchersObject = require('./jestMatchersObject');
  9. var _matchers = _interopRequireDefault(require('./matchers'));
  10. var _spyMatchers = _interopRequireDefault(require('./spyMatchers'));
  11. var _toThrowMatchers = _interopRequireWildcard(require('./toThrowMatchers'));
  12. var _utils = require('./utils');
  13. function _interopRequireDefault(obj) {
  14. return obj && obj.__esModule ? obj : {default: obj};
  15. }
  16. function _getRequireWildcardCache() {
  17. if (typeof WeakMap !== 'function') return null;
  18. var cache = new WeakMap();
  19. _getRequireWildcardCache = function () {
  20. return cache;
  21. };
  22. return cache;
  23. }
  24. function _interopRequireWildcard(obj) {
  25. if (obj && obj.__esModule) {
  26. return obj;
  27. }
  28. if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
  29. return {default: obj};
  30. }
  31. var cache = _getRequireWildcardCache();
  32. if (cache && cache.has(obj)) {
  33. return cache.get(obj);
  34. }
  35. var newObj = {};
  36. var hasPropertyDescriptor =
  37. Object.defineProperty && Object.getOwnPropertyDescriptor;
  38. for (var key in obj) {
  39. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  40. var desc = hasPropertyDescriptor
  41. ? Object.getOwnPropertyDescriptor(obj, key)
  42. : null;
  43. if (desc && (desc.get || desc.set)) {
  44. Object.defineProperty(newObj, key, desc);
  45. } else {
  46. newObj[key] = obj[key];
  47. }
  48. }
  49. }
  50. newObj.default = obj;
  51. if (cache) {
  52. cache.set(obj, newObj);
  53. }
  54. return newObj;
  55. }
  56. var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
  57. var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
  58. var Promise = global[Symbol.for('jest-native-promise')] || global.Promise;
  59. function _defineProperty(obj, key, value) {
  60. if (key in obj) {
  61. Object.defineProperty(obj, key, {
  62. value: value,
  63. enumerable: true,
  64. configurable: true,
  65. writable: true
  66. });
  67. } else {
  68. obj[key] = value;
  69. }
  70. return obj;
  71. }
  72. class JestAssertionError extends Error {
  73. constructor(...args) {
  74. super(...args);
  75. _defineProperty(this, 'matcherResult', void 0);
  76. }
  77. }
  78. const isPromise = obj =>
  79. !!obj &&
  80. (typeof obj === 'object' || typeof obj === 'function') &&
  81. typeof obj.then === 'function';
  82. const createToThrowErrorMatchingSnapshotMatcher = function (matcher) {
  83. return function (received, testNameOrInlineSnapshot) {
  84. return matcher.apply(this, [received, testNameOrInlineSnapshot, true]);
  85. };
  86. };
  87. const getPromiseMatcher = (name, matcher) => {
  88. if (name === 'toThrow' || name === 'toThrowError') {
  89. return (0, _toThrowMatchers.createMatcher)(name, true);
  90. } else if (
  91. name === 'toThrowErrorMatchingSnapshot' ||
  92. name === 'toThrowErrorMatchingInlineSnapshot'
  93. ) {
  94. return createToThrowErrorMatchingSnapshotMatcher(matcher);
  95. }
  96. return null;
  97. };
  98. const expect = (actual, ...rest) => {
  99. if (rest.length !== 0) {
  100. throw new Error('Expect takes at most one argument.');
  101. }
  102. const allMatchers = (0, _jestMatchersObject.getMatchers)();
  103. const expectation = {
  104. not: {},
  105. rejects: {
  106. not: {}
  107. },
  108. resolves: {
  109. not: {}
  110. }
  111. };
  112. const err = new JestAssertionError();
  113. Object.keys(allMatchers).forEach(name => {
  114. const matcher = allMatchers[name];
  115. const promiseMatcher = getPromiseMatcher(name, matcher) || matcher;
  116. expectation[name] = makeThrowingMatcher(matcher, false, '', actual);
  117. expectation.not[name] = makeThrowingMatcher(matcher, true, '', actual);
  118. expectation.resolves[name] = makeResolveMatcher(
  119. name,
  120. promiseMatcher,
  121. false,
  122. actual,
  123. err
  124. );
  125. expectation.resolves.not[name] = makeResolveMatcher(
  126. name,
  127. promiseMatcher,
  128. true,
  129. actual,
  130. err
  131. );
  132. expectation.rejects[name] = makeRejectMatcher(
  133. name,
  134. promiseMatcher,
  135. false,
  136. actual,
  137. err
  138. );
  139. expectation.rejects.not[name] = makeRejectMatcher(
  140. name,
  141. promiseMatcher,
  142. true,
  143. actual,
  144. err
  145. );
  146. });
  147. return expectation;
  148. };
  149. const getMessage = message =>
  150. (message && message()) ||
  151. matcherUtils.RECEIVED_COLOR('No message was specified for this matcher.');
  152. const makeResolveMatcher = (matcherName, matcher, isNot, actual, outerErr) => (
  153. ...args
  154. ) => {
  155. const options = {
  156. isNot,
  157. promise: 'resolves'
  158. };
  159. if (!isPromise(actual)) {
  160. throw new JestAssertionError(
  161. matcherUtils.matcherErrorMessage(
  162. matcherUtils.matcherHint(matcherName, undefined, '', options),
  163. `${matcherUtils.RECEIVED_COLOR('received')} value must be a promise`,
  164. matcherUtils.printWithType(
  165. 'Received',
  166. actual,
  167. matcherUtils.printReceived
  168. )
  169. )
  170. );
  171. }
  172. const innerErr = new JestAssertionError();
  173. return actual.then(
  174. result =>
  175. makeThrowingMatcher(matcher, isNot, 'resolves', result, innerErr).apply(
  176. null,
  177. args
  178. ),
  179. reason => {
  180. outerErr.message =
  181. matcherUtils.matcherHint(matcherName, undefined, '', options) +
  182. '\n\n' +
  183. `Received promise rejected instead of resolved\n` +
  184. `Rejected to value: ${matcherUtils.printReceived(reason)}`;
  185. return Promise.reject(outerErr);
  186. }
  187. );
  188. };
  189. const makeRejectMatcher = (matcherName, matcher, isNot, actual, outerErr) => (
  190. ...args
  191. ) => {
  192. const options = {
  193. isNot,
  194. promise: 'rejects'
  195. };
  196. const actualWrapper = typeof actual === 'function' ? actual() : actual;
  197. if (!isPromise(actualWrapper)) {
  198. throw new JestAssertionError(
  199. matcherUtils.matcherErrorMessage(
  200. matcherUtils.matcherHint(matcherName, undefined, '', options),
  201. `${matcherUtils.RECEIVED_COLOR(
  202. 'received'
  203. )} value must be a promise or a function returning a promise`,
  204. matcherUtils.printWithType(
  205. 'Received',
  206. actual,
  207. matcherUtils.printReceived
  208. )
  209. )
  210. );
  211. }
  212. const innerErr = new JestAssertionError();
  213. return actualWrapper.then(
  214. result => {
  215. outerErr.message =
  216. matcherUtils.matcherHint(matcherName, undefined, '', options) +
  217. '\n\n' +
  218. `Received promise resolved instead of rejected\n` +
  219. `Resolved to value: ${matcherUtils.printReceived(result)}`;
  220. return Promise.reject(outerErr);
  221. },
  222. reason =>
  223. makeThrowingMatcher(matcher, isNot, 'rejects', reason, innerErr).apply(
  224. null,
  225. args
  226. )
  227. );
  228. };
  229. const makeThrowingMatcher = (matcher, isNot, promise, actual, err) =>
  230. function throwingMatcher(...args) {
  231. let throws = true;
  232. const utils = {
  233. ...matcherUtils,
  234. iterableEquality: _utils.iterableEquality,
  235. subsetEquality: _utils.subsetEquality
  236. };
  237. const matcherContext = {
  238. // When throws is disabled, the matcher will not throw errors during test
  239. // execution but instead add them to the global matcher state. If a
  240. // matcher throws, test execution is normally stopped immediately. The
  241. // snapshot matcher uses it because we want to log all snapshot
  242. // failures in a test.
  243. dontThrow: () => (throws = false),
  244. ...(0, _jestMatchersObject.getState)(),
  245. equals: _jasmineUtils.equals,
  246. error: err,
  247. isNot,
  248. promise,
  249. utils
  250. };
  251. const processResult = (result, asyncError) => {
  252. _validateResult(result);
  253. (0, _jestMatchersObject.getState)().assertionCalls++;
  254. if ((result.pass && isNot) || (!result.pass && !isNot)) {
  255. // XOR
  256. const message = getMessage(result.message);
  257. let error;
  258. if (err) {
  259. error = err;
  260. error.message = message;
  261. } else if (asyncError) {
  262. error = asyncError;
  263. error.message = message;
  264. } else {
  265. error = new JestAssertionError(message); // Try to remove this function from the stack trace frame.
  266. // Guard for some environments (browsers) that do not support this feature.
  267. if (Error.captureStackTrace) {
  268. Error.captureStackTrace(error, throwingMatcher);
  269. }
  270. } // Passing the result of the matcher with the error so that a custom
  271. // reporter could access the actual and expected objects of the result
  272. // for example in order to display a custom visual diff
  273. error.matcherResult = result;
  274. if (throws) {
  275. throw error;
  276. } else {
  277. (0, _jestMatchersObject.getState)().suppressedErrors.push(error);
  278. }
  279. }
  280. };
  281. const handleError = error => {
  282. if (
  283. matcher[_jestMatchersObject.INTERNAL_MATCHER_FLAG] === true &&
  284. !(error instanceof JestAssertionError) &&
  285. error.name !== 'PrettyFormatPluginError' && // Guard for some environments (browsers) that do not support this feature.
  286. Error.captureStackTrace
  287. ) {
  288. // Try to remove this and deeper functions from the stack trace frame.
  289. Error.captureStackTrace(error, throwingMatcher);
  290. }
  291. throw error;
  292. };
  293. let potentialResult;
  294. try {
  295. potentialResult =
  296. matcher[_jestMatchersObject.INTERNAL_MATCHER_FLAG] === true
  297. ? matcher.call(matcherContext, actual, ...args) // It's a trap specifically for inline snapshot to capture this name
  298. : // in the stack trace, so that it can correctly get the custom matcher
  299. // function call.
  300. (function __EXTERNAL_MATCHER_TRAP__() {
  301. return matcher.call(matcherContext, actual, ...args);
  302. })();
  303. if (isPromise(potentialResult)) {
  304. const asyncResult = potentialResult;
  305. const asyncError = new JestAssertionError();
  306. if (Error.captureStackTrace) {
  307. Error.captureStackTrace(asyncError, throwingMatcher);
  308. }
  309. return asyncResult
  310. .then(aResult => processResult(aResult, asyncError))
  311. .catch(handleError);
  312. } else {
  313. const syncResult = potentialResult;
  314. return processResult(syncResult);
  315. }
  316. } catch (error) {
  317. return handleError(error);
  318. }
  319. };
  320. expect.extend = matchers =>
  321. (0, _jestMatchersObject.setMatchers)(matchers, false, expect);
  322. expect.anything = _asymmetricMatchers.anything;
  323. expect.any = _asymmetricMatchers.any;
  324. expect.not = {
  325. arrayContaining: _asymmetricMatchers.arrayNotContaining,
  326. objectContaining: _asymmetricMatchers.objectNotContaining,
  327. stringContaining: _asymmetricMatchers.stringNotContaining,
  328. stringMatching: _asymmetricMatchers.stringNotMatching
  329. };
  330. expect.objectContaining = _asymmetricMatchers.objectContaining;
  331. expect.arrayContaining = _asymmetricMatchers.arrayContaining;
  332. expect.stringContaining = _asymmetricMatchers.stringContaining;
  333. expect.stringMatching = _asymmetricMatchers.stringMatching;
  334. const _validateResult = result => {
  335. if (
  336. typeof result !== 'object' ||
  337. typeof result.pass !== 'boolean' ||
  338. (result.message &&
  339. typeof result.message !== 'string' &&
  340. typeof result.message !== 'function')
  341. ) {
  342. throw new Error(
  343. 'Unexpected return from a matcher function.\n' +
  344. 'Matcher functions should ' +
  345. 'return an object in the following format:\n' +
  346. ' {message?: string | function, pass: boolean}\n' +
  347. `'${matcherUtils.stringify(result)}' was returned`
  348. );
  349. }
  350. };
  351. function assertions(expected) {
  352. const error = new Error();
  353. if (Error.captureStackTrace) {
  354. Error.captureStackTrace(error, assertions);
  355. }
  356. (0, _jestMatchersObject.getState)().expectedAssertionsNumber = expected;
  357. (0, _jestMatchersObject.getState)().expectedAssertionsNumberError = error;
  358. }
  359. function hasAssertions(...args) {
  360. const error = new Error();
  361. if (Error.captureStackTrace) {
  362. Error.captureStackTrace(error, hasAssertions);
  363. }
  364. matcherUtils.ensureNoExpected(args[0], '.hasAssertions');
  365. (0, _jestMatchersObject.getState)().isExpectingAssertions = true;
  366. (0, _jestMatchersObject.getState)().isExpectingAssertionsError = error;
  367. } // add default jest matchers
  368. (0, _jestMatchersObject.setMatchers)(_matchers.default, true, expect);
  369. (0, _jestMatchersObject.setMatchers)(_spyMatchers.default, true, expect);
  370. (0, _jestMatchersObject.setMatchers)(_toThrowMatchers.default, true, expect);
  371. expect.addSnapshotSerializer = () => void 0;
  372. expect.assertions = assertions;
  373. expect.hasAssertions = hasAssertions;
  374. expect.getState = _jestMatchersObject.getState;
  375. expect.setState = _jestMatchersObject.setState;
  376. expect.extractExpectedAssertionsErrors =
  377. _extractExpectedAssertionsErrors.default;
  378. const expectExport = expect;
  379. module.exports = expectExport;