123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645 |
- 'use strict';
- var fs = _interopRequireWildcard(require('graceful-fs'));
- var _jestMatcherUtils = require('jest-matcher-utils');
- var _SnapshotResolver = require('./SnapshotResolver');
- var _State = _interopRequireDefault(require('./State'));
- var _plugins = require('./plugins');
- var _printSnapshot = require('./printSnapshot');
- var utils = _interopRequireWildcard(require('./utils'));
- function _interopRequireDefault(obj) {
- return obj && obj.__esModule ? obj : {default: obj};
- }
- function _getRequireWildcardCache(nodeInterop) {
- if (typeof WeakMap !== 'function') return null;
- var cacheBabelInterop = new WeakMap();
- var cacheNodeInterop = new WeakMap();
- return (_getRequireWildcardCache = function (nodeInterop) {
- return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
- })(nodeInterop);
- }
- function _interopRequireWildcard(obj, nodeInterop) {
- if (!nodeInterop && obj && obj.__esModule) {
- return obj;
- }
- if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
- return {default: obj};
- }
- var cache = _getRequireWildcardCache(nodeInterop);
- if (cache && cache.has(obj)) {
- return cache.get(obj);
- }
- var newObj = {};
- var hasPropertyDescriptor =
- Object.defineProperty && Object.getOwnPropertyDescriptor;
- for (var key in obj) {
- if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
- var desc = hasPropertyDescriptor
- ? Object.getOwnPropertyDescriptor(obj, key)
- : null;
- if (desc && (desc.get || desc.set)) {
- Object.defineProperty(newObj, key, desc);
- } else {
- newObj[key] = obj[key];
- }
- }
- }
- newObj.default = obj;
- if (cache) {
- cache.set(obj, newObj);
- }
- return newObj;
- }
- var global = (function () {
- if (typeof globalThis !== 'undefined') {
- return globalThis;
- } else if (typeof global !== 'undefined') {
- return global;
- } else if (typeof self !== 'undefined') {
- return self;
- } else if (typeof window !== 'undefined') {
- return window;
- } else {
- return Function('return this')();
- }
- })();
- var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
- var global = (function () {
- if (typeof globalThis !== 'undefined') {
- return globalThis;
- } else if (typeof global !== 'undefined') {
- return global;
- } else if (typeof self !== 'undefined') {
- return self;
- } else if (typeof window !== 'undefined') {
- return window;
- } else {
- return Function('return this')();
- }
- })();
- var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
- var global = (function () {
- if (typeof globalThis !== 'undefined') {
- return globalThis;
- } else if (typeof global !== 'undefined') {
- return global;
- } else if (typeof self !== 'undefined') {
- return self;
- } else if (typeof window !== 'undefined') {
- return window;
- } else {
- return Function('return this')();
- }
- })();
- var jestExistsFile =
- global[Symbol.for('jest-native-exists-file')] || fs.existsSync;
- const DID_NOT_THROW = 'Received function did not throw'; // same as toThrow
- const NOT_SNAPSHOT_MATCHERS = `Snapshot matchers cannot be used with ${(0,
- _jestMatcherUtils.BOLD_WEIGHT)('not')}`;
- const INDENTATION_REGEX = /^([^\S\n]*)\S/m; // Display name in report when matcher fails same as in snapshot file,
- // but with optional hint argument in bold weight.
- const printSnapshotName = (concatenatedBlockNames = '', hint = '', count) => {
- const hasNames = concatenatedBlockNames.length !== 0;
- const hasHint = hint.length !== 0;
- return (
- 'Snapshot name: `' +
- (hasNames ? utils.escapeBacktickString(concatenatedBlockNames) : '') +
- (hasNames && hasHint ? ': ' : '') +
- (hasHint
- ? (0, _jestMatcherUtils.BOLD_WEIGHT)(utils.escapeBacktickString(hint))
- : '') +
- ' ' +
- count +
- '`'
- );
- };
- function stripAddedIndentation(inlineSnapshot) {
- // Find indentation if exists.
- const match = inlineSnapshot.match(INDENTATION_REGEX);
- if (!match || !match[1]) {
- // No indentation.
- return inlineSnapshot;
- }
- const indentation = match[1];
- const lines = inlineSnapshot.split('\n');
- if (lines.length <= 2) {
- // Must be at least 3 lines.
- return inlineSnapshot;
- }
- if (lines[0].trim() !== '' || lines[lines.length - 1].trim() !== '') {
- // If not blank first and last lines, abort.
- return inlineSnapshot;
- }
- for (let i = 1; i < lines.length - 1; i++) {
- if (lines[i] !== '') {
- if (lines[i].indexOf(indentation) !== 0) {
- // All lines except first and last should either be blank or have the same
- // indent as the first line (or more). If this isn't the case we don't
- // want to touch the snapshot at all.
- return inlineSnapshot;
- }
- lines[i] = lines[i].substring(indentation.length);
- }
- } // Last line is a special case because it won't have the same indent as others
- // but may still have been given some indent to line up.
- lines[lines.length - 1] = ''; // Return inline snapshot, now at indent 0.
- inlineSnapshot = lines.join('\n');
- return inlineSnapshot;
- }
- const fileExists = (filePath, hasteFS) =>
- hasteFS.exists(filePath) || jestExistsFile(filePath);
- const cleanup = (hasteFS, update, snapshotResolver, testPathIgnorePatterns) => {
- const pattern = '\\.' + _SnapshotResolver.EXTENSION + '$';
- const files = hasteFS.matchFiles(pattern);
- let testIgnorePatternsRegex = null;
- if (testPathIgnorePatterns && testPathIgnorePatterns.length > 0) {
- testIgnorePatternsRegex = new RegExp(testPathIgnorePatterns.join('|'));
- }
- const list = files.filter(snapshotFile => {
- const testPath = snapshotResolver.resolveTestPath(snapshotFile); // ignore snapshots of ignored tests
- if (testIgnorePatternsRegex && testIgnorePatternsRegex.test(testPath)) {
- return false;
- }
- if (!fileExists(testPath, hasteFS)) {
- if (update === 'all') {
- fs.unlinkSync(snapshotFile);
- }
- return true;
- }
- return false;
- });
- return {
- filesRemoved: list.length,
- filesRemovedList: list
- };
- };
- const toMatchSnapshot = function (received, propertiesOrHint, hint) {
- const matcherName = 'toMatchSnapshot';
- let properties;
- const length = arguments.length;
- if (length === 2 && typeof propertiesOrHint === 'string') {
- hint = propertiesOrHint;
- } else if (length >= 2) {
- if (typeof propertiesOrHint !== 'object' || propertiesOrHint === null) {
- const options = {
- isNot: this.isNot,
- promise: this.promise
- };
- let printedWithType = (0, _jestMatcherUtils.printWithType)(
- 'Expected properties',
- propertiesOrHint,
- _printSnapshot.printExpected
- );
- if (length === 3) {
- options.secondArgument = 'hint';
- options.secondArgumentColor = _jestMatcherUtils.BOLD_WEIGHT;
- if (propertiesOrHint == null) {
- printedWithType +=
- "\n\nTo provide a hint without properties: toMatchSnapshot('hint')";
- }
- }
- throw new Error(
- (0, _jestMatcherUtils.matcherErrorMessage)(
- (0, _jestMatcherUtils.matcherHint)(
- matcherName,
- undefined,
- _printSnapshot.PROPERTIES_ARG,
- options
- ),
- `Expected ${(0, _jestMatcherUtils.EXPECTED_COLOR)(
- 'properties'
- )} must be an object`,
- printedWithType
- )
- );
- } // Future breaking change: Snapshot hint must be a string
- // if (arguments.length === 3 && typeof hint !== 'string') {}
- properties = propertiesOrHint;
- }
- return _toMatchSnapshot({
- context: this,
- hint,
- isInline: false,
- matcherName,
- properties,
- received
- });
- };
- const toMatchInlineSnapshot = function (
- received,
- propertiesOrSnapshot,
- inlineSnapshot
- ) {
- const matcherName = 'toMatchInlineSnapshot';
- let properties;
- const length = arguments.length;
- if (length === 2 && typeof propertiesOrSnapshot === 'string') {
- inlineSnapshot = propertiesOrSnapshot;
- } else if (length >= 2) {
- const options = {
- isNot: this.isNot,
- promise: this.promise
- };
- if (length === 3) {
- options.secondArgument = _printSnapshot.SNAPSHOT_ARG;
- options.secondArgumentColor = _printSnapshot.noColor;
- }
- if (
- typeof propertiesOrSnapshot !== 'object' ||
- propertiesOrSnapshot === null
- ) {
- throw new Error(
- (0, _jestMatcherUtils.matcherErrorMessage)(
- (0, _jestMatcherUtils.matcherHint)(
- matcherName,
- undefined,
- _printSnapshot.PROPERTIES_ARG,
- options
- ),
- `Expected ${(0, _jestMatcherUtils.EXPECTED_COLOR)(
- 'properties'
- )} must be an object`,
- (0, _jestMatcherUtils.printWithType)(
- 'Expected properties',
- propertiesOrSnapshot,
- _printSnapshot.printExpected
- )
- )
- );
- }
- if (length === 3 && typeof inlineSnapshot !== 'string') {
- throw new Error(
- (0, _jestMatcherUtils.matcherErrorMessage)(
- (0, _jestMatcherUtils.matcherHint)(
- matcherName,
- undefined,
- _printSnapshot.PROPERTIES_ARG,
- options
- ),
- 'Inline snapshot must be a string',
- (0, _jestMatcherUtils.printWithType)(
- 'Inline snapshot',
- inlineSnapshot,
- utils.serialize
- )
- )
- );
- }
- properties = propertiesOrSnapshot;
- }
- return _toMatchSnapshot({
- context: this,
- inlineSnapshot:
- inlineSnapshot !== undefined
- ? stripAddedIndentation(inlineSnapshot)
- : undefined,
- isInline: true,
- matcherName,
- properties,
- received
- });
- };
- const _toMatchSnapshot = config => {
- const {context, hint, inlineSnapshot, isInline, matcherName, properties} =
- config;
- let {received} = config;
- context.dontThrow && context.dontThrow();
- const {currentTestName, isNot, snapshotState} = context;
- if (isNot) {
- throw new Error(
- (0, _jestMatcherUtils.matcherErrorMessage)(
- (0, _printSnapshot.matcherHintFromConfig)(config, false),
- NOT_SNAPSHOT_MATCHERS
- )
- );
- }
- if (snapshotState == null) {
- // Because the state is the problem, this is not a matcher error.
- // Call generic stringify from jest-matcher-utils package
- // because uninitialized snapshot state does not need snapshot serializers.
- throw new Error(
- (0, _printSnapshot.matcherHintFromConfig)(config, false) +
- '\n\n' +
- 'Snapshot state must be initialized' +
- '\n\n' +
- (0, _jestMatcherUtils.printWithType)(
- 'Snapshot state',
- snapshotState,
- _jestMatcherUtils.stringify
- )
- );
- }
- const fullTestName =
- currentTestName && hint
- ? `${currentTestName}: ${hint}`
- : currentTestName || ''; // future BREAKING change: || hint
- if (typeof properties === 'object') {
- if (typeof received !== 'object' || received === null) {
- throw new Error(
- (0, _jestMatcherUtils.matcherErrorMessage)(
- (0, _printSnapshot.matcherHintFromConfig)(config, false),
- `${(0, _jestMatcherUtils.RECEIVED_COLOR)(
- 'received'
- )} value must be an object when the matcher has ${(0,
- _jestMatcherUtils.EXPECTED_COLOR)('properties')}`,
- (0, _jestMatcherUtils.printWithType)(
- 'Received',
- received,
- _printSnapshot.printReceived
- )
- )
- );
- }
- const propertyPass = context.equals(received, properties, [
- context.utils.iterableEquality,
- context.utils.subsetEquality
- ]);
- if (!propertyPass) {
- const key = snapshotState.fail(fullTestName, received);
- const matched = /(\d+)$/.exec(key);
- const count = matched === null ? 1 : Number(matched[1]);
- const message = () =>
- (0, _printSnapshot.matcherHintFromConfig)(config, false) +
- '\n\n' +
- printSnapshotName(currentTestName, hint, count) +
- '\n\n' +
- (0, _printSnapshot.printPropertiesAndReceived)(
- properties,
- received,
- snapshotState.expand
- );
- return {
- message,
- name: matcherName,
- pass: false
- };
- } else {
- received = utils.deepMerge(received, properties);
- }
- }
- const result = snapshotState.match({
- error: context.error,
- inlineSnapshot,
- isInline,
- received,
- testName: fullTestName
- });
- const {actual, count, expected, pass} = result;
- if (pass) {
- return {
- message: () => '',
- pass: true
- };
- }
- const message =
- expected === undefined
- ? () =>
- (0, _printSnapshot.matcherHintFromConfig)(config, true) +
- '\n\n' +
- printSnapshotName(currentTestName, hint, count) +
- '\n\n' +
- `New snapshot was ${(0, _jestMatcherUtils.BOLD_WEIGHT)(
- 'not written'
- )}. The update flag ` +
- 'must be explicitly passed to write a new snapshot.\n\n' +
- 'This is likely because this test is run in a continuous integration ' +
- '(CI) environment in which snapshots are not written by default.\n\n' +
- `Received:${actual.includes('\n') ? '\n' : ' '}${(0,
- _printSnapshot.bReceivedColor)(actual)}`
- : () =>
- (0, _printSnapshot.matcherHintFromConfig)(config, true) +
- '\n\n' +
- printSnapshotName(currentTestName, hint, count) +
- '\n\n' +
- (0, _printSnapshot.printSnapshotAndReceived)(
- expected,
- actual,
- received,
- snapshotState.expand
- ); // Passing the actual and expected objects so that a custom reporter
- // could access them, for example in order to display a custom visual diff,
- // or create a different error message
- return {
- actual,
- expected,
- message,
- name: matcherName,
- pass: false
- };
- };
- const toThrowErrorMatchingSnapshot = function (
- received,
- hint, // because error TS1016 for hint?: string
- fromPromise
- ) {
- const matcherName = 'toThrowErrorMatchingSnapshot'; // Future breaking change: Snapshot hint must be a string
- // if (hint !== undefined && typeof hint !== string) {}
- return _toThrowErrorMatchingSnapshot(
- {
- context: this,
- hint,
- isInline: false,
- matcherName,
- received
- },
- fromPromise
- );
- };
- const toThrowErrorMatchingInlineSnapshot = function (
- received,
- inlineSnapshot,
- fromPromise
- ) {
- const matcherName = 'toThrowErrorMatchingInlineSnapshot';
- if (inlineSnapshot !== undefined && typeof inlineSnapshot !== 'string') {
- const options = {
- expectedColor: _printSnapshot.noColor,
- isNot: this.isNot,
- promise: this.promise
- };
- throw new Error(
- (0, _jestMatcherUtils.matcherErrorMessage)(
- (0, _jestMatcherUtils.matcherHint)(
- matcherName,
- undefined,
- _printSnapshot.SNAPSHOT_ARG,
- options
- ),
- 'Inline snapshot must be a string',
- (0, _jestMatcherUtils.printWithType)(
- 'Inline snapshot',
- inlineSnapshot,
- utils.serialize
- )
- )
- );
- }
- return _toThrowErrorMatchingSnapshot(
- {
- context: this,
- inlineSnapshot:
- inlineSnapshot !== undefined
- ? stripAddedIndentation(inlineSnapshot)
- : undefined,
- isInline: true,
- matcherName,
- received
- },
- fromPromise
- );
- };
- const _toThrowErrorMatchingSnapshot = (config, fromPromise) => {
- const {context, hint, inlineSnapshot, isInline, matcherName, received} =
- config;
- context.dontThrow && context.dontThrow();
- const {isNot, promise} = context;
- if (!fromPromise) {
- if (typeof received !== 'function') {
- const options = {
- isNot,
- promise
- };
- throw new Error(
- (0, _jestMatcherUtils.matcherErrorMessage)(
- (0, _jestMatcherUtils.matcherHint)(
- matcherName,
- undefined,
- '',
- options
- ),
- `${(0, _jestMatcherUtils.RECEIVED_COLOR)(
- 'received'
- )} value must be a function`,
- (0, _jestMatcherUtils.printWithType)(
- 'Received',
- received,
- _printSnapshot.printReceived
- )
- )
- );
- }
- }
- if (isNot) {
- throw new Error(
- (0, _jestMatcherUtils.matcherErrorMessage)(
- (0, _printSnapshot.matcherHintFromConfig)(config, false),
- NOT_SNAPSHOT_MATCHERS
- )
- );
- }
- let error;
- if (fromPromise) {
- error = received;
- } else {
- try {
- received();
- } catch (e) {
- error = e;
- }
- }
- if (error === undefined) {
- // Because the received value is a function, this is not a matcher error.
- throw new Error(
- (0, _printSnapshot.matcherHintFromConfig)(config, false) +
- '\n\n' +
- DID_NOT_THROW
- );
- }
- return _toMatchSnapshot({
- context,
- hint,
- inlineSnapshot,
- isInline,
- matcherName,
- received: error.message
- });
- };
- const JestSnapshot = {
- EXTENSION: _SnapshotResolver.EXTENSION,
- SnapshotState: _State.default,
- addSerializer: _plugins.addSerializer,
- buildSnapshotResolver: _SnapshotResolver.buildSnapshotResolver,
- cleanup,
- getSerializers: _plugins.getSerializers,
- isSnapshotPath: _SnapshotResolver.isSnapshotPath,
- toMatchInlineSnapshot,
- toMatchSnapshot,
- toThrowErrorMatchingInlineSnapshot,
- toThrowErrorMatchingSnapshot,
- utils
- };
- module.exports = JestSnapshot;
|