eslint-plugin-playwright 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.cjs +329 -123
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ESLint Plugin Playwright
|
|
2
2
|
|
|
3
|
-
[](https://github.com/mskelton/eslint-plugin-playwright/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/eslint-plugin-playwright)
|
|
5
5
|
[](https://github.com/semantic-release/semantic-release)
|
|
6
6
|
|
|
@@ -79,8 +79,8 @@ can configure this plugin to be aware of these additional names.
|
|
|
79
79
|
"settings": {
|
|
80
80
|
"playwright": {
|
|
81
81
|
"globalAliases": {
|
|
82
|
-
"test": ["
|
|
83
|
-
"expect": ["
|
|
82
|
+
"test": ["it"],
|
|
83
|
+
"expect": ["assert"]
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -118,27 +118,55 @@ var Chain = class {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
};
|
|
121
|
-
|
|
121
|
+
function resolvePossibleAliasedGlobal(context, name) {
|
|
122
122
|
const settings = context.settings;
|
|
123
123
|
const globalAliases = settings?.playwright?.globalAliases ?? {};
|
|
124
|
-
const alias = Object.entries(globalAliases).find(([, aliases]) => aliases.includes(
|
|
124
|
+
const alias = Object.entries(globalAliases).find(([, aliases]) => aliases.includes(name));
|
|
125
125
|
return alias?.[0] ?? null;
|
|
126
|
-
}
|
|
126
|
+
}
|
|
127
|
+
function resolveImportAlias(context, node) {
|
|
128
|
+
if (node.type !== "Identifier") {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const scope = context.sourceCode.getScope(node);
|
|
132
|
+
const ref = scope.references.find((r) => r.identifier === node);
|
|
133
|
+
for (const def of ref?.resolved?.defs ?? []) {
|
|
134
|
+
if (def.type === "ImportBinding" && def.node.type === "ImportSpecifier") {
|
|
135
|
+
const imported = getStringValue(def.node.imported);
|
|
136
|
+
if (imported !== node.name) {
|
|
137
|
+
return imported;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
127
143
|
var resolveToPlaywrightFn = (context, accessor) => {
|
|
128
144
|
const ident = getStringValue(accessor);
|
|
129
145
|
const resolved = /(^expect|Expect)$/.test(ident) ? "expect" : ident;
|
|
146
|
+
if (resolved === "test" || resolved === "expect") {
|
|
147
|
+
return { original: null, local: resolved };
|
|
148
|
+
}
|
|
130
149
|
return {
|
|
131
|
-
|
|
132
|
-
original: resolvePossibleAliasedGlobal(context, resolved),
|
|
150
|
+
original: resolvePossibleAliasedGlobal(context, resolved) ?? resolveImportAlias(context, accessor),
|
|
133
151
|
local: resolved
|
|
134
152
|
};
|
|
135
153
|
};
|
|
136
154
|
function determinePlaywrightFnGroup(name) {
|
|
137
|
-
if (name === "step")
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (name === "
|
|
141
|
-
|
|
155
|
+
if (name === "step") {
|
|
156
|
+
return "step";
|
|
157
|
+
}
|
|
158
|
+
if (name === "expect") {
|
|
159
|
+
return "expect";
|
|
160
|
+
}
|
|
161
|
+
if (name === "describe") {
|
|
162
|
+
return "describe";
|
|
163
|
+
}
|
|
164
|
+
if (name === "test") {
|
|
165
|
+
return "test";
|
|
166
|
+
}
|
|
167
|
+
if (testHooks.has(name)) {
|
|
168
|
+
return "hook";
|
|
169
|
+
}
|
|
142
170
|
return "unknown";
|
|
143
171
|
}
|
|
144
172
|
var modifiers = /* @__PURE__ */ new Set(["not", "resolves", "rejects"]);
|
|
@@ -213,14 +241,43 @@ var findTopMostCallExpression = (node) => {
|
|
|
213
241
|
}
|
|
214
242
|
return top;
|
|
215
243
|
};
|
|
244
|
+
function isTestExtendCall(context, node) {
|
|
245
|
+
if (node.type !== "CallExpression" || node.callee.type !== "MemberExpression" || !isPropertyAccessor(node.callee, "extend")) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
const object = node.callee.object;
|
|
249
|
+
if (object.type === "Identifier") {
|
|
250
|
+
const resolved = resolveToPlaywrightFn(context, object);
|
|
251
|
+
if ((resolved?.original ?? resolved?.local) === "test") {
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
const dereferenced = dereference(context, object);
|
|
255
|
+
if (dereferenced) {
|
|
256
|
+
return isTestExtendCall(context, dereferenced);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
216
261
|
function parse(context, node) {
|
|
217
262
|
const chain = new Chain(node);
|
|
218
|
-
if (!chain.nodes?.length)
|
|
263
|
+
if (!chain.nodes?.length) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
219
266
|
const [first, ...rest] = chain.nodes;
|
|
220
|
-
|
|
221
|
-
if (!resolved)
|
|
267
|
+
let resolved = resolveToPlaywrightFn(context, first);
|
|
268
|
+
if (!resolved) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
222
271
|
let name = resolved.original ?? resolved.local;
|
|
223
272
|
const links = [name, ...rest.map((link) => getStringValue(link))];
|
|
273
|
+
if (determinePlaywrightFnGroup(name) === "unknown") {
|
|
274
|
+
const dereferenced = dereference(context, first);
|
|
275
|
+
if (dereferenced && isTestExtendCall(context, dereferenced)) {
|
|
276
|
+
name = "test";
|
|
277
|
+
links[0] = "test";
|
|
278
|
+
resolved = { local: resolved.local, original: "test" };
|
|
279
|
+
}
|
|
280
|
+
}
|
|
224
281
|
if (name === "test" && links.length > 1) {
|
|
225
282
|
const nextLinkName = links[1];
|
|
226
283
|
const nextLinkGroup = determinePlaywrightFnGroup(nextLinkName);
|
|
@@ -246,7 +303,9 @@ function parse(context, node) {
|
|
|
246
303
|
parsedFnCall.members.shift();
|
|
247
304
|
}
|
|
248
305
|
const result = parseExpectCall(chain, parsedFnCall, stage);
|
|
249
|
-
if (!result)
|
|
306
|
+
if (!result) {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
250
309
|
if (typeof result === "string" && findTopMostCallExpression(node) !== node) {
|
|
251
310
|
return null;
|
|
252
311
|
}
|
|
@@ -294,7 +353,9 @@ var isTypeOfFnCall = (context, node, types) => {
|
|
|
294
353
|
|
|
295
354
|
// src/utils/ast.ts
|
|
296
355
|
function getStringValue(node) {
|
|
297
|
-
if (!node)
|
|
356
|
+
if (!node) {
|
|
357
|
+
return "";
|
|
358
|
+
}
|
|
298
359
|
return node.type === "Identifier" ? node.name : node.type === "TemplateLiteral" ? node.quasis[0].value.raw : node.type === "Literal" && typeof node.value === "string" ? node.value : "";
|
|
299
360
|
}
|
|
300
361
|
function getRawValue(node) {
|
|
@@ -323,7 +384,9 @@ function isPropertyAccessor(node, name) {
|
|
|
323
384
|
}
|
|
324
385
|
function findParent(node, type) {
|
|
325
386
|
const parent = node.parent;
|
|
326
|
-
if (!parent)
|
|
387
|
+
if (!parent) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
327
390
|
return parent.type === type ? parent : findParent(parent, type);
|
|
328
391
|
}
|
|
329
392
|
function dig(node, identifier) {
|
|
@@ -394,6 +457,9 @@ var getPaddingLineSequences = (prevNode, nextNode, sourceCode) => {
|
|
|
394
457
|
return pairs;
|
|
395
458
|
};
|
|
396
459
|
var areTokensOnSameLine = (left, right) => left.loc.end.line === right.loc.start.line;
|
|
460
|
+
var isPromiseAccessor = (node) => {
|
|
461
|
+
return node.type === "MemberExpression" && isIdentifier(node.property, /^(then|catch|finally)$/);
|
|
462
|
+
};
|
|
397
463
|
|
|
398
464
|
// src/utils/createRule.ts
|
|
399
465
|
function interpolate(str, data) {
|
|
@@ -683,7 +749,7 @@ var max_expects_default = createRule({
|
|
|
683
749
|
"ArrowFunctionExpression:exit": maybeResetCount,
|
|
684
750
|
"CallExpression"(node) {
|
|
685
751
|
const call = parseFnCall(context, node);
|
|
686
|
-
if (call?.type !== "expect"
|
|
752
|
+
if (call?.type !== "expect") {
|
|
687
753
|
return;
|
|
688
754
|
}
|
|
689
755
|
count += 1;
|
|
@@ -872,26 +938,65 @@ var missing_playwright_await_default = createRule({
|
|
|
872
938
|
// Add any custom matchers to the set
|
|
873
939
|
...options.customMatchers || []
|
|
874
940
|
]);
|
|
941
|
+
function isVariableConsumed(declarator, checkValidity2, validTypes2, visited) {
|
|
942
|
+
const variables = context.sourceCode.getDeclaredVariables(declarator);
|
|
943
|
+
for (const variable of variables) {
|
|
944
|
+
for (const ref of variable.references) {
|
|
945
|
+
if (!ref.isRead()) {
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
const refParent = ref.identifier.parent;
|
|
949
|
+
if (visited.has(refParent)) {
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
if (validTypes2.has(refParent.type)) {
|
|
953
|
+
return true;
|
|
954
|
+
}
|
|
955
|
+
if (refParent.type === "VariableDeclarator") {
|
|
956
|
+
if (checkValidity2(ref.identifier, visited)) {
|
|
957
|
+
return true;
|
|
958
|
+
}
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
if (checkValidity2(refParent, visited)) {
|
|
962
|
+
return true;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
return false;
|
|
967
|
+
}
|
|
875
968
|
function checkValidity(node, visited) {
|
|
876
969
|
const parent = node.parent;
|
|
877
|
-
if (!parent)
|
|
878
|
-
|
|
970
|
+
if (!parent) {
|
|
971
|
+
return false;
|
|
972
|
+
}
|
|
973
|
+
if (visited.has(parent)) {
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
879
976
|
visited.add(parent);
|
|
880
|
-
if (validTypes.has(parent.type))
|
|
977
|
+
if (validTypes.has(parent.type)) {
|
|
978
|
+
return true;
|
|
979
|
+
}
|
|
980
|
+
if (isPromiseAccessor(parent) && parent.parent?.type === "CallExpression") {
|
|
981
|
+
return checkValidity(parent.parent, visited);
|
|
982
|
+
}
|
|
983
|
+
if (parent.type === "CallExpression" && parent.callee === node && isPromiseAccessor(node)) {
|
|
984
|
+
return checkValidity(parent, visited);
|
|
985
|
+
}
|
|
881
986
|
if (parent.type === "ArrayExpression") {
|
|
882
987
|
return checkValidity(parent, visited);
|
|
883
988
|
}
|
|
989
|
+
if (parent.type === "ConditionalExpression") {
|
|
990
|
+
return checkValidity(parent, visited);
|
|
991
|
+
}
|
|
992
|
+
if (parent.type === "SpreadElement") {
|
|
993
|
+
return checkValidity(parent, visited);
|
|
994
|
+
}
|
|
884
995
|
if (parent.type === "CallExpression" && parent.callee.type === "MemberExpression" && isIdentifier(parent.callee.object, "Promise") && isIdentifier(parent.callee.property, "all")) {
|
|
885
996
|
return true;
|
|
886
997
|
}
|
|
887
998
|
if (parent.type === "VariableDeclarator") {
|
|
888
|
-
|
|
889
|
-
for (const ref of scope.references) {
|
|
890
|
-
const refParent = ref.identifier.parent;
|
|
891
|
-
if (visited.has(refParent)) continue;
|
|
892
|
-
if (validTypes.has(refParent.type)) return true;
|
|
893
|
-
if (checkValidity(refParent, visited)) return true;
|
|
894
|
-
}
|
|
999
|
+
return isVariableConsumed(parent, checkValidity, validTypes, visited);
|
|
895
1000
|
}
|
|
896
1001
|
return false;
|
|
897
1002
|
}
|
|
@@ -909,7 +1014,9 @@ var missing_playwright_await_default = createRule({
|
|
|
909
1014
|
return;
|
|
910
1015
|
}
|
|
911
1016
|
const call = parseFnCall(context, node);
|
|
912
|
-
if (call?.type !== "step" && call?.type !== "expect")
|
|
1017
|
+
if (call?.type !== "step" && call?.type !== "expect") {
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
913
1020
|
const result = getCallType(call, awaitableMatchers);
|
|
914
1021
|
const isValid = result ? checkValidity(node, /* @__PURE__ */ new Set()) : false;
|
|
915
1022
|
if (result && !isValid) {
|
|
@@ -967,7 +1074,9 @@ function hasTests(context, node) {
|
|
|
967
1074
|
var no_commented_out_tests_default = createRule({
|
|
968
1075
|
create(context) {
|
|
969
1076
|
function checkNode(node) {
|
|
970
|
-
if (!hasTests(context, node))
|
|
1077
|
+
if (!hasTests(context, node)) {
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
971
1080
|
context.report({
|
|
972
1081
|
messageId: "commentedTests",
|
|
973
1082
|
node
|
|
@@ -994,18 +1103,6 @@ var no_commented_out_tests_default = createRule({
|
|
|
994
1103
|
|
|
995
1104
|
// src/rules/no-conditional-expect.ts
|
|
996
1105
|
var isCatchCall = (node) => node.callee.type === "MemberExpression" && isPropertyAccessor(node.callee, "catch");
|
|
997
|
-
var getTestCallExpressionsFromDeclaredVariables = (context, declaredVariables) => {
|
|
998
|
-
return declaredVariables.reduce(
|
|
999
|
-
(acc, { references }) => [
|
|
1000
|
-
...acc,
|
|
1001
|
-
...references.map(({ identifier }) => identifier.parent).filter(
|
|
1002
|
-
// ESLint types are infurating
|
|
1003
|
-
(node) => node?.type === "CallExpression" && isTypeOfFnCall(context, node, ["test"])
|
|
1004
|
-
)
|
|
1005
|
-
],
|
|
1006
|
-
[]
|
|
1007
|
-
);
|
|
1008
|
-
};
|
|
1009
1106
|
var no_conditional_expect_default = createRule({
|
|
1010
1107
|
create(context) {
|
|
1011
1108
|
let conditionalDepth = 0;
|
|
@@ -1047,16 +1144,6 @@ var no_conditional_expect_default = createRule({
|
|
|
1047
1144
|
"CatchClause:exit": decreaseConditionalDepth,
|
|
1048
1145
|
"ConditionalExpression": increaseConditionalDepth,
|
|
1049
1146
|
"ConditionalExpression:exit": decreaseConditionalDepth,
|
|
1050
|
-
"FunctionDeclaration"(node) {
|
|
1051
|
-
const declaredVariables = context.sourceCode.getDeclaredVariables(node);
|
|
1052
|
-
const testCallExpressions = getTestCallExpressionsFromDeclaredVariables(
|
|
1053
|
-
context,
|
|
1054
|
-
declaredVariables
|
|
1055
|
-
);
|
|
1056
|
-
if (testCallExpressions.length > 0) {
|
|
1057
|
-
inTestCase = true;
|
|
1058
|
-
}
|
|
1059
|
-
},
|
|
1060
1147
|
"IfStatement": increaseConditionalDepth,
|
|
1061
1148
|
"IfStatement:exit": decreaseConditionalDepth,
|
|
1062
1149
|
"LogicalExpression": increaseConditionalDepth,
|
|
@@ -1086,11 +1173,15 @@ var no_conditional_in_test_default = createRule({
|
|
|
1086
1173
|
return;
|
|
1087
1174
|
}
|
|
1088
1175
|
const call = findParent(node, "CallExpression");
|
|
1089
|
-
if (!call)
|
|
1176
|
+
if (!call) {
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1090
1179
|
if (isTypeOfFnCall(context, call, ["test", "step"])) {
|
|
1091
1180
|
const testFunction = call.arguments[call.arguments.length - 1];
|
|
1092
1181
|
const functionBody = findParent(node, "BlockStatement");
|
|
1093
|
-
if (!functionBody)
|
|
1182
|
+
if (!functionBody) {
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1094
1185
|
let currentParent = functionBody.parent;
|
|
1095
1186
|
while (currentParent && currentParent !== testFunction) {
|
|
1096
1187
|
currentParent = currentParent.parent;
|
|
@@ -1128,7 +1219,9 @@ var no_duplicate_hooks_default = createRule({
|
|
|
1128
1219
|
return {
|
|
1129
1220
|
"CallExpression"(node) {
|
|
1130
1221
|
const call = parseFnCall(context, node);
|
|
1131
|
-
if (!call)
|
|
1222
|
+
if (!call) {
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1132
1225
|
if (call.type === "describe") {
|
|
1133
1226
|
hookContexts.push({});
|
|
1134
1227
|
}
|
|
@@ -1174,7 +1267,9 @@ var no_duplicate_slow_default = createRule({
|
|
|
1174
1267
|
return {
|
|
1175
1268
|
"CallExpression"(node) {
|
|
1176
1269
|
const call = parseFnCall(context, node);
|
|
1177
|
-
if (!call)
|
|
1270
|
+
if (!call) {
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1178
1273
|
if (call.type === "test" || call.type === "describe") {
|
|
1179
1274
|
scopes.push(scopes[scopes.length - 1]);
|
|
1180
1275
|
}
|
|
@@ -1295,7 +1390,9 @@ var no_focused_test_default = createRule({
|
|
|
1295
1390
|
return;
|
|
1296
1391
|
}
|
|
1297
1392
|
const onlyNode = call.members.find((s) => getStringValue(s) === "only");
|
|
1298
|
-
if (!onlyNode)
|
|
1393
|
+
if (!onlyNode) {
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1299
1396
|
context.report({
|
|
1300
1397
|
messageId: "noFocusedTest",
|
|
1301
1398
|
node: onlyNode,
|
|
@@ -1380,7 +1477,7 @@ var no_get_by_title_default = createRule({
|
|
|
1380
1477
|
create(context) {
|
|
1381
1478
|
return {
|
|
1382
1479
|
CallExpression(node) {
|
|
1383
|
-
if (
|
|
1480
|
+
if (node.callee.type === "MemberExpression" && getStringValue(node.callee.property) === "getByTitle") {
|
|
1384
1481
|
context.report({ messageId: "noGetByTitle", node });
|
|
1385
1482
|
}
|
|
1386
1483
|
}
|
|
@@ -1409,7 +1506,9 @@ var no_hooks_default = createRule({
|
|
|
1409
1506
|
return {
|
|
1410
1507
|
CallExpression(node) {
|
|
1411
1508
|
const call = parseFnCall(context, node);
|
|
1412
|
-
if (!call)
|
|
1509
|
+
if (!call) {
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1413
1512
|
if (call.type === "hook" && !options.allow.includes(call.name)) {
|
|
1414
1513
|
context.report({
|
|
1415
1514
|
data: { hookName: call.name },
|
|
@@ -1504,20 +1603,26 @@ var no_networkidle_default = createRule({
|
|
|
1504
1603
|
create(context) {
|
|
1505
1604
|
return {
|
|
1506
1605
|
CallExpression(node) {
|
|
1507
|
-
if (node.callee.type !== "MemberExpression")
|
|
1606
|
+
if (node.callee.type !== "MemberExpression") {
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1508
1609
|
const methodName = getStringValue(node.callee.property);
|
|
1509
|
-
if (!methods.has(methodName))
|
|
1610
|
+
if (!methods.has(methodName)) {
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1510
1613
|
if (methodName === "waitForLoadState") {
|
|
1511
1614
|
const arg = node.arguments[0];
|
|
1512
|
-
if (arg &&
|
|
1615
|
+
if (arg && isStringNode(arg, "networkidle")) {
|
|
1513
1616
|
context.report({ messageId, node: arg });
|
|
1514
1617
|
}
|
|
1515
1618
|
return;
|
|
1516
1619
|
}
|
|
1517
1620
|
if (node.arguments.length >= 2) {
|
|
1518
1621
|
const [_, arg] = node.arguments;
|
|
1519
|
-
if (arg.type !== "ObjectExpression")
|
|
1520
|
-
|
|
1622
|
+
if (arg.type !== "ObjectExpression") {
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
const property = arg.properties.filter((p) => p.type === "Property").find((p) => isStringNode(p.value, "networkidle"));
|
|
1521
1626
|
if (property) {
|
|
1522
1627
|
context.report({ messageId, node: property.value });
|
|
1523
1628
|
}
|
|
@@ -1544,9 +1649,13 @@ var no_nth_methods_default = createRule({
|
|
|
1544
1649
|
create(context) {
|
|
1545
1650
|
return {
|
|
1546
1651
|
CallExpression(node) {
|
|
1547
|
-
if (node.callee.type !== "MemberExpression")
|
|
1652
|
+
if (node.callee.type !== "MemberExpression") {
|
|
1653
|
+
return;
|
|
1654
|
+
}
|
|
1548
1655
|
const method = getStringValue(node.callee.property);
|
|
1549
|
-
if (!methods2.has(method))
|
|
1656
|
+
if (!methods2.has(method)) {
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1550
1659
|
context.report({
|
|
1551
1660
|
data: { method },
|
|
1552
1661
|
loc: {
|
|
@@ -1611,8 +1720,9 @@ var no_raw_locators_default = createRule({
|
|
|
1611
1720
|
}
|
|
1612
1721
|
return {
|
|
1613
1722
|
CallExpression(node) {
|
|
1614
|
-
if (node.callee.type !== "MemberExpression" || node.arguments[0]?.type === "Identifier")
|
|
1723
|
+
if (node.callee.type !== "MemberExpression" || node.arguments[0]?.type === "Identifier") {
|
|
1615
1724
|
return;
|
|
1725
|
+
}
|
|
1616
1726
|
const method = getStringValue(node.callee.property);
|
|
1617
1727
|
const arg = getStringValue(node.arguments[0]);
|
|
1618
1728
|
const isLocator = isPageMethod(node, "locator") || method === "locator";
|
|
@@ -1670,7 +1780,7 @@ var no_restricted_locators_default = createRule({
|
|
|
1670
1780
|
return;
|
|
1671
1781
|
}
|
|
1672
1782
|
for (const [restrictedType, message] of restrictionMap.entries()) {
|
|
1673
|
-
if (
|
|
1783
|
+
if (getStringValue(node.callee.property) === restrictedType) {
|
|
1674
1784
|
context.report({
|
|
1675
1785
|
data: {
|
|
1676
1786
|
message: message ?? "",
|
|
@@ -1725,7 +1835,9 @@ var no_restricted_matchers_default = createRule({
|
|
|
1725
1835
|
return {
|
|
1726
1836
|
CallExpression(node) {
|
|
1727
1837
|
const call = parseFnCall(context, node);
|
|
1728
|
-
if (call?.type !== "expect")
|
|
1838
|
+
if (call?.type !== "expect") {
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1729
1841
|
Object.entries(restrictedChains).map(([restriction, message]) => {
|
|
1730
1842
|
const chain = call.members;
|
|
1731
1843
|
const restrictionLinks = restriction.split(".").length;
|
|
@@ -1857,9 +1969,11 @@ var no_skipped_test_default = createRule({
|
|
|
1857
1969
|
return;
|
|
1858
1970
|
}
|
|
1859
1971
|
const skipNode = call.members.find((s) => getStringValue(s) === "skip");
|
|
1860
|
-
if (!skipNode)
|
|
1972
|
+
if (!skipNode) {
|
|
1973
|
+
return;
|
|
1974
|
+
}
|
|
1861
1975
|
const isStandalone = call.type === "config";
|
|
1862
|
-
if (isStandalone && allowConditional && (node.arguments.length !== 0 || findParent(node, "BlockStatement")?.parent?.type === "IfStatement")) {
|
|
1976
|
+
if (isStandalone && allowConditional && (node.arguments.length !== 0 || findParent(node, "BlockStatement")?.parent?.type === "IfStatement" || findParent(node, "SwitchCase") !== void 0)) {
|
|
1863
1977
|
return;
|
|
1864
1978
|
}
|
|
1865
1979
|
context.report({
|
|
@@ -1919,7 +2033,9 @@ var no_slowed_test_default = createRule({
|
|
|
1919
2033
|
return;
|
|
1920
2034
|
}
|
|
1921
2035
|
const slowNode = call.members.find((s) => getStringValue(s) === "slow");
|
|
1922
|
-
if (!slowNode)
|
|
2036
|
+
if (!slowNode) {
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
1923
2039
|
const isStandalone = call.type === "config";
|
|
1924
2040
|
if (isStandalone && allowConditional && (node.arguments.length !== 0 || findParent(node, "BlockStatement")?.parent?.type === "IfStatement")) {
|
|
1925
2041
|
return;
|
|
@@ -2043,7 +2159,7 @@ var no_standalone_expect_default = createRule({
|
|
|
2043
2159
|
},
|
|
2044
2160
|
"CallExpression:exit"(node) {
|
|
2045
2161
|
const top = callStack.at(-1);
|
|
2046
|
-
if (top === "test" && isTypeOfFnCall(context, node, ["test"]) && node
|
|
2162
|
+
if (top === "test" && isTypeOfFnCall(context, node, ["test"]) || top === "hook" && isTypeOfFnCall(context, node, ["hook"]) || top === "template" && node.callee.type === "TaggedTemplateExpression" || top === "fixture" && node.callee.type === "MemberExpression" && isPropertyAccessor(node.callee, "extend")) {
|
|
2047
2163
|
callStack.pop();
|
|
2048
2164
|
}
|
|
2049
2165
|
}
|
|
@@ -2072,16 +2188,22 @@ var truthy = Boolean;
|
|
|
2072
2188
|
|
|
2073
2189
|
// src/rules/no-unsafe-references.ts
|
|
2074
2190
|
function collectVariables(scope) {
|
|
2075
|
-
if (!scope || scope.type === "global")
|
|
2191
|
+
if (!scope || scope.type === "global") {
|
|
2192
|
+
return [];
|
|
2193
|
+
}
|
|
2076
2194
|
return [...collectVariables(scope.upper), ...scope.variables.map((ref) => ref.name)];
|
|
2077
2195
|
}
|
|
2078
2196
|
function addArgument(fixer, node, refs) {
|
|
2079
|
-
if (!node.arguments.length)
|
|
2197
|
+
if (!node.arguments.length) {
|
|
2198
|
+
return;
|
|
2199
|
+
}
|
|
2080
2200
|
if (node.arguments.length === 1) {
|
|
2081
2201
|
return fixer.insertTextAfter(node.arguments[0], `, [${refs}]`);
|
|
2082
2202
|
}
|
|
2083
2203
|
const arg = node.arguments.at(-1);
|
|
2084
|
-
if (!arg)
|
|
2204
|
+
if (!arg) {
|
|
2205
|
+
return;
|
|
2206
|
+
}
|
|
2085
2207
|
if (arg.type !== "ArrayExpression") {
|
|
2086
2208
|
return fixer.replaceText(arg, `[${getStringValue(arg)}, ${refs}]`);
|
|
2087
2209
|
}
|
|
@@ -2107,9 +2229,13 @@ var no_unsafe_references_default = createRule({
|
|
|
2107
2229
|
create(context) {
|
|
2108
2230
|
return {
|
|
2109
2231
|
CallExpression(node) {
|
|
2110
|
-
if (!isPageMethod(node, "evaluate") && !isPageMethod(node, "addInitScript"))
|
|
2232
|
+
if (!isPageMethod(node, "evaluate") && !isPageMethod(node, "addInitScript")) {
|
|
2233
|
+
return;
|
|
2234
|
+
}
|
|
2111
2235
|
const [fn] = node.arguments;
|
|
2112
|
-
if (!fn || !isFunction(fn))
|
|
2236
|
+
if (!fn || !isFunction(fn)) {
|
|
2237
|
+
return;
|
|
2238
|
+
}
|
|
2113
2239
|
const { through, upper } = context.sourceCode.getScope(fn.body);
|
|
2114
2240
|
const allRefs = new Set(collectVariables(upper));
|
|
2115
2241
|
through.filter((ref) => {
|
|
@@ -2242,7 +2368,9 @@ var expectMatchers = /* @__PURE__ */ new Set([
|
|
|
2242
2368
|
"toThrowError"
|
|
2243
2369
|
]);
|
|
2244
2370
|
function isSupportedMethod(node) {
|
|
2245
|
-
if (node.callee.type !== "MemberExpression")
|
|
2371
|
+
if (node.callee.type !== "MemberExpression") {
|
|
2372
|
+
return false;
|
|
2373
|
+
}
|
|
2246
2374
|
const name = getStringValue(node.callee.property);
|
|
2247
2375
|
return locatorMethods.has(name) || pageMethods.has(name) && isPageMethod(node, name);
|
|
2248
2376
|
}
|
|
@@ -2297,7 +2425,9 @@ function replaceAccessorFixer(fixer, node, text) {
|
|
|
2297
2425
|
}
|
|
2298
2426
|
function removePropertyFixer(fixer, property) {
|
|
2299
2427
|
const parent = property.parent;
|
|
2300
|
-
if (parent?.type !== "ObjectExpression")
|
|
2428
|
+
if (parent?.type !== "ObjectExpression") {
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2301
2431
|
if (parent.properties.length === 1) {
|
|
2302
2432
|
return fixer.remove(parent);
|
|
2303
2433
|
}
|
|
@@ -2321,7 +2451,9 @@ var matcherConfig = {
|
|
|
2321
2451
|
};
|
|
2322
2452
|
function getOptions(call, name) {
|
|
2323
2453
|
const [arg] = call.matcherArgs;
|
|
2324
|
-
if (arg?.type !== "ObjectExpression")
|
|
2454
|
+
if (arg?.type !== "ObjectExpression") {
|
|
2455
|
+
return;
|
|
2456
|
+
}
|
|
2325
2457
|
const property = arg.properties.find(
|
|
2326
2458
|
(p) => p.type === "Property" && getStringValue(p.key) === name && isBooleanLiteral(p.value)
|
|
2327
2459
|
);
|
|
@@ -2336,13 +2468,21 @@ var no_useless_not_default = createRule({
|
|
|
2336
2468
|
return {
|
|
2337
2469
|
CallExpression(node) {
|
|
2338
2470
|
const call = parseFnCall(context, node);
|
|
2339
|
-
if (call?.type !== "expect")
|
|
2471
|
+
if (call?.type !== "expect") {
|
|
2472
|
+
return;
|
|
2473
|
+
}
|
|
2340
2474
|
const config = matcherConfig[call.matcherName];
|
|
2341
|
-
if (!config)
|
|
2475
|
+
if (!config) {
|
|
2476
|
+
return;
|
|
2477
|
+
}
|
|
2342
2478
|
const options = config.argName ? getOptions(call, config.argName) : void 0;
|
|
2343
|
-
if (options?.arg && options.value === void 0)
|
|
2479
|
+
if (options?.arg && options.value === void 0) {
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2344
2482
|
const notModifier = call.modifiers.find((mod) => getStringValue(mod) === "not");
|
|
2345
|
-
if (!notModifier && !options?.property)
|
|
2483
|
+
if (!notModifier && !options?.property) {
|
|
2484
|
+
return;
|
|
2485
|
+
}
|
|
2346
2486
|
const isInverted = !!notModifier !== (options?.value === false);
|
|
2347
2487
|
const newMatcherName = isInverted ? config.inverse : call.matcherName;
|
|
2348
2488
|
context.report({
|
|
@@ -2435,7 +2575,7 @@ var no_wait_for_selector_default = createRule({
|
|
|
2435
2575
|
suggest: [
|
|
2436
2576
|
{
|
|
2437
2577
|
fix: (fixer) => fixer.remove(
|
|
2438
|
-
node.parent && node.parent.type !== "AwaitExpression" ? node.parent : node.parent.parent
|
|
2578
|
+
node.parent && node.parent.type !== "AwaitExpression" && node.parent.type !== "VariableDeclarator" ? node.parent : node.parent.parent
|
|
2439
2579
|
),
|
|
2440
2580
|
messageId: "removeWaitForSelector"
|
|
2441
2581
|
}
|
|
@@ -2472,7 +2612,7 @@ var no_wait_for_timeout_default = createRule({
|
|
|
2472
2612
|
suggest: [
|
|
2473
2613
|
{
|
|
2474
2614
|
fix: (fixer) => fixer.remove(
|
|
2475
|
-
node.parent && node.parent.type !== "AwaitExpression" ? node.parent : node.parent.parent
|
|
2615
|
+
node.parent && node.parent.type !== "AwaitExpression" && node.parent.type !== "VariableDeclarator" ? node.parent : node.parent.parent
|
|
2476
2616
|
),
|
|
2477
2617
|
messageId: "removeWaitForTimeout"
|
|
2478
2618
|
}
|
|
@@ -2504,6 +2644,7 @@ var isString = (node) => {
|
|
|
2504
2644
|
var isComparingToString = (expression) => {
|
|
2505
2645
|
return isString(expression.left) || isString(expression.right);
|
|
2506
2646
|
};
|
|
2647
|
+
var skipModifiers = /* @__PURE__ */ new Set(["not", "soft", "poll"]);
|
|
2507
2648
|
var invertedOperators = {
|
|
2508
2649
|
"<": ">=",
|
|
2509
2650
|
"<=": ">",
|
|
@@ -2525,9 +2666,16 @@ var prefer_comparison_matcher_default = createRule({
|
|
|
2525
2666
|
return {
|
|
2526
2667
|
CallExpression(node) {
|
|
2527
2668
|
const call = parseFnCall(context, node);
|
|
2528
|
-
if (call?.type !== "expect" || call.matcherArgs.length === 0)
|
|
2529
|
-
|
|
2530
|
-
|
|
2669
|
+
if (call?.type !== "expect" || call.matcherArgs.length === 0) {
|
|
2670
|
+
return;
|
|
2671
|
+
}
|
|
2672
|
+
let expect = call.head.node.parent;
|
|
2673
|
+
while (expect?.type === "MemberExpression") {
|
|
2674
|
+
expect = expect.parent;
|
|
2675
|
+
}
|
|
2676
|
+
if (expect?.type !== "CallExpression") {
|
|
2677
|
+
return;
|
|
2678
|
+
}
|
|
2531
2679
|
const [comparison] = expect.arguments;
|
|
2532
2680
|
const expectCallEnd = expect.range[1];
|
|
2533
2681
|
const [matcherArg] = call.matcherArgs;
|
|
@@ -2546,7 +2694,7 @@ var prefer_comparison_matcher_default = createRule({
|
|
|
2546
2694
|
data: { preferredMatcher },
|
|
2547
2695
|
fix(fixer) {
|
|
2548
2696
|
const [modifier] = call.modifiers;
|
|
2549
|
-
const modifierText = modifier && getStringValue(modifier)
|
|
2697
|
+
const modifierText = modifier && !skipModifiers.has(getStringValue(modifier)) ? `.${getStringValue(modifier)}` : "";
|
|
2550
2698
|
return [
|
|
2551
2699
|
// Replace the comparison argument with the left-hand side of the comparison
|
|
2552
2700
|
fixer.replaceText(comparison, context.sourceCode.getText(comparison.left)),
|
|
@@ -2585,9 +2733,13 @@ var prefer_equality_matcher_default = createRule({
|
|
|
2585
2733
|
return {
|
|
2586
2734
|
CallExpression(node) {
|
|
2587
2735
|
const call = parseFnCall(context, node);
|
|
2588
|
-
if (call?.type !== "expect" || call.matcherArgs.length === 0)
|
|
2736
|
+
if (call?.type !== "expect" || call.matcherArgs.length === 0) {
|
|
2737
|
+
return;
|
|
2738
|
+
}
|
|
2589
2739
|
const expect = call.head.node.parent;
|
|
2590
|
-
if (expect?.type !== "CallExpression")
|
|
2740
|
+
if (expect?.type !== "CallExpression") {
|
|
2741
|
+
return;
|
|
2742
|
+
}
|
|
2591
2743
|
const [comparison] = expect.arguments;
|
|
2592
2744
|
const expectCallEnd = expect.range[1];
|
|
2593
2745
|
const [matcherArg] = call.matcherArgs;
|
|
@@ -2649,7 +2801,9 @@ var prefer_hooks_in_order_default = createRule({
|
|
|
2649
2801
|
let inHook = false;
|
|
2650
2802
|
return {
|
|
2651
2803
|
"CallExpression"(node) {
|
|
2652
|
-
if (inHook)
|
|
2804
|
+
if (inHook) {
|
|
2805
|
+
return;
|
|
2806
|
+
}
|
|
2653
2807
|
const call = parseFnCall(context, node);
|
|
2654
2808
|
if (call?.type !== "hook") {
|
|
2655
2809
|
previousHookIndex = -1;
|
|
@@ -2676,7 +2830,9 @@ var prefer_hooks_in_order_default = createRule({
|
|
|
2676
2830
|
inHook = false;
|
|
2677
2831
|
return;
|
|
2678
2832
|
}
|
|
2679
|
-
if (inHook)
|
|
2833
|
+
if (inHook) {
|
|
2834
|
+
return;
|
|
2835
|
+
}
|
|
2680
2836
|
previousHookIndex = -1;
|
|
2681
2837
|
}
|
|
2682
2838
|
};
|
|
@@ -2753,7 +2909,9 @@ var pageMethods2 = /* @__PURE__ */ new Set([
|
|
|
2753
2909
|
"uncheck"
|
|
2754
2910
|
]);
|
|
2755
2911
|
function isSupportedMethod2(node) {
|
|
2756
|
-
if (node.callee.type !== "MemberExpression")
|
|
2912
|
+
if (node.callee.type !== "MemberExpression") {
|
|
2913
|
+
return false;
|
|
2914
|
+
}
|
|
2757
2915
|
const name = getStringValue(node.callee.property);
|
|
2758
2916
|
return pageMethods2.has(name) && isPageMethod(node, name);
|
|
2759
2917
|
}
|
|
@@ -2761,7 +2919,9 @@ var prefer_locator_default = createRule({
|
|
|
2761
2919
|
create(context) {
|
|
2762
2920
|
return {
|
|
2763
2921
|
CallExpression(node) {
|
|
2764
|
-
if (!isSupportedMethod2(node))
|
|
2922
|
+
if (!isSupportedMethod2(node)) {
|
|
2923
|
+
return;
|
|
2924
|
+
}
|
|
2765
2925
|
context.report({
|
|
2766
2926
|
messageId: "preferLocator",
|
|
2767
2927
|
node
|
|
@@ -2922,9 +3082,13 @@ var prefer_native_locators_default = createRule({
|
|
|
2922
3082
|
const patterns = compilePatterns({ testIdAttribute });
|
|
2923
3083
|
return {
|
|
2924
3084
|
CallExpression(node) {
|
|
2925
|
-
if (node.callee.type !== "MemberExpression")
|
|
3085
|
+
if (node.callee.type !== "MemberExpression") {
|
|
3086
|
+
return;
|
|
3087
|
+
}
|
|
2926
3088
|
const query = getStringValue(node.arguments[0]);
|
|
2927
|
-
if (!isPageMethod(node, "locator"))
|
|
3089
|
+
if (!isPageMethod(node, "locator")) {
|
|
3090
|
+
return;
|
|
3091
|
+
}
|
|
2928
3092
|
for (const pattern of patterns) {
|
|
2929
3093
|
const match = query.match(pattern.pattern);
|
|
2930
3094
|
if (match) {
|
|
@@ -2982,7 +3146,9 @@ var prefer_strict_equal_default = createRule({
|
|
|
2982
3146
|
return {
|
|
2983
3147
|
CallExpression(node) {
|
|
2984
3148
|
const call = parseFnCall(context, node);
|
|
2985
|
-
if (call?.type !== "expect")
|
|
3149
|
+
if (call?.type !== "expect") {
|
|
3150
|
+
return;
|
|
3151
|
+
}
|
|
2986
3152
|
if (call.matcherName === "toEqual") {
|
|
2987
3153
|
context.report({
|
|
2988
3154
|
messageId: "useToStrictEqual",
|
|
@@ -3050,7 +3216,9 @@ var prefer_to_be_default = createRule({
|
|
|
3050
3216
|
return {
|
|
3051
3217
|
CallExpression(node) {
|
|
3052
3218
|
const call = parseFnCall(context, node);
|
|
3053
|
-
if (call?.type !== "expect")
|
|
3219
|
+
if (call?.type !== "expect") {
|
|
3220
|
+
return;
|
|
3221
|
+
}
|
|
3054
3222
|
const notMatchers = ["toBeUndefined", "toBeDefined"];
|
|
3055
3223
|
const notModifier = call.modifiers.find((node2) => getStringValue(node2) === "not");
|
|
3056
3224
|
if (notModifier && notMatchers.includes(call.matcherName)) {
|
|
@@ -3107,9 +3275,13 @@ var prefer_to_contain_default = createRule({
|
|
|
3107
3275
|
return {
|
|
3108
3276
|
CallExpression(node) {
|
|
3109
3277
|
const call = parseFnCall(context, node);
|
|
3110
|
-
if (call?.type !== "expect" || call.matcherArgs.length === 0)
|
|
3278
|
+
if (call?.type !== "expect" || call.matcherArgs.length === 0) {
|
|
3279
|
+
return;
|
|
3280
|
+
}
|
|
3111
3281
|
const expect = call.head.node.parent;
|
|
3112
|
-
if (expect?.type !== "CallExpression")
|
|
3282
|
+
if (expect?.type !== "CallExpression") {
|
|
3283
|
+
return;
|
|
3284
|
+
}
|
|
3113
3285
|
const [includesCall] = expect.arguments;
|
|
3114
3286
|
const { matcher } = call;
|
|
3115
3287
|
const [matcherArg] = call.matcherArgs;
|
|
@@ -3304,19 +3476,29 @@ var prefer_web_first_assertions_default = createRule({
|
|
|
3304
3476
|
return {
|
|
3305
3477
|
CallExpression(node) {
|
|
3306
3478
|
const fnCall = parseFnCall(context, node);
|
|
3307
|
-
if (fnCall?.type !== "expect")
|
|
3479
|
+
if (fnCall?.type !== "expect") {
|
|
3480
|
+
return;
|
|
3481
|
+
}
|
|
3308
3482
|
const expect = findParent(fnCall.head.node, "CallExpression");
|
|
3309
|
-
if (!expect)
|
|
3483
|
+
if (!expect) {
|
|
3484
|
+
return;
|
|
3485
|
+
}
|
|
3310
3486
|
const arg = dereference(context, fnCall.args[0]);
|
|
3311
|
-
if (!arg)
|
|
3487
|
+
if (!arg) {
|
|
3488
|
+
return;
|
|
3489
|
+
}
|
|
3312
3490
|
const call = arg.type === "AwaitExpression" ? arg.argument : arg;
|
|
3313
3491
|
if (call.type !== "CallExpression" || call.callee.type !== "MemberExpression") {
|
|
3314
3492
|
return;
|
|
3315
3493
|
}
|
|
3316
|
-
if (!supportedMatchers.has(fnCall.matcherName))
|
|
3494
|
+
if (!supportedMatchers.has(fnCall.matcherName)) {
|
|
3495
|
+
return;
|
|
3496
|
+
}
|
|
3317
3497
|
const method = getStringValue(call.callee.property);
|
|
3318
3498
|
const methodConfig = methods3[method];
|
|
3319
|
-
if (!Object.hasOwn(methods3, method))
|
|
3499
|
+
if (!Object.hasOwn(methods3, method)) {
|
|
3500
|
+
return;
|
|
3501
|
+
}
|
|
3320
3502
|
const notModifier = fnCall.modifiers.find((mod) => getStringValue(mod) === "not");
|
|
3321
3503
|
const isFalsy = methodConfig.type === "boolean" && (!!fnCall.matcherArgs.length && isBooleanLiteral(fnCall.matcherArgs[0], false) || fnCall.matcherName === "toBeFalsy");
|
|
3322
3504
|
const isInverse = methodConfig.inverse ? notModifier || isFalsy : notModifier && isFalsy;
|
|
@@ -3516,10 +3698,11 @@ function hasTagInOptions(node) {
|
|
|
3516
3698
|
}
|
|
3517
3699
|
function hasTagInTitle(node) {
|
|
3518
3700
|
const title = node.arguments[0];
|
|
3519
|
-
if (!title
|
|
3701
|
+
if (!title) {
|
|
3520
3702
|
return false;
|
|
3521
3703
|
}
|
|
3522
|
-
|
|
3704
|
+
const value = getStringValue(title);
|
|
3705
|
+
return !!value && tagRegex.test(value);
|
|
3523
3706
|
}
|
|
3524
3707
|
function hasTags(node) {
|
|
3525
3708
|
return hasTagInTitle(node) || hasTagInOptions(node);
|
|
@@ -3614,7 +3797,9 @@ var require_to_throw_message_default = createRule({
|
|
|
3614
3797
|
return {
|
|
3615
3798
|
CallExpression(node) {
|
|
3616
3799
|
const call = parseFnCall(context, node);
|
|
3617
|
-
if (call?.type !== "expect")
|
|
3800
|
+
if (call?.type !== "expect") {
|
|
3801
|
+
return;
|
|
3802
|
+
}
|
|
3618
3803
|
if (call.matcherArgs.length === 0 && ["toThrow", "toThrowError"].includes(call.matcherName) && !call.modifiers.some((nod) => getStringValue(nod) === "not")) {
|
|
3619
3804
|
context.report({
|
|
3620
3805
|
data: { matcherName: call.matcherName },
|
|
@@ -3651,7 +3836,9 @@ var require_top_level_describe_default = createRule({
|
|
|
3651
3836
|
return {
|
|
3652
3837
|
"CallExpression"(node) {
|
|
3653
3838
|
const call = parseFnCall(context, node);
|
|
3654
|
-
if (!call)
|
|
3839
|
+
if (!call) {
|
|
3840
|
+
return;
|
|
3841
|
+
}
|
|
3655
3842
|
if (call.type === "describe") {
|
|
3656
3843
|
describeCount++;
|
|
3657
3844
|
if (describeCount === 1) {
|
|
@@ -3720,7 +3907,9 @@ var valid_describe_callback_default = createRule({
|
|
|
3720
3907
|
return {
|
|
3721
3908
|
CallExpression(node) {
|
|
3722
3909
|
const call = parseFnCall(context, node);
|
|
3723
|
-
if (call?.group !== "describe")
|
|
3910
|
+
if (call?.group !== "describe") {
|
|
3911
|
+
return;
|
|
3912
|
+
}
|
|
3724
3913
|
if (call.members.some((s) => getStringValue(s) === "configure")) {
|
|
3725
3914
|
return;
|
|
3726
3915
|
}
|
|
@@ -3823,7 +4012,9 @@ var isTestCaseCallWithCallbackArg = (context, node) => {
|
|
|
3823
4012
|
};
|
|
3824
4013
|
var isPromiseMethodThatUsesValue = (node, identifier) => {
|
|
3825
4014
|
const name = getStringValue(identifier);
|
|
3826
|
-
if (node.argument == null)
|
|
4015
|
+
if (node.argument == null) {
|
|
4016
|
+
return false;
|
|
4017
|
+
}
|
|
3827
4018
|
if (node.argument.type === "CallExpression" && node.argument.arguments.length > 0) {
|
|
3828
4019
|
const nodeName = getNodeName(node.argument);
|
|
3829
4020
|
if (["Promise.all", "Promise.allSettled"].includes(nodeName)) {
|
|
@@ -4080,7 +4271,9 @@ var valid_expect_default = createRule({
|
|
|
4080
4271
|
return;
|
|
4081
4272
|
}
|
|
4082
4273
|
const { parent: expect } = call.head.node;
|
|
4083
|
-
if (expect?.type !== "CallExpression")
|
|
4274
|
+
if (expect?.type !== "CallExpression") {
|
|
4275
|
+
return;
|
|
4276
|
+
}
|
|
4084
4277
|
if (expect.arguments.length < minArgs) {
|
|
4085
4278
|
const expectLength = getStringValue(call.head.node).length;
|
|
4086
4279
|
const loc = {
|
|
@@ -4129,6 +4322,7 @@ var valid_expect_default = createRule({
|
|
|
4129
4322
|
messages: {
|
|
4130
4323
|
matcherNotCalled: "Matchers must be called to assert.",
|
|
4131
4324
|
matcherNotFound: "Expect must have a corresponding matcher call.",
|
|
4325
|
+
modifierUnknown: "Expect has an unknown modifier.",
|
|
4132
4326
|
notEnoughArgs: "Expect requires at least {{amount}} argument{{s}}.",
|
|
4133
4327
|
tooManyArgs: "Expect takes at most {{amount}} argument{{s}}."
|
|
4134
4328
|
},
|
|
@@ -4206,9 +4400,13 @@ var valid_test_tags_default = createRule({
|
|
|
4206
4400
|
return {
|
|
4207
4401
|
CallExpression(node) {
|
|
4208
4402
|
const call = parseFnCall(context, node);
|
|
4209
|
-
if (!call)
|
|
4403
|
+
if (!call) {
|
|
4404
|
+
return;
|
|
4405
|
+
}
|
|
4210
4406
|
const { type } = call;
|
|
4211
|
-
if (type !== "test" && type !== "describe" && type !== "step")
|
|
4407
|
+
if (type !== "test" && type !== "describe" && type !== "step") {
|
|
4408
|
+
return;
|
|
4409
|
+
}
|
|
4212
4410
|
if (node.arguments.length > 0) {
|
|
4213
4411
|
const titleArg = node.arguments[0];
|
|
4214
4412
|
if (titleArg && titleArg.type === "Literal" && typeof titleArg.value === "string") {
|
|
@@ -4218,14 +4416,20 @@ var valid_test_tags_default = createRule({
|
|
|
4218
4416
|
}
|
|
4219
4417
|
}
|
|
4220
4418
|
}
|
|
4221
|
-
if (node.arguments.length < 2)
|
|
4419
|
+
if (node.arguments.length < 2) {
|
|
4420
|
+
return;
|
|
4421
|
+
}
|
|
4222
4422
|
const optionsArg = node.arguments[1];
|
|
4223
|
-
if (!optionsArg || optionsArg.type !== "ObjectExpression")
|
|
4423
|
+
if (!optionsArg || optionsArg.type !== "ObjectExpression") {
|
|
4424
|
+
return;
|
|
4425
|
+
}
|
|
4224
4426
|
const tagProperty = optionsArg.properties.find(
|
|
4225
4427
|
(prop) => prop.type === "Property" && !("argument" in prop) && // Ensure it's not a spread element
|
|
4226
4428
|
prop.key.type === "Identifier" && prop.key.name === "tag"
|
|
4227
4429
|
);
|
|
4228
|
-
if (!tagProperty)
|
|
4430
|
+
if (!tagProperty) {
|
|
4431
|
+
return;
|
|
4432
|
+
}
|
|
4229
4433
|
const tagValue = tagProperty.value;
|
|
4230
4434
|
if (tagValue.type === "Literal") {
|
|
4231
4435
|
if (typeof tagValue.value !== "string") {
|
|
@@ -4362,7 +4566,9 @@ var valid_title_default = createRule({
|
|
|
4362
4566
|
}
|
|
4363
4567
|
const [argument] = node.arguments;
|
|
4364
4568
|
const title = dereference(context, argument) ?? argument;
|
|
4365
|
-
if (!title)
|
|
4569
|
+
if (!title) {
|
|
4570
|
+
return;
|
|
4571
|
+
}
|
|
4366
4572
|
if (!isStringNode(title)) {
|
|
4367
4573
|
if (title.type === "BinaryExpression" && doesBinaryExpressionContainStringNode(title)) {
|
|
4368
4574
|
return;
|
|
@@ -4411,15 +4617,15 @@ var valid_title_default = createRule({
|
|
|
4411
4617
|
node: title
|
|
4412
4618
|
});
|
|
4413
4619
|
}
|
|
4414
|
-
const [firstWord] = titleString.split(" ");
|
|
4620
|
+
const [firstWord, ...rest] = titleString.split(" ");
|
|
4415
4621
|
if (firstWord.toLowerCase() === functionName) {
|
|
4416
4622
|
context.report({
|
|
4417
|
-
fix: (fixer) => [
|
|
4623
|
+
fix: rest.length > 0 ? (fixer) => [
|
|
4418
4624
|
fixer.replaceTextRange(
|
|
4419
4625
|
title.range,
|
|
4420
4626
|
quoteStringValue(title).replace(/^([`'"]).+? /u, "$1")
|
|
4421
4627
|
)
|
|
4422
|
-
],
|
|
4628
|
+
] : void 0,
|
|
4423
4629
|
messageId: "duplicatePrefix",
|
|
4424
4630
|
node: title
|
|
4425
4631
|
});
|