Skip to content

Commit 035fbe0

Browse files
authored
Update internal rule fix-snapshot-test (#2121)
1 parent 80df427 commit 035fbe0

File tree

1 file changed

+120
-87
lines changed

1 file changed

+120
-87
lines changed

scripts/internal-rules/fix-snapshot-test.js

Lines changed: 120 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const assert = require('node:assert');
33
const {
44
isCommaToken,
55
} = require('@eslint-community/eslint-utils');
6-
const {methodCallSelector} = require('../../rules/selectors/index.js');
6+
const {isMethodCall} = require('../../rules/ast/index.js');
77

88
const MESSAGE_ID_DISALLOWED_PROPERTY = 'disallow-property';
99
const MESSAGE_ID_NO_SINGLE_CODE_OBJECT = 'use-string';
@@ -15,38 +15,19 @@ const messages = {
1515
};
1616

1717
// Top-level `test.snapshot({invalid: []})`
18-
const snapshotTestCallSelector = [
19-
'Program > ExpressionStatement.body > .expression',
18+
const isTestSnapshot = node =>
2019
// `test.snapshot()`
21-
methodCallSelector({
20+
isMethodCall(node, {
2221
argumentsLength: 1,
2322
object: 'test',
2423
method: 'snapshot',
25-
}),
26-
].join('');
27-
28-
const propertySelector = [
29-
snapshotTestCallSelector,
30-
' > ObjectExpression.arguments:first-child',
31-
/*
32-
```
33-
test.snapshot({
34-
invalid: [], <- Property
24+
optionalCall: false,
25+
optionalMember: false,
3526
})
36-
```
37-
*/
38-
' > Property.properties',
39-
'[computed!=true]',
40-
'[method!=true]',
41-
'[shorthand!=true]',
42-
'[kind="init"]',
43-
'[key.type="Identifier"]',
44-
'[key.name="invalid"]',
45-
46-
' > ArrayExpression.value',
47-
' > ObjectExpression.elements',
48-
' > Property.properties[computed!=true][key.type="Identifier"]',
49-
].join('');
27+
&& node.parent.type === 'ExpressionStatement'
28+
&& node.parent.expression === node
29+
&& node.parent.parent.type === 'Program'
30+
&& node.parent.parent.body.includes(node.parent);
5031

5132
function * removeObjectProperty(node, fixer, sourceCode) {
5233
yield fixer.remove(node);
@@ -73,71 +54,123 @@ function getFixMarkComment(snapshotTestCall, sourceCode) {
7354
}
7455
}
7556

76-
module.exports = {
77-
create(context) {
78-
const {sourceCode} = context;
57+
function checkFixMark(node, context) {
58+
const comment = getFixMarkComment(node, context.sourceCode);
7959

80-
return {
81-
[snapshotTestCallSelector](snapshotTestCall) {
82-
const comment = getFixMarkComment(snapshotTestCall, sourceCode);
60+
if (!comment) {
61+
return;
62+
}
8363

84-
if (!comment) {
85-
return;
86-
}
64+
context.report({
65+
node: comment,
66+
messageId: MESSAGE_ID_REMOVE_FIX_MARK_COMMENT,
67+
});
68+
}
69+
70+
function checkInvalidCases(node, context) {
71+
const testCasesNode = node.arguments[0];
72+
if (testCasesNode?.type !== 'ObjectExpression') {
73+
return;
74+
}
8775

76+
/*
77+
```
78+
test.snapshot({
79+
invalid: [], <- Property
80+
})
81+
```
82+
*/
83+
const invalidCasesNode = testCasesNode.properties.find(node =>
84+
node.type === 'Property'
85+
&& !node.computed
86+
&& !node.method
87+
&& !node.shorthand
88+
&& node.kind === 'init'
89+
&& node.key.type === 'Identifier'
90+
&& node.key.name === 'invalid'
91+
&& node.value.type === 'ArrayExpression',
92+
);
93+
94+
if (!invalidCasesNode) {
95+
return;
96+
}
97+
98+
for (const testCaseNode of invalidCasesNode.value.elements) {
99+
if (testCaseNode?.type !== 'ObjectExpression') {
100+
continue;
101+
}
102+
103+
for (const propertyNode of testCaseNode.properties) {
104+
if (propertyNode.computed || propertyNode.key.type !== 'Identifier') {
105+
continue;
106+
}
107+
108+
checkTestCaseProperty(propertyNode, context);
109+
}
110+
}
111+
}
112+
113+
function checkTestCaseProperty(propertyNode, context) {
114+
const {key} = propertyNode;
115+
const {sourceCode} = context;
116+
117+
switch (key.name) {
118+
case 'errors':
119+
case 'output': {
120+
const canFix = sourceCode.getCommentsInside(propertyNode).length === 0;
121+
const hasFixMark = Boolean(getFixMarkComment(
122+
propertyNode.parent.parent.parent.parent.parent,
123+
sourceCode,
124+
));
125+
126+
context.report({
127+
node: key,
128+
messageId: MESSAGE_ID_DISALLOWED_PROPERTY,
129+
data: {
130+
name: key.name,
131+
autoFixEnableTip: !hasFixMark && canFix
132+
? ' Put /* fix */ before `test.snapshot()` to enable auto-fix.'
133+
: '',
134+
},
135+
fix: hasFixMark && canFix
136+
? fixer => removeObjectProperty(propertyNode, fixer, sourceCode)
137+
: undefined
138+
,
139+
});
140+
break;
141+
}
142+
143+
case 'code': {
144+
const testCase = propertyNode.parent;
145+
if (testCase.properties.length === 1) {
146+
const commentsCount = sourceCode.getCommentsInside(testCase).length
147+
- sourceCode.getCommentsInside(propertyNode).length;
88148
context.report({
89-
node: comment,
90-
messageId: MESSAGE_ID_REMOVE_FIX_MARK_COMMENT,
149+
node: testCase,
150+
messageId: MESSAGE_ID_NO_SINGLE_CODE_OBJECT,
151+
fix: commentsCount === 0
152+
? fixer => fixer.replaceText(testCase, sourceCode.getText(propertyNode.value))
153+
: undefined,
91154
});
92-
},
93-
[propertySelector](propertyNode) {
94-
const {key} = propertyNode;
95-
96-
switch (key.name) {
97-
case 'errors':
98-
case 'output': {
99-
const canFix = sourceCode.getCommentsInside(propertyNode).length === 0;
100-
const hasFixMark = Boolean(getFixMarkComment(
101-
propertyNode.parent.parent.parent.parent.parent,
102-
sourceCode,
103-
));
104-
105-
context.report({
106-
node: key,
107-
messageId: MESSAGE_ID_DISALLOWED_PROPERTY,
108-
data: {
109-
name: key.name,
110-
autoFixEnableTip: !hasFixMark && canFix
111-
? ' Put /* fix */ before `test.snapshot()` to enable auto-fix.'
112-
: '',
113-
},
114-
fix: hasFixMark && canFix
115-
? fixer => removeObjectProperty(propertyNode, fixer, sourceCode)
116-
: undefined
117-
,
118-
});
119-
break;
120-
}
121-
122-
case 'code': {
123-
const testCase = propertyNode.parent;
124-
if (testCase.properties.length === 1) {
125-
const commentsCount = sourceCode.getCommentsInside(testCase).length
126-
- sourceCode.getCommentsInside(propertyNode).length;
127-
context.report({
128-
node: testCase,
129-
messageId: MESSAGE_ID_NO_SINGLE_CODE_OBJECT,
130-
fix: commentsCount === 0
131-
? fixer => fixer.replaceText(testCase, sourceCode.getText(propertyNode.value))
132-
: undefined,
133-
});
134-
}
135-
136-
break;
137-
}
138-
139-
// No default
155+
}
156+
157+
break;
158+
}
159+
160+
// No default
161+
}
162+
}
163+
164+
module.exports = {
165+
create(context) {
166+
return {
167+
CallExpression(snapshotTestCall) {
168+
if (!isTestSnapshot(snapshotTestCall)) {
169+
return;
140170
}
171+
172+
checkFixMark(snapshotTestCall, context);
173+
checkInvalidCases(snapshotTestCall, context);
141174
},
142175
};
143176
},

0 commit comments

Comments
 (0)