jest-snapshot
Advanced tools
Comparing version 29.5.0 to 29.6.0
@@ -102,2 +102,8 @@ 'use strict'; | ||
globalThis[Symbol.for('jest-native-exists-file')] || fs.existsSync; | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
const DID_NOT_THROW = 'Received function did not throw'; // same as toThrow | ||
@@ -202,7 +208,3 @@ const NOT_SNAPSHOT_MATCHERS = `Snapshot matchers cannot be used with ${(0, | ||
} else if (length >= 2) { | ||
if ( | ||
Array.isArray(propertiesOrHint) || | ||
typeof propertiesOrHint !== 'object' || | ||
propertiesOrHint === null | ||
) { | ||
if (typeof propertiesOrHint !== 'object' || propertiesOrHint === null) { | ||
const options = { | ||
@@ -276,3 +278,2 @@ isNot: this.isNot, | ||
if ( | ||
Array.isArray(propertiesOrSnapshot) || | ||
typeof propertiesOrSnapshot !== 'object' || | ||
@@ -338,3 +339,5 @@ propertiesOrSnapshot === null | ||
context.dontThrow && context.dontThrow(); | ||
const {currentTestName, isNot, snapshotState} = context; | ||
const {currentConcurrentTestName, isNot, snapshotState} = context; | ||
const currentTestName = | ||
currentConcurrentTestName?.getStore() ?? context.currentTestName; | ||
if (isNot) { | ||
@@ -341,0 +344,0 @@ throw new Error( |
@@ -61,8 +61,9 @@ 'use strict'; | ||
globalThis[Symbol.for('jest-native-read-file')] || fs.readFileSync; | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
// prettier-ignore | ||
const babelTraverse = // @ts-expect-error requireOutside Babel transform | ||
require(require.resolve('@babel/traverse', { | ||
[(globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol).for('jest-resolve-outside-vm-option')]: true | ||
})).default; | ||
// prettier-ignore | ||
const generate = // @ts-expect-error requireOutside Babel transform | ||
@@ -73,6 +74,7 @@ require(require.resolve('@babel/generator', { | ||
const { | ||
file, | ||
isAwaitExpression, | ||
templateElement, | ||
templateLiteral | ||
templateLiteral, | ||
traverse, | ||
traverseFast | ||
} = require(require.resolve('@babel/types', { // @ts-expect-error requireOutside Babel transform | ||
@@ -174,15 +176,19 @@ [(globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol).for( | ||
(sourceSoFar, nextSnapshot) => { | ||
const {node} = nextSnapshot; | ||
if ( | ||
!nextSnapshot.node || | ||
typeof nextSnapshot.node.start !== 'number' || | ||
typeof nextSnapshot.node.end !== 'number' | ||
!node || | ||
typeof node.start !== 'number' || | ||
typeof node.end !== 'number' | ||
) { | ||
throw new Error('Jest: no snapshot insert location found'); | ||
} | ||
// A hack to prevent unexpected line breaks in the generated code | ||
node.loc.end.line = node.loc.start.line; | ||
return ( | ||
sourceSoFar.slice(0, nextSnapshot.node.start) + | ||
generate(nextSnapshot.node, { | ||
sourceSoFar.slice(0, node.start) + | ||
generate(node, { | ||
retainLines: true | ||
}).code.trim() + | ||
sourceSoFar.slice(nextSnapshot.node.end) | ||
sourceSoFar.slice(node.end) | ||
); | ||
@@ -247,59 +253,46 @@ }, | ||
}; | ||
const resolveAst = fileOrProgram => { | ||
// Flow uses a 'Program' parent node, babel expects a 'File'. | ||
let ast = fileOrProgram; | ||
if (ast.type !== 'File') { | ||
ast = file(ast, ast.comments, ast.tokens); | ||
delete ast.program.comments; | ||
} | ||
return ast; | ||
}; | ||
const traverseAst = (snapshots, fileOrProgram, snapshotMatcherNames) => { | ||
const ast = resolveAst(fileOrProgram); | ||
const traverseAst = (snapshots, ast, snapshotMatcherNames) => { | ||
const groupedSnapshots = groupSnapshotsByFrame(snapshots); | ||
const remainingSnapshots = new Set(snapshots.map(({snapshot}) => snapshot)); | ||
babelTraverse(ast, { | ||
CallExpression({node}) { | ||
const {arguments: args, callee} = node; | ||
if ( | ||
callee.type !== 'MemberExpression' || | ||
callee.property.type !== 'Identifier' || | ||
callee.property.loc == null | ||
) { | ||
return; | ||
} | ||
const {line, column} = callee.property.loc.start; | ||
const snapshotsForFrame = groupedSnapshots[`${line}:${column}`]; | ||
if (!snapshotsForFrame) { | ||
return; | ||
} | ||
if (snapshotsForFrame.length > 1) { | ||
throw new Error( | ||
'Jest: Multiple inline snapshots for the same call are not supported.' | ||
); | ||
} | ||
snapshotMatcherNames.push(callee.property.name); | ||
const snapshotIndex = args.findIndex( | ||
({type}) => type === 'TemplateLiteral' | ||
traverseFast(ast, node => { | ||
if (node.type !== 'CallExpression') return; | ||
const {arguments: args, callee} = node; | ||
if ( | ||
callee.type !== 'MemberExpression' || | ||
callee.property.type !== 'Identifier' || | ||
callee.property.loc == null | ||
) { | ||
return; | ||
} | ||
const {line, column} = callee.property.loc.start; | ||
const snapshotsForFrame = groupedSnapshots[`${line}:${column}`]; | ||
if (!snapshotsForFrame) { | ||
return; | ||
} | ||
if (snapshotsForFrame.length > 1) { | ||
throw new Error( | ||
'Jest: Multiple inline snapshots for the same call are not supported.' | ||
); | ||
const values = snapshotsForFrame.map(inlineSnapshot => { | ||
inlineSnapshot.node = node; | ||
const {snapshot} = inlineSnapshot; | ||
remainingSnapshots.delete(snapshot); | ||
return templateLiteral( | ||
[ | ||
templateElement({ | ||
raw: (0, _utils.escapeBacktickString)(snapshot) | ||
}) | ||
], | ||
[] | ||
); | ||
}); | ||
const replacementNode = values[0]; | ||
if (snapshotIndex > -1) { | ||
args[snapshotIndex] = replacementNode; | ||
} else { | ||
args.push(replacementNode); | ||
} | ||
} | ||
const inlineSnapshot = snapshotsForFrame[0]; | ||
inlineSnapshot.node = node; | ||
snapshotMatcherNames.push(callee.property.name); | ||
const snapshotIndex = args.findIndex( | ||
({type}) => type === 'TemplateLiteral' | ||
); | ||
const {snapshot} = inlineSnapshot; | ||
remainingSnapshots.delete(snapshot); | ||
const replacementNode = templateLiteral( | ||
[ | ||
templateElement({ | ||
raw: (0, _utils.escapeBacktickString)(snapshot) | ||
}) | ||
], | ||
[] | ||
); | ||
if (snapshotIndex > -1) { | ||
args[snapshotIndex] = replacementNode; | ||
} else { | ||
args.push(replacementNode); | ||
} | ||
}); | ||
@@ -362,51 +355,52 @@ if (remainingSnapshots.size) { | ||
options.parser = inferredParser; | ||
const ast = resolveAst(parsers[inferredParser](text, options)); | ||
babelTraverse(ast, { | ||
CallExpression({node: {arguments: args, callee}, parent}) { | ||
if ( | ||
callee.type !== 'MemberExpression' || | ||
callee.property.type !== 'Identifier' || | ||
!snapshotMatcherNames.includes(callee.property.name) || | ||
!callee.loc || | ||
callee.computed | ||
) { | ||
return; | ||
const ast = parsers[inferredParser](text, options); | ||
traverse(ast, (node, ancestors) => { | ||
if (node.type !== 'CallExpression') return; | ||
const {arguments: args, callee} = node; | ||
if ( | ||
callee.type !== 'MemberExpression' || | ||
callee.property.type !== 'Identifier' || | ||
!snapshotMatcherNames.includes(callee.property.name) || | ||
!callee.loc || | ||
callee.computed | ||
) { | ||
return; | ||
} | ||
let snapshotIndex; | ||
let snapshot; | ||
for (let i = 0; i < args.length; i++) { | ||
const node = args[i]; | ||
if (node.type === 'TemplateLiteral') { | ||
snapshotIndex = i; | ||
snapshot = node.quasis[0].value.raw; | ||
} | ||
let snapshotIndex; | ||
let snapshot; | ||
for (let i = 0; i < args.length; i++) { | ||
const node = args[i]; | ||
if (node.type === 'TemplateLiteral') { | ||
snapshotIndex = i; | ||
snapshot = node.quasis[0].value.raw; | ||
} | ||
} | ||
if (snapshot === undefined || snapshotIndex === undefined) { | ||
return; | ||
} | ||
const startColumn = | ||
isAwaitExpression(parent) && parent.loc | ||
? parent.loc.start.column | ||
: callee.loc.start.column; | ||
const useSpaces = !options.useTabs; | ||
snapshot = indent( | ||
snapshot, | ||
Math.ceil( | ||
useSpaces | ||
? startColumn / (options.tabWidth ?? 1) | ||
: // Each tab is 2 characters. | ||
startColumn / 2 | ||
), | ||
useSpaces ? ' '.repeat(options.tabWidth ?? 1) : '\t' | ||
); | ||
const replacementNode = templateLiteral( | ||
[ | ||
templateElement({ | ||
raw: snapshot | ||
}) | ||
], | ||
[] | ||
); | ||
args[snapshotIndex] = replacementNode; | ||
} | ||
if (snapshot === undefined) { | ||
return; | ||
} | ||
const parent = ancestors[ancestors.length - 1].node; | ||
const startColumn = | ||
isAwaitExpression(parent) && parent.loc | ||
? parent.loc.start.column | ||
: callee.loc.start.column; | ||
const useSpaces = !options.useTabs; | ||
snapshot = indent( | ||
snapshot, | ||
Math.ceil( | ||
useSpaces | ||
? startColumn / (options.tabWidth ?? 1) | ||
: // Each tab is 2 characters. | ||
startColumn / 2 | ||
), | ||
useSpaces ? ' '.repeat(options.tabWidth ?? 1) : '\t' | ||
); | ||
const replacementNode = templateLiteral( | ||
[ | ||
templateElement({ | ||
raw: snapshot | ||
}) | ||
], | ||
[] | ||
); | ||
args[snapshotIndex] = replacementNode; | ||
}); | ||
@@ -413,0 +407,0 @@ return ast; |
@@ -55,2 +55,8 @@ 'use strict'; | ||
globalThis[Symbol.for('jest-native-exists-file')] || fs.existsSync; | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
class SnapshotState { | ||
@@ -57,0 +63,0 @@ _counters; |
@@ -82,2 +82,8 @@ 'use strict'; | ||
globalThis[Symbol.for('jest-native-exists-file')] || fs.existsSync; | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
const SNAPSHOT_VERSION = '1'; | ||
@@ -245,3 +251,3 @@ exports.SNAPSHOT_VERSION = SNAPSHOT_VERSION; | ||
try { | ||
fs.mkdirSync(path.join(path.dirname(filePath)), { | ||
fs.mkdirSync(path.dirname(filePath), { | ||
recursive: true | ||
@@ -269,2 +275,6 @@ }); | ||
exports.saveSnapshotFile = saveSnapshotFile; | ||
const isAnyOrAnything = input => | ||
'$$typeof' in input && | ||
input.$$typeof === Symbol.for('jest.asymmetricMatcher') && | ||
['Any', 'Anything'].includes(input.constructor.name); | ||
const deepMergeArray = (target, source) => { | ||
@@ -274,5 +284,5 @@ const mergedOutput = Array.from(target); | ||
const targetElement = mergedOutput[index]; | ||
if (Array.isArray(target[index])) { | ||
if (Array.isArray(target[index]) && Array.isArray(sourceElement)) { | ||
mergedOutput[index] = deepMergeArray(target[index], sourceElement); | ||
} else if (isObject(targetElement)) { | ||
} else if (isObject(targetElement) && !isAnyOrAnything(sourceElement)) { | ||
mergedOutput[index] = deepMerge(target[index], sourceElement); | ||
@@ -279,0 +289,0 @@ } else { |
{ | ||
"name": "jest-snapshot", | ||
"version": "29.5.0", | ||
"version": "29.6.0", | ||
"repository": { | ||
@@ -24,21 +24,19 @@ "type": "git", | ||
"@babel/plugin-syntax-typescript": "^7.7.2", | ||
"@babel/traverse": "^7.7.2", | ||
"@babel/types": "^7.3.3", | ||
"@jest/expect-utils": "^29.5.0", | ||
"@jest/transform": "^29.5.0", | ||
"@jest/types": "^29.5.0", | ||
"@types/babel__traverse": "^7.0.6", | ||
"@jest/expect-utils": "^29.6.0", | ||
"@jest/transform": "^29.6.0", | ||
"@jest/types": "^29.6.0", | ||
"@types/prettier": "^2.1.5", | ||
"babel-preset-current-node-syntax": "^1.0.0", | ||
"chalk": "^4.0.0", | ||
"expect": "^29.5.0", | ||
"expect": "^29.6.0", | ||
"graceful-fs": "^4.2.9", | ||
"jest-diff": "^29.5.0", | ||
"jest-diff": "^29.6.0", | ||
"jest-get-type": "^29.4.3", | ||
"jest-matcher-utils": "^29.5.0", | ||
"jest-message-util": "^29.5.0", | ||
"jest-util": "^29.5.0", | ||
"jest-matcher-utils": "^29.6.0", | ||
"jest-message-util": "^29.6.0", | ||
"jest-util": "^29.6.0", | ||
"natural-compare": "^1.4.0", | ||
"pretty-format": "^29.5.0", | ||
"semver": "^7.3.5" | ||
"pretty-format": "^29.6.0", | ||
"semver": "^7.5.3" | ||
}, | ||
@@ -48,4 +46,4 @@ "devDependencies": { | ||
"@babel/preset-react": "^7.12.1", | ||
"@jest/test-utils": "^29.5.0", | ||
"@tsd/typescript": "^4.9.0", | ||
"@jest/test-utils": "^29.6.0", | ||
"@tsd/typescript": "^5.0.4", | ||
"@types/babel__core": "^7.1.14", | ||
@@ -58,3 +56,3 @@ "@types/graceful-fs": "^4.1.3", | ||
"prettier": "^2.1.1", | ||
"tsd-lite": "^0.6.0" | ||
"tsd-lite": "^0.7.0" | ||
}, | ||
@@ -67,3 +65,3 @@ "engines": { | ||
}, | ||
"gitHead": "39f3beda6b396665bebffab94e8d7c45be30454c" | ||
"gitHead": "c1e5b8a38ef54bb138409f89831942ebf6a7a67e" | ||
} |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
83078
21
2474
5
- Removed@babel/traverse@^7.7.2
- Removed@types/babel__traverse@^7.0.6
- Removed@types/babel__traverse@7.20.5(transitive)
Updated@jest/expect-utils@^29.6.0
Updated@jest/transform@^29.6.0
Updated@jest/types@^29.6.0
Updatedexpect@^29.6.0
Updatedjest-diff@^29.6.0
Updatedjest-matcher-utils@^29.6.0
Updatedjest-message-util@^29.6.0
Updatedjest-util@^29.6.0
Updatedpretty-format@^29.6.0
Updatedsemver@^7.5.3