diff --git a/docs/rules/no-large-snapshots.md b/docs/rules/no-large-snapshots.md index a83aefec9..d2b4e5ea9 100644 --- a/docs/rules/no-large-snapshots.md +++ b/docs/rules/no-large-snapshots.md @@ -122,8 +122,8 @@ If only `maxSize` is provided on options, the value of `maxSize` will be used to both snapshot types (Inline and External). Since `eslint-disable` comments are not preserved by Jest when updating -snapshots, you can use the `whitelistedSnapshots` option to have specific -snapshots allowed regardless of their size. +snapshots, you can use the `allowedSnapshots` option to have specific snapshots +allowed regardless of their size. This option takes a map, with the key being the absolute filepath to a snapshot file, and the value an array of values made up of strings and regular @@ -141,7 +141,7 @@ module.exports = { 'jest/no-large-snapshots': [ 'error', { - whitelistedSnapshots: { + allowedSnapshots: { '/path/to/file.js.snap': ['snapshot name 1', /a big snapshot \d+/], }, }, @@ -161,7 +161,7 @@ module.exports = { 'jest/no-large-snapshots': [ 'error', { - whitelistedSnapshots: { + allowedSnapshots: { [path.resolve('test/__snapshots__/get.js.snap')]: ['full request'], [path.resolve('test/__snapshots__/put.js.snap')]: ['full request'], }, diff --git a/src/rules/__tests__/no-large-snapshots.test.ts b/src/rules/__tests__/no-large-snapshots.test.ts index d26ecdaab..d939a9075 100644 --- a/src/rules/__tests__/no-large-snapshots.test.ts +++ b/src/rules/__tests__/no-large-snapshots.test.ts @@ -1,13 +1,7 @@ -import { - AST_NODE_TYPES, - TSESLint, - TSESTree, -} from '@typescript-eslint/experimental-utils'; +import { TSESLint } from '@typescript-eslint/experimental-utils'; import resolveFrom from 'resolve-from'; import rule from '../no-large-snapshots'; -const noLargeSnapshots = rule.create.bind(rule); - const ruleTester = new TSESLint.RuleTester({ parser: resolveFrom(require.resolve('eslint'), 'espree'), parserOptions: { @@ -71,12 +65,12 @@ ruleTester.run('no-large-snapshots', rule, { code: generateExportsSnapshotString(20), }, { - // "it should not report whitelisted large snapshots" + // "it should not report snapshots that are allowed to be large" filename: '/mock-component.jsx.snap', code: generateExportsSnapshotString(58), options: [ { - whitelistedSnapshots: { + allowedSnapshots: { '/mock-component.jsx.snap': ['a big component 1'], }, }, @@ -178,13 +172,12 @@ ruleTester.run('no-large-snapshots', rule, { ], }, { - // "it should report if file is not whitelisted" + // "it should report if file is not allowed" filename: '/mock-component.jsx.snap', - // code: generateExportsSnapshotString(58), code: generateExportsSnapshotString(58), options: [ { - whitelistedSnapshots: { + allowedSnapshots: { '/another-mock-component.jsx.snap': [/a big component \d+/u], }, }, @@ -196,6 +189,27 @@ ruleTester.run('no-large-snapshots', rule, { }, ], }, + { + // "should not report allowed large snapshots based on regexp" + filename: '/mock-component.jsx.snap', + code: [ + generateExportsSnapshotString(58, 'a big component w/ text'), + generateExportsSnapshotString(58, 'a big component 2'), + ].join('\n\n'), + options: [ + { + allowedSnapshots: { + '/mock-component.jsx.snap': [/a big component \d+/u], + }, + }, + ], + errors: [ + { + messageId: 'tooLongSnapshots', + data: { lineLimit: 50, lineCount: 58 }, + }, + ], + }, { // "should not report whitelisted large snapshots based on regexp" filename: '/mock-component.jsx.snap', @@ -218,7 +232,26 @@ ruleTester.run('no-large-snapshots', rule, { ], }, { - // "should not report whitelisted large snapshots based on regexp" + filename: '/mock-component.jsx.snap', + code: [ + generateExportsSnapshotString(58, 'a big component w/ text'), + generateExportsSnapshotString(58, 'a big component 2'), + ].join('\n\n'), + options: [ + { + allowedSnapshots: { + '/mock-component.jsx.snap': ['a big component 2'], + }, + }, + ], + errors: [ + { + messageId: 'tooLongSnapshots', + data: { lineLimit: 50, lineCount: 58 }, + }, + ], + }, + { filename: '/mock-component.jsx.snap', code: [ generateExportsSnapshotString(58, 'a big component w/ text'), @@ -242,47 +275,31 @@ ruleTester.run('no-large-snapshots', rule, { }); describe('no-large-snapshots', () => { - const buildBaseNode = ( - type: Type, - ): TSESTree.BaseNode & { type: Type } => ({ - type, - range: [0, 1], - loc: { - start: { line: 1, column: 0 }, - end: { line: 1, column: 1 }, - }, - }); - - describe('when "whitelistedSnapshots" option contains relative paths', () => { + describe('when "allowedSnapshots" option contains relative paths', () => { it('should throw an exception', () => { - const { ExpressionStatement = () => {} } = noLargeSnapshots({ - id: 'my-id', - getFilename: () => '/mock-component.jsx.snap', - options: [ + expect(() => { + const linter = new TSESLint.Linter(); + + linter.defineRule('no-large-snapshots', rule); + + linter.verify( + 'console.log()', { - whitelistedSnapshots: { - 'mock-component.jsx.snap': [/a big component \d+/u], + rules: { + 'no-large-snapshots': [ + 'error', + { + allowedSnapshots: { + 'mock-component.jsx.snap': [/a big component \d+/u], + }, + }, + ], }, }, - ], - parserOptions: {}, - parserPath: '', - settings: {}, - getAncestors: () => [], - getDeclaredVariables: () => [], - getScope: jest.fn(), - getSourceCode: jest.fn(), - markVariableAsUsed: () => false, - report: jest.fn(), - }); - - expect(() => - ExpressionStatement({ - ...buildBaseNode(AST_NODE_TYPES.ExpressionStatement), - expression: buildBaseNode(AST_NODE_TYPES.JSXClosingFragment), - }), - ).toThrow( - 'All paths for whitelistedSnapshots must be absolute. You can use JS config and `path.resolve`', + 'mock-component.jsx.snap', + ); + }).toThrow( + 'All paths for allowedSnapshots must be absolute. You can use JS config and `path.resolve`', ); }); }); diff --git a/src/rules/no-large-snapshots.ts b/src/rules/no-large-snapshots.ts index 914e5bfba..33dba29e6 100644 --- a/src/rules/no-large-snapshots.ts +++ b/src/rules/no-large-snapshots.ts @@ -14,6 +14,7 @@ import { interface RuleOptions { maxSize?: number; inlineMaxSize?: number; + allowedSnapshots?: Record>; whitelistedSnapshots?: Record>; } @@ -24,23 +25,25 @@ type RuleContext = TSESLint.RuleContext; const reportOnViolation = ( context: RuleContext, node: TSESTree.CallExpression | TSESTree.ExpressionStatement, - { maxSize: lineLimit = 50, whitelistedSnapshots = {} }: RuleOptions, + { + maxSize: lineLimit = 50, + whitelistedSnapshots = {}, + allowedSnapshots = whitelistedSnapshots, + }: RuleOptions, ) => { const startLine = node.loc.start.line; const endLine = node.loc.end.line; const lineCount = endLine - startLine; - const allPathsAreAbsolute = Object.keys(whitelistedSnapshots).every( - isAbsolute, - ); + const allPathsAreAbsolute = Object.keys(allowedSnapshots).every(isAbsolute); if (!allPathsAreAbsolute) { throw new Error( - 'All paths for whitelistedSnapshots must be absolute. You can use JS config and `path.resolve`', + 'All paths for allowedSnapshots must be absolute. You can use JS config and `path.resolve`', ); } - let isWhitelisted = false; + let isAllowed = false; if ( node.type === AST_NODE_TYPES.ExpressionStatement && @@ -48,12 +51,12 @@ const reportOnViolation = ( isExpectMember(node.expression.left) ) { const fileName = context.getFilename(); - const whitelistedSnapshotsInFile = whitelistedSnapshots[fileName]; + const allowedSnapshotsInFile = allowedSnapshots[fileName]; - if (whitelistedSnapshotsInFile) { + if (allowedSnapshotsInFile) { const snapshotName = getAccessorValue(node.expression.left.property); - isWhitelisted = whitelistedSnapshotsInFile.some(name => { + isAllowed = allowedSnapshotsInFile.some(name => { if (name instanceof RegExp) { return name.test(snapshotName); } @@ -63,7 +66,7 @@ const reportOnViolation = ( } } - if (!isWhitelisted && lineCount > lineLimit) { + if (!isAllowed && lineCount > lineLimit) { context.report({ messageId: lineLimit === 0 ? 'noSnapshot' : 'tooLongSnapshots', data: { lineLimit, lineCount }, @@ -96,6 +99,10 @@ export default createRule<[RuleOptions], MessageId>({ inlineMaxSize: { type: 'number', }, + allowedSnapshots: { + type: 'object', + additionalProperties: { type: 'array' }, + }, whitelistedSnapshots: { type: 'object', patternProperties: { @@ -109,6 +116,12 @@ export default createRule<[RuleOptions], MessageId>({ }, defaultOptions: [{}], create(context, [options]) { + if ('whitelistedSnapshots' in options) { + console.warn( + 'jest/no-large-snapshots: the "whitelistedSnapshots" option has been renamed to "allowedSnapshots"', + ); + } + if (context.getFilename().endsWith('.snap')) { return { ExpressionStatement(node) {