eslint-plugin-playwright 0.20.0 → 0.22.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 +1 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +101 -18
- package/dist/index.mjs +109 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -162,6 +162,7 @@ command line option.\
|
|
|
162
162
|
| | | | [no-restricted-matchers](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-restricted-matchers.md) | Disallow specific matchers & modifiers |
|
|
163
163
|
| ✔ | | 💡 | [no-skipped-test](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-skipped-test.md) | Disallow usage of the `.skip` annotation |
|
|
164
164
|
| ✔ | 🔧 | | [no-useless-not](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-useless-not.md) | Disallow usage of `not` matchers when a specific matcher exists |
|
|
165
|
+
| ✔ | | 💡 | [no-wait-for-selector](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-wait-for-selector.md) | Disallow usage of `page.waitForSelector` |
|
|
165
166
|
| ✔ | | 💡 | [no-wait-for-timeout](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-wait-for-timeout.md) | Disallow usage of `page.waitForTimeout` |
|
|
166
167
|
| | | 💡 | [prefer-strict-equal](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-strict-equal.md) | Suggest using `toStrictEqual()` |
|
|
167
168
|
| | 🔧 | | [prefer-lowercase-title](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-lowercase-title.md) | Enforce lowercase test names |
|
package/dist/index.d.mts
CHANGED
|
@@ -27,6 +27,7 @@ declare const _default: {
|
|
|
27
27
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
28
28
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
29
29
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
30
|
+
'no-wait-for-selector': eslint.Rule.RuleModule;
|
|
30
31
|
'no-wait-for-timeout': eslint.Rule.RuleModule;
|
|
31
32
|
'prefer-lowercase-title': eslint.Rule.RuleModule;
|
|
32
33
|
'prefer-strict-equal': eslint.Rule.RuleModule;
|
|
@@ -75,6 +76,7 @@ declare const _default: {
|
|
|
75
76
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
76
77
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
77
78
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
79
|
+
'no-wait-for-selector': eslint.Rule.RuleModule;
|
|
78
80
|
'no-wait-for-timeout': eslint.Rule.RuleModule;
|
|
79
81
|
'prefer-lowercase-title': eslint.Rule.RuleModule;
|
|
80
82
|
'prefer-strict-equal': eslint.Rule.RuleModule;
|
|
@@ -106,6 +108,7 @@ declare const _default: {
|
|
|
106
108
|
'playwright/no-skipped-test': string;
|
|
107
109
|
'playwright/no-useless-await': string;
|
|
108
110
|
'playwright/no-useless-not': string;
|
|
111
|
+
'playwright/no-wait-for-selector': string;
|
|
109
112
|
'playwright/no-wait-for-timeout': string;
|
|
110
113
|
'playwright/prefer-web-first-assertions': string;
|
|
111
114
|
'playwright/valid-expect': string;
|
|
@@ -155,6 +158,7 @@ declare const _default: {
|
|
|
155
158
|
'playwright/no-skipped-test': string;
|
|
156
159
|
'playwright/no-useless-await': string;
|
|
157
160
|
'playwright/no-useless-not': string;
|
|
161
|
+
'playwright/no-wait-for-selector': string;
|
|
158
162
|
'playwright/no-wait-for-timeout': string;
|
|
159
163
|
'playwright/prefer-web-first-assertions': string;
|
|
160
164
|
'playwright/valid-expect': string;
|
|
@@ -182,6 +186,7 @@ declare const _default: {
|
|
|
182
186
|
'playwright/no-skipped-test': string;
|
|
183
187
|
'playwright/no-useless-await': string;
|
|
184
188
|
'playwright/no-useless-not': string;
|
|
189
|
+
'playwright/no-wait-for-selector': string;
|
|
185
190
|
'playwright/no-wait-for-timeout': string;
|
|
186
191
|
'playwright/prefer-web-first-assertions': string;
|
|
187
192
|
'playwright/valid-expect': string;
|
|
@@ -207,6 +212,7 @@ declare const _default: {
|
|
|
207
212
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
208
213
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
209
214
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
215
|
+
'no-wait-for-selector': eslint.Rule.RuleModule;
|
|
210
216
|
'no-wait-for-timeout': eslint.Rule.RuleModule;
|
|
211
217
|
'prefer-lowercase-title': eslint.Rule.RuleModule;
|
|
212
218
|
'prefer-strict-equal': eslint.Rule.RuleModule;
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ declare const _default: {
|
|
|
27
27
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
28
28
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
29
29
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
30
|
+
'no-wait-for-selector': eslint.Rule.RuleModule;
|
|
30
31
|
'no-wait-for-timeout': eslint.Rule.RuleModule;
|
|
31
32
|
'prefer-lowercase-title': eslint.Rule.RuleModule;
|
|
32
33
|
'prefer-strict-equal': eslint.Rule.RuleModule;
|
|
@@ -75,6 +76,7 @@ declare const _default: {
|
|
|
75
76
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
76
77
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
77
78
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
79
|
+
'no-wait-for-selector': eslint.Rule.RuleModule;
|
|
78
80
|
'no-wait-for-timeout': eslint.Rule.RuleModule;
|
|
79
81
|
'prefer-lowercase-title': eslint.Rule.RuleModule;
|
|
80
82
|
'prefer-strict-equal': eslint.Rule.RuleModule;
|
|
@@ -106,6 +108,7 @@ declare const _default: {
|
|
|
106
108
|
'playwright/no-skipped-test': string;
|
|
107
109
|
'playwright/no-useless-await': string;
|
|
108
110
|
'playwright/no-useless-not': string;
|
|
111
|
+
'playwright/no-wait-for-selector': string;
|
|
109
112
|
'playwright/no-wait-for-timeout': string;
|
|
110
113
|
'playwright/prefer-web-first-assertions': string;
|
|
111
114
|
'playwright/valid-expect': string;
|
|
@@ -155,6 +158,7 @@ declare const _default: {
|
|
|
155
158
|
'playwright/no-skipped-test': string;
|
|
156
159
|
'playwright/no-useless-await': string;
|
|
157
160
|
'playwright/no-useless-not': string;
|
|
161
|
+
'playwright/no-wait-for-selector': string;
|
|
158
162
|
'playwright/no-wait-for-timeout': string;
|
|
159
163
|
'playwright/prefer-web-first-assertions': string;
|
|
160
164
|
'playwright/valid-expect': string;
|
|
@@ -182,6 +186,7 @@ declare const _default: {
|
|
|
182
186
|
'playwright/no-skipped-test': string;
|
|
183
187
|
'playwright/no-useless-await': string;
|
|
184
188
|
'playwright/no-useless-not': string;
|
|
189
|
+
'playwright/no-wait-for-selector': string;
|
|
185
190
|
'playwright/no-wait-for-timeout': string;
|
|
186
191
|
'playwright/prefer-web-first-assertions': string;
|
|
187
192
|
'playwright/valid-expect': string;
|
|
@@ -207,6 +212,7 @@ declare const _default: {
|
|
|
207
212
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
208
213
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
209
214
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
215
|
+
'no-wait-for-selector': eslint.Rule.RuleModule;
|
|
210
216
|
'no-wait-for-timeout': eslint.Rule.RuleModule;
|
|
211
217
|
'prefer-lowercase-title': eslint.Rule.RuleModule;
|
|
212
218
|
'prefer-strict-equal': eslint.Rule.RuleModule;
|
package/dist/index.js
CHANGED
|
@@ -303,31 +303,27 @@ var playwrightTestMatchers = [
|
|
|
303
303
|
];
|
|
304
304
|
function getCallType(node, awaitableMatchers) {
|
|
305
305
|
if (node.callee.type === "MemberExpression" && isIdentifier(node.callee.object, "test") && isPropertyAccessor(node.callee, "step")) {
|
|
306
|
-
return { messageId: "testStep" };
|
|
306
|
+
return { messageId: "testStep", node };
|
|
307
307
|
}
|
|
308
308
|
const expectType = getExpectType(node);
|
|
309
309
|
if (!expectType)
|
|
310
310
|
return;
|
|
311
|
-
if (expectType === "poll") {
|
|
312
|
-
return { messageId: "expectPoll" };
|
|
313
|
-
}
|
|
314
311
|
const [lastMatcher] = getMatchers(node).slice(-1);
|
|
312
|
+
const grandparent = lastMatcher?.parent?.parent;
|
|
313
|
+
if (grandparent?.type !== "CallExpression")
|
|
314
|
+
return;
|
|
315
315
|
const matcherName = getStringValue(lastMatcher);
|
|
316
|
-
if (awaitableMatchers.has(matcherName)) {
|
|
317
|
-
return {
|
|
316
|
+
if (expectType === "poll" || awaitableMatchers.has(matcherName)) {
|
|
317
|
+
return {
|
|
318
|
+
data: { matcherName },
|
|
319
|
+
messageId: expectType === "poll" ? "expectPoll" : "expect",
|
|
320
|
+
node: grandparent
|
|
321
|
+
};
|
|
318
322
|
}
|
|
319
323
|
}
|
|
320
|
-
function isPromiseAll(node) {
|
|
321
|
-
return node.type === "ArrayExpression" && node.parent.type === "CallExpression" && node.parent.callee.type === "MemberExpression" && isIdentifier(node.parent.callee.object, "Promise") && isIdentifier(node.parent.callee.property, "all") ? node.parent : null;
|
|
322
|
-
}
|
|
323
|
-
function checkValidity(node) {
|
|
324
|
-
if (validTypes.has(node.parent.type))
|
|
325
|
-
return;
|
|
326
|
-
const promiseAll = isPromiseAll(node.parent);
|
|
327
|
-
return promiseAll ? checkValidity(promiseAll) : node.parent.type === "MemberExpression" || node.parent.type === "CallExpression" && node.parent.callee === node ? checkValidity(node.parent) : node;
|
|
328
|
-
}
|
|
329
324
|
var missing_playwright_await_default = {
|
|
330
325
|
create(context) {
|
|
326
|
+
const sourceCode = context.sourceCode ?? context.getSourceCode();
|
|
331
327
|
const options = context.options[0] || {};
|
|
332
328
|
const awaitableMatchers = /* @__PURE__ */ new Set([
|
|
333
329
|
...expectPlaywrightMatchers,
|
|
@@ -335,11 +331,33 @@ var missing_playwright_await_default = {
|
|
|
335
331
|
// Add any custom matchers to the set
|
|
336
332
|
...options.customMatchers || []
|
|
337
333
|
]);
|
|
334
|
+
function checkValidity(node) {
|
|
335
|
+
if (validTypes.has(node.parent.type))
|
|
336
|
+
return true;
|
|
337
|
+
if (node.parent.type === "ArrayExpression") {
|
|
338
|
+
return checkValidity(node.parent);
|
|
339
|
+
}
|
|
340
|
+
if (node.parent.type === "CallExpression" && node.parent.callee.type === "MemberExpression" && isIdentifier(node.parent.callee.object, "Promise") && isIdentifier(node.parent.callee.property, "all")) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
if (node.parent.type === "VariableDeclarator") {
|
|
344
|
+
const scope = sourceCode.getScope(node.parent.parent);
|
|
345
|
+
for (const ref of scope.references) {
|
|
346
|
+
const refParent = ref.identifier.parent;
|
|
347
|
+
if (validTypes.has(refParent.type))
|
|
348
|
+
return true;
|
|
349
|
+
if (checkValidity(refParent))
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
338
355
|
return {
|
|
339
356
|
CallExpression(node) {
|
|
340
357
|
const result = getCallType(node, awaitableMatchers);
|
|
341
|
-
|
|
342
|
-
|
|
358
|
+
console.log(result);
|
|
359
|
+
const isValid = result ? checkValidity(result.node) : false;
|
|
360
|
+
if (result && !isValid) {
|
|
343
361
|
context.report({
|
|
344
362
|
data: result.data,
|
|
345
363
|
fix: (fixer) => fixer.insertTextBefore(node, "await "),
|
|
@@ -748,14 +766,27 @@ var no_page_pause_default = {
|
|
|
748
766
|
};
|
|
749
767
|
|
|
750
768
|
// src/rules/no-raw-locators.ts
|
|
769
|
+
function normalize(str) {
|
|
770
|
+
const match = /\[([^=]+?)=['"]?([^'"]+?)['"]?\]/.exec(str);
|
|
771
|
+
return match ? `[${match[1]}=${match[2]}]` : str;
|
|
772
|
+
}
|
|
751
773
|
var no_raw_locators_default = {
|
|
752
774
|
create(context) {
|
|
775
|
+
const options = {
|
|
776
|
+
allowed: [],
|
|
777
|
+
...context.options?.[0] ?? {}
|
|
778
|
+
};
|
|
779
|
+
function isAllowed(arg) {
|
|
780
|
+
return options.allowed.some((a) => normalize(a) === normalize(arg));
|
|
781
|
+
}
|
|
753
782
|
return {
|
|
754
783
|
CallExpression(node) {
|
|
755
784
|
if (node.callee.type !== "MemberExpression")
|
|
756
785
|
return;
|
|
757
786
|
const method = getStringValue(node.callee.property);
|
|
758
|
-
|
|
787
|
+
const arg = getStringValue(node.arguments[0]);
|
|
788
|
+
const isLocator = isPageMethod(node, "locator") || method === "locator";
|
|
789
|
+
if (isLocator && !isAllowed(arg)) {
|
|
759
790
|
context.report({ messageId: "noRawLocator", node });
|
|
760
791
|
}
|
|
761
792
|
}
|
|
@@ -771,6 +802,18 @@ var no_raw_locators_default = {
|
|
|
771
802
|
messages: {
|
|
772
803
|
noRawLocator: "Usage of raw locator detected. Use methods like .getByRole() or .getByText() instead of raw locators."
|
|
773
804
|
},
|
|
805
|
+
schema: [
|
|
806
|
+
{
|
|
807
|
+
additionalProperties: false,
|
|
808
|
+
properties: {
|
|
809
|
+
allowed: {
|
|
810
|
+
items: { type: "string" },
|
|
811
|
+
type: "array"
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
type: "object"
|
|
815
|
+
}
|
|
816
|
+
],
|
|
774
817
|
type: "suggestion"
|
|
775
818
|
}
|
|
776
819
|
};
|
|
@@ -1073,6 +1116,44 @@ var no_useless_not_default = {
|
|
|
1073
1116
|
}
|
|
1074
1117
|
};
|
|
1075
1118
|
|
|
1119
|
+
// src/rules/no-wait-for-selector.ts
|
|
1120
|
+
var no_wait_for_selector_default = {
|
|
1121
|
+
create(context) {
|
|
1122
|
+
return {
|
|
1123
|
+
CallExpression(node) {
|
|
1124
|
+
if (isPageMethod(node, "waitForSelector")) {
|
|
1125
|
+
context.report({
|
|
1126
|
+
messageId: "noWaitForSelector",
|
|
1127
|
+
node,
|
|
1128
|
+
suggest: [
|
|
1129
|
+
{
|
|
1130
|
+
fix: (fixer) => fixer.remove(
|
|
1131
|
+
node.parent && node.parent.type !== "AwaitExpression" ? node.parent : node.parent.parent
|
|
1132
|
+
),
|
|
1133
|
+
messageId: "removeWaitForSelector"
|
|
1134
|
+
}
|
|
1135
|
+
]
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1140
|
+
},
|
|
1141
|
+
meta: {
|
|
1142
|
+
docs: {
|
|
1143
|
+
category: "Best Practices",
|
|
1144
|
+
description: "Prevent usage of page.waitForSelector()",
|
|
1145
|
+
recommended: true,
|
|
1146
|
+
url: "https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-wait-for-selector.md"
|
|
1147
|
+
},
|
|
1148
|
+
hasSuggestions: true,
|
|
1149
|
+
messages: {
|
|
1150
|
+
noWaitForSelector: "Unexpected use of page.waitForSelector().",
|
|
1151
|
+
removeWaitForSelector: "Remove the page.waitForSelector() method."
|
|
1152
|
+
},
|
|
1153
|
+
type: "suggestion"
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
|
|
1076
1157
|
// src/rules/no-wait-for-timeout.ts
|
|
1077
1158
|
var no_wait_for_timeout_default = {
|
|
1078
1159
|
create(context) {
|
|
@@ -2061,6 +2142,7 @@ var index = {
|
|
|
2061
2142
|
"no-skipped-test": no_skipped_test_default,
|
|
2062
2143
|
"no-useless-await": no_useless_await_default,
|
|
2063
2144
|
"no-useless-not": no_useless_not_default,
|
|
2145
|
+
"no-wait-for-selector": no_wait_for_selector_default,
|
|
2064
2146
|
"no-wait-for-timeout": no_wait_for_timeout_default,
|
|
2065
2147
|
"prefer-lowercase-title": prefer_lowercase_title_default,
|
|
2066
2148
|
"prefer-strict-equal": prefer_strict_equal_default,
|
|
@@ -2092,6 +2174,7 @@ var sharedConfig = {
|
|
|
2092
2174
|
"playwright/no-skipped-test": "warn",
|
|
2093
2175
|
"playwright/no-useless-await": "warn",
|
|
2094
2176
|
"playwright/no-useless-not": "warn",
|
|
2177
|
+
"playwright/no-wait-for-selector": "warn",
|
|
2095
2178
|
"playwright/no-wait-for-timeout": "warn",
|
|
2096
2179
|
"playwright/prefer-web-first-assertions": "error",
|
|
2097
2180
|
"playwright/valid-expect": "error",
|
package/dist/index.mjs
CHANGED
|
@@ -260,29 +260,24 @@ var init_max_nested_describe = __esm({
|
|
|
260
260
|
// src/rules/missing-playwright-await.ts
|
|
261
261
|
function getCallType(node, awaitableMatchers) {
|
|
262
262
|
if (node.callee.type === "MemberExpression" && isIdentifier(node.callee.object, "test") && isPropertyAccessor(node.callee, "step")) {
|
|
263
|
-
return { messageId: "testStep" };
|
|
263
|
+
return { messageId: "testStep", node };
|
|
264
264
|
}
|
|
265
265
|
const expectType = getExpectType(node);
|
|
266
266
|
if (!expectType)
|
|
267
267
|
return;
|
|
268
|
-
if (expectType === "poll") {
|
|
269
|
-
return { messageId: "expectPoll" };
|
|
270
|
-
}
|
|
271
268
|
const [lastMatcher] = getMatchers(node).slice(-1);
|
|
269
|
+
const grandparent = lastMatcher?.parent?.parent;
|
|
270
|
+
if (grandparent?.type !== "CallExpression")
|
|
271
|
+
return;
|
|
272
272
|
const matcherName = getStringValue(lastMatcher);
|
|
273
|
-
if (awaitableMatchers.has(matcherName)) {
|
|
274
|
-
return {
|
|
273
|
+
if (expectType === "poll" || awaitableMatchers.has(matcherName)) {
|
|
274
|
+
return {
|
|
275
|
+
data: { matcherName },
|
|
276
|
+
messageId: expectType === "poll" ? "expectPoll" : "expect",
|
|
277
|
+
node: grandparent
|
|
278
|
+
};
|
|
275
279
|
}
|
|
276
280
|
}
|
|
277
|
-
function isPromiseAll(node) {
|
|
278
|
-
return node.type === "ArrayExpression" && node.parent.type === "CallExpression" && node.parent.callee.type === "MemberExpression" && isIdentifier(node.parent.callee.object, "Promise") && isIdentifier(node.parent.callee.property, "all") ? node.parent : null;
|
|
279
|
-
}
|
|
280
|
-
function checkValidity(node) {
|
|
281
|
-
if (validTypes.has(node.parent.type))
|
|
282
|
-
return;
|
|
283
|
-
const promiseAll = isPromiseAll(node.parent);
|
|
284
|
-
return promiseAll ? checkValidity(promiseAll) : node.parent.type === "MemberExpression" || node.parent.type === "CallExpression" && node.parent.callee === node ? checkValidity(node.parent) : node;
|
|
285
|
-
}
|
|
286
281
|
var validTypes, expectPlaywrightMatchers, playwrightTestMatchers, missing_playwright_await_default;
|
|
287
282
|
var init_missing_playwright_await = __esm({
|
|
288
283
|
"src/rules/missing-playwright-await.ts"() {
|
|
@@ -341,6 +336,7 @@ var init_missing_playwright_await = __esm({
|
|
|
341
336
|
];
|
|
342
337
|
missing_playwright_await_default = {
|
|
343
338
|
create(context) {
|
|
339
|
+
const sourceCode = context.sourceCode ?? context.getSourceCode();
|
|
344
340
|
const options = context.options[0] || {};
|
|
345
341
|
const awaitableMatchers = /* @__PURE__ */ new Set([
|
|
346
342
|
...expectPlaywrightMatchers,
|
|
@@ -348,11 +344,33 @@ var init_missing_playwright_await = __esm({
|
|
|
348
344
|
// Add any custom matchers to the set
|
|
349
345
|
...options.customMatchers || []
|
|
350
346
|
]);
|
|
347
|
+
function checkValidity(node) {
|
|
348
|
+
if (validTypes.has(node.parent.type))
|
|
349
|
+
return true;
|
|
350
|
+
if (node.parent.type === "ArrayExpression") {
|
|
351
|
+
return checkValidity(node.parent);
|
|
352
|
+
}
|
|
353
|
+
if (node.parent.type === "CallExpression" && node.parent.callee.type === "MemberExpression" && isIdentifier(node.parent.callee.object, "Promise") && isIdentifier(node.parent.callee.property, "all")) {
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
if (node.parent.type === "VariableDeclarator") {
|
|
357
|
+
const scope = sourceCode.getScope(node.parent.parent);
|
|
358
|
+
for (const ref of scope.references) {
|
|
359
|
+
const refParent = ref.identifier.parent;
|
|
360
|
+
if (validTypes.has(refParent.type))
|
|
361
|
+
return true;
|
|
362
|
+
if (checkValidity(refParent))
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
351
368
|
return {
|
|
352
369
|
CallExpression(node) {
|
|
353
370
|
const result = getCallType(node, awaitableMatchers);
|
|
354
|
-
|
|
355
|
-
|
|
371
|
+
console.log(result);
|
|
372
|
+
const isValid = result ? checkValidity(result.node) : false;
|
|
373
|
+
if (result && !isValid) {
|
|
356
374
|
context.report({
|
|
357
375
|
data: result.data,
|
|
358
376
|
fix: (fixer) => fixer.insertTextBefore(node, "await "),
|
|
@@ -826,6 +844,10 @@ var init_no_page_pause = __esm({
|
|
|
826
844
|
});
|
|
827
845
|
|
|
828
846
|
// src/rules/no-raw-locators.ts
|
|
847
|
+
function normalize(str) {
|
|
848
|
+
const match = /\[([^=]+?)=['"]?([^'"]+?)['"]?\]/.exec(str);
|
|
849
|
+
return match ? `[${match[1]}=${match[2]}]` : str;
|
|
850
|
+
}
|
|
829
851
|
var no_raw_locators_default;
|
|
830
852
|
var init_no_raw_locators = __esm({
|
|
831
853
|
"src/rules/no-raw-locators.ts"() {
|
|
@@ -833,12 +855,21 @@ var init_no_raw_locators = __esm({
|
|
|
833
855
|
init_ast();
|
|
834
856
|
no_raw_locators_default = {
|
|
835
857
|
create(context) {
|
|
858
|
+
const options = {
|
|
859
|
+
allowed: [],
|
|
860
|
+
...context.options?.[0] ?? {}
|
|
861
|
+
};
|
|
862
|
+
function isAllowed(arg) {
|
|
863
|
+
return options.allowed.some((a) => normalize(a) === normalize(arg));
|
|
864
|
+
}
|
|
836
865
|
return {
|
|
837
866
|
CallExpression(node) {
|
|
838
867
|
if (node.callee.type !== "MemberExpression")
|
|
839
868
|
return;
|
|
840
869
|
const method = getStringValue(node.callee.property);
|
|
841
|
-
|
|
870
|
+
const arg = getStringValue(node.arguments[0]);
|
|
871
|
+
const isLocator = isPageMethod(node, "locator") || method === "locator";
|
|
872
|
+
if (isLocator && !isAllowed(arg)) {
|
|
842
873
|
context.report({ messageId: "noRawLocator", node });
|
|
843
874
|
}
|
|
844
875
|
}
|
|
@@ -854,6 +885,18 @@ var init_no_raw_locators = __esm({
|
|
|
854
885
|
messages: {
|
|
855
886
|
noRawLocator: "Usage of raw locator detected. Use methods like .getByRole() or .getByText() instead of raw locators."
|
|
856
887
|
},
|
|
888
|
+
schema: [
|
|
889
|
+
{
|
|
890
|
+
additionalProperties: false,
|
|
891
|
+
properties: {
|
|
892
|
+
allowed: {
|
|
893
|
+
items: { type: "string" },
|
|
894
|
+
type: "array"
|
|
895
|
+
}
|
|
896
|
+
},
|
|
897
|
+
type: "object"
|
|
898
|
+
}
|
|
899
|
+
],
|
|
857
900
|
type: "suggestion"
|
|
858
901
|
}
|
|
859
902
|
};
|
|
@@ -1202,6 +1245,51 @@ var init_no_useless_not = __esm({
|
|
|
1202
1245
|
}
|
|
1203
1246
|
});
|
|
1204
1247
|
|
|
1248
|
+
// src/rules/no-wait-for-selector.ts
|
|
1249
|
+
var no_wait_for_selector_default;
|
|
1250
|
+
var init_no_wait_for_selector = __esm({
|
|
1251
|
+
"src/rules/no-wait-for-selector.ts"() {
|
|
1252
|
+
"use strict";
|
|
1253
|
+
init_ast();
|
|
1254
|
+
no_wait_for_selector_default = {
|
|
1255
|
+
create(context) {
|
|
1256
|
+
return {
|
|
1257
|
+
CallExpression(node) {
|
|
1258
|
+
if (isPageMethod(node, "waitForSelector")) {
|
|
1259
|
+
context.report({
|
|
1260
|
+
messageId: "noWaitForSelector",
|
|
1261
|
+
node,
|
|
1262
|
+
suggest: [
|
|
1263
|
+
{
|
|
1264
|
+
fix: (fixer) => fixer.remove(
|
|
1265
|
+
node.parent && node.parent.type !== "AwaitExpression" ? node.parent : node.parent.parent
|
|
1266
|
+
),
|
|
1267
|
+
messageId: "removeWaitForSelector"
|
|
1268
|
+
}
|
|
1269
|
+
]
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
};
|
|
1274
|
+
},
|
|
1275
|
+
meta: {
|
|
1276
|
+
docs: {
|
|
1277
|
+
category: "Best Practices",
|
|
1278
|
+
description: "Prevent usage of page.waitForSelector()",
|
|
1279
|
+
recommended: true,
|
|
1280
|
+
url: "https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-wait-for-selector.md"
|
|
1281
|
+
},
|
|
1282
|
+
hasSuggestions: true,
|
|
1283
|
+
messages: {
|
|
1284
|
+
noWaitForSelector: "Unexpected use of page.waitForSelector().",
|
|
1285
|
+
removeWaitForSelector: "Remove the page.waitForSelector() method."
|
|
1286
|
+
},
|
|
1287
|
+
type: "suggestion"
|
|
1288
|
+
}
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
});
|
|
1292
|
+
|
|
1205
1293
|
// src/rules/no-wait-for-timeout.ts
|
|
1206
1294
|
var no_wait_for_timeout_default;
|
|
1207
1295
|
var init_no_wait_for_timeout = __esm({
|
|
@@ -2285,6 +2373,7 @@ var require_src = __commonJS({
|
|
|
2285
2373
|
init_no_skipped_test();
|
|
2286
2374
|
init_no_useless_await();
|
|
2287
2375
|
init_no_useless_not();
|
|
2376
|
+
init_no_wait_for_selector();
|
|
2288
2377
|
init_no_wait_for_timeout();
|
|
2289
2378
|
init_prefer_lowercase_title();
|
|
2290
2379
|
init_prefer_strict_equal();
|
|
@@ -2317,6 +2406,7 @@ var require_src = __commonJS({
|
|
|
2317
2406
|
"no-skipped-test": no_skipped_test_default,
|
|
2318
2407
|
"no-useless-await": no_useless_await_default,
|
|
2319
2408
|
"no-useless-not": no_useless_not_default,
|
|
2409
|
+
"no-wait-for-selector": no_wait_for_selector_default,
|
|
2320
2410
|
"no-wait-for-timeout": no_wait_for_timeout_default,
|
|
2321
2411
|
"prefer-lowercase-title": prefer_lowercase_title_default,
|
|
2322
2412
|
"prefer-strict-equal": prefer_strict_equal_default,
|
|
@@ -2348,6 +2438,7 @@ var require_src = __commonJS({
|
|
|
2348
2438
|
"playwright/no-skipped-test": "warn",
|
|
2349
2439
|
"playwright/no-useless-await": "warn",
|
|
2350
2440
|
"playwright/no-useless-not": "warn",
|
|
2441
|
+
"playwright/no-wait-for-selector": "warn",
|
|
2351
2442
|
"playwright/no-wait-for-timeout": "warn",
|
|
2352
2443
|
"playwright/prefer-web-first-assertions": "error",
|
|
2353
2444
|
"playwright/valid-expect": "error",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-playwright",
|
|
3
3
|
"description": "ESLint plugin for Playwright testing.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.22.0",
|
|
5
5
|
"repository": "https://github.com/playwright-community/eslint-plugin-playwright",
|
|
6
6
|
"author": "Mark Skelton <mark@mskelton.dev>",
|
|
7
7
|
"packageManager": "pnpm@8.12.0",
|