eslint-plugin-playwright 1.0.0 → 1.1.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 +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +149 -14
- package/dist/index.mjs +176 -20
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -131,6 +131,7 @@ command line option.\
|
|
|
131
131
|
| ✔ | | | [no-networkidle](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-networkidle.md) | Disallow usage of the `networkidle` option |
|
|
132
132
|
| | | | [no-nth-methods](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-nth-methods.md) | Disallow usage of `first()`, `last()`, and `nth()` methods |
|
|
133
133
|
| ✔ | | | [no-page-pause](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-page-pause.md) | Disallow using `page.pause()` |
|
|
134
|
+
| ✔ | 🔧 | | [no-unsafe-references](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-unsafe-references.md) | Prevent unsafe variable references in `page.evaluate()` |
|
|
134
135
|
| | 🔧 | | [no-get-by-title](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-get-by-title.md) | Disallow using `getByTitle()` |
|
|
135
136
|
| | | | [no-raw-locators](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-raw-locators.md) | Disallow using raw locators |
|
|
136
137
|
| ✔ | 🔧 | | [no-useless-await](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-useless-await.md) | Disallow unnecessary `await`s for Playwright methods |
|
package/dist/index.d.mts
CHANGED
|
@@ -18,6 +18,7 @@ declare const _default: {
|
|
|
18
18
|
'no-eval': eslint.Rule.RuleModule;
|
|
19
19
|
'no-focused-test': eslint.Rule.RuleModule;
|
|
20
20
|
'no-force-option': eslint.Rule.RuleModule;
|
|
21
|
+
'no-get-by-title': eslint.Rule.RuleModule;
|
|
21
22
|
'no-nested-step': eslint.Rule.RuleModule;
|
|
22
23
|
'no-networkidle': eslint.Rule.RuleModule;
|
|
23
24
|
'no-nth-methods': eslint.Rule.RuleModule;
|
|
@@ -25,6 +26,7 @@ declare const _default: {
|
|
|
25
26
|
'no-raw-locators': eslint.Rule.RuleModule;
|
|
26
27
|
'no-restricted-matchers': eslint.Rule.RuleModule;
|
|
27
28
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
29
|
+
'no-unsafe-references': eslint.Rule.RuleModule;
|
|
28
30
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
29
31
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
30
32
|
'no-wait-for-selector': eslint.Rule.RuleModule;
|
|
@@ -67,6 +69,7 @@ declare const _default: {
|
|
|
67
69
|
'no-eval': eslint.Rule.RuleModule;
|
|
68
70
|
'no-focused-test': eslint.Rule.RuleModule;
|
|
69
71
|
'no-force-option': eslint.Rule.RuleModule;
|
|
72
|
+
'no-get-by-title': eslint.Rule.RuleModule;
|
|
70
73
|
'no-nested-step': eslint.Rule.RuleModule;
|
|
71
74
|
'no-networkidle': eslint.Rule.RuleModule;
|
|
72
75
|
'no-nth-methods': eslint.Rule.RuleModule;
|
|
@@ -74,6 +77,7 @@ declare const _default: {
|
|
|
74
77
|
'no-raw-locators': eslint.Rule.RuleModule;
|
|
75
78
|
'no-restricted-matchers': eslint.Rule.RuleModule;
|
|
76
79
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
80
|
+
'no-unsafe-references': eslint.Rule.RuleModule;
|
|
77
81
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
78
82
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
79
83
|
'no-wait-for-selector': eslint.Rule.RuleModule;
|
|
@@ -106,6 +110,7 @@ declare const _default: {
|
|
|
106
110
|
'playwright/no-networkidle': string;
|
|
107
111
|
'playwright/no-page-pause': string;
|
|
108
112
|
'playwright/no-skipped-test': string;
|
|
113
|
+
'playwright/no-unsafe-references': string;
|
|
109
114
|
'playwright/no-useless-await': string;
|
|
110
115
|
'playwright/no-useless-not': string;
|
|
111
116
|
'playwright/no-wait-for-selector': string;
|
|
@@ -156,6 +161,7 @@ declare const _default: {
|
|
|
156
161
|
'playwright/no-networkidle': string;
|
|
157
162
|
'playwright/no-page-pause': string;
|
|
158
163
|
'playwright/no-skipped-test': string;
|
|
164
|
+
'playwright/no-unsafe-references': string;
|
|
159
165
|
'playwright/no-useless-await': string;
|
|
160
166
|
'playwright/no-useless-not': string;
|
|
161
167
|
'playwright/no-wait-for-selector': string;
|
|
@@ -184,6 +190,7 @@ declare const _default: {
|
|
|
184
190
|
'playwright/no-networkidle': string;
|
|
185
191
|
'playwright/no-page-pause': string;
|
|
186
192
|
'playwright/no-skipped-test': string;
|
|
193
|
+
'playwright/no-unsafe-references': string;
|
|
187
194
|
'playwright/no-useless-await': string;
|
|
188
195
|
'playwright/no-useless-not': string;
|
|
189
196
|
'playwright/no-wait-for-selector': string;
|
|
@@ -203,6 +210,7 @@ declare const _default: {
|
|
|
203
210
|
'no-eval': eslint.Rule.RuleModule;
|
|
204
211
|
'no-focused-test': eslint.Rule.RuleModule;
|
|
205
212
|
'no-force-option': eslint.Rule.RuleModule;
|
|
213
|
+
'no-get-by-title': eslint.Rule.RuleModule;
|
|
206
214
|
'no-nested-step': eslint.Rule.RuleModule;
|
|
207
215
|
'no-networkidle': eslint.Rule.RuleModule;
|
|
208
216
|
'no-nth-methods': eslint.Rule.RuleModule;
|
|
@@ -210,6 +218,7 @@ declare const _default: {
|
|
|
210
218
|
'no-raw-locators': eslint.Rule.RuleModule;
|
|
211
219
|
'no-restricted-matchers': eslint.Rule.RuleModule;
|
|
212
220
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
221
|
+
'no-unsafe-references': eslint.Rule.RuleModule;
|
|
213
222
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
214
223
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
215
224
|
'no-wait-for-selector': eslint.Rule.RuleModule;
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ declare const _default: {
|
|
|
18
18
|
'no-eval': eslint.Rule.RuleModule;
|
|
19
19
|
'no-focused-test': eslint.Rule.RuleModule;
|
|
20
20
|
'no-force-option': eslint.Rule.RuleModule;
|
|
21
|
+
'no-get-by-title': eslint.Rule.RuleModule;
|
|
21
22
|
'no-nested-step': eslint.Rule.RuleModule;
|
|
22
23
|
'no-networkidle': eslint.Rule.RuleModule;
|
|
23
24
|
'no-nth-methods': eslint.Rule.RuleModule;
|
|
@@ -25,6 +26,7 @@ declare const _default: {
|
|
|
25
26
|
'no-raw-locators': eslint.Rule.RuleModule;
|
|
26
27
|
'no-restricted-matchers': eslint.Rule.RuleModule;
|
|
27
28
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
29
|
+
'no-unsafe-references': eslint.Rule.RuleModule;
|
|
28
30
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
29
31
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
30
32
|
'no-wait-for-selector': eslint.Rule.RuleModule;
|
|
@@ -67,6 +69,7 @@ declare const _default: {
|
|
|
67
69
|
'no-eval': eslint.Rule.RuleModule;
|
|
68
70
|
'no-focused-test': eslint.Rule.RuleModule;
|
|
69
71
|
'no-force-option': eslint.Rule.RuleModule;
|
|
72
|
+
'no-get-by-title': eslint.Rule.RuleModule;
|
|
70
73
|
'no-nested-step': eslint.Rule.RuleModule;
|
|
71
74
|
'no-networkidle': eslint.Rule.RuleModule;
|
|
72
75
|
'no-nth-methods': eslint.Rule.RuleModule;
|
|
@@ -74,6 +77,7 @@ declare const _default: {
|
|
|
74
77
|
'no-raw-locators': eslint.Rule.RuleModule;
|
|
75
78
|
'no-restricted-matchers': eslint.Rule.RuleModule;
|
|
76
79
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
80
|
+
'no-unsafe-references': eslint.Rule.RuleModule;
|
|
77
81
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
78
82
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
79
83
|
'no-wait-for-selector': eslint.Rule.RuleModule;
|
|
@@ -106,6 +110,7 @@ declare const _default: {
|
|
|
106
110
|
'playwright/no-networkidle': string;
|
|
107
111
|
'playwright/no-page-pause': string;
|
|
108
112
|
'playwright/no-skipped-test': string;
|
|
113
|
+
'playwright/no-unsafe-references': string;
|
|
109
114
|
'playwright/no-useless-await': string;
|
|
110
115
|
'playwright/no-useless-not': string;
|
|
111
116
|
'playwright/no-wait-for-selector': string;
|
|
@@ -156,6 +161,7 @@ declare const _default: {
|
|
|
156
161
|
'playwright/no-networkidle': string;
|
|
157
162
|
'playwright/no-page-pause': string;
|
|
158
163
|
'playwright/no-skipped-test': string;
|
|
164
|
+
'playwright/no-unsafe-references': string;
|
|
159
165
|
'playwright/no-useless-await': string;
|
|
160
166
|
'playwright/no-useless-not': string;
|
|
161
167
|
'playwright/no-wait-for-selector': string;
|
|
@@ -184,6 +190,7 @@ declare const _default: {
|
|
|
184
190
|
'playwright/no-networkidle': string;
|
|
185
191
|
'playwright/no-page-pause': string;
|
|
186
192
|
'playwright/no-skipped-test': string;
|
|
193
|
+
'playwright/no-unsafe-references': string;
|
|
187
194
|
'playwright/no-useless-await': string;
|
|
188
195
|
'playwright/no-useless-not': string;
|
|
189
196
|
'playwright/no-wait-for-selector': string;
|
|
@@ -203,6 +210,7 @@ declare const _default: {
|
|
|
203
210
|
'no-eval': eslint.Rule.RuleModule;
|
|
204
211
|
'no-focused-test': eslint.Rule.RuleModule;
|
|
205
212
|
'no-force-option': eslint.Rule.RuleModule;
|
|
213
|
+
'no-get-by-title': eslint.Rule.RuleModule;
|
|
206
214
|
'no-nested-step': eslint.Rule.RuleModule;
|
|
207
215
|
'no-networkidle': eslint.Rule.RuleModule;
|
|
208
216
|
'no-nth-methods': eslint.Rule.RuleModule;
|
|
@@ -210,6 +218,7 @@ declare const _default: {
|
|
|
210
218
|
'no-raw-locators': eslint.Rule.RuleModule;
|
|
211
219
|
'no-restricted-matchers': eslint.Rule.RuleModule;
|
|
212
220
|
'no-skipped-test': eslint.Rule.RuleModule;
|
|
221
|
+
'no-unsafe-references': eslint.Rule.RuleModule;
|
|
213
222
|
'no-useless-await': eslint.Rule.RuleModule;
|
|
214
223
|
'no-useless-not': eslint.Rule.RuleModule;
|
|
215
224
|
'no-wait-for-selector': eslint.Rule.RuleModule;
|
package/dist/index.js
CHANGED
|
@@ -123,6 +123,19 @@ function dig(node, identifier) {
|
|
|
123
123
|
function isPageMethod(node, name) {
|
|
124
124
|
return node.callee.type === "MemberExpression" && dig(node.callee.object, /(^(page|frame)|(Page|Frame)$)/) && isPropertyAccessor(node.callee, name);
|
|
125
125
|
}
|
|
126
|
+
function isFunction(node) {
|
|
127
|
+
return node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression";
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/utils/misc.ts
|
|
131
|
+
var getAmountData = (amount) => ({
|
|
132
|
+
amount: amount.toString(),
|
|
133
|
+
s: amount === 1 ? "" : "s"
|
|
134
|
+
});
|
|
135
|
+
function getSourceCode(context) {
|
|
136
|
+
return context.sourceCode ?? context.getSourceCode();
|
|
137
|
+
}
|
|
138
|
+
var truthy = Boolean;
|
|
126
139
|
|
|
127
140
|
// src/rules/expect-expect.ts
|
|
128
141
|
function isAssertionCall(context, node, assertFunctionNames) {
|
|
@@ -134,7 +147,7 @@ var expect_expect_default = {
|
|
|
134
147
|
assertFunctionNames: [],
|
|
135
148
|
...context.options?.[0] ?? {}
|
|
136
149
|
};
|
|
137
|
-
const sourceCode =
|
|
150
|
+
const sourceCode = getSourceCode(context);
|
|
138
151
|
const unchecked = [];
|
|
139
152
|
function checkExpressions(nodes) {
|
|
140
153
|
for (const node of nodes) {
|
|
@@ -323,7 +336,7 @@ function getCallType(context, node, awaitableMatchers) {
|
|
|
323
336
|
}
|
|
324
337
|
var missing_playwright_await_default = {
|
|
325
338
|
create(context) {
|
|
326
|
-
const sourceCode =
|
|
339
|
+
const sourceCode = getSourceCode(context);
|
|
327
340
|
const options = context.options[0] || {};
|
|
328
341
|
const awaitableMatchers = /* @__PURE__ */ new Set([
|
|
329
342
|
...expectPlaywrightMatchers,
|
|
@@ -556,7 +569,7 @@ var no_focused_test_default = {
|
|
|
556
569
|
|
|
557
570
|
// src/rules/no-force-option.ts
|
|
558
571
|
function isForceOptionEnabled(node) {
|
|
559
|
-
const arg = node.arguments
|
|
572
|
+
const arg = node.arguments.at(-1);
|
|
560
573
|
return arg?.type === "ObjectExpression" && arg.properties.find(
|
|
561
574
|
(property) => property.type === "Property" && getStringValue(property.key) === "force" && isBooleanLiteral(property.value, true)
|
|
562
575
|
);
|
|
@@ -601,6 +614,31 @@ var no_force_option_default = {
|
|
|
601
614
|
}
|
|
602
615
|
};
|
|
603
616
|
|
|
617
|
+
// src/rules/no-get-by-title.ts
|
|
618
|
+
var no_get_by_title_default = {
|
|
619
|
+
create(context) {
|
|
620
|
+
return {
|
|
621
|
+
CallExpression(node) {
|
|
622
|
+
if (isPageMethod(node, "getByTitle")) {
|
|
623
|
+
context.report({ messageId: "noGetByTitle", node });
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
},
|
|
628
|
+
meta: {
|
|
629
|
+
docs: {
|
|
630
|
+
category: "Best Practices",
|
|
631
|
+
description: "Disallows the usage of getByTitle()",
|
|
632
|
+
recommended: false,
|
|
633
|
+
url: "https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-get-by-title.md"
|
|
634
|
+
},
|
|
635
|
+
messages: {
|
|
636
|
+
noGetByTitle: "The HTML title attribute is not an accessible name. Prefer getByRole() or getByLabelText() instead."
|
|
637
|
+
},
|
|
638
|
+
type: "suggestion"
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
|
|
604
642
|
// src/rules/no-nested-step.ts
|
|
605
643
|
function isStepCall(node) {
|
|
606
644
|
const inner = node.type === "CallExpression" ? node.callee : node;
|
|
@@ -876,7 +914,7 @@ var no_restricted_matchers_default = {
|
|
|
876
914
|
context.report({
|
|
877
915
|
data: { message: message ?? "", restriction },
|
|
878
916
|
loc: {
|
|
879
|
-
end: chain
|
|
917
|
+
end: chain.at(-1).loc.end,
|
|
880
918
|
start: chain[0].loc.start
|
|
881
919
|
},
|
|
882
920
|
messageId: message ? "restrictedWithMessage" : "restricted"
|
|
@@ -968,6 +1006,93 @@ var no_skipped_test_default = {
|
|
|
968
1006
|
}
|
|
969
1007
|
};
|
|
970
1008
|
|
|
1009
|
+
// src/rules/no-unsafe-references.ts
|
|
1010
|
+
function collectVariables(scope) {
|
|
1011
|
+
if (!scope)
|
|
1012
|
+
return [];
|
|
1013
|
+
return [
|
|
1014
|
+
...collectVariables(scope.upper),
|
|
1015
|
+
...scope.variables.map((ref) => ref.name)
|
|
1016
|
+
];
|
|
1017
|
+
}
|
|
1018
|
+
function addArgument(fixer, node, refs) {
|
|
1019
|
+
if (!node.arguments.length)
|
|
1020
|
+
return;
|
|
1021
|
+
if (node.arguments.length === 1) {
|
|
1022
|
+
return fixer.insertTextAfter(node.arguments[0], `, [${refs}]`);
|
|
1023
|
+
}
|
|
1024
|
+
const arr = node.arguments.at(-1);
|
|
1025
|
+
if (!arr || arr.type !== "ArrayExpression")
|
|
1026
|
+
return;
|
|
1027
|
+
const lastItem = arr.elements.at(-1);
|
|
1028
|
+
return lastItem ? fixer.insertTextAfter(lastItem, `, ${refs}`) : fixer.replaceText(arr, `[${refs}]`);
|
|
1029
|
+
}
|
|
1030
|
+
function getParen(sourceCode, node) {
|
|
1031
|
+
let token = sourceCode.getFirstToken(node);
|
|
1032
|
+
while (token && token.value !== "(") {
|
|
1033
|
+
token = sourceCode.getTokenAfter(token);
|
|
1034
|
+
}
|
|
1035
|
+
return token;
|
|
1036
|
+
}
|
|
1037
|
+
function addParam(sourceCode, fixer, node, refs) {
|
|
1038
|
+
const lastParam = node.params.at(-1);
|
|
1039
|
+
if (lastParam) {
|
|
1040
|
+
return fixer.insertTextAfter(lastParam, `, ${refs}`);
|
|
1041
|
+
}
|
|
1042
|
+
const token = getParen(sourceCode, node);
|
|
1043
|
+
return token ? fixer.insertTextAfter(token, `[${refs}]`) : null;
|
|
1044
|
+
}
|
|
1045
|
+
var no_unsafe_references_default = {
|
|
1046
|
+
create(context) {
|
|
1047
|
+
return {
|
|
1048
|
+
CallExpression(node) {
|
|
1049
|
+
if (!isPageMethod(node, "evaluate"))
|
|
1050
|
+
return;
|
|
1051
|
+
const [fn] = node.arguments;
|
|
1052
|
+
if (!fn || !isFunction(fn))
|
|
1053
|
+
return;
|
|
1054
|
+
const sourceCode = getSourceCode(context);
|
|
1055
|
+
const { through, upper } = sourceCode.getScope(fn.body);
|
|
1056
|
+
const allRefs = new Set(collectVariables(upper));
|
|
1057
|
+
through.filter((ref) => allRefs.has(ref.identifier.name)).forEach((ref, i, arr) => {
|
|
1058
|
+
const descriptor = {
|
|
1059
|
+
data: { variable: ref.identifier.name },
|
|
1060
|
+
messageId: "noUnsafeReference",
|
|
1061
|
+
node: ref.identifier
|
|
1062
|
+
};
|
|
1063
|
+
if (i !== 0) {
|
|
1064
|
+
context.report(descriptor);
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
context.report({
|
|
1068
|
+
...descriptor,
|
|
1069
|
+
fix(fixer) {
|
|
1070
|
+
const refs = arr.map((ref2) => ref2.identifier.name).join(", ");
|
|
1071
|
+
return [
|
|
1072
|
+
addArgument(fixer, node, refs),
|
|
1073
|
+
addParam(sourceCode, fixer, fn, refs)
|
|
1074
|
+
].filter(truthy);
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
1080
|
+
},
|
|
1081
|
+
meta: {
|
|
1082
|
+
docs: {
|
|
1083
|
+
category: "Possible Errors",
|
|
1084
|
+
description: "Prevent unsafe variable references in page.evaluate()",
|
|
1085
|
+
recommended: true,
|
|
1086
|
+
url: "https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-unsafe-references.md"
|
|
1087
|
+
},
|
|
1088
|
+
fixable: "code",
|
|
1089
|
+
messages: {
|
|
1090
|
+
noUnsafeReference: 'Unsafe reference to variable "{{ variable }}" in page.evaluate()'
|
|
1091
|
+
},
|
|
1092
|
+
type: "problem"
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
1095
|
+
|
|
971
1096
|
// src/rules/no-useless-await.ts
|
|
972
1097
|
var locatorMethods = /* @__PURE__ */ new Set([
|
|
973
1098
|
"and",
|
|
@@ -1440,7 +1565,7 @@ var prefer_to_contain_default = {
|
|
|
1440
1565
|
);
|
|
1441
1566
|
context.report({
|
|
1442
1567
|
fix(fixer) {
|
|
1443
|
-
const sourceCode =
|
|
1568
|
+
const sourceCode = getSourceCode(context);
|
|
1444
1569
|
const addNotModifier = matcherArg.type === "Literal" && matcherArg.value === !!notModifier;
|
|
1445
1570
|
const fixes = [
|
|
1446
1571
|
// remove the "includes" call entirely
|
|
@@ -1636,6 +1761,19 @@ var supportedMatchers = /* @__PURE__ */ new Set([
|
|
|
1636
1761
|
"toBeTruthy",
|
|
1637
1762
|
"toBeFalsy"
|
|
1638
1763
|
]);
|
|
1764
|
+
function dereference(context, node) {
|
|
1765
|
+
if (node.type !== "Identifier") {
|
|
1766
|
+
return node;
|
|
1767
|
+
}
|
|
1768
|
+
const sourceCode = getSourceCode(context);
|
|
1769
|
+
const scope = sourceCode.getScope(node);
|
|
1770
|
+
for (const ref of scope.references) {
|
|
1771
|
+
const refParent = ref.identifier.parent;
|
|
1772
|
+
if (refParent.type === "VariableDeclarator") {
|
|
1773
|
+
return refParent.init;
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1639
1777
|
var prefer_web_first_assertions_default = {
|
|
1640
1778
|
create(context) {
|
|
1641
1779
|
return {
|
|
@@ -1643,8 +1781,8 @@ var prefer_web_first_assertions_default = {
|
|
|
1643
1781
|
const expectCall = parseExpectCall(context, node);
|
|
1644
1782
|
if (!expectCall)
|
|
1645
1783
|
return;
|
|
1646
|
-
const
|
|
1647
|
-
if (arg.type !== "AwaitExpression" || arg.argument.type !== "CallExpression" || arg.argument.callee.type !== "MemberExpression") {
|
|
1784
|
+
const arg = dereference(context, node.arguments[0]);
|
|
1785
|
+
if (!arg || arg.type !== "AwaitExpression" || arg.argument.type !== "CallExpression" || arg.argument.callee.type !== "MemberExpression") {
|
|
1648
1786
|
return;
|
|
1649
1787
|
}
|
|
1650
1788
|
if (!supportedMatchers.has(expectCall.matcherName))
|
|
@@ -1668,7 +1806,7 @@ var prefer_web_first_assertions_default = {
|
|
|
1668
1806
|
},
|
|
1669
1807
|
fix: (fixer) => {
|
|
1670
1808
|
const methodArgs = arg.argument.type === "CallExpression" ? arg.argument.arguments : [];
|
|
1671
|
-
const methodEnd = methodArgs.length ? methodArgs
|
|
1809
|
+
const methodEnd = methodArgs.length ? methodArgs.at(-1).range[1] + 1 : callee.property.range[1] + 2;
|
|
1672
1810
|
const fixes = [
|
|
1673
1811
|
// Add await to the expect call
|
|
1674
1812
|
fixer.insertTextBefore(node, "await "),
|
|
@@ -1766,12 +1904,6 @@ var require_soft_assertions_default = {
|
|
|
1766
1904
|
}
|
|
1767
1905
|
};
|
|
1768
1906
|
|
|
1769
|
-
// src/utils/misc.ts
|
|
1770
|
-
var getAmountData = (amount) => ({
|
|
1771
|
-
amount: amount.toString(),
|
|
1772
|
-
s: amount === 1 ? "" : "s"
|
|
1773
|
-
});
|
|
1774
|
-
|
|
1775
1907
|
// src/rules/require-top-level-describe.ts
|
|
1776
1908
|
var require_top_level_describe_default = {
|
|
1777
1909
|
create(context) {
|
|
@@ -2147,6 +2279,7 @@ var index = {
|
|
|
2147
2279
|
"no-eval": no_eval_default,
|
|
2148
2280
|
"no-focused-test": no_focused_test_default,
|
|
2149
2281
|
"no-force-option": no_force_option_default,
|
|
2282
|
+
"no-get-by-title": no_get_by_title_default,
|
|
2150
2283
|
"no-nested-step": no_nested_step_default,
|
|
2151
2284
|
"no-networkidle": no_networkidle_default,
|
|
2152
2285
|
"no-nth-methods": no_nth_methods_default,
|
|
@@ -2154,6 +2287,7 @@ var index = {
|
|
|
2154
2287
|
"no-raw-locators": no_raw_locators_default,
|
|
2155
2288
|
"no-restricted-matchers": no_restricted_matchers_default,
|
|
2156
2289
|
"no-skipped-test": no_skipped_test_default,
|
|
2290
|
+
"no-unsafe-references": no_unsafe_references_default,
|
|
2157
2291
|
"no-useless-await": no_useless_await_default,
|
|
2158
2292
|
"no-useless-not": no_useless_not_default,
|
|
2159
2293
|
"no-wait-for-selector": no_wait_for_selector_default,
|
|
@@ -2186,6 +2320,7 @@ var sharedConfig = {
|
|
|
2186
2320
|
"playwright/no-networkidle": "error",
|
|
2187
2321
|
"playwright/no-page-pause": "warn",
|
|
2188
2322
|
"playwright/no-skipped-test": "warn",
|
|
2323
|
+
"playwright/no-unsafe-references": "error",
|
|
2189
2324
|
"playwright/no-useless-await": "warn",
|
|
2190
2325
|
"playwright/no-useless-not": "warn",
|
|
2191
2326
|
"playwright/no-wait-for-selector": "warn",
|
package/dist/index.mjs
CHANGED
|
@@ -93,6 +93,9 @@ function dig(node, identifier) {
|
|
|
93
93
|
function isPageMethod(node, name) {
|
|
94
94
|
return node.callee.type === "MemberExpression" && dig(node.callee.object, /(^(page|frame)|(Page|Frame)$)/) && isPropertyAccessor(node.callee, name);
|
|
95
95
|
}
|
|
96
|
+
function isFunction(node) {
|
|
97
|
+
return node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression";
|
|
98
|
+
}
|
|
96
99
|
var isTemplateLiteral, describeProperties, testHooks, expectSubCommands;
|
|
97
100
|
var init_ast = __esm({
|
|
98
101
|
"src/utils/ast.ts"() {
|
|
@@ -111,6 +114,22 @@ var init_ast = __esm({
|
|
|
111
114
|
}
|
|
112
115
|
});
|
|
113
116
|
|
|
117
|
+
// src/utils/misc.ts
|
|
118
|
+
function getSourceCode(context) {
|
|
119
|
+
return context.sourceCode ?? context.getSourceCode();
|
|
120
|
+
}
|
|
121
|
+
var getAmountData, truthy;
|
|
122
|
+
var init_misc = __esm({
|
|
123
|
+
"src/utils/misc.ts"() {
|
|
124
|
+
"use strict";
|
|
125
|
+
getAmountData = (amount) => ({
|
|
126
|
+
amount: amount.toString(),
|
|
127
|
+
s: amount === 1 ? "" : "s"
|
|
128
|
+
});
|
|
129
|
+
truthy = Boolean;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
114
133
|
// src/rules/expect-expect.ts
|
|
115
134
|
function isAssertionCall(context, node, assertFunctionNames) {
|
|
116
135
|
return isExpectCall(context, node) || assertFunctionNames.find((name) => dig(node.callee, name));
|
|
@@ -120,13 +139,14 @@ var init_expect_expect = __esm({
|
|
|
120
139
|
"src/rules/expect-expect.ts"() {
|
|
121
140
|
"use strict";
|
|
122
141
|
init_ast();
|
|
142
|
+
init_misc();
|
|
123
143
|
expect_expect_default = {
|
|
124
144
|
create(context) {
|
|
125
145
|
const options = {
|
|
126
146
|
assertFunctionNames: [],
|
|
127
147
|
...context.options?.[0] ?? {}
|
|
128
148
|
};
|
|
129
|
-
const sourceCode =
|
|
149
|
+
const sourceCode = getSourceCode(context);
|
|
130
150
|
const unchecked = [];
|
|
131
151
|
function checkExpressions(nodes) {
|
|
132
152
|
for (const node of nodes) {
|
|
@@ -275,6 +295,7 @@ var init_missing_playwright_await = __esm({
|
|
|
275
295
|
"src/rules/missing-playwright-await.ts"() {
|
|
276
296
|
"use strict";
|
|
277
297
|
init_ast();
|
|
298
|
+
init_misc();
|
|
278
299
|
validTypes = /* @__PURE__ */ new Set([
|
|
279
300
|
"AwaitExpression",
|
|
280
301
|
"ReturnStatement",
|
|
@@ -329,7 +350,7 @@ var init_missing_playwright_await = __esm({
|
|
|
329
350
|
];
|
|
330
351
|
missing_playwright_await_default = {
|
|
331
352
|
create(context) {
|
|
332
|
-
const sourceCode =
|
|
353
|
+
const sourceCode = getSourceCode(context);
|
|
333
354
|
const options = context.options[0] || {};
|
|
334
355
|
const awaitableMatchers = /* @__PURE__ */ new Set([
|
|
335
356
|
...expectPlaywrightMatchers,
|
|
@@ -592,7 +613,7 @@ var init_no_focused_test = __esm({
|
|
|
592
613
|
|
|
593
614
|
// src/rules/no-force-option.ts
|
|
594
615
|
function isForceOptionEnabled(node) {
|
|
595
|
-
const arg = node.arguments
|
|
616
|
+
const arg = node.arguments.at(-1);
|
|
596
617
|
return arg?.type === "ObjectExpression" && arg.properties.find(
|
|
597
618
|
(property) => property.type === "Property" && getStringValue(property.key) === "force" && isBooleanLiteral(property.value, true)
|
|
598
619
|
);
|
|
@@ -644,6 +665,38 @@ var init_no_force_option = __esm({
|
|
|
644
665
|
}
|
|
645
666
|
});
|
|
646
667
|
|
|
668
|
+
// src/rules/no-get-by-title.ts
|
|
669
|
+
var no_get_by_title_default;
|
|
670
|
+
var init_no_get_by_title = __esm({
|
|
671
|
+
"src/rules/no-get-by-title.ts"() {
|
|
672
|
+
"use strict";
|
|
673
|
+
init_ast();
|
|
674
|
+
no_get_by_title_default = {
|
|
675
|
+
create(context) {
|
|
676
|
+
return {
|
|
677
|
+
CallExpression(node) {
|
|
678
|
+
if (isPageMethod(node, "getByTitle")) {
|
|
679
|
+
context.report({ messageId: "noGetByTitle", node });
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
},
|
|
684
|
+
meta: {
|
|
685
|
+
docs: {
|
|
686
|
+
category: "Best Practices",
|
|
687
|
+
description: "Disallows the usage of getByTitle()",
|
|
688
|
+
recommended: false,
|
|
689
|
+
url: "https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-get-by-title.md"
|
|
690
|
+
},
|
|
691
|
+
messages: {
|
|
692
|
+
noGetByTitle: "The HTML title attribute is not an accessible name. Prefer getByRole() or getByLabelText() instead."
|
|
693
|
+
},
|
|
694
|
+
type: "suggestion"
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
|
|
647
700
|
// src/rules/no-nested-step.ts
|
|
648
701
|
function isStepCall(node) {
|
|
649
702
|
const inner = node.type === "CallExpression" ? node.callee : node;
|
|
@@ -967,7 +1020,7 @@ var init_no_restricted_matchers = __esm({
|
|
|
967
1020
|
context.report({
|
|
968
1021
|
data: { message: message ?? "", restriction },
|
|
969
1022
|
loc: {
|
|
970
|
-
end: chain
|
|
1023
|
+
end: chain.at(-1).loc.end,
|
|
971
1024
|
start: chain[0].loc.start
|
|
972
1025
|
},
|
|
973
1026
|
messageId: message ? "restrictedWithMessage" : "restricted"
|
|
@@ -1068,6 +1121,101 @@ var init_no_skipped_test = __esm({
|
|
|
1068
1121
|
}
|
|
1069
1122
|
});
|
|
1070
1123
|
|
|
1124
|
+
// src/rules/no-unsafe-references.ts
|
|
1125
|
+
function collectVariables(scope) {
|
|
1126
|
+
if (!scope)
|
|
1127
|
+
return [];
|
|
1128
|
+
return [
|
|
1129
|
+
...collectVariables(scope.upper),
|
|
1130
|
+
...scope.variables.map((ref) => ref.name)
|
|
1131
|
+
];
|
|
1132
|
+
}
|
|
1133
|
+
function addArgument(fixer, node, refs) {
|
|
1134
|
+
if (!node.arguments.length)
|
|
1135
|
+
return;
|
|
1136
|
+
if (node.arguments.length === 1) {
|
|
1137
|
+
return fixer.insertTextAfter(node.arguments[0], `, [${refs}]`);
|
|
1138
|
+
}
|
|
1139
|
+
const arr = node.arguments.at(-1);
|
|
1140
|
+
if (!arr || arr.type !== "ArrayExpression")
|
|
1141
|
+
return;
|
|
1142
|
+
const lastItem = arr.elements.at(-1);
|
|
1143
|
+
return lastItem ? fixer.insertTextAfter(lastItem, `, ${refs}`) : fixer.replaceText(arr, `[${refs}]`);
|
|
1144
|
+
}
|
|
1145
|
+
function getParen(sourceCode, node) {
|
|
1146
|
+
let token = sourceCode.getFirstToken(node);
|
|
1147
|
+
while (token && token.value !== "(") {
|
|
1148
|
+
token = sourceCode.getTokenAfter(token);
|
|
1149
|
+
}
|
|
1150
|
+
return token;
|
|
1151
|
+
}
|
|
1152
|
+
function addParam(sourceCode, fixer, node, refs) {
|
|
1153
|
+
const lastParam = node.params.at(-1);
|
|
1154
|
+
if (lastParam) {
|
|
1155
|
+
return fixer.insertTextAfter(lastParam, `, ${refs}`);
|
|
1156
|
+
}
|
|
1157
|
+
const token = getParen(sourceCode, node);
|
|
1158
|
+
return token ? fixer.insertTextAfter(token, `[${refs}]`) : null;
|
|
1159
|
+
}
|
|
1160
|
+
var no_unsafe_references_default;
|
|
1161
|
+
var init_no_unsafe_references = __esm({
|
|
1162
|
+
"src/rules/no-unsafe-references.ts"() {
|
|
1163
|
+
"use strict";
|
|
1164
|
+
init_ast();
|
|
1165
|
+
init_misc();
|
|
1166
|
+
no_unsafe_references_default = {
|
|
1167
|
+
create(context) {
|
|
1168
|
+
return {
|
|
1169
|
+
CallExpression(node) {
|
|
1170
|
+
if (!isPageMethod(node, "evaluate"))
|
|
1171
|
+
return;
|
|
1172
|
+
const [fn] = node.arguments;
|
|
1173
|
+
if (!fn || !isFunction(fn))
|
|
1174
|
+
return;
|
|
1175
|
+
const sourceCode = getSourceCode(context);
|
|
1176
|
+
const { through, upper } = sourceCode.getScope(fn.body);
|
|
1177
|
+
const allRefs = new Set(collectVariables(upper));
|
|
1178
|
+
through.filter((ref) => allRefs.has(ref.identifier.name)).forEach((ref, i, arr) => {
|
|
1179
|
+
const descriptor = {
|
|
1180
|
+
data: { variable: ref.identifier.name },
|
|
1181
|
+
messageId: "noUnsafeReference",
|
|
1182
|
+
node: ref.identifier
|
|
1183
|
+
};
|
|
1184
|
+
if (i !== 0) {
|
|
1185
|
+
context.report(descriptor);
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
context.report({
|
|
1189
|
+
...descriptor,
|
|
1190
|
+
fix(fixer) {
|
|
1191
|
+
const refs = arr.map((ref2) => ref2.identifier.name).join(", ");
|
|
1192
|
+
return [
|
|
1193
|
+
addArgument(fixer, node, refs),
|
|
1194
|
+
addParam(sourceCode, fixer, fn, refs)
|
|
1195
|
+
].filter(truthy);
|
|
1196
|
+
}
|
|
1197
|
+
});
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
},
|
|
1202
|
+
meta: {
|
|
1203
|
+
docs: {
|
|
1204
|
+
category: "Possible Errors",
|
|
1205
|
+
description: "Prevent unsafe variable references in page.evaluate()",
|
|
1206
|
+
recommended: true,
|
|
1207
|
+
url: "https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-unsafe-references.md"
|
|
1208
|
+
},
|
|
1209
|
+
fixable: "code",
|
|
1210
|
+
messages: {
|
|
1211
|
+
noUnsafeReference: 'Unsafe reference to variable "{{ variable }}" in page.evaluate()'
|
|
1212
|
+
},
|
|
1213
|
+
type: "problem"
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1071
1219
|
// src/rules/no-useless-await.ts
|
|
1072
1220
|
function isSupportedMethod(node) {
|
|
1073
1221
|
if (node.callee.type !== "MemberExpression")
|
|
@@ -1585,6 +1733,7 @@ var init_prefer_to_contain = __esm({
|
|
|
1585
1733
|
"src/rules/prefer-to-contain.ts"() {
|
|
1586
1734
|
"use strict";
|
|
1587
1735
|
init_ast();
|
|
1736
|
+
init_misc();
|
|
1588
1737
|
init_parseExpectCall();
|
|
1589
1738
|
matchers = /* @__PURE__ */ new Set(["toBe", "toEqual", "toStrictEqual"]);
|
|
1590
1739
|
isFixableIncludesCallExpression = (node) => node.type === "CallExpression" && node.callee.type === "MemberExpression" && isPropertyAccessor(node.callee, "includes") && node.arguments.length === 1 && node.arguments[0].type !== "SpreadElement";
|
|
@@ -1606,7 +1755,7 @@ var init_prefer_to_contain = __esm({
|
|
|
1606
1755
|
);
|
|
1607
1756
|
context.report({
|
|
1608
1757
|
fix(fixer) {
|
|
1609
|
-
const sourceCode =
|
|
1758
|
+
const sourceCode = getSourceCode(context);
|
|
1610
1759
|
const addNotModifier = matcherArg.type === "Literal" && matcherArg.value === !!notModifier;
|
|
1611
1760
|
const fixes = [
|
|
1612
1761
|
// remove the "includes" call entirely
|
|
@@ -1781,11 +1930,25 @@ var init_prefer_to_have_length = __esm({
|
|
|
1781
1930
|
});
|
|
1782
1931
|
|
|
1783
1932
|
// src/rules/prefer-web-first-assertions.ts
|
|
1933
|
+
function dereference(context, node) {
|
|
1934
|
+
if (node.type !== "Identifier") {
|
|
1935
|
+
return node;
|
|
1936
|
+
}
|
|
1937
|
+
const sourceCode = getSourceCode(context);
|
|
1938
|
+
const scope = sourceCode.getScope(node);
|
|
1939
|
+
for (const ref of scope.references) {
|
|
1940
|
+
const refParent = ref.identifier.parent;
|
|
1941
|
+
if (refParent.type === "VariableDeclarator") {
|
|
1942
|
+
return refParent.init;
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1784
1946
|
var methods3, supportedMatchers, prefer_web_first_assertions_default;
|
|
1785
1947
|
var init_prefer_web_first_assertions = __esm({
|
|
1786
1948
|
"src/rules/prefer-web-first-assertions.ts"() {
|
|
1787
1949
|
"use strict";
|
|
1788
1950
|
init_ast();
|
|
1951
|
+
init_misc();
|
|
1789
1952
|
init_parseExpectCall();
|
|
1790
1953
|
methods3 = {
|
|
1791
1954
|
getAttribute: {
|
|
@@ -1835,8 +1998,8 @@ var init_prefer_web_first_assertions = __esm({
|
|
|
1835
1998
|
const expectCall = parseExpectCall(context, node);
|
|
1836
1999
|
if (!expectCall)
|
|
1837
2000
|
return;
|
|
1838
|
-
const
|
|
1839
|
-
if (arg.type !== "AwaitExpression" || arg.argument.type !== "CallExpression" || arg.argument.callee.type !== "MemberExpression") {
|
|
2001
|
+
const arg = dereference(context, node.arguments[0]);
|
|
2002
|
+
if (!arg || arg.type !== "AwaitExpression" || arg.argument.type !== "CallExpression" || arg.argument.callee.type !== "MemberExpression") {
|
|
1840
2003
|
return;
|
|
1841
2004
|
}
|
|
1842
2005
|
if (!supportedMatchers.has(expectCall.matcherName))
|
|
@@ -1860,7 +2023,7 @@ var init_prefer_web_first_assertions = __esm({
|
|
|
1860
2023
|
},
|
|
1861
2024
|
fix: (fixer) => {
|
|
1862
2025
|
const methodArgs = arg.argument.type === "CallExpression" ? arg.argument.arguments : [];
|
|
1863
|
-
const methodEnd = methodArgs.length ? methodArgs
|
|
2026
|
+
const methodEnd = methodArgs.length ? methodArgs.at(-1).range[1] + 1 : callee.property.range[1] + 2;
|
|
1864
2027
|
const fixes = [
|
|
1865
2028
|
// Add await to the expect call
|
|
1866
2029
|
fixer.insertTextBefore(node, "await "),
|
|
@@ -1967,18 +2130,6 @@ var init_require_soft_assertions = __esm({
|
|
|
1967
2130
|
}
|
|
1968
2131
|
});
|
|
1969
2132
|
|
|
1970
|
-
// src/utils/misc.ts
|
|
1971
|
-
var getAmountData;
|
|
1972
|
-
var init_misc = __esm({
|
|
1973
|
-
"src/utils/misc.ts"() {
|
|
1974
|
-
"use strict";
|
|
1975
|
-
getAmountData = (amount) => ({
|
|
1976
|
-
amount: amount.toString(),
|
|
1977
|
-
s: amount === 1 ? "" : "s"
|
|
1978
|
-
});
|
|
1979
|
-
}
|
|
1980
|
-
});
|
|
1981
|
-
|
|
1982
2133
|
// src/rules/require-top-level-describe.ts
|
|
1983
2134
|
var require_top_level_describe_default;
|
|
1984
2135
|
var init_require_top_level_describe = __esm({
|
|
@@ -2378,6 +2529,7 @@ var require_src = __commonJS({
|
|
|
2378
2529
|
init_no_eval();
|
|
2379
2530
|
init_no_focused_test();
|
|
2380
2531
|
init_no_force_option();
|
|
2532
|
+
init_no_get_by_title();
|
|
2381
2533
|
init_no_nested_step();
|
|
2382
2534
|
init_no_networkidle();
|
|
2383
2535
|
init_no_nth_methods();
|
|
@@ -2385,6 +2537,7 @@ var require_src = __commonJS({
|
|
|
2385
2537
|
init_no_raw_locators();
|
|
2386
2538
|
init_no_restricted_matchers();
|
|
2387
2539
|
init_no_skipped_test();
|
|
2540
|
+
init_no_unsafe_references();
|
|
2388
2541
|
init_no_useless_await();
|
|
2389
2542
|
init_no_useless_not();
|
|
2390
2543
|
init_no_wait_for_selector();
|
|
@@ -2411,6 +2564,7 @@ var require_src = __commonJS({
|
|
|
2411
2564
|
"no-eval": no_eval_default,
|
|
2412
2565
|
"no-focused-test": no_focused_test_default,
|
|
2413
2566
|
"no-force-option": no_force_option_default,
|
|
2567
|
+
"no-get-by-title": no_get_by_title_default,
|
|
2414
2568
|
"no-nested-step": no_nested_step_default,
|
|
2415
2569
|
"no-networkidle": no_networkidle_default,
|
|
2416
2570
|
"no-nth-methods": no_nth_methods_default,
|
|
@@ -2418,6 +2572,7 @@ var require_src = __commonJS({
|
|
|
2418
2572
|
"no-raw-locators": no_raw_locators_default,
|
|
2419
2573
|
"no-restricted-matchers": no_restricted_matchers_default,
|
|
2420
2574
|
"no-skipped-test": no_skipped_test_default,
|
|
2575
|
+
"no-unsafe-references": no_unsafe_references_default,
|
|
2421
2576
|
"no-useless-await": no_useless_await_default,
|
|
2422
2577
|
"no-useless-not": no_useless_not_default,
|
|
2423
2578
|
"no-wait-for-selector": no_wait_for_selector_default,
|
|
@@ -2450,6 +2605,7 @@ var require_src = __commonJS({
|
|
|
2450
2605
|
"playwright/no-networkidle": "error",
|
|
2451
2606
|
"playwright/no-page-pause": "warn",
|
|
2452
2607
|
"playwright/no-skipped-test": "warn",
|
|
2608
|
+
"playwright/no-unsafe-references": "error",
|
|
2453
2609
|
"playwright/no-useless-await": "warn",
|
|
2454
2610
|
"playwright/no-useless-not": "warn",
|
|
2455
2611
|
"playwright/no-wait-for-selector": "warn",
|
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": "1.
|
|
4
|
+
"version": "1.1.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",
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
"workspaces": [
|
|
13
13
|
"examples"
|
|
14
14
|
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=16.6.0"
|
|
17
|
+
},
|
|
15
18
|
"types": "./dist/index.d.ts",
|
|
16
19
|
"exports": {
|
|
17
20
|
"import": {
|
|
@@ -35,9 +38,12 @@
|
|
|
35
38
|
"ts": "tsc --noEmit"
|
|
36
39
|
},
|
|
37
40
|
"devDependencies": {
|
|
41
|
+
"@jest/globals": "^29.7.0",
|
|
38
42
|
"@mskelton/eslint-config": "^8.4.0",
|
|
43
|
+
"@mskelton/semantic-release-config": "^1.0.1",
|
|
39
44
|
"@types/eslint": "^8.44.3",
|
|
40
45
|
"@types/estree": "^1.0.2",
|
|
46
|
+
"@types/node": "^20.11.17",
|
|
41
47
|
"@typescript-eslint/eslint-plugin": "^6.7.3",
|
|
42
48
|
"@typescript-eslint/parser": "^6.7.3",
|
|
43
49
|
"dedent": "^1.5.1",
|
|
@@ -45,7 +51,8 @@
|
|
|
45
51
|
"eslint-plugin-sort": "^2.10.0",
|
|
46
52
|
"jest": "^29.7.0",
|
|
47
53
|
"prettier": "^3.0.3",
|
|
48
|
-
"
|
|
54
|
+
"prettier-plugin-jsdoc": "^1.3.0",
|
|
55
|
+
"semantic-release": "^23.0.2",
|
|
49
56
|
"ts-jest": "^29.1.1",
|
|
50
57
|
"tsup": "^8.0.1",
|
|
51
58
|
"typescript": "^5.2.2"
|