Skip to content

Commit

Permalink
feat(rules): add no-interpolation-inline-snapshot rule
Browse files Browse the repository at this point in the history
  • Loading branch information
viestat committed Apr 2, 2020
1 parent f6e0bd0 commit 118351c
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 1 deletion.
54 changes: 54 additions & 0 deletions docs/rules/no-interpolation-inline-snapshot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# No string interpolation inside inline snapshots (no-interpolation-inline-snapshot)

Prevents the use of string interpolations within `toMatchInlineSnapshot`.

## Rule Details

Interpolation prevents snapshots from being updated. Instead, properties should
be overloaded with a matcher by passing the optional `propertyMatchers` argument
to `toMatchInlineSnapshot`.

Examples of **incorrect** code for this rule:

```js
expect(something).toMatchInlineSnapshot(
`Object {
property: ${interpolated}
}`,
);

expect(something).toMatchInlineSnapshot(
{ other: expect.any(Number) },
`Object {
other: Any<Number>,
property: ${interpolated}
}`,
);
```

Examples of **correct** code for this rule:

```js
expect(something).toMatchInlineSnapshot();

expect(something).toMatchInlineSnapshot(
`Object {
property: 1
}`,
);

expect(something).toMatchInlineSnapshot(
{ property: expect.any(Date) },
`Object {
property: Any<Date>
}`,
);
```

\*Note that this rule will not trigger if the helper function is never used even
thought the `expect` will not execute. Rely on a rule like no-unused-vars for
this case.

## When Not To Use It

Don't use this rule on non-jest test files.
1 change: 1 addition & 0 deletions src/__tests__/__snapshots__/rules.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Object {
"jest/no-hooks": "error",
"jest/no-identical-title": "error",
"jest/no-if": "error",
"jest/no-interpolation-inline-snapshot": "error",
"jest/no-jasmine-globals": "error",
"jest/no-jest-import": "error",
"jest/no-large-snapshots": "error",
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/rules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { resolve } from 'path';
import plugin from '../';

const ruleNames = Object.keys(plugin.rules);
const numberOfRules = 40;
const numberOfRules = 41;

describe('rules', () => {
it('should have a corresponding doc for each rule', () => {
Expand Down
40 changes: 40 additions & 0 deletions src/rules/__tests__/no-interpolation-inline-snapshot.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { TSESLint } from '@typescript-eslint/experimental-utils';
import resolveFrom from 'resolve-from';
import rule from '../no-interpolation-inline-snapshot';

const ruleTester = new TSESLint.RuleTester({
parser: resolveFrom(require.resolve('eslint'), 'espree'),
parserOptions: {
ecmaVersion: 2017,
},
});

ruleTester.run('no-interpolation-inline-snapshot', rule, {
valid: [
'expect(something).toMatchInlineSnapshot();',
'expect(something).toMatchInlineSnapshot(`No interpolation`);',
'expect(something).toMatchInlineSnapshot({}, `No interpolation`);',
],
invalid: [
{
code: 'expect(something).toMatchInlineSnapshot(`${interpolated}`);',
errors: [
{
endColumn: 58,
column: 41,
messageId: 'noInterpolation',
},
],
},
{
code: 'expect(something).toMatchInlineSnapshot({}, `${interpolated}`);',
errors: [
{
endColumn: 62,
column: 45,
messageId: 'noInterpolation',
},
],
},
],
});
48 changes: 48 additions & 0 deletions src/rules/no-interpolation-inline-snapshot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils';
import { createRule } from './utils';

export default createRule({
name: __filename,
meta: {
docs: {
category: 'Best Practices',
description: 'Disallow string interpolation inside inline snapshots.',
recommended: false,
},
messages: {
noInterpolation:
'Do not use string interpolation inside of inline snapshots',
},
schema: [],
type: 'suggestion',
},
defaultOptions: [],
create(context) {
return {
CallExpression(node) {
const { callee, arguments: nodeArguments } = node;

if (
callee.type !== AST_NODE_TYPES.MemberExpression ||
callee.property.type !== AST_NODE_TYPES.Identifier ||
callee.property.name !== 'toMatchInlineSnapshot'
) {
return;
}

// Check all since the optional 'propertyMatchers' argument might be present
nodeArguments.forEach(argument => {
if (
argument.type === AST_NODE_TYPES.TemplateLiteral &&
argument.expressions.length > 0
) {
context.report({
messageId: 'noInterpolation',
node: argument,
});
}
});
},
};
},
});

0 comments on commit 118351c

Please sign in to comment.