Skip to content

Commit 4e4d317

Browse files
committed
refactor: migrate no-wait-for-snapshot to v4
1 parent 6f506ee commit 4e4d317

File tree

2 files changed

+97
-103
lines changed

2 files changed

+97
-103
lines changed

lib/rules/no-wait-for-snapshot.ts

+33-95
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { ESLintUtils, TSESTree } from '@typescript-eslint/experimental-utils';
2-
import { getDocsUrl, ASYNC_UTILS, LIBRARY_MODULES } from '../utils';
1+
import { ASTUtils, TSESTree } from '@typescript-eslint/experimental-utils';
2+
import { createTestingLibraryRule } from '../create-testing-library-rule';
3+
import { ASYNC_UTILS } from '../utils';
34
import {
45
findClosestCallExpressionNode,
56
isMemberExpression,
@@ -9,10 +10,9 @@ export const RULE_NAME = 'no-wait-for-snapshot';
910
export type MessageIds = 'noWaitForSnapshot';
1011
type Options = [];
1112

12-
const ASYNC_UTILS_REGEXP = new RegExp(`^(${ASYNC_UTILS.join('|')})$`);
1313
const SNAPSHOT_REGEXP = /^(toMatchSnapshot|toMatchInlineSnapshot)$/;
1414

15-
export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
15+
export default createTestingLibraryRule<Options, MessageIds>({
1616
name: RULE_NAME,
1717
meta: {
1818
type: 'problem',
@@ -31,102 +31,40 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
3131
},
3232
defaultOptions: [],
3333

34-
create(context) {
35-
const asyncUtilsUsage: Array<{
36-
node: TSESTree.Identifier | TSESTree.MemberExpression;
37-
name: string;
38-
}> = [];
39-
const importedAsyncUtils: string[] = [];
40-
const snapshotUsage: TSESTree.Identifier[] = [];
41-
42-
return {
43-
'ImportDeclaration > ImportSpecifier,ImportNamespaceSpecifier'(
44-
node: TSESTree.Node
45-
) {
46-
const parent = node.parent as TSESTree.ImportDeclaration;
47-
48-
if (!LIBRARY_MODULES.includes(parent.source.value.toString())) {
49-
return;
50-
}
51-
52-
let name;
53-
if (node.type === 'ImportSpecifier') {
54-
name = node.imported.name;
34+
create(context, _, helpers) {
35+
function getClosestAsyncUtil(node: TSESTree.Node) {
36+
let n = node;
37+
do {
38+
const callExpression = findClosestCallExpressionNode(n);
39+
if (
40+
ASTUtils.isIdentifier(callExpression.callee) &&
41+
helpers.isNodeComingFromTestingLibrary(callExpression.callee) &&
42+
ASYNC_UTILS.includes(callExpression.callee.name)
43+
) {
44+
return callExpression.callee;
5545
}
56-
57-
if (node.type === 'ImportNamespaceSpecifier') {
58-
name = node.local.name;
46+
if (
47+
isMemberExpression(callExpression.callee) &&
48+
ASTUtils.isIdentifier(callExpression.callee.property) &&
49+
helpers.isNodeComingFromTestingLibrary(callExpression.callee)
50+
) {
51+
return callExpression.callee.property;
5952
}
53+
n = findClosestCallExpressionNode(callExpression.parent);
54+
} while (n !== null);
55+
return null;
56+
}
6057

61-
importedAsyncUtils.push(name);
62-
},
63-
[`CallExpression > Identifier[name=${ASYNC_UTILS_REGEXP}]`](
64-
node: TSESTree.Identifier
65-
) {
66-
asyncUtilsUsage.push({ node, name: node.name });
67-
},
68-
[`CallExpression > MemberExpression > Identifier[name=${ASYNC_UTILS_REGEXP}]`](
69-
node: TSESTree.Identifier
70-
) {
71-
const memberExpression = node.parent as TSESTree.MemberExpression;
72-
const identifier = memberExpression.object as TSESTree.Identifier;
73-
const memberExpressionName = identifier.name;
74-
75-
asyncUtilsUsage.push({
76-
node: memberExpression,
77-
name: memberExpressionName,
78-
});
79-
},
58+
return {
8059
[`Identifier[name=${SNAPSHOT_REGEXP}]`](node: TSESTree.Identifier) {
81-
snapshotUsage.push(node);
82-
},
83-
'Program:exit'() {
84-
const testingLibraryUtilUsage = asyncUtilsUsage.filter((usage) => {
85-
if (isMemberExpression(usage.node)) {
86-
const object = usage.node.object as TSESTree.Identifier;
87-
88-
return importedAsyncUtils.includes(object.name);
89-
}
90-
91-
return importedAsyncUtils.includes(usage.name);
92-
});
93-
94-
function getClosestAsyncUtil(
95-
asyncUtilUsage: {
96-
node: TSESTree.Identifier | TSESTree.MemberExpression;
97-
name: string;
98-
},
99-
node: TSESTree.Node
100-
) {
101-
let callExpression = findClosestCallExpressionNode(node);
102-
while (callExpression != null) {
103-
if (callExpression.callee === asyncUtilUsage.node)
104-
return asyncUtilUsage;
105-
callExpression = findClosestCallExpressionNode(
106-
callExpression.parent
107-
);
108-
}
109-
return null;
60+
const closestAsyncUtil = getClosestAsyncUtil(node);
61+
if (closestAsyncUtil === null) {
62+
return;
11063
}
111-
112-
snapshotUsage.forEach((node) => {
113-
testingLibraryUtilUsage.forEach((asyncUtilUsage) => {
114-
const closestAsyncUtil = getClosestAsyncUtil(asyncUtilUsage, node);
115-
if (closestAsyncUtil != null) {
116-
let name;
117-
if (isMemberExpression(closestAsyncUtil.node)) {
118-
name = (closestAsyncUtil.node.property as TSESTree.Identifier)
119-
.name;
120-
} else {
121-
name = closestAsyncUtil.name;
122-
}
123-
context.report({
124-
node,
125-
messageId: 'noWaitForSnapshot',
126-
data: { name },
127-
});
128-
}
129-
});
64+
context.report({
65+
node,
66+
messageId: 'noWaitForSnapshot',
67+
data: { name: closestAsyncUtil.name },
13068
});
13169
},
13270
};

tests/lib/rules/no-wait-for-snapshot.test.ts

+64-8
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,14 @@ ruleTester.run(RULE_NAME, rule, {
131131
await ${asyncUtil}(() => expect(foo).toMatchSnapshot());
132132
});
133133
`,
134-
errors: [{ line: 4, messageId: 'noWaitForSnapshot' }],
134+
errors: [
135+
{
136+
line: 4,
137+
messageId: 'noWaitForSnapshot',
138+
data: { name: asyncUtil },
139+
column: 36 + asyncUtil.length,
140+
},
141+
],
135142
})),
136143
...ASYNC_UTILS.map((asyncUtil) => ({
137144
code: `
@@ -142,7 +149,14 @@ ruleTester.run(RULE_NAME, rule, {
142149
});
143150
});
144151
`,
145-
errors: [{ line: 5, messageId: 'noWaitForSnapshot' }],
152+
errors: [
153+
{
154+
line: 5,
155+
messageId: 'noWaitForSnapshot',
156+
data: { name: asyncUtil },
157+
column: 27,
158+
},
159+
],
146160
})),
147161
...ASYNC_UTILS.map((asyncUtil) => ({
148162
code: `
@@ -151,7 +165,14 @@ ruleTester.run(RULE_NAME, rule, {
151165
await asyncUtils.${asyncUtil}(() => expect(foo).toMatchSnapshot());
152166
});
153167
`,
154-
errors: [{ line: 4, messageId: 'noWaitForSnapshot' }],
168+
errors: [
169+
{
170+
line: 4,
171+
messageId: 'noWaitForSnapshot',
172+
data: { name: asyncUtil },
173+
column: 47 + asyncUtil.length,
174+
},
175+
],
155176
})),
156177
...ASYNC_UTILS.map((asyncUtil) => ({
157178
code: `
@@ -162,7 +183,14 @@ ruleTester.run(RULE_NAME, rule, {
162183
});
163184
});
164185
`,
165-
errors: [{ line: 5, messageId: 'noWaitForSnapshot' }],
186+
errors: [
187+
{
188+
line: 5,
189+
messageId: 'noWaitForSnapshot',
190+
data: { name: asyncUtil },
191+
column: 27,
192+
},
193+
],
166194
})),
167195
...ASYNC_UTILS.map((asyncUtil) => ({
168196
code: `
@@ -171,7 +199,14 @@ ruleTester.run(RULE_NAME, rule, {
171199
await ${asyncUtil}(() => expect(foo).toMatchInlineSnapshot());
172200
});
173201
`,
174-
errors: [{ line: 4, messageId: 'noWaitForSnapshot' }],
202+
errors: [
203+
{
204+
line: 4,
205+
messageId: 'noWaitForSnapshot',
206+
data: { name: asyncUtil },
207+
column: 36 + asyncUtil.length,
208+
},
209+
],
175210
})),
176211
...ASYNC_UTILS.map((asyncUtil) => ({
177212
code: `
@@ -182,7 +217,14 @@ ruleTester.run(RULE_NAME, rule, {
182217
});
183218
});
184219
`,
185-
errors: [{ line: 5, messageId: 'noWaitForSnapshot' }],
220+
errors: [
221+
{
222+
line: 5,
223+
messageId: 'noWaitForSnapshot',
224+
data: { name: asyncUtil },
225+
column: 27,
226+
},
227+
],
186228
})),
187229
...ASYNC_UTILS.map((asyncUtil) => ({
188230
code: `
@@ -191,7 +233,14 @@ ruleTester.run(RULE_NAME, rule, {
191233
await asyncUtils.${asyncUtil}(() => expect(foo).toMatchInlineSnapshot());
192234
});
193235
`,
194-
errors: [{ line: 4, messageId: 'noWaitForSnapshot' }],
236+
errors: [
237+
{
238+
line: 4,
239+
messageId: 'noWaitForSnapshot',
240+
data: { name: asyncUtil },
241+
column: 47 + asyncUtil.length,
242+
},
243+
],
195244
})),
196245
...ASYNC_UTILS.map((asyncUtil) => ({
197246
code: `
@@ -202,7 +251,14 @@ ruleTester.run(RULE_NAME, rule, {
202251
});
203252
});
204253
`,
205-
errors: [{ line: 5, messageId: 'noWaitForSnapshot' }],
254+
errors: [
255+
{
256+
line: 5,
257+
messageId: 'noWaitForSnapshot',
258+
data: { name: asyncUtil },
259+
column: 27,
260+
},
261+
],
206262
})),
207263
],
208264
});

0 commit comments

Comments
 (0)