index.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. 'use strict';
  2. var _fs = require('fs');
  3. var _fs2 = _interopRequireDefault(_fs);
  4. var _path = require('path');
  5. var _path2 = _interopRequireDefault(_path);
  6. var _jestDiff = require('jest-diff');
  7. var _jestDiff2 = _interopRequireDefault(_jestDiff);
  8. var _jestMatcherUtils = require('jest-matcher-utils');
  9. var _State = require('./State');
  10. var _State2 = _interopRequireDefault(_State);
  11. var _plugins = require('./plugins');
  12. var _utils = require('./utils');
  13. var utils = _interopRequireWildcard(_utils);
  14. function _interopRequireWildcard(obj) {
  15. if (obj && obj.__esModule) {
  16. return obj;
  17. } else {
  18. var newObj = {};
  19. if (obj != null) {
  20. for (var key in obj) {
  21. if (Object.prototype.hasOwnProperty.call(obj, key))
  22. newObj[key] = obj[key];
  23. }
  24. }
  25. newObj.default = obj;
  26. return newObj;
  27. }
  28. }
  29. function _interopRequireDefault(obj) {
  30. return obj && obj.__esModule ? obj : {default: obj};
  31. }
  32. /**
  33. * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
  34. *
  35. * This source code is licensed under the MIT license found in the
  36. * LICENSE file in the root directory of this source tree.
  37. *
  38. *
  39. */
  40. const fileExists = (filePath, hasteFS) =>
  41. hasteFS.exists(filePath) || _fs2.default.existsSync(filePath);
  42. const cleanup = (hasteFS, update) => {
  43. const pattern = '\\.' + utils.SNAPSHOT_EXTENSION + '$';
  44. const files = hasteFS.matchFiles(pattern);
  45. const filesRemoved = files
  46. .filter(
  47. snapshotFile =>
  48. !fileExists(
  49. _path2.default.resolve(
  50. _path2.default.dirname(snapshotFile),
  51. '..',
  52. _path2.default.basename(
  53. snapshotFile,
  54. '.' + utils.SNAPSHOT_EXTENSION
  55. )
  56. ),
  57. hasteFS
  58. )
  59. )
  60. .map(snapshotFile => {
  61. if (update === 'all') {
  62. _fs2.default.unlinkSync(snapshotFile);
  63. }
  64. }).length;
  65. return {
  66. filesRemoved: filesRemoved
  67. };
  68. };
  69. const toMatchSnapshot = function(received, propertyMatchers, testName) {
  70. if (arguments.length === 3 && !propertyMatchers) {
  71. throw new Error(
  72. 'Property matchers must be an object.\n\nTo provide a snapshot test name without property matchers, use: toMatchSnapshot("name")'
  73. );
  74. }
  75. return _toMatchSnapshot({
  76. context: this,
  77. propertyMatchers: propertyMatchers,
  78. received: received,
  79. testName: testName
  80. });
  81. };
  82. const toMatchInlineSnapshot = function(
  83. received,
  84. propertyMatchersOrInlineSnapshot,
  85. inlineSnapshot
  86. ) {
  87. let propertyMatchers;
  88. if (typeof propertyMatchersOrInlineSnapshot === 'string') {
  89. inlineSnapshot = propertyMatchersOrInlineSnapshot;
  90. } else {
  91. propertyMatchers = propertyMatchersOrInlineSnapshot;
  92. }
  93. return _toMatchSnapshot({
  94. context: this,
  95. inlineSnapshot: inlineSnapshot || '',
  96. propertyMatchers: propertyMatchers,
  97. received: received
  98. });
  99. };
  100. const _toMatchSnapshot = _ref => {
  101. let context = _ref.context,
  102. received = _ref.received,
  103. propertyMatchers = _ref.propertyMatchers,
  104. testName = _ref.testName,
  105. inlineSnapshot = _ref.inlineSnapshot;
  106. context.dontThrow && context.dontThrow();
  107. testName = typeof propertyMatchers === 'string' ? propertyMatchers : testName;
  108. const currentTestName = context.currentTestName,
  109. isNot = context.isNot,
  110. snapshotState = context.snapshotState;
  111. if (isNot) {
  112. const matcherName =
  113. typeof inlineSnapshot === 'string'
  114. ? 'toMatchInlineSnapshot'
  115. : 'toMatchSnapshot';
  116. throw new Error(
  117. `Jest: \`.not\` cannot be used with \`.${matcherName}()\`.`
  118. );
  119. }
  120. if (!snapshotState) {
  121. throw new Error('Jest: snapshot state must be initialized.');
  122. }
  123. const fullTestName =
  124. testName && currentTestName
  125. ? `${currentTestName}: ${testName}`
  126. : currentTestName || '';
  127. if (typeof propertyMatchers === 'object') {
  128. if (propertyMatchers === null) {
  129. throw new Error(`Property matchers must be an object.`);
  130. }
  131. const propertyPass = context.equals(received, propertyMatchers, [
  132. context.utils.iterableEquality,
  133. context.utils.subsetEquality
  134. ]);
  135. if (!propertyPass) {
  136. const key = snapshotState.fail(fullTestName, received);
  137. const report = () =>
  138. `${(0, _jestMatcherUtils.RECEIVED_COLOR)(
  139. 'Received value'
  140. )} does not match ` +
  141. `${(0, _jestMatcherUtils.EXPECTED_COLOR)(
  142. `snapshot properties for "${key}"`
  143. )}.\n\n` +
  144. `Expected snapshot to match properties:\n` +
  145. ` ${context.utils.printExpected(propertyMatchers)}` +
  146. `\nReceived:\n` +
  147. ` ${context.utils.printReceived(received)}`;
  148. return {
  149. message: () =>
  150. (0, _jestMatcherUtils.matcherHint)(
  151. '.toMatchSnapshot',
  152. 'value',
  153. 'properties'
  154. ) +
  155. '\n\n' +
  156. report(),
  157. name: 'toMatchSnapshot',
  158. pass: false,
  159. report: report
  160. };
  161. } else {
  162. received = utils.deepMerge(received, propertyMatchers);
  163. }
  164. }
  165. const result = snapshotState.match({
  166. error: context.error,
  167. inlineSnapshot: inlineSnapshot,
  168. received: received,
  169. testName: fullTestName
  170. });
  171. const pass = result.pass;
  172. let actual = result.actual,
  173. expected = result.expected;
  174. let report;
  175. if (pass) {
  176. return {message: () => '', pass: true};
  177. } else if (!expected) {
  178. report = () =>
  179. `New snapshot was ${(0, _jestMatcherUtils.RECEIVED_COLOR)(
  180. 'not written'
  181. )}. The update flag ` +
  182. `must be explicitly passed to write a new snapshot.\n\n` +
  183. `This is likely because this test is run in a continuous integration ` +
  184. `(CI) environment in which snapshots are not written by default.\n\n` +
  185. `${(0, _jestMatcherUtils.RECEIVED_COLOR)('Received value')} ` +
  186. `${actual}`;
  187. } else {
  188. expected = (expected || '').trim();
  189. actual = (actual || '').trim();
  190. const diffMessage = (0, _jestDiff2.default)(expected, actual, {
  191. aAnnotation: 'Snapshot',
  192. bAnnotation: 'Received',
  193. expand: snapshotState.expand
  194. });
  195. report = () =>
  196. `${(0, _jestMatcherUtils.RECEIVED_COLOR)(
  197. 'Received value'
  198. )} does not match ` +
  199. `${(0, _jestMatcherUtils.EXPECTED_COLOR)(
  200. `stored snapshot "${result.key}"`
  201. )}.\n\n` +
  202. (diffMessage ||
  203. (0, _jestMatcherUtils.EXPECTED_COLOR)('- ' + (expected || '')) +
  204. '\n' +
  205. (0, _jestMatcherUtils.RECEIVED_COLOR)('+ ' + actual));
  206. }
  207. // Passing the the actual and expected objects so that a custom reporter
  208. // could access them, for example in order to display a custom visual diff,
  209. // or create a different error message
  210. return {
  211. actual: actual,
  212. expected: expected,
  213. message: () =>
  214. (0, _jestMatcherUtils.matcherHint)('.toMatchSnapshot', 'value', '') +
  215. '\n\n' +
  216. report(),
  217. name: 'toMatchSnapshot',
  218. pass: false,
  219. report: report
  220. };
  221. };
  222. const toThrowErrorMatchingSnapshot = function(received, testName, fromPromise) {
  223. return _toThrowErrorMatchingSnapshot({
  224. context: this,
  225. fromPromise: fromPromise,
  226. received: received,
  227. testName: testName
  228. });
  229. };
  230. const toThrowErrorMatchingInlineSnapshot = function(
  231. received,
  232. inlineSnapshot,
  233. fromPromise
  234. ) {
  235. return _toThrowErrorMatchingSnapshot({
  236. context: this,
  237. fromPromise: fromPromise,
  238. inlineSnapshot: inlineSnapshot || '',
  239. received: received
  240. });
  241. };
  242. const _toThrowErrorMatchingSnapshot = _ref2 => {
  243. let context = _ref2.context,
  244. received = _ref2.received,
  245. testName = _ref2.testName,
  246. fromPromise = _ref2.fromPromise,
  247. inlineSnapshot = _ref2.inlineSnapshot;
  248. context.dontThrow && context.dontThrow();
  249. const isNot = context.isNot;
  250. const matcherName =
  251. typeof inlineSnapshot === 'string'
  252. ? 'toThrowErrorMatchingInlineSnapshot'
  253. : 'toThrowErrorMatchingSnapshot';
  254. if (isNot) {
  255. throw new Error(
  256. `Jest: \`.not\` cannot be used with \`.${matcherName}()\`.`
  257. );
  258. }
  259. let error;
  260. if (fromPromise) {
  261. error = received;
  262. } else {
  263. try {
  264. received();
  265. } catch (e) {
  266. error = e;
  267. }
  268. }
  269. if (error === undefined) {
  270. throw new Error(
  271. (0, _jestMatcherUtils.matcherHint)(`.${matcherName}`, '() => {}', '') +
  272. '\n\n' +
  273. `Expected the function to throw an error.\n` +
  274. `But it didn't throw anything.`
  275. );
  276. }
  277. return _toMatchSnapshot({
  278. context: context,
  279. inlineSnapshot: inlineSnapshot,
  280. received: error.message,
  281. testName: testName
  282. });
  283. };
  284. module.exports = {
  285. EXTENSION: utils.SNAPSHOT_EXTENSION,
  286. SnapshotState: _State2.default,
  287. addSerializer: _plugins.addSerializer,
  288. cleanup: cleanup,
  289. getSerializers: _plugins.getSerializers,
  290. toMatchInlineSnapshot: toMatchInlineSnapshot,
  291. toMatchSnapshot: toMatchSnapshot,
  292. toThrowErrorMatchingInlineSnapshot: toThrowErrorMatchingInlineSnapshot,
  293. toThrowErrorMatchingSnapshot: toThrowErrorMatchingSnapshot,
  294. utils: utils
  295. };