Skip to content

Commit

Permalink
feat(no-large-snapshots): deprecate whitelistedSnapshots for new na…
Browse files Browse the repository at this point in the history
…me (#632)
  • Loading branch information
G-Rath committed Jul 30, 2020
1 parent 4cb1e88 commit 706f5c2
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 64 deletions.
8 changes: 4 additions & 4 deletions docs/rules/no-large-snapshots.md
Expand Up @@ -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
Expand All @@ -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+/],
},
},
Expand All @@ -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'],
},
Expand Down
117 changes: 67 additions & 50 deletions 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: {
Expand Down Expand Up @@ -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'],
},
},
Expand Down Expand Up @@ -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],
},
},
Expand All @@ -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',
Expand All @@ -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'),
Expand All @@ -242,47 +275,31 @@ ruleTester.run('no-large-snapshots', rule, {
});

describe('no-large-snapshots', () => {
const buildBaseNode = <Type extends AST_NODE_TYPES>(
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`',
);
});
});
Expand Down
33 changes: 23 additions & 10 deletions src/rules/no-large-snapshots.ts
Expand Up @@ -14,6 +14,7 @@ import {
interface RuleOptions {
maxSize?: number;
inlineMaxSize?: number;
allowedSnapshots?: Record<string, Array<string | RegExp>>;
whitelistedSnapshots?: Record<string, Array<string | RegExp>>;
}

Expand All @@ -24,36 +25,38 @@ type RuleContext = TSESLint.RuleContext<MessageId, [RuleOptions]>;
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 &&
'left' in node.expression &&
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);
}
Expand All @@ -63,7 +66,7 @@ const reportOnViolation = (
}
}

if (!isWhitelisted && lineCount > lineLimit) {
if (!isAllowed && lineCount > lineLimit) {
context.report({
messageId: lineLimit === 0 ? 'noSnapshot' : 'tooLongSnapshots',
data: { lineLimit, lineCount },
Expand Down Expand Up @@ -96,6 +99,10 @@ export default createRule<[RuleOptions], MessageId>({
inlineMaxSize: {
type: 'number',
},
allowedSnapshots: {
type: 'object',
additionalProperties: { type: 'array' },
},
whitelistedSnapshots: {
type: 'object',
patternProperties: {
Expand All @@ -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) {
Expand Down

0 comments on commit 706f5c2

Please sign in to comment.