eslint-plugin-playwright 2.9.0 → 2.10.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/dist/index.cjs +158 -20
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -861,6 +861,105 @@ var waitForMethods = [
|
|
|
861
861
|
"waitForWebSocket"
|
|
862
862
|
];
|
|
863
863
|
var waitForMethodsRegex = new RegExp(`^(${waitForMethods.join("|")})$`);
|
|
864
|
+
var pageMethods = /* @__PURE__ */ new Set([
|
|
865
|
+
"addInitScript",
|
|
866
|
+
"addScriptTag",
|
|
867
|
+
"addStyleTag",
|
|
868
|
+
"bringToFront",
|
|
869
|
+
"check",
|
|
870
|
+
"click",
|
|
871
|
+
"close",
|
|
872
|
+
"dblclick",
|
|
873
|
+
"dispatchEvent",
|
|
874
|
+
"dragAndDrop",
|
|
875
|
+
"emulateMedia",
|
|
876
|
+
"evaluate",
|
|
877
|
+
"evaluateHandle",
|
|
878
|
+
"exposeBinding",
|
|
879
|
+
"exposeFunction",
|
|
880
|
+
"fill",
|
|
881
|
+
"focus",
|
|
882
|
+
"getAttribute",
|
|
883
|
+
"goBack",
|
|
884
|
+
"goForward",
|
|
885
|
+
"goto",
|
|
886
|
+
"hover",
|
|
887
|
+
"innerHTML",
|
|
888
|
+
"innerText",
|
|
889
|
+
"inputValue",
|
|
890
|
+
"isChecked",
|
|
891
|
+
"isDisabled",
|
|
892
|
+
"isEditable",
|
|
893
|
+
"isEnabled",
|
|
894
|
+
"isHidden",
|
|
895
|
+
"isVisible",
|
|
896
|
+
"pdf",
|
|
897
|
+
"press",
|
|
898
|
+
"reload",
|
|
899
|
+
"route",
|
|
900
|
+
"routeFromHAR",
|
|
901
|
+
"screenshot",
|
|
902
|
+
"selectOption",
|
|
903
|
+
"setBypassCSP",
|
|
904
|
+
"setContent",
|
|
905
|
+
"setChecked",
|
|
906
|
+
"setExtraHTTPHeaders",
|
|
907
|
+
"setInputFiles",
|
|
908
|
+
"setViewportSize",
|
|
909
|
+
"tap",
|
|
910
|
+
"textContent",
|
|
911
|
+
"title",
|
|
912
|
+
"type",
|
|
913
|
+
"uncheck",
|
|
914
|
+
"unroute",
|
|
915
|
+
"unrouteAll",
|
|
916
|
+
"waitForLoadState",
|
|
917
|
+
"waitForTimeout",
|
|
918
|
+
"waitForURL"
|
|
919
|
+
]);
|
|
920
|
+
var locatorMethods = /* @__PURE__ */ new Set([
|
|
921
|
+
"all",
|
|
922
|
+
"allInnerTexts",
|
|
923
|
+
"allTextContents",
|
|
924
|
+
"blur",
|
|
925
|
+
"boundingBox",
|
|
926
|
+
"check",
|
|
927
|
+
"clear",
|
|
928
|
+
"click",
|
|
929
|
+
"count",
|
|
930
|
+
"dblclick",
|
|
931
|
+
"dispatchEvent",
|
|
932
|
+
"dragTo",
|
|
933
|
+
"evaluate",
|
|
934
|
+
"evaluateAll",
|
|
935
|
+
"evaluateHandle",
|
|
936
|
+
"fill",
|
|
937
|
+
"focus",
|
|
938
|
+
"getAttribute",
|
|
939
|
+
"hover",
|
|
940
|
+
"innerHTML",
|
|
941
|
+
"innerText",
|
|
942
|
+
"inputValue",
|
|
943
|
+
"isChecked",
|
|
944
|
+
"isDisabled",
|
|
945
|
+
"isEditable",
|
|
946
|
+
"isEnabled",
|
|
947
|
+
"isHidden",
|
|
948
|
+
"isVisible",
|
|
949
|
+
"press",
|
|
950
|
+
"pressSequentially",
|
|
951
|
+
"screenshot",
|
|
952
|
+
"scrollIntoViewIfNeeded",
|
|
953
|
+
"selectOption",
|
|
954
|
+
"selectText",
|
|
955
|
+
"setChecked",
|
|
956
|
+
"setInputFiles",
|
|
957
|
+
"tap",
|
|
958
|
+
"textContent",
|
|
959
|
+
"type",
|
|
960
|
+
"uncheck",
|
|
961
|
+
"waitFor"
|
|
962
|
+
]);
|
|
864
963
|
var expectPlaywrightMatchers = [
|
|
865
964
|
"toBeChecked",
|
|
866
965
|
"toBeDisabled",
|
|
@@ -916,14 +1015,18 @@ function getReportNode(node) {
|
|
|
916
1015
|
}
|
|
917
1016
|
function getCallType(call, awaitableMatchers) {
|
|
918
1017
|
if (call.type === "step") {
|
|
919
|
-
return {
|
|
1018
|
+
return {
|
|
1019
|
+
data: { name: "test.step" },
|
|
1020
|
+
messageId: "missingAwait",
|
|
1021
|
+
node: call.head.node
|
|
1022
|
+
};
|
|
920
1023
|
}
|
|
921
1024
|
if (call.type === "expect") {
|
|
922
1025
|
const isPoll = call.modifiers.some((m) => getStringValue(m) === "poll");
|
|
923
1026
|
if (isPoll || awaitableMatchers.has(call.matcherName)) {
|
|
924
1027
|
return {
|
|
925
|
-
data: {
|
|
926
|
-
messageId:
|
|
1028
|
+
data: { name: isPoll ? "expect.poll" : call.matcherName },
|
|
1029
|
+
messageId: "missingAwait",
|
|
927
1030
|
node: call.head.node
|
|
928
1031
|
};
|
|
929
1032
|
}
|
|
@@ -932,6 +1035,7 @@ function getCallType(call, awaitableMatchers) {
|
|
|
932
1035
|
var missing_playwright_await_default = createRule({
|
|
933
1036
|
create(context) {
|
|
934
1037
|
const options = context.options[0] || {};
|
|
1038
|
+
const includePageLocatorMethods = !!options.includePageLocatorMethods;
|
|
935
1039
|
const awaitableMatchers = /* @__PURE__ */ new Set([
|
|
936
1040
|
...expectPlaywrightMatchers,
|
|
937
1041
|
...playwrightTestMatchers,
|
|
@@ -992,9 +1096,18 @@ var missing_playwright_await_default = createRule({
|
|
|
992
1096
|
if (parent.type === "SpreadElement") {
|
|
993
1097
|
return checkValidity(parent, visited);
|
|
994
1098
|
}
|
|
995
|
-
if (parent.type === "CallExpression" && parent.callee.type === "MemberExpression" && isIdentifier(parent.callee.object, "Promise") && isIdentifier(parent.callee.property,
|
|
1099
|
+
if (parent.type === "CallExpression" && parent.callee.type === "MemberExpression" && isIdentifier(parent.callee.object, "Promise") && isIdentifier(parent.callee.property, /^(all|allSettled|race|any)$/)) {
|
|
996
1100
|
return true;
|
|
997
1101
|
}
|
|
1102
|
+
if (parent.type === "MemberExpression" && parent.object === node && getStringValue(parent.property) === "resolves" && node.type === "CallExpression" && isIdentifier(node.callee, "expect")) {
|
|
1103
|
+
return checkValidity(parent, visited);
|
|
1104
|
+
}
|
|
1105
|
+
if (parent.type === "MemberExpression" && parent.object === node) {
|
|
1106
|
+
return checkValidity(parent, visited);
|
|
1107
|
+
}
|
|
1108
|
+
if (parent.type === "CallExpression" && parent.callee === node) {
|
|
1109
|
+
return checkValidity(parent, visited);
|
|
1110
|
+
}
|
|
998
1111
|
if (parent.type === "VariableDeclarator") {
|
|
999
1112
|
return isVariableConsumed(parent, checkValidity, validTypes, visited);
|
|
1000
1113
|
}
|
|
@@ -1006,13 +1119,27 @@ var missing_playwright_await_default = createRule({
|
|
|
1006
1119
|
if (!checkValidity(node, /* @__PURE__ */ new Set())) {
|
|
1007
1120
|
const methodName = getStringValue(node.callee.property);
|
|
1008
1121
|
context.report({
|
|
1009
|
-
data: { methodName },
|
|
1010
|
-
messageId: "
|
|
1122
|
+
data: { name: methodName },
|
|
1123
|
+
messageId: "missingAwait",
|
|
1011
1124
|
node
|
|
1012
1125
|
});
|
|
1013
1126
|
}
|
|
1014
1127
|
return;
|
|
1015
1128
|
}
|
|
1129
|
+
if (includePageLocatorMethods && node.callee.type === "MemberExpression") {
|
|
1130
|
+
const methodName = getStringValue(node.callee.property);
|
|
1131
|
+
const isPlaywrightMethod = locatorMethods.has(methodName) || pageMethods.has(methodName) && isPageMethod(node, methodName);
|
|
1132
|
+
if (isPlaywrightMethod) {
|
|
1133
|
+
if (!checkValidity(node, /* @__PURE__ */ new Set())) {
|
|
1134
|
+
context.report({
|
|
1135
|
+
data: { name: methodName },
|
|
1136
|
+
messageId: "missingAwait",
|
|
1137
|
+
node
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1016
1143
|
const call = parseFnCall(context, node);
|
|
1017
1144
|
if (call?.type !== "step" && call?.type !== "expect") {
|
|
1018
1145
|
return;
|
|
@@ -1038,10 +1165,7 @@ var missing_playwright_await_default = createRule({
|
|
|
1038
1165
|
},
|
|
1039
1166
|
fixable: "code",
|
|
1040
1167
|
messages: {
|
|
1041
|
-
|
|
1042
|
-
expectPoll: "'expect.poll' matchers must be awaited or returned.",
|
|
1043
|
-
testStep: "'test.step' must be awaited or returned.",
|
|
1044
|
-
waitFor: "'{{methodName}}' must be awaited or returned."
|
|
1168
|
+
missingAwait: "'{{name}}' must be awaited or returned."
|
|
1045
1169
|
},
|
|
1046
1170
|
schema: [
|
|
1047
1171
|
{
|
|
@@ -1050,6 +1174,9 @@ var missing_playwright_await_default = createRule({
|
|
|
1050
1174
|
customMatchers: {
|
|
1051
1175
|
items: { type: "string" },
|
|
1052
1176
|
type: "array"
|
|
1177
|
+
},
|
|
1178
|
+
includePageLocatorMethods: {
|
|
1179
|
+
type: "boolean"
|
|
1053
1180
|
}
|
|
1054
1181
|
},
|
|
1055
1182
|
type: "object"
|
|
@@ -1962,11 +2089,15 @@ var no_skipped_test_default = createRule({
|
|
|
1962
2089
|
CallExpression(node) {
|
|
1963
2090
|
const options = context.options[0] || {};
|
|
1964
2091
|
const allowConditional = !!options.allowConditional;
|
|
2092
|
+
const disallowFixme = !!options.disallowFixme;
|
|
1965
2093
|
const call = parseFnCall(context, node);
|
|
1966
2094
|
if (call?.group !== "test" && call?.group !== "describe" && call?.group !== "step") {
|
|
1967
2095
|
return;
|
|
1968
2096
|
}
|
|
1969
|
-
const skipNode = call.members.find((
|
|
2097
|
+
const skipNode = call.members.find((member) => {
|
|
2098
|
+
const value = getStringValue(member);
|
|
2099
|
+
return value === "skip" || disallowFixme && value === "fixme";
|
|
2100
|
+
});
|
|
1970
2101
|
if (!skipNode) {
|
|
1971
2102
|
return;
|
|
1972
2103
|
}
|
|
@@ -1974,18 +2105,21 @@ var no_skipped_test_default = createRule({
|
|
|
1974
2105
|
if (isStandalone && allowConditional && (node.arguments.length !== 0 || findParent(node, "BlockStatement")?.parent?.type === "IfStatement" || findParent(node, "SwitchCase") !== void 0)) {
|
|
1975
2106
|
return;
|
|
1976
2107
|
}
|
|
2108
|
+
const annotation = getStringValue(skipNode);
|
|
1977
2109
|
context.report({
|
|
2110
|
+
data: { annotation },
|
|
1978
2111
|
messageId: "noSkippedTest",
|
|
1979
2112
|
node: isStandalone ? node : skipNode,
|
|
1980
2113
|
suggest: [
|
|
1981
2114
|
{
|
|
2115
|
+
data: { annotation: getStringValue(skipNode) },
|
|
1982
2116
|
fix: (fixer) => {
|
|
1983
2117
|
return isStandalone ? fixer.remove(node.parent) : fixer.removeRange([
|
|
1984
2118
|
skipNode.range[0] - 1,
|
|
1985
2119
|
skipNode.range[1] + Number(skipNode.type !== "Identifier")
|
|
1986
2120
|
]);
|
|
1987
2121
|
},
|
|
1988
|
-
messageId: "
|
|
2122
|
+
messageId: "removeAnnotation"
|
|
1989
2123
|
}
|
|
1990
2124
|
]
|
|
1991
2125
|
});
|
|
@@ -2000,8 +2134,8 @@ var no_skipped_test_default = createRule({
|
|
|
2000
2134
|
},
|
|
2001
2135
|
hasSuggestions: true,
|
|
2002
2136
|
messages: {
|
|
2003
|
-
noSkippedTest: "Unexpected use of the `.
|
|
2004
|
-
|
|
2137
|
+
noSkippedTest: "Unexpected use of the `.{{annotation}}()` annotation.",
|
|
2138
|
+
removeAnnotation: "Remove the `.{{annotation}}()` annotation."
|
|
2005
2139
|
},
|
|
2006
2140
|
schema: [
|
|
2007
2141
|
{
|
|
@@ -2010,6 +2144,10 @@ var no_skipped_test_default = createRule({
|
|
|
2010
2144
|
allowConditional: {
|
|
2011
2145
|
default: false,
|
|
2012
2146
|
type: "boolean"
|
|
2147
|
+
},
|
|
2148
|
+
disallowFixme: {
|
|
2149
|
+
default: false,
|
|
2150
|
+
type: "boolean"
|
|
2013
2151
|
}
|
|
2014
2152
|
},
|
|
2015
2153
|
type: "object"
|
|
@@ -2306,7 +2444,7 @@ var no_unused_locators_default = createRule({
|
|
|
2306
2444
|
});
|
|
2307
2445
|
|
|
2308
2446
|
// src/rules/no-useless-await.ts
|
|
2309
|
-
var
|
|
2447
|
+
var locatorMethods2 = /* @__PURE__ */ new Set([
|
|
2310
2448
|
"and",
|
|
2311
2449
|
"first",
|
|
2312
2450
|
"getByAltText",
|
|
@@ -2321,7 +2459,7 @@ var locatorMethods = /* @__PURE__ */ new Set([
|
|
|
2321
2459
|
"nth",
|
|
2322
2460
|
"or"
|
|
2323
2461
|
]);
|
|
2324
|
-
var
|
|
2462
|
+
var pageMethods2 = /* @__PURE__ */ new Set([
|
|
2325
2463
|
"childFrames",
|
|
2326
2464
|
"frame",
|
|
2327
2465
|
"frameLocator",
|
|
@@ -2370,7 +2508,7 @@ function isSupportedMethod(node) {
|
|
|
2370
2508
|
return false;
|
|
2371
2509
|
}
|
|
2372
2510
|
const name = getStringValue(node.callee.property);
|
|
2373
|
-
return
|
|
2511
|
+
return locatorMethods2.has(name) || pageMethods2.has(name) && isPageMethod(node, name);
|
|
2374
2512
|
}
|
|
2375
2513
|
var no_useless_await_default = createRule({
|
|
2376
2514
|
create(context) {
|
|
@@ -2881,7 +3019,7 @@ var prefer_hooks_on_top_default = createRule({
|
|
|
2881
3019
|
});
|
|
2882
3020
|
|
|
2883
3021
|
// src/rules/prefer-locator.ts
|
|
2884
|
-
var
|
|
3022
|
+
var pageMethods3 = /* @__PURE__ */ new Set([
|
|
2885
3023
|
"click",
|
|
2886
3024
|
"dblclick",
|
|
2887
3025
|
"dispatchEvent",
|
|
@@ -2911,7 +3049,7 @@ function isSupportedMethod2(node) {
|
|
|
2911
3049
|
return false;
|
|
2912
3050
|
}
|
|
2913
3051
|
const name = getStringValue(node.callee.property);
|
|
2914
|
-
return
|
|
3052
|
+
return pageMethods3.has(name) && isPageMethod(node, name);
|
|
2915
3053
|
}
|
|
2916
3054
|
var prefer_locator_default = createRule({
|
|
2917
3055
|
create(context) {
|
|
@@ -4015,7 +4153,7 @@ var isPromiseMethodThatUsesValue = (node, identifier) => {
|
|
|
4015
4153
|
}
|
|
4016
4154
|
if (node.argument.type === "CallExpression" && node.argument.arguments.length > 0) {
|
|
4017
4155
|
const nodeName = getNodeName(node.argument);
|
|
4018
|
-
if (
|
|
4156
|
+
if (/^Promise\.(all|allSettled|race|any)$/.test(nodeName)) {
|
|
4019
4157
|
const [firstArg] = node.argument.arguments;
|
|
4020
4158
|
if (firstArg.type === "ArrayExpression" && firstArg.elements.some((nod) => nod && isIdentifier(nod, name))) {
|
|
4021
4159
|
return true;
|