eslint-plugin-playwright 1.3.0 → 1.4.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/LICENSE +1 -1
- package/README.md +48 -45
- package/dist/index.d.mts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +984 -391
- package/dist/index.mjs +1051 -418
- package/package.json +5 -7
package/dist/index.mjs
CHANGED
|
@@ -6,6 +6,244 @@ var __commonJS = (cb, mod) => function __require() {
|
|
|
6
6
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
+
// src/utils/parseFnCall.ts
|
|
10
|
+
function getNodeChain(node) {
|
|
11
|
+
if (isSupportedAccessor(node)) {
|
|
12
|
+
return [node];
|
|
13
|
+
}
|
|
14
|
+
switch (node.type) {
|
|
15
|
+
case "TaggedTemplateExpression":
|
|
16
|
+
return getNodeChain(node.tag);
|
|
17
|
+
case "MemberExpression":
|
|
18
|
+
return joinChains(getNodeChain(node.object), getNodeChain(node.property));
|
|
19
|
+
case "CallExpression":
|
|
20
|
+
return getNodeChain(node.callee);
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
function determinePlaywrightFnType(name) {
|
|
25
|
+
if (name === "step")
|
|
26
|
+
return "step";
|
|
27
|
+
if (name === "expect")
|
|
28
|
+
return "expect";
|
|
29
|
+
if (name === "describe")
|
|
30
|
+
return "describe";
|
|
31
|
+
if (name === "test")
|
|
32
|
+
return "test";
|
|
33
|
+
if (testHooks.has(name))
|
|
34
|
+
return "hook";
|
|
35
|
+
return "unknown";
|
|
36
|
+
}
|
|
37
|
+
function getExpectArguments(call) {
|
|
38
|
+
return findParent(call.head.node, "CallExpression")?.arguments ?? [];
|
|
39
|
+
}
|
|
40
|
+
function parse(context, node) {
|
|
41
|
+
const chain = getNodeChain(node);
|
|
42
|
+
if (!chain?.length) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const [first, ...rest] = chain;
|
|
46
|
+
const resolved = resolveToPlaywrightFn(context, first);
|
|
47
|
+
if (!resolved)
|
|
48
|
+
return null;
|
|
49
|
+
let name = resolved.original ?? resolved.local;
|
|
50
|
+
const links = [name, ...rest.map((link) => getStringValue(link))];
|
|
51
|
+
if (name !== "expect" && !VALID_CHAINS.has(links.join("."))) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
if (name === "test" && links.length > 1) {
|
|
55
|
+
const nextLinkName = links[1];
|
|
56
|
+
const nextLinkType = determinePlaywrightFnType(nextLinkName);
|
|
57
|
+
if (nextLinkType !== "unknown") {
|
|
58
|
+
name = nextLinkName;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const parsedFnCall = {
|
|
62
|
+
head: { ...resolved, node: first },
|
|
63
|
+
// every member node must have a member expression as their parent
|
|
64
|
+
// in order to be part of the call chain we're parsing
|
|
65
|
+
members: rest,
|
|
66
|
+
name
|
|
67
|
+
};
|
|
68
|
+
const type = determinePlaywrightFnType(name);
|
|
69
|
+
if (type === "expect") {
|
|
70
|
+
const result = parseExpectCall(parsedFnCall);
|
|
71
|
+
if (typeof result === "string" && findTopMostCallExpression(node) !== node) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
if (result === "matcher-not-found") {
|
|
75
|
+
if (getParent(node)?.type === "MemberExpression") {
|
|
76
|
+
return "matcher-not-called";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
if (chain.slice(0, chain.length - 1).some((n) => getParent(n)?.type !== "MemberExpression")) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const parent = getParent(node);
|
|
85
|
+
if (parent?.type === "CallExpression" || parent?.type === "MemberExpression") {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return { ...parsedFnCall, type };
|
|
89
|
+
}
|
|
90
|
+
function parseFnCallWithReason(context, node) {
|
|
91
|
+
if (cache.has(node)) {
|
|
92
|
+
return cache.get(node);
|
|
93
|
+
}
|
|
94
|
+
const call = parse(context, node);
|
|
95
|
+
cache.set(node, call);
|
|
96
|
+
return call;
|
|
97
|
+
}
|
|
98
|
+
function parseFnCall(context, node) {
|
|
99
|
+
const call = parseFnCallWithReason(context, node);
|
|
100
|
+
return typeof call === "string" ? null : call;
|
|
101
|
+
}
|
|
102
|
+
var testHooks, VALID_CHAINS, joinChains, isSupportedAccessor, resolvePossibleAliasedGlobal, resolveToPlaywrightFn, modifiers, findModifiersAndMatcher, parseExpectCall, findTopMostCallExpression, cache, isTypeOfFnCall;
|
|
103
|
+
var init_parseFnCall = __esm({
|
|
104
|
+
"src/utils/parseFnCall.ts"() {
|
|
105
|
+
"use strict";
|
|
106
|
+
init_ast();
|
|
107
|
+
testHooks = /* @__PURE__ */ new Set(["afterAll", "afterEach", "beforeAll", "beforeEach"]);
|
|
108
|
+
VALID_CHAINS = /* @__PURE__ */ new Set([
|
|
109
|
+
// Hooks
|
|
110
|
+
"afterAll",
|
|
111
|
+
"afterEach",
|
|
112
|
+
"beforeAll",
|
|
113
|
+
"beforeEach",
|
|
114
|
+
"test.afterAll",
|
|
115
|
+
"test.afterEach",
|
|
116
|
+
"test.beforeAll",
|
|
117
|
+
"test.beforeEach",
|
|
118
|
+
// Describe
|
|
119
|
+
"describe",
|
|
120
|
+
"describe.only",
|
|
121
|
+
"describe.skip",
|
|
122
|
+
"describe.fixme",
|
|
123
|
+
"describe.fixme.only",
|
|
124
|
+
"describe.configure",
|
|
125
|
+
"describe.serial",
|
|
126
|
+
"describe.serial.only",
|
|
127
|
+
"describe.serial.skip",
|
|
128
|
+
"describe.serial.fixme",
|
|
129
|
+
"describe.serial.fixme.only",
|
|
130
|
+
"describe.parallel",
|
|
131
|
+
"describe.parallel.only",
|
|
132
|
+
"describe.parallel.skip",
|
|
133
|
+
"describe.parallel.fixme",
|
|
134
|
+
"describe.parallel.fixme.only",
|
|
135
|
+
"test.describe",
|
|
136
|
+
"test.describe.only",
|
|
137
|
+
"test.describe.skip",
|
|
138
|
+
"test.describe.fixme",
|
|
139
|
+
"test.describe.fixme.only",
|
|
140
|
+
"test.describe.configure",
|
|
141
|
+
"test.describe.serial",
|
|
142
|
+
"test.describe.serial.only",
|
|
143
|
+
"test.describe.serial.skip",
|
|
144
|
+
"test.describe.serial.fixme",
|
|
145
|
+
"test.describe.serial.fixme.only",
|
|
146
|
+
"test.describe.parallel",
|
|
147
|
+
"test.describe.parallel.only",
|
|
148
|
+
"test.describe.parallel.skip",
|
|
149
|
+
"test.describe.parallel.fixme",
|
|
150
|
+
"test.describe.parallel.fixme.only",
|
|
151
|
+
// Test
|
|
152
|
+
"test",
|
|
153
|
+
"test.fail",
|
|
154
|
+
"test.fixme",
|
|
155
|
+
"test.only",
|
|
156
|
+
"test.skip",
|
|
157
|
+
"test.step",
|
|
158
|
+
"test.slow",
|
|
159
|
+
"test.use"
|
|
160
|
+
]);
|
|
161
|
+
joinChains = (a, b) => a && b ? [...a, ...b] : null;
|
|
162
|
+
isSupportedAccessor = (node, value) => isIdentifier(node, value) || isStringNode(node, value);
|
|
163
|
+
resolvePossibleAliasedGlobal = (context, global) => {
|
|
164
|
+
const globalAliases = context.settings.playwright?.globalAliases ?? {};
|
|
165
|
+
const alias = Object.entries(globalAliases).find(
|
|
166
|
+
([, aliases]) => aliases.includes(global)
|
|
167
|
+
);
|
|
168
|
+
return alias?.[0] ?? null;
|
|
169
|
+
};
|
|
170
|
+
resolveToPlaywrightFn = (context, accessor) => {
|
|
171
|
+
const ident = getStringValue(accessor);
|
|
172
|
+
const resolved = /(^expect|Expect)$/.test(ident) ? "expect" : ident;
|
|
173
|
+
return {
|
|
174
|
+
// eslint-disable-next-line sort/object-properties
|
|
175
|
+
original: resolvePossibleAliasedGlobal(context, resolved),
|
|
176
|
+
local: resolved
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
modifiers = /* @__PURE__ */ new Set(["not", "resolves", "rejects"]);
|
|
180
|
+
findModifiersAndMatcher = (members) => {
|
|
181
|
+
const modifiers2 = [];
|
|
182
|
+
for (const member of members) {
|
|
183
|
+
const name = getStringValue(member);
|
|
184
|
+
if (name === "soft" || name === "poll") {
|
|
185
|
+
if (modifiers2.length > 0) {
|
|
186
|
+
return "modifier-unknown";
|
|
187
|
+
}
|
|
188
|
+
} else if (name === "resolves" || name === "rejects") {
|
|
189
|
+
const lastModifier = getStringValue(modifiers2.at(-1));
|
|
190
|
+
if (lastModifier && lastModifier !== "soft" && lastModifier !== "poll") {
|
|
191
|
+
return "modifier-unknown";
|
|
192
|
+
}
|
|
193
|
+
} else if (name !== "not") {
|
|
194
|
+
if (member.parent?.type === "MemberExpression" && member.parent.parent?.type === "CallExpression") {
|
|
195
|
+
return {
|
|
196
|
+
matcher: member,
|
|
197
|
+
matcherArgs: member.parent.parent.arguments,
|
|
198
|
+
matcherName: name,
|
|
199
|
+
modifiers: modifiers2
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
return "modifier-unknown";
|
|
203
|
+
}
|
|
204
|
+
modifiers2.push(member);
|
|
205
|
+
}
|
|
206
|
+
return "matcher-not-found";
|
|
207
|
+
};
|
|
208
|
+
parseExpectCall = (call) => {
|
|
209
|
+
const modifiersAndMatcher = findModifiersAndMatcher(call.members);
|
|
210
|
+
if (typeof modifiersAndMatcher === "string") {
|
|
211
|
+
return modifiersAndMatcher;
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
...call,
|
|
215
|
+
args: getExpectArguments(call),
|
|
216
|
+
type: "expect",
|
|
217
|
+
...modifiersAndMatcher
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
findTopMostCallExpression = (node) => {
|
|
221
|
+
let top = node;
|
|
222
|
+
let parent = getParent(node);
|
|
223
|
+
let child = node;
|
|
224
|
+
while (parent) {
|
|
225
|
+
if (parent.type === "CallExpression" && parent.callee === child) {
|
|
226
|
+
top = parent;
|
|
227
|
+
node = parent;
|
|
228
|
+
parent = getParent(parent);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (parent.type !== "MemberExpression") {
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
child = parent;
|
|
235
|
+
parent = getParent(parent);
|
|
236
|
+
}
|
|
237
|
+
return top;
|
|
238
|
+
};
|
|
239
|
+
cache = /* @__PURE__ */ new WeakMap();
|
|
240
|
+
isTypeOfFnCall = (context, node, types) => {
|
|
241
|
+
const call = parseFnCall(context, node);
|
|
242
|
+
return call !== null && types.includes(call.type);
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
9
247
|
// src/utils/ast.ts
|
|
10
248
|
function getStringValue(node) {
|
|
11
249
|
if (!node)
|
|
@@ -16,7 +254,7 @@ function getRawValue(node) {
|
|
|
16
254
|
return node.type === "Literal" ? node.raw : void 0;
|
|
17
255
|
}
|
|
18
256
|
function isIdentifier(node, name) {
|
|
19
|
-
return node.type === "Identifier" && (typeof name === "string" ? node.name === name : name.test(node.name));
|
|
257
|
+
return node.type === "Identifier" && (!name || (typeof name === "string" ? node.name === name : name.test(node.name)));
|
|
20
258
|
}
|
|
21
259
|
function isLiteral(node, type, value) {
|
|
22
260
|
return node.type === "Literal" && (value === void 0 ? typeof node.value === type : node.value === value);
|
|
@@ -27,91 +265,20 @@ function isStringLiteral(node, value) {
|
|
|
27
265
|
function isBooleanLiteral(node, value) {
|
|
28
266
|
return isLiteral(node, "boolean", value);
|
|
29
267
|
}
|
|
30
|
-
function isStringNode(node) {
|
|
31
|
-
return node && (isStringLiteral(node) || isTemplateLiteral(node));
|
|
268
|
+
function isStringNode(node, value) {
|
|
269
|
+
return node && (isStringLiteral(node, value) || isTemplateLiteral(node, value));
|
|
32
270
|
}
|
|
33
271
|
function isPropertyAccessor(node, name) {
|
|
34
272
|
return getStringValue(node.property) === name;
|
|
35
273
|
}
|
|
36
|
-
function getTestNames(context) {
|
|
37
|
-
const aliases = context.settings.playwright?.globalAliases?.test ?? [];
|
|
38
|
-
return ["test", ...aliases];
|
|
39
|
-
}
|
|
40
|
-
function isTestIdentifier(context, node) {
|
|
41
|
-
const testNames = getTestNames(context);
|
|
42
|
-
const regex = new RegExp(`^(${testNames.join("|")})$`);
|
|
43
|
-
return isIdentifier(node, regex) || node.type === "MemberExpression" && isIdentifier(node.object, regex);
|
|
44
|
-
}
|
|
45
|
-
function isDescribeCall(node) {
|
|
46
|
-
const inner = node.type === "CallExpression" ? node.callee : node;
|
|
47
|
-
if (isIdentifier(inner, "describe")) {
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
if (inner.type !== "MemberExpression") {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
return isPropertyAccessor(inner, "describe") ? true : describeProperties.has(getStringValue(inner.property)) ? isDescribeCall(inner.object) : false;
|
|
54
|
-
}
|
|
55
274
|
function getParent(node) {
|
|
56
275
|
return node.parent;
|
|
57
276
|
}
|
|
58
277
|
function findParent(node, type) {
|
|
59
|
-
|
|
278
|
+
const parent = node.parent;
|
|
279
|
+
if (!parent)
|
|
60
280
|
return;
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
function isTestCall(context, node, modifiers) {
|
|
64
|
-
return isTestIdentifier(context, node.callee) && !isDescribeCall(node) && (node.callee.type !== "MemberExpression" || !modifiers || modifiers?.includes(getStringValue(node.callee.property))) && node.arguments.length === 2 && isFunction(node.arguments[1]);
|
|
65
|
-
}
|
|
66
|
-
function isTestHook(context, node) {
|
|
67
|
-
return node.callee.type === "MemberExpression" && isTestIdentifier(context, node.callee.object) && testHooks.has(getStringValue(node.callee.property));
|
|
68
|
-
}
|
|
69
|
-
function parseFnCall(context, node) {
|
|
70
|
-
if (isTestCall(context, node)) {
|
|
71
|
-
return {
|
|
72
|
-
fn: node.arguments[1],
|
|
73
|
-
name: getStringValue(node.callee),
|
|
74
|
-
type: "test"
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
if (node.callee.type === "MemberExpression" && isTestIdentifier(context, node.callee.object) && testHooks.has(getStringValue(node.callee.property))) {
|
|
78
|
-
return {
|
|
79
|
-
fn: node.arguments[0],
|
|
80
|
-
name: getStringValue(node.callee.property),
|
|
81
|
-
type: "hook"
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
if (isDescribeCall(node)) {
|
|
85
|
-
return {
|
|
86
|
-
name: getStringValue(node.callee),
|
|
87
|
-
type: "describe"
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
function getExpectType(context, node) {
|
|
92
|
-
const aliases = context.settings.playwright?.globalAliases?.expect ?? [];
|
|
93
|
-
const expectNames = ["expect", ...aliases];
|
|
94
|
-
const regex = new RegExp(`(^(${expectNames.join("|")})|Expect)$`);
|
|
95
|
-
if (isIdentifier(node.callee, regex)) {
|
|
96
|
-
return "standalone";
|
|
97
|
-
}
|
|
98
|
-
if (node.callee.type === "MemberExpression" && // TODO: Maybe
|
|
99
|
-
isIdentifier(node.callee.object, "expect")) {
|
|
100
|
-
const type = getStringValue(node.callee.property);
|
|
101
|
-
return expectSubCommands.has(type) ? type : void 0;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
function isExpectCall(context, node) {
|
|
105
|
-
return !!getExpectType(context, node);
|
|
106
|
-
}
|
|
107
|
-
function getMatchers(node, chain = []) {
|
|
108
|
-
if (node.parent.type === "MemberExpression" && node.parent.object === node) {
|
|
109
|
-
return getMatchers(node.parent, [
|
|
110
|
-
...chain,
|
|
111
|
-
node.parent.property
|
|
112
|
-
]);
|
|
113
|
-
}
|
|
114
|
-
return chain;
|
|
281
|
+
return parent.type === type ? parent : findParent(parent, type);
|
|
115
282
|
}
|
|
116
283
|
function dig(node, identifier) {
|
|
117
284
|
return node.type === "MemberExpression" ? dig(node.property, identifier) : node.type === "CallExpression" ? dig(node.callee, identifier) : node.type === "Identifier" ? isIdentifier(node, identifier) : false;
|
|
@@ -120,36 +287,42 @@ function isPageMethod(node, name) {
|
|
|
120
287
|
return node.callee.type === "MemberExpression" && dig(node.callee.object, /(^(page|frame)|(Page|Frame)$)/) && isPropertyAccessor(node.callee, name);
|
|
121
288
|
}
|
|
122
289
|
function isFunction(node) {
|
|
123
|
-
return node
|
|
290
|
+
return node?.type === "ArrowFunctionExpression" || node?.type === "FunctionExpression";
|
|
291
|
+
}
|
|
292
|
+
function getNodeName(node) {
|
|
293
|
+
if (isSupportedAccessor(node)) {
|
|
294
|
+
return getStringValue(node);
|
|
295
|
+
}
|
|
296
|
+
switch (node.type) {
|
|
297
|
+
case "TaggedTemplateExpression":
|
|
298
|
+
return getNodeName(node.tag);
|
|
299
|
+
case "MemberExpression":
|
|
300
|
+
return joinNames(getNodeName(node.object), getNodeName(node.property));
|
|
301
|
+
case "NewExpression":
|
|
302
|
+
case "CallExpression":
|
|
303
|
+
return getNodeName(node.callee);
|
|
304
|
+
}
|
|
305
|
+
return null;
|
|
124
306
|
}
|
|
125
|
-
var isTemplateLiteral,
|
|
307
|
+
var isTemplateLiteral, equalityMatchers, joinNames;
|
|
126
308
|
var init_ast = __esm({
|
|
127
309
|
"src/utils/ast.ts"() {
|
|
128
310
|
"use strict";
|
|
311
|
+
init_parseFnCall();
|
|
129
312
|
isTemplateLiteral = (node, value) => node.type === "TemplateLiteral" && node.quasis.length === 1 && // bail out if not simple
|
|
130
313
|
(value === void 0 || node.quasis[0].value.raw === value);
|
|
131
|
-
describeProperties = /* @__PURE__ */ new Set([
|
|
132
|
-
"parallel",
|
|
133
|
-
"serial",
|
|
134
|
-
"only",
|
|
135
|
-
"skip",
|
|
136
|
-
"fixme"
|
|
137
|
-
]);
|
|
138
|
-
testHooks = /* @__PURE__ */ new Set(["afterAll", "afterEach", "beforeAll", "beforeEach"]);
|
|
139
|
-
expectSubCommands = /* @__PURE__ */ new Set(["soft", "poll"]);
|
|
140
314
|
equalityMatchers = /* @__PURE__ */ new Set(["toBe", "toEqual", "toStrictEqual"]);
|
|
315
|
+
joinNames = (a, b) => a && b ? `${a}.${b}` : null;
|
|
141
316
|
}
|
|
142
317
|
});
|
|
143
318
|
|
|
144
319
|
// src/rules/expect-expect.ts
|
|
145
|
-
function isAssertionCall(context, node, assertFunctionNames) {
|
|
146
|
-
return isExpectCall(context, node) || assertFunctionNames.find((name) => dig(node.callee, name));
|
|
147
|
-
}
|
|
148
320
|
var expect_expect_default;
|
|
149
321
|
var init_expect_expect = __esm({
|
|
150
322
|
"src/rules/expect-expect.ts"() {
|
|
151
323
|
"use strict";
|
|
152
324
|
init_ast();
|
|
325
|
+
init_parseFnCall();
|
|
153
326
|
expect_expect_default = {
|
|
154
327
|
create(context) {
|
|
155
328
|
const options = {
|
|
@@ -168,9 +341,10 @@ var init_expect_expect = __esm({
|
|
|
168
341
|
}
|
|
169
342
|
return {
|
|
170
343
|
CallExpression(node) {
|
|
171
|
-
|
|
344
|
+
const call = parseFnCall(context, node);
|
|
345
|
+
if (call?.type === "test") {
|
|
172
346
|
unchecked.push(node);
|
|
173
|
-
} else if (
|
|
347
|
+
} else if (call?.type === "expect" || options.assertFunctionNames.find((name) => dig(node.callee, name))) {
|
|
174
348
|
const ancestors = context.sourceCode.getAncestors(node);
|
|
175
349
|
checkExpressions(ancestors);
|
|
176
350
|
}
|
|
@@ -216,6 +390,7 @@ var init_max_expects = __esm({
|
|
|
216
390
|
"src/rules/max-expects.ts"() {
|
|
217
391
|
"use strict";
|
|
218
392
|
init_ast();
|
|
393
|
+
init_parseFnCall();
|
|
219
394
|
max_expects_default = {
|
|
220
395
|
create(context) {
|
|
221
396
|
const options = {
|
|
@@ -225,7 +400,7 @@ var init_max_expects = __esm({
|
|
|
225
400
|
let count = 0;
|
|
226
401
|
const maybeResetCount = (node) => {
|
|
227
402
|
const parent = getParent(node);
|
|
228
|
-
const isTestFn = parent?.type !== "CallExpression" ||
|
|
403
|
+
const isTestFn = parent?.type !== "CallExpression" || isTypeOfFnCall(context, parent, ["test"]);
|
|
229
404
|
if (isTestFn) {
|
|
230
405
|
count = 0;
|
|
231
406
|
}
|
|
@@ -234,8 +409,10 @@ var init_max_expects = __esm({
|
|
|
234
409
|
ArrowFunctionExpression: maybeResetCount,
|
|
235
410
|
"ArrowFunctionExpression:exit": maybeResetCount,
|
|
236
411
|
CallExpression(node) {
|
|
237
|
-
|
|
412
|
+
const call = parseFnCall(context, node);
|
|
413
|
+
if (call?.type !== "expect" || getParent(call.head.node)?.type === "MemberExpression") {
|
|
238
414
|
return;
|
|
415
|
+
}
|
|
239
416
|
count += 1;
|
|
240
417
|
if (count > options.max) {
|
|
241
418
|
context.report({
|
|
@@ -285,39 +462,33 @@ var max_nested_describe_default;
|
|
|
285
462
|
var init_max_nested_describe = __esm({
|
|
286
463
|
"src/rules/max-nested-describe.ts"() {
|
|
287
464
|
"use strict";
|
|
288
|
-
|
|
465
|
+
init_parseFnCall();
|
|
289
466
|
max_nested_describe_default = {
|
|
290
467
|
create(context) {
|
|
291
468
|
const { options } = context;
|
|
292
469
|
const max = options[0]?.max ?? 5;
|
|
293
|
-
const
|
|
294
|
-
function pushDescribeCallback(node) {
|
|
295
|
-
if (node.parent.type !== "CallExpression" || !isDescribeCall(node.parent)) {
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
describeCallbackStack.push(0);
|
|
299
|
-
if (describeCallbackStack.length > max) {
|
|
300
|
-
context.report({
|
|
301
|
-
data: {
|
|
302
|
-
depth: describeCallbackStack.length.toString(),
|
|
303
|
-
max: max.toString()
|
|
304
|
-
},
|
|
305
|
-
messageId: "exceededMaxDepth",
|
|
306
|
-
node: node.parent.callee
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
function popDescribeCallback(node) {
|
|
311
|
-
const { parent } = node;
|
|
312
|
-
if (parent.type === "CallExpression" && isDescribeCall(parent)) {
|
|
313
|
-
describeCallbackStack.pop();
|
|
314
|
-
}
|
|
315
|
-
}
|
|
470
|
+
const describes = [];
|
|
316
471
|
return {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
472
|
+
CallExpression(node) {
|
|
473
|
+
if (isTypeOfFnCall(context, node, ["describe"])) {
|
|
474
|
+
describes.unshift(node);
|
|
475
|
+
if (describes.length > max) {
|
|
476
|
+
context.report({
|
|
477
|
+
data: {
|
|
478
|
+
depth: describes.length.toString(),
|
|
479
|
+
max: max.toString()
|
|
480
|
+
},
|
|
481
|
+
messageId: "exceededMaxDepth",
|
|
482
|
+
node: node.callee
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
"CallExpression:exit"(node) {
|
|
488
|
+
if (describes[0] === node) {
|
|
489
|
+
describes.shift();
|
|
490
|
+
}
|
|
491
|
+
}
|
|
321
492
|
};
|
|
322
493
|
},
|
|
323
494
|
meta: {
|
|
@@ -349,24 +520,23 @@ var init_max_nested_describe = __esm({
|
|
|
349
520
|
});
|
|
350
521
|
|
|
351
522
|
// src/rules/missing-playwright-await.ts
|
|
352
|
-
function
|
|
353
|
-
|
|
354
|
-
|
|
523
|
+
function getReportNode(node) {
|
|
524
|
+
const parent = getParent(node);
|
|
525
|
+
return parent?.type === "MemberExpression" ? parent : node;
|
|
526
|
+
}
|
|
527
|
+
function getCallType(call, awaitableMatchers) {
|
|
528
|
+
if (call.type === "step") {
|
|
529
|
+
return { messageId: "testStep", node: call.head.node };
|
|
355
530
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
return {
|
|
366
|
-
data: { matcherName },
|
|
367
|
-
messageId: expectType === "poll" ? "expectPoll" : "expect",
|
|
368
|
-
node: grandparent
|
|
369
|
-
};
|
|
531
|
+
if (call.type === "expect") {
|
|
532
|
+
const isPoll = call.modifiers.some((m) => getStringValue(m) === "poll");
|
|
533
|
+
if (isPoll || awaitableMatchers.has(call.matcherName)) {
|
|
534
|
+
return {
|
|
535
|
+
data: { matcherName: call.matcherName },
|
|
536
|
+
messageId: isPoll ? "expectPoll" : "expect",
|
|
537
|
+
node: call.head.node
|
|
538
|
+
};
|
|
539
|
+
}
|
|
370
540
|
}
|
|
371
541
|
}
|
|
372
542
|
var validTypes, expectPlaywrightMatchers, playwrightTestMatchers, missing_playwright_await_default;
|
|
@@ -374,6 +544,7 @@ var init_missing_playwright_await = __esm({
|
|
|
374
544
|
"src/rules/missing-playwright-await.ts"() {
|
|
375
545
|
"use strict";
|
|
376
546
|
init_ast();
|
|
547
|
+
init_parseFnCall();
|
|
377
548
|
validTypes = /* @__PURE__ */ new Set([
|
|
378
549
|
"AwaitExpression",
|
|
379
550
|
"ReturnStatement",
|
|
@@ -436,16 +607,19 @@ var init_missing_playwright_await = __esm({
|
|
|
436
607
|
...options.customMatchers || []
|
|
437
608
|
]);
|
|
438
609
|
function checkValidity(node) {
|
|
439
|
-
|
|
610
|
+
const parent = getParent(node);
|
|
611
|
+
if (!parent)
|
|
612
|
+
return false;
|
|
613
|
+
if (validTypes.has(parent.type))
|
|
440
614
|
return true;
|
|
441
|
-
if (
|
|
442
|
-
return checkValidity(
|
|
615
|
+
if (parent.type === "ArrayExpression") {
|
|
616
|
+
return checkValidity(parent);
|
|
443
617
|
}
|
|
444
|
-
if (
|
|
618
|
+
if (parent.type === "CallExpression" && parent.callee.type === "MemberExpression" && isIdentifier(parent.callee.object, "Promise") && isIdentifier(parent.callee.property, "all")) {
|
|
445
619
|
return true;
|
|
446
620
|
}
|
|
447
|
-
if (
|
|
448
|
-
const scope = context.sourceCode.getScope(
|
|
621
|
+
if (parent.type === "VariableDeclarator") {
|
|
622
|
+
const scope = context.sourceCode.getScope(parent.parent);
|
|
449
623
|
for (const ref of scope.references) {
|
|
450
624
|
const refParent = ref.identifier.parent;
|
|
451
625
|
if (validTypes.has(refParent.type))
|
|
@@ -458,14 +632,17 @@ var init_missing_playwright_await = __esm({
|
|
|
458
632
|
}
|
|
459
633
|
return {
|
|
460
634
|
CallExpression(node) {
|
|
461
|
-
const
|
|
462
|
-
|
|
635
|
+
const call = parseFnCall(context, node);
|
|
636
|
+
if (call?.type !== "step" && call?.type !== "expect")
|
|
637
|
+
return;
|
|
638
|
+
const result = getCallType(call, awaitableMatchers);
|
|
639
|
+
const isValid = result ? checkValidity(node) : false;
|
|
463
640
|
if (result && !isValid) {
|
|
464
641
|
context.report({
|
|
465
642
|
data: result.data,
|
|
466
643
|
fix: (fixer) => fixer.insertTextBefore(node, "await "),
|
|
467
644
|
messageId: result.messageId,
|
|
468
|
-
node: node
|
|
645
|
+
node: getReportNode(result.node)
|
|
469
646
|
});
|
|
470
647
|
}
|
|
471
648
|
}
|
|
@@ -502,6 +679,10 @@ var init_missing_playwright_await = __esm({
|
|
|
502
679
|
});
|
|
503
680
|
|
|
504
681
|
// src/rules/no-commented-out-tests.ts
|
|
682
|
+
function getTestNames(context) {
|
|
683
|
+
const aliases = context.settings.playwright?.globalAliases?.test ?? [];
|
|
684
|
+
return ["test", ...aliases];
|
|
685
|
+
}
|
|
505
686
|
function hasTests(context, node) {
|
|
506
687
|
const testNames = getTestNames(context);
|
|
507
688
|
const names = testNames.join("|");
|
|
@@ -515,7 +696,6 @@ var no_commented_out_tests_default;
|
|
|
515
696
|
var init_no_commented_out_tests = __esm({
|
|
516
697
|
"src/rules/no-commented-out-tests.ts"() {
|
|
517
698
|
"use strict";
|
|
518
|
-
init_ast();
|
|
519
699
|
no_commented_out_tests_default = {
|
|
520
700
|
create(context) {
|
|
521
701
|
function checkNode(node) {
|
|
@@ -554,13 +734,15 @@ var init_no_conditional_expect = __esm({
|
|
|
554
734
|
"src/rules/no-conditional-expect.ts"() {
|
|
555
735
|
"use strict";
|
|
556
736
|
init_ast();
|
|
737
|
+
init_parseFnCall();
|
|
557
738
|
isCatchCall = (node) => node.callee.type === "MemberExpression" && isPropertyAccessor(node.callee, "catch");
|
|
558
739
|
getTestCallExpressionsFromDeclaredVariables = (context, declaredVariables) => {
|
|
559
740
|
return declaredVariables.reduce(
|
|
560
741
|
(acc, { references }) => [
|
|
561
742
|
...acc,
|
|
562
743
|
...references.map(({ identifier }) => getParent(identifier)).filter(
|
|
563
|
-
|
|
744
|
+
// ESLint types are infurating
|
|
745
|
+
(node) => node?.type === "CallExpression" && isTypeOfFnCall(context, node, ["test"])
|
|
564
746
|
)
|
|
565
747
|
],
|
|
566
748
|
[]
|
|
@@ -575,20 +757,20 @@ var init_no_conditional_expect = __esm({
|
|
|
575
757
|
const decreaseConditionalDepth = () => inTestCase && conditionalDepth--;
|
|
576
758
|
return {
|
|
577
759
|
CallExpression(node) {
|
|
578
|
-
|
|
760
|
+
const call = parseFnCall(context, node);
|
|
761
|
+
if (call?.type === "test") {
|
|
579
762
|
inTestCase = true;
|
|
580
763
|
}
|
|
581
764
|
if (isCatchCall(node)) {
|
|
582
765
|
inPromiseCatch = true;
|
|
583
766
|
}
|
|
584
|
-
|
|
585
|
-
if (inTestCase && expectType && conditionalDepth > 0) {
|
|
767
|
+
if (inTestCase && call?.type === "expect" && conditionalDepth > 0) {
|
|
586
768
|
context.report({
|
|
587
769
|
messageId: "conditionalExpect",
|
|
588
770
|
node
|
|
589
771
|
});
|
|
590
772
|
}
|
|
591
|
-
if (inPromiseCatch &&
|
|
773
|
+
if (inPromiseCatch && call?.type === "expect") {
|
|
592
774
|
context.report({
|
|
593
775
|
messageId: "conditionalExpect",
|
|
594
776
|
node
|
|
@@ -596,7 +778,7 @@ var init_no_conditional_expect = __esm({
|
|
|
596
778
|
}
|
|
597
779
|
},
|
|
598
780
|
"CallExpression:exit"(node) {
|
|
599
|
-
if (
|
|
781
|
+
if (isTypeOfFnCall(context, node, ["test"])) {
|
|
600
782
|
inTestCase = false;
|
|
601
783
|
}
|
|
602
784
|
if (isCatchCall(node)) {
|
|
@@ -647,11 +829,18 @@ var init_no_conditional_in_test = __esm({
|
|
|
647
829
|
"src/rules/no-conditional-in-test.ts"() {
|
|
648
830
|
"use strict";
|
|
649
831
|
init_ast();
|
|
832
|
+
init_parseFnCall();
|
|
650
833
|
no_conditional_in_test_default = {
|
|
651
834
|
create(context) {
|
|
652
835
|
function checkConditional(node) {
|
|
653
836
|
const call = findParent(node, "CallExpression");
|
|
654
|
-
if (call
|
|
837
|
+
if (!call)
|
|
838
|
+
return;
|
|
839
|
+
const fnCall = parseFnCall(context, call);
|
|
840
|
+
if (fnCall?.type === "test" && fnCall.members.some((member) => getStringValue(member) === "skip") && call.arguments[0]?.type === "LogicalExpression") {
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
if (fnCall?.type === "test" || fnCall?.type === "step") {
|
|
655
844
|
context.report({ messageId: "conditionalInTest", node });
|
|
656
845
|
}
|
|
657
846
|
}
|
|
@@ -685,15 +874,19 @@ var init_no_duplicate_hooks = __esm({
|
|
|
685
874
|
"src/rules/no-duplicate-hooks.ts"() {
|
|
686
875
|
"use strict";
|
|
687
876
|
init_ast();
|
|
877
|
+
init_parseFnCall();
|
|
688
878
|
no_duplicate_hooks_default = {
|
|
689
879
|
create(context) {
|
|
690
880
|
const hookContexts = [{}];
|
|
691
881
|
return {
|
|
692
882
|
CallExpression(node) {
|
|
693
|
-
|
|
883
|
+
const call = parseFnCall(context, node);
|
|
884
|
+
if (!call)
|
|
885
|
+
return;
|
|
886
|
+
if (call.type === "describe") {
|
|
694
887
|
hookContexts.push({});
|
|
695
888
|
}
|
|
696
|
-
if (
|
|
889
|
+
if (call.type !== "hook") {
|
|
697
890
|
return;
|
|
698
891
|
}
|
|
699
892
|
const currentLayer = hookContexts[hookContexts.length - 1];
|
|
@@ -709,7 +902,7 @@ var init_no_duplicate_hooks = __esm({
|
|
|
709
902
|
}
|
|
710
903
|
},
|
|
711
904
|
"CallExpression:exit"(node) {
|
|
712
|
-
if (
|
|
905
|
+
if (isTypeOfFnCall(context, node, ["describe"])) {
|
|
713
906
|
hookContexts.pop();
|
|
714
907
|
}
|
|
715
908
|
}
|
|
@@ -838,27 +1031,33 @@ var init_no_focused_test = __esm({
|
|
|
838
1031
|
"src/rules/no-focused-test.ts"() {
|
|
839
1032
|
"use strict";
|
|
840
1033
|
init_ast();
|
|
1034
|
+
init_parseFnCall();
|
|
841
1035
|
no_focused_test_default = {
|
|
842
1036
|
create(context) {
|
|
843
1037
|
return {
|
|
844
1038
|
CallExpression(node) {
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
messageId: "noFocusedTest",
|
|
849
|
-
node: node.callee.property,
|
|
850
|
-
suggest: [
|
|
851
|
-
{
|
|
852
|
-
// - 1 to remove the `.only` annotation with dot notation
|
|
853
|
-
fix: (fixer) => fixer.removeRange([
|
|
854
|
-
callee.property.range[0] - 1,
|
|
855
|
-
callee.range[1]
|
|
856
|
-
]),
|
|
857
|
-
messageId: "suggestRemoveOnly"
|
|
858
|
-
}
|
|
859
|
-
]
|
|
860
|
-
});
|
|
1039
|
+
const call = parseFnCall(context, node);
|
|
1040
|
+
if (call?.type !== "test" && call?.type !== "describe") {
|
|
1041
|
+
return;
|
|
861
1042
|
}
|
|
1043
|
+
const onlyNode = call.members.find((s) => getStringValue(s) === "only");
|
|
1044
|
+
if (!onlyNode)
|
|
1045
|
+
return;
|
|
1046
|
+
context.report({
|
|
1047
|
+
messageId: "noFocusedTest",
|
|
1048
|
+
node: onlyNode,
|
|
1049
|
+
suggest: [
|
|
1050
|
+
{
|
|
1051
|
+
fix: (fixer) => {
|
|
1052
|
+
return fixer.removeRange([
|
|
1053
|
+
onlyNode.range[0] - 1,
|
|
1054
|
+
onlyNode.range[1] + Number(onlyNode.type !== "Identifier")
|
|
1055
|
+
]);
|
|
1056
|
+
},
|
|
1057
|
+
messageId: "suggestRemoveOnly"
|
|
1058
|
+
}
|
|
1059
|
+
]
|
|
1060
|
+
});
|
|
862
1061
|
}
|
|
863
1062
|
};
|
|
864
1063
|
},
|
|
@@ -971,7 +1170,7 @@ var no_hooks_default;
|
|
|
971
1170
|
var init_no_hooks = __esm({
|
|
972
1171
|
"src/rules/no-hooks.ts"() {
|
|
973
1172
|
"use strict";
|
|
974
|
-
|
|
1173
|
+
init_parseFnCall();
|
|
975
1174
|
no_hooks_default = {
|
|
976
1175
|
create(context) {
|
|
977
1176
|
const options = {
|
|
@@ -981,7 +1180,9 @@ var init_no_hooks = __esm({
|
|
|
981
1180
|
return {
|
|
982
1181
|
CallExpression(node) {
|
|
983
1182
|
const call = parseFnCall(context, node);
|
|
984
|
-
if (
|
|
1183
|
+
if (!call)
|
|
1184
|
+
return;
|
|
1185
|
+
if (call.type === "hook" && !options.allow.includes(call.name)) {
|
|
985
1186
|
context.report({
|
|
986
1187
|
data: { hookName: call.name },
|
|
987
1188
|
messageId: "unexpectedHook",
|
|
@@ -1270,62 +1471,23 @@ var init_no_raw_locators = __esm({
|
|
|
1270
1471
|
}
|
|
1271
1472
|
});
|
|
1272
1473
|
|
|
1273
|
-
// src/utils/parseExpectCall.ts
|
|
1274
|
-
function getExpectArguments(node) {
|
|
1275
|
-
const grandparent = node.parent.parent;
|
|
1276
|
-
return grandparent.type === "CallExpression" ? grandparent.arguments : [];
|
|
1277
|
-
}
|
|
1278
|
-
function parseExpectCall(context, node) {
|
|
1279
|
-
if (!isExpectCall(context, node)) {
|
|
1280
|
-
return;
|
|
1281
|
-
}
|
|
1282
|
-
const members = getMatchers(node);
|
|
1283
|
-
const modifiers = [];
|
|
1284
|
-
let matcher;
|
|
1285
|
-
members.forEach((item) => {
|
|
1286
|
-
if (MODIFIER_NAMES.has(getStringValue(item))) {
|
|
1287
|
-
modifiers.push(item);
|
|
1288
|
-
} else {
|
|
1289
|
-
matcher = item;
|
|
1290
|
-
}
|
|
1291
|
-
});
|
|
1292
|
-
if (!matcher) {
|
|
1293
|
-
return;
|
|
1294
|
-
}
|
|
1295
|
-
return {
|
|
1296
|
-
args: getExpectArguments(matcher),
|
|
1297
|
-
matcher,
|
|
1298
|
-
matcherName: getStringValue(matcher),
|
|
1299
|
-
members,
|
|
1300
|
-
modifiers
|
|
1301
|
-
};
|
|
1302
|
-
}
|
|
1303
|
-
var MODIFIER_NAMES;
|
|
1304
|
-
var init_parseExpectCall = __esm({
|
|
1305
|
-
"src/utils/parseExpectCall.ts"() {
|
|
1306
|
-
"use strict";
|
|
1307
|
-
init_ast();
|
|
1308
|
-
MODIFIER_NAMES = /* @__PURE__ */ new Set(["not", "resolves", "rejects"]);
|
|
1309
|
-
}
|
|
1310
|
-
});
|
|
1311
|
-
|
|
1312
1474
|
// src/rules/no-restricted-matchers.ts
|
|
1313
1475
|
var no_restricted_matchers_default;
|
|
1314
1476
|
var init_no_restricted_matchers = __esm({
|
|
1315
1477
|
"src/rules/no-restricted-matchers.ts"() {
|
|
1316
1478
|
"use strict";
|
|
1317
1479
|
init_ast();
|
|
1318
|
-
|
|
1480
|
+
init_parseFnCall();
|
|
1319
1481
|
no_restricted_matchers_default = {
|
|
1320
1482
|
create(context) {
|
|
1321
1483
|
const restrictedChains = context.options?.[0] ?? {};
|
|
1322
1484
|
return {
|
|
1323
1485
|
CallExpression(node) {
|
|
1324
|
-
const
|
|
1325
|
-
if (
|
|
1486
|
+
const call = parseFnCall(context, node);
|
|
1487
|
+
if (call?.type !== "expect")
|
|
1326
1488
|
return;
|
|
1327
1489
|
Object.entries(restrictedChains).map(([restriction, message]) => {
|
|
1328
|
-
const chain =
|
|
1490
|
+
const chain = call.members;
|
|
1329
1491
|
const restrictionLinks = restriction.split(".").length;
|
|
1330
1492
|
const startIndex = chain.findIndex((_, i) => {
|
|
1331
1493
|
const partial = chain.slice(i, i + restrictionLinks).map(getStringValue).join(".");
|
|
@@ -1382,34 +1544,39 @@ var init_no_skipped_test = __esm({
|
|
|
1382
1544
|
"src/rules/no-skipped-test.ts"() {
|
|
1383
1545
|
"use strict";
|
|
1384
1546
|
init_ast();
|
|
1547
|
+
init_parseFnCall();
|
|
1385
1548
|
no_skipped_test_default = {
|
|
1386
1549
|
create(context) {
|
|
1387
1550
|
return {
|
|
1388
1551
|
CallExpression(node) {
|
|
1389
1552
|
const options = context.options[0] || {};
|
|
1390
1553
|
const allowConditional = !!options.allowConditional;
|
|
1391
|
-
const
|
|
1392
|
-
if (
|
|
1393
|
-
|
|
1394
|
-
if (!isHook && allowConditional && node.arguments.length) {
|
|
1395
|
-
return;
|
|
1396
|
-
}
|
|
1397
|
-
context.report({
|
|
1398
|
-
messageId: "noSkippedTest",
|
|
1399
|
-
node: isHook ? callee.property : node,
|
|
1400
|
-
suggest: [
|
|
1401
|
-
{
|
|
1402
|
-
fix: (fixer) => {
|
|
1403
|
-
return isHook ? fixer.removeRange([
|
|
1404
|
-
callee.property.range[0] - 1,
|
|
1405
|
-
callee.range[1]
|
|
1406
|
-
]) : fixer.remove(node.parent);
|
|
1407
|
-
},
|
|
1408
|
-
messageId: "removeSkippedTestAnnotation"
|
|
1409
|
-
}
|
|
1410
|
-
]
|
|
1411
|
-
});
|
|
1554
|
+
const call = parseFnCall(context, node);
|
|
1555
|
+
if (call?.type !== "test" && call?.type !== "describe") {
|
|
1556
|
+
return;
|
|
1412
1557
|
}
|
|
1558
|
+
const skipNode = call.members.find((s) => getStringValue(s) === "skip");
|
|
1559
|
+
if (!skipNode)
|
|
1560
|
+
return;
|
|
1561
|
+
const isStandalone = call.type === "test" && !isFunction(node.arguments[1]);
|
|
1562
|
+
if (isStandalone && allowConditional && node.arguments.length) {
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
context.report({
|
|
1566
|
+
messageId: "noSkippedTest",
|
|
1567
|
+
node: isStandalone ? node : skipNode,
|
|
1568
|
+
suggest: [
|
|
1569
|
+
{
|
|
1570
|
+
fix: (fixer) => {
|
|
1571
|
+
return isStandalone ? fixer.remove(node.parent) : fixer.removeRange([
|
|
1572
|
+
skipNode.range[0] - 1,
|
|
1573
|
+
skipNode.range[1] + Number(skipNode.type !== "Identifier")
|
|
1574
|
+
]);
|
|
1575
|
+
},
|
|
1576
|
+
messageId: "removeSkippedTestAnnotation"
|
|
1577
|
+
}
|
|
1578
|
+
]
|
|
1579
|
+
});
|
|
1413
1580
|
}
|
|
1414
1581
|
};
|
|
1415
1582
|
},
|
|
@@ -1449,7 +1616,8 @@ var init_no_standalone_expect = __esm({
|
|
|
1449
1616
|
"src/rules/no-standalone-expect.ts"() {
|
|
1450
1617
|
"use strict";
|
|
1451
1618
|
init_ast();
|
|
1452
|
-
|
|
1619
|
+
init_parseFnCall();
|
|
1620
|
+
getBlockType = (context, statement) => {
|
|
1453
1621
|
const func = getParent(statement);
|
|
1454
1622
|
if (!func) {
|
|
1455
1623
|
throw new Error(
|
|
@@ -1464,7 +1632,7 @@ var init_no_standalone_expect = __esm({
|
|
|
1464
1632
|
if (expr.type === "VariableDeclarator" || expr.type === "MethodDefinition") {
|
|
1465
1633
|
return "function";
|
|
1466
1634
|
}
|
|
1467
|
-
if (expr.type === "CallExpression" &&
|
|
1635
|
+
if (expr.type === "CallExpression" && isTypeOfFnCall(context, expr, ["describe"])) {
|
|
1468
1636
|
return "describe";
|
|
1469
1637
|
}
|
|
1470
1638
|
}
|
|
@@ -1480,43 +1648,48 @@ var init_no_standalone_expect = __esm({
|
|
|
1480
1648
|
}
|
|
1481
1649
|
},
|
|
1482
1650
|
"ArrowFunctionExpression:exit"() {
|
|
1483
|
-
if (callStack
|
|
1651
|
+
if (callStack.at(-1) === "arrow") {
|
|
1484
1652
|
callStack.pop();
|
|
1485
1653
|
}
|
|
1486
1654
|
},
|
|
1487
1655
|
BlockStatement(statement) {
|
|
1488
|
-
const blockType = getBlockType(statement);
|
|
1656
|
+
const blockType = getBlockType(context, statement);
|
|
1489
1657
|
if (blockType) {
|
|
1490
1658
|
callStack.push(blockType);
|
|
1491
1659
|
}
|
|
1492
1660
|
},
|
|
1493
1661
|
"BlockStatement:exit"(statement) {
|
|
1494
|
-
if (callStack
|
|
1662
|
+
if (callStack.at(-1) === getBlockType(context, statement)) {
|
|
1495
1663
|
callStack.pop();
|
|
1496
1664
|
}
|
|
1497
1665
|
},
|
|
1498
1666
|
CallExpression(node) {
|
|
1499
|
-
|
|
1667
|
+
const call = parseFnCall(context, node);
|
|
1668
|
+
if (call?.type === "expect") {
|
|
1669
|
+
if (getParent(call.head.node)?.type === "MemberExpression" && call.members.length === 1 && !["assertions", "hasAssertions"].includes(
|
|
1670
|
+
getStringValue(call.members[0])
|
|
1671
|
+
)) {
|
|
1672
|
+
return;
|
|
1673
|
+
}
|
|
1500
1674
|
const parent = callStack.at(-1);
|
|
1501
1675
|
if (!parent || parent === "describe") {
|
|
1502
|
-
|
|
1503
|
-
context.report({
|
|
1504
|
-
messageId: "unexpectedExpect",
|
|
1505
|
-
node: root ?? node
|
|
1506
|
-
});
|
|
1676
|
+
context.report({ messageId: "unexpectedExpect", node });
|
|
1507
1677
|
}
|
|
1508
1678
|
return;
|
|
1509
1679
|
}
|
|
1510
|
-
if (
|
|
1680
|
+
if (call?.type === "test") {
|
|
1511
1681
|
callStack.push("test");
|
|
1512
1682
|
}
|
|
1683
|
+
if (call?.type === "hook") {
|
|
1684
|
+
callStack.push("hook");
|
|
1685
|
+
}
|
|
1513
1686
|
if (node.callee.type === "TaggedTemplateExpression") {
|
|
1514
1687
|
callStack.push("template");
|
|
1515
1688
|
}
|
|
1516
1689
|
},
|
|
1517
1690
|
"CallExpression:exit"(node) {
|
|
1518
|
-
const top = callStack
|
|
1519
|
-
if (top === "test" &&
|
|
1691
|
+
const top = callStack.at(-1);
|
|
1692
|
+
if (top === "test" && isTypeOfFnCall(context, node, ["test"]) && node.callee.type !== "MemberExpression" || top === "template" && node.callee.type === "TaggedTemplateExpression") {
|
|
1520
1693
|
callStack.pop();
|
|
1521
1694
|
}
|
|
1522
1695
|
}
|
|
@@ -1764,7 +1937,7 @@ var init_no_useless_not = __esm({
|
|
|
1764
1937
|
"use strict";
|
|
1765
1938
|
init_ast();
|
|
1766
1939
|
init_fixer();
|
|
1767
|
-
|
|
1940
|
+
init_parseFnCall();
|
|
1768
1941
|
matcherMap = {
|
|
1769
1942
|
toBeDisabled: "toBeEnabled",
|
|
1770
1943
|
toBeEnabled: "toBeDisabled",
|
|
@@ -1775,27 +1948,28 @@ var init_no_useless_not = __esm({
|
|
|
1775
1948
|
create(context) {
|
|
1776
1949
|
return {
|
|
1777
1950
|
CallExpression(node) {
|
|
1778
|
-
const
|
|
1779
|
-
if (
|
|
1951
|
+
const call = parseFnCall(context, node);
|
|
1952
|
+
if (call?.type !== "expect")
|
|
1780
1953
|
return;
|
|
1781
|
-
const notModifier =
|
|
1954
|
+
const notModifier = call.modifiers.find(
|
|
1782
1955
|
(mod) => getStringValue(mod) === "not"
|
|
1783
1956
|
);
|
|
1784
1957
|
if (!notModifier)
|
|
1785
1958
|
return;
|
|
1786
|
-
|
|
1787
|
-
|
|
1959
|
+
const matcherName = call.matcherName;
|
|
1960
|
+
if (matcherName in matcherMap) {
|
|
1961
|
+
const newMatcher = matcherMap[matcherName];
|
|
1788
1962
|
context.report({
|
|
1789
|
-
data: { new: newMatcher, old:
|
|
1963
|
+
data: { new: newMatcher, old: matcherName },
|
|
1790
1964
|
fix: (fixer) => [
|
|
1791
1965
|
fixer.removeRange([
|
|
1792
1966
|
notModifier.range[0] - getRangeOffset(notModifier),
|
|
1793
1967
|
notModifier.range[1] + 1
|
|
1794
1968
|
]),
|
|
1795
|
-
replaceAccessorFixer(fixer,
|
|
1969
|
+
replaceAccessorFixer(fixer, call.matcher, newMatcher)
|
|
1796
1970
|
],
|
|
1797
1971
|
loc: {
|
|
1798
|
-
end:
|
|
1972
|
+
end: call.matcher.loc.end,
|
|
1799
1973
|
start: notModifier.loc.start
|
|
1800
1974
|
},
|
|
1801
1975
|
messageId: "noUselessNot"
|
|
@@ -1917,7 +2091,7 @@ var init_prefer_comparison_matcher = __esm({
|
|
|
1917
2091
|
"src/rules/prefer-comparison-matcher.ts"() {
|
|
1918
2092
|
"use strict";
|
|
1919
2093
|
init_ast();
|
|
1920
|
-
|
|
2094
|
+
init_parseFnCall();
|
|
1921
2095
|
isString = (node) => {
|
|
1922
2096
|
return isStringLiteral(node) || node.type === "TemplateLiteral";
|
|
1923
2097
|
};
|
|
@@ -1944,17 +2118,19 @@ var init_prefer_comparison_matcher = __esm({
|
|
|
1944
2118
|
create(context) {
|
|
1945
2119
|
return {
|
|
1946
2120
|
CallExpression(node) {
|
|
1947
|
-
const
|
|
1948
|
-
if (
|
|
2121
|
+
const call = parseFnCall(context, node);
|
|
2122
|
+
if (call?.type !== "expect" || call.matcherArgs.length === 0)
|
|
1949
2123
|
return;
|
|
1950
|
-
const
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
const [
|
|
1954
|
-
|
|
2124
|
+
const expect = findParent(call.head.node, "CallExpression");
|
|
2125
|
+
if (!expect)
|
|
2126
|
+
return;
|
|
2127
|
+
const [comparison] = expect.arguments;
|
|
2128
|
+
const expectCallEnd = expect.range[1];
|
|
2129
|
+
const [matcherArg] = call.matcherArgs;
|
|
2130
|
+
if (comparison?.type !== "BinaryExpression" || isComparingToString(comparison) || !equalityMatchers.has(call.matcherName) || !isBooleanLiteral(matcherArg)) {
|
|
1955
2131
|
return;
|
|
1956
2132
|
}
|
|
1957
|
-
const hasNot =
|
|
2133
|
+
const hasNot = call.modifiers.some(
|
|
1958
2134
|
(node2) => getStringValue(node2) === "not"
|
|
1959
2135
|
);
|
|
1960
2136
|
const preferredMatcher = determineMatcher(
|
|
@@ -1967,7 +2143,7 @@ var init_prefer_comparison_matcher = __esm({
|
|
|
1967
2143
|
context.report({
|
|
1968
2144
|
data: { preferredMatcher },
|
|
1969
2145
|
fix(fixer) {
|
|
1970
|
-
const [modifier] =
|
|
2146
|
+
const [modifier] = call.modifiers;
|
|
1971
2147
|
const modifierText = modifier && getStringValue(modifier) !== "not" ? `.${getStringValue(modifier)}` : "";
|
|
1972
2148
|
return [
|
|
1973
2149
|
// Replace the comparison argument with the left-hand side of the comparison
|
|
@@ -1977,7 +2153,7 @@ var init_prefer_comparison_matcher = __esm({
|
|
|
1977
2153
|
),
|
|
1978
2154
|
// Replace the current matcher & modifier with the preferred matcher
|
|
1979
2155
|
fixer.replaceTextRange(
|
|
1980
|
-
[expectCallEnd, getParent(matcher).range[1]],
|
|
2156
|
+
[expectCallEnd, getParent(call.matcher).range[1]],
|
|
1981
2157
|
`${modifierText}.${preferredMatcher}`
|
|
1982
2158
|
),
|
|
1983
2159
|
// Replace the matcher argument with the right-hand side of the comparison
|
|
@@ -1988,7 +2164,7 @@ var init_prefer_comparison_matcher = __esm({
|
|
|
1988
2164
|
];
|
|
1989
2165
|
},
|
|
1990
2166
|
messageId: "useToBeComparison",
|
|
1991
|
-
node: matcher
|
|
2167
|
+
node: call.matcher
|
|
1992
2168
|
});
|
|
1993
2169
|
}
|
|
1994
2170
|
};
|
|
@@ -2015,30 +2191,32 @@ var init_prefer_equality_matcher = __esm({
|
|
|
2015
2191
|
"src/rules/prefer-equality-matcher.ts"() {
|
|
2016
2192
|
"use strict";
|
|
2017
2193
|
init_ast();
|
|
2018
|
-
|
|
2194
|
+
init_parseFnCall();
|
|
2019
2195
|
prefer_equality_matcher_default = {
|
|
2020
2196
|
create(context) {
|
|
2021
2197
|
return {
|
|
2022
2198
|
CallExpression(node) {
|
|
2023
|
-
const
|
|
2024
|
-
if (
|
|
2199
|
+
const call = parseFnCall(context, node);
|
|
2200
|
+
if (call?.type !== "expect" || call.matcherArgs.length === 0)
|
|
2025
2201
|
return;
|
|
2026
|
-
const
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
const [
|
|
2030
|
-
|
|
2202
|
+
const expect = findParent(call.head.node, "CallExpression");
|
|
2203
|
+
if (!expect)
|
|
2204
|
+
return;
|
|
2205
|
+
const [comparison] = expect.arguments;
|
|
2206
|
+
const expectCallEnd = expect.range[1];
|
|
2207
|
+
const [matcherArg] = call.matcherArgs;
|
|
2208
|
+
if (comparison?.type !== "BinaryExpression" || comparison.operator !== "===" && comparison.operator !== "!==" || !equalityMatchers.has(call.matcherName) || !isBooleanLiteral(matcherArg)) {
|
|
2031
2209
|
return;
|
|
2032
2210
|
}
|
|
2033
2211
|
const matcherValue = getRawValue(matcherArg) === "true";
|
|
2034
|
-
const [modifier] =
|
|
2035
|
-
const hasNot =
|
|
2212
|
+
const [modifier] = call.modifiers;
|
|
2213
|
+
const hasNot = call.modifiers.some(
|
|
2036
2214
|
(node2) => getStringValue(node2) === "not"
|
|
2037
2215
|
);
|
|
2038
2216
|
const addNotModifier = (comparison.operator === "!==" ? !matcherValue : matcherValue) === hasNot;
|
|
2039
2217
|
context.report({
|
|
2040
2218
|
messageId: "useEqualityMatcher",
|
|
2041
|
-
node: matcher,
|
|
2219
|
+
node: call.matcher,
|
|
2042
2220
|
suggest: [...equalityMatchers.keys()].map((equalityMatcher) => ({
|
|
2043
2221
|
data: { matcher: equalityMatcher },
|
|
2044
2222
|
fix(fixer) {
|
|
@@ -2054,7 +2232,7 @@ var init_prefer_equality_matcher = __esm({
|
|
|
2054
2232
|
),
|
|
2055
2233
|
// replace the current matcher & modifier with the preferred matcher
|
|
2056
2234
|
fixer.replaceTextRange(
|
|
2057
|
-
[expectCallEnd, getParent(matcher).range[1]],
|
|
2235
|
+
[expectCallEnd, getParent(call.matcher).range[1]],
|
|
2058
2236
|
`${modifierText}.${equalityMatcher}`
|
|
2059
2237
|
),
|
|
2060
2238
|
// replace the matcher argument with the right-hand side of the comparison
|
|
@@ -2089,12 +2267,12 @@ var init_prefer_equality_matcher = __esm({
|
|
|
2089
2267
|
});
|
|
2090
2268
|
|
|
2091
2269
|
// src/rules/prefer-hooks-in-order.ts
|
|
2092
|
-
var
|
|
2270
|
+
var order, prefer_hooks_in_order_default;
|
|
2093
2271
|
var init_prefer_hooks_in_order = __esm({
|
|
2094
2272
|
"src/rules/prefer-hooks-in-order.ts"() {
|
|
2095
2273
|
"use strict";
|
|
2096
|
-
|
|
2097
|
-
|
|
2274
|
+
init_parseFnCall();
|
|
2275
|
+
order = ["beforeAll", "beforeEach", "afterEach", "afterAll"];
|
|
2098
2276
|
prefer_hooks_in_order_default = {
|
|
2099
2277
|
create(context) {
|
|
2100
2278
|
let previousHookIndex = -1;
|
|
@@ -2103,33 +2281,34 @@ var init_prefer_hooks_in_order = __esm({
|
|
|
2103
2281
|
CallExpression(node) {
|
|
2104
2282
|
if (inHook)
|
|
2105
2283
|
return;
|
|
2106
|
-
|
|
2284
|
+
const call = parseFnCall(context, node);
|
|
2285
|
+
if (call?.type !== "hook") {
|
|
2107
2286
|
previousHookIndex = -1;
|
|
2108
2287
|
return;
|
|
2109
2288
|
}
|
|
2110
2289
|
inHook = true;
|
|
2111
|
-
const currentHook =
|
|
2112
|
-
const currentHookIndex =
|
|
2290
|
+
const currentHook = call.name;
|
|
2291
|
+
const currentHookIndex = order.indexOf(currentHook);
|
|
2113
2292
|
if (currentHookIndex < previousHookIndex) {
|
|
2114
|
-
|
|
2293
|
+
context.report({
|
|
2115
2294
|
data: {
|
|
2116
2295
|
currentHook,
|
|
2117
|
-
previousHook:
|
|
2296
|
+
previousHook: order[previousHookIndex]
|
|
2118
2297
|
},
|
|
2119
2298
|
messageId: "reorderHooks",
|
|
2120
2299
|
node
|
|
2121
2300
|
});
|
|
2301
|
+
return;
|
|
2122
2302
|
}
|
|
2123
2303
|
previousHookIndex = currentHookIndex;
|
|
2124
2304
|
},
|
|
2125
2305
|
"CallExpression:exit"(node) {
|
|
2126
|
-
if (
|
|
2306
|
+
if (isTypeOfFnCall(context, node, ["hook"])) {
|
|
2127
2307
|
inHook = false;
|
|
2128
2308
|
return;
|
|
2129
2309
|
}
|
|
2130
|
-
if (inHook)
|
|
2310
|
+
if (inHook)
|
|
2131
2311
|
return;
|
|
2132
|
-
}
|
|
2133
2312
|
previousHookIndex = -1;
|
|
2134
2313
|
}
|
|
2135
2314
|
};
|
|
@@ -2155,20 +2334,17 @@ var prefer_hooks_on_top_default;
|
|
|
2155
2334
|
var init_prefer_hooks_on_top = __esm({
|
|
2156
2335
|
"src/rules/prefer-hooks-on-top.ts"() {
|
|
2157
2336
|
"use strict";
|
|
2158
|
-
|
|
2337
|
+
init_parseFnCall();
|
|
2159
2338
|
prefer_hooks_on_top_default = {
|
|
2160
2339
|
create(context) {
|
|
2161
2340
|
const stack = [false];
|
|
2162
2341
|
return {
|
|
2163
2342
|
CallExpression(node) {
|
|
2164
|
-
if (
|
|
2343
|
+
if (isTypeOfFnCall(context, node, ["test"])) {
|
|
2165
2344
|
stack[stack.length - 1] = true;
|
|
2166
2345
|
}
|
|
2167
|
-
if (stack.at(-1) &&
|
|
2168
|
-
context.report({
|
|
2169
|
-
messageId: "noHookOnTop",
|
|
2170
|
-
node
|
|
2171
|
-
});
|
|
2346
|
+
if (stack.at(-1) && isTypeOfFnCall(context, node, ["hook"])) {
|
|
2347
|
+
context.report({ messageId: "noHookOnTop", node });
|
|
2172
2348
|
}
|
|
2173
2349
|
stack.push(false);
|
|
2174
2350
|
},
|
|
@@ -2199,6 +2375,7 @@ var init_prefer_lowercase_title = __esm({
|
|
|
2199
2375
|
"src/rules/prefer-lowercase-title.ts"() {
|
|
2200
2376
|
"use strict";
|
|
2201
2377
|
init_ast();
|
|
2378
|
+
init_parseFnCall();
|
|
2202
2379
|
prefer_lowercase_title_default = {
|
|
2203
2380
|
create(context) {
|
|
2204
2381
|
const { allowedPrefixes, ignore, ignoreTopLevelDescribe } = {
|
|
@@ -2210,14 +2387,15 @@ var init_prefer_lowercase_title = __esm({
|
|
|
2210
2387
|
let describeCount = 0;
|
|
2211
2388
|
return {
|
|
2212
2389
|
CallExpression(node) {
|
|
2213
|
-
const
|
|
2214
|
-
if (
|
|
2390
|
+
const call = parseFnCall(context, node);
|
|
2391
|
+
if (call?.type !== "describe" && call?.type !== "test") {
|
|
2392
|
+
return;
|
|
2393
|
+
}
|
|
2394
|
+
if (call.type === "describe") {
|
|
2215
2395
|
describeCount++;
|
|
2216
2396
|
if (ignoreTopLevelDescribe && describeCount === 1) {
|
|
2217
2397
|
return;
|
|
2218
2398
|
}
|
|
2219
|
-
} else if (!method) {
|
|
2220
|
-
return;
|
|
2221
2399
|
}
|
|
2222
2400
|
const [title] = node.arguments;
|
|
2223
2401
|
if (!isStringNode(title)) {
|
|
@@ -2227,6 +2405,7 @@ var init_prefer_lowercase_title = __esm({
|
|
|
2227
2405
|
if (!description || allowedPrefixes.some((name) => description.startsWith(name))) {
|
|
2228
2406
|
return;
|
|
2229
2407
|
}
|
|
2408
|
+
const method = call.type === "describe" ? "test.describe" : "test";
|
|
2230
2409
|
const firstCharacter = description.charAt(0);
|
|
2231
2410
|
if (!firstCharacter || firstCharacter === firstCharacter.toLowerCase() || ignore.includes(method)) {
|
|
2232
2411
|
return;
|
|
@@ -2246,7 +2425,7 @@ var init_prefer_lowercase_title = __esm({
|
|
|
2246
2425
|
});
|
|
2247
2426
|
},
|
|
2248
2427
|
"CallExpression:exit"(node) {
|
|
2249
|
-
if (
|
|
2428
|
+
if (isTypeOfFnCall(context, node, ["describe"])) {
|
|
2250
2429
|
describeCount--;
|
|
2251
2430
|
}
|
|
2252
2431
|
}
|
|
@@ -2299,22 +2478,24 @@ var init_prefer_strict_equal = __esm({
|
|
|
2299
2478
|
"src/rules/prefer-strict-equal.ts"() {
|
|
2300
2479
|
"use strict";
|
|
2301
2480
|
init_fixer();
|
|
2302
|
-
|
|
2481
|
+
init_parseFnCall();
|
|
2303
2482
|
prefer_strict_equal_default = {
|
|
2304
2483
|
create(context) {
|
|
2305
2484
|
return {
|
|
2306
2485
|
CallExpression(node) {
|
|
2307
|
-
const
|
|
2308
|
-
if (
|
|
2486
|
+
const call = parseFnCall(context, node);
|
|
2487
|
+
if (call?.type !== "expect")
|
|
2488
|
+
return;
|
|
2489
|
+
if (call.matcherName === "toEqual") {
|
|
2309
2490
|
context.report({
|
|
2310
2491
|
messageId: "useToStrictEqual",
|
|
2311
|
-
node:
|
|
2492
|
+
node: call.matcher,
|
|
2312
2493
|
suggest: [
|
|
2313
2494
|
{
|
|
2314
2495
|
fix: (fixer) => {
|
|
2315
2496
|
return replaceAccessorFixer(
|
|
2316
2497
|
fixer,
|
|
2317
|
-
|
|
2498
|
+
call.matcher,
|
|
2318
2499
|
"toStrictEqual"
|
|
2319
2500
|
);
|
|
2320
2501
|
},
|
|
@@ -2347,8 +2528,8 @@ var init_prefer_strict_equal = __esm({
|
|
|
2347
2528
|
});
|
|
2348
2529
|
|
|
2349
2530
|
// src/rules/prefer-to-be.ts
|
|
2350
|
-
function shouldUseToBe(
|
|
2351
|
-
let arg =
|
|
2531
|
+
function shouldUseToBe(call) {
|
|
2532
|
+
let arg = call.matcherArgs[0];
|
|
2352
2533
|
if (arg.type === "UnaryExpression" && arg.operator === "-") {
|
|
2353
2534
|
arg = arg.argument;
|
|
2354
2535
|
}
|
|
@@ -2357,14 +2538,14 @@ function shouldUseToBe(expectCall) {
|
|
|
2357
2538
|
}
|
|
2358
2539
|
return arg.type === "TemplateLiteral";
|
|
2359
2540
|
}
|
|
2360
|
-
function reportPreferToBe(context,
|
|
2541
|
+
function reportPreferToBe(context, call, whatToBe, notModifier) {
|
|
2361
2542
|
context.report({
|
|
2362
2543
|
fix(fixer) {
|
|
2363
2544
|
const fixes = [
|
|
2364
|
-
replaceAccessorFixer(fixer,
|
|
2545
|
+
replaceAccessorFixer(fixer, call.matcher, `toBe${whatToBe}`)
|
|
2365
2546
|
];
|
|
2366
|
-
if (
|
|
2367
|
-
fixes.push(fixer.remove(
|
|
2547
|
+
if (call.matcherArgs?.length && whatToBe !== "") {
|
|
2548
|
+
fixes.push(fixer.remove(call.matcherArgs[0]));
|
|
2368
2549
|
}
|
|
2369
2550
|
if (notModifier) {
|
|
2370
2551
|
const [start, end] = notModifier.range;
|
|
@@ -2373,7 +2554,7 @@ function reportPreferToBe(context, expectCall, whatToBe, notModifier) {
|
|
|
2373
2554
|
return fixes;
|
|
2374
2555
|
},
|
|
2375
2556
|
messageId: `useToBe${whatToBe}`,
|
|
2376
|
-
node:
|
|
2557
|
+
node: call.matcher
|
|
2377
2558
|
});
|
|
2378
2559
|
}
|
|
2379
2560
|
var prefer_to_be_default;
|
|
@@ -2382,42 +2563,42 @@ var init_prefer_to_be = __esm({
|
|
|
2382
2563
|
"use strict";
|
|
2383
2564
|
init_ast();
|
|
2384
2565
|
init_fixer();
|
|
2385
|
-
|
|
2566
|
+
init_parseFnCall();
|
|
2386
2567
|
prefer_to_be_default = {
|
|
2387
2568
|
create(context) {
|
|
2388
2569
|
return {
|
|
2389
2570
|
CallExpression(node) {
|
|
2390
|
-
const
|
|
2391
|
-
if (
|
|
2571
|
+
const call = parseFnCall(context, node);
|
|
2572
|
+
if (call?.type !== "expect")
|
|
2392
2573
|
return;
|
|
2393
2574
|
const notMatchers = ["toBeUndefined", "toBeDefined"];
|
|
2394
|
-
const notModifier =
|
|
2575
|
+
const notModifier = call.modifiers.find(
|
|
2395
2576
|
(node2) => getStringValue(node2) === "not"
|
|
2396
2577
|
);
|
|
2397
|
-
if (notModifier && notMatchers.includes(
|
|
2578
|
+
if (notModifier && notMatchers.includes(call.matcherName)) {
|
|
2398
2579
|
return reportPreferToBe(
|
|
2399
2580
|
context,
|
|
2400
|
-
|
|
2401
|
-
|
|
2581
|
+
call,
|
|
2582
|
+
call.matcherName === "toBeDefined" ? "Undefined" : "Defined",
|
|
2402
2583
|
notModifier
|
|
2403
2584
|
);
|
|
2404
2585
|
}
|
|
2405
|
-
const firstArg =
|
|
2406
|
-
if (!equalityMatchers.has(
|
|
2586
|
+
const firstArg = call.matcherArgs[0];
|
|
2587
|
+
if (!equalityMatchers.has(call.matcherName) || !firstArg) {
|
|
2407
2588
|
return;
|
|
2408
2589
|
}
|
|
2409
2590
|
if (firstArg.type === "Literal" && firstArg.value === null) {
|
|
2410
|
-
return reportPreferToBe(context,
|
|
2591
|
+
return reportPreferToBe(context, call, "Null");
|
|
2411
2592
|
}
|
|
2412
2593
|
if (isIdentifier(firstArg, "undefined")) {
|
|
2413
2594
|
const name = notModifier ? "Defined" : "Undefined";
|
|
2414
|
-
return reportPreferToBe(context,
|
|
2595
|
+
return reportPreferToBe(context, call, name, notModifier);
|
|
2415
2596
|
}
|
|
2416
2597
|
if (isIdentifier(firstArg, "NaN")) {
|
|
2417
|
-
return reportPreferToBe(context,
|
|
2598
|
+
return reportPreferToBe(context, call, "NaN");
|
|
2418
2599
|
}
|
|
2419
|
-
if (shouldUseToBe(
|
|
2420
|
-
reportPreferToBe(context,
|
|
2600
|
+
if (shouldUseToBe(call) && call.matcherName !== "toBe") {
|
|
2601
|
+
reportPreferToBe(context, call, "");
|
|
2421
2602
|
}
|
|
2422
2603
|
}
|
|
2423
2604
|
};
|
|
@@ -2450,22 +2631,25 @@ var init_prefer_to_contain = __esm({
|
|
|
2450
2631
|
"src/rules/prefer-to-contain.ts"() {
|
|
2451
2632
|
"use strict";
|
|
2452
2633
|
init_ast();
|
|
2453
|
-
|
|
2634
|
+
init_parseFnCall();
|
|
2454
2635
|
isFixableIncludesCallExpression = (node) => node.type === "CallExpression" && node.callee.type === "MemberExpression" && isPropertyAccessor(node.callee, "includes") && node.arguments.length === 1 && node.arguments[0].type !== "SpreadElement";
|
|
2455
2636
|
prefer_to_contain_default = {
|
|
2456
2637
|
create(context) {
|
|
2457
2638
|
return {
|
|
2458
2639
|
CallExpression(node) {
|
|
2459
|
-
const
|
|
2460
|
-
if (
|
|
2640
|
+
const call = parseFnCall(context, node);
|
|
2641
|
+
if (call?.type !== "expect" || call.matcherArgs.length === 0)
|
|
2642
|
+
return;
|
|
2643
|
+
const expect = findParent(call.head.node, "CallExpression");
|
|
2644
|
+
if (!expect)
|
|
2461
2645
|
return;
|
|
2462
|
-
const
|
|
2463
|
-
const
|
|
2464
|
-
const [matcherArg] =
|
|
2465
|
-
if (!includesCall || matcherArg.type === "SpreadElement" || !equalityMatchers.has(
|
|
2646
|
+
const [includesCall] = expect.arguments;
|
|
2647
|
+
const { matcher } = call;
|
|
2648
|
+
const [matcherArg] = call.matcherArgs;
|
|
2649
|
+
if (!includesCall || matcherArg.type === "SpreadElement" || !equalityMatchers.has(getStringValue(matcher)) || !isBooleanLiteral(matcherArg) || !isFixableIncludesCallExpression(includesCall)) {
|
|
2466
2650
|
return;
|
|
2467
2651
|
}
|
|
2468
|
-
const notModifier =
|
|
2652
|
+
const notModifier = call.modifiers.find(
|
|
2469
2653
|
(node2) => getStringValue(node2) === "not"
|
|
2470
2654
|
);
|
|
2471
2655
|
context.report({
|
|
@@ -2484,7 +2668,7 @@ var init_prefer_to_contain = __esm({
|
|
|
2484
2668
|
),
|
|
2485
2669
|
// replace the matcher argument with the value from the "includes"
|
|
2486
2670
|
fixer.replaceText(
|
|
2487
|
-
|
|
2671
|
+
call.matcherArgs[0],
|
|
2488
2672
|
context.sourceCode.getText(includesCall.arguments[0])
|
|
2489
2673
|
)
|
|
2490
2674
|
];
|
|
@@ -2528,17 +2712,17 @@ var init_prefer_to_have_count = __esm({
|
|
|
2528
2712
|
"use strict";
|
|
2529
2713
|
init_ast();
|
|
2530
2714
|
init_fixer();
|
|
2531
|
-
|
|
2715
|
+
init_parseFnCall();
|
|
2532
2716
|
prefer_to_have_count_default = {
|
|
2533
2717
|
create(context) {
|
|
2534
2718
|
return {
|
|
2535
2719
|
CallExpression(node) {
|
|
2536
|
-
const
|
|
2537
|
-
if (
|
|
2720
|
+
const call = parseFnCall(context, node);
|
|
2721
|
+
if (call?.type !== "expect" || !equalityMatchers.has(call.matcherName)) {
|
|
2538
2722
|
return;
|
|
2539
2723
|
}
|
|
2540
|
-
const [argument] =
|
|
2541
|
-
if (argument
|
|
2724
|
+
const [argument] = call.args;
|
|
2725
|
+
if (argument?.type !== "AwaitExpression" || argument.argument.type !== "CallExpression" || argument.argument.callee.type !== "MemberExpression" || !isPropertyAccessor(argument.argument.callee, "count")) {
|
|
2542
2726
|
return;
|
|
2543
2727
|
}
|
|
2544
2728
|
const callee = argument.argument.callee;
|
|
@@ -2556,13 +2740,13 @@ var init_prefer_to_have_count = __esm({
|
|
|
2556
2740
|
argument.argument.range[1]
|
|
2557
2741
|
]),
|
|
2558
2742
|
// replace the current matcher with "toHaveCount"
|
|
2559
|
-
replaceAccessorFixer(fixer,
|
|
2743
|
+
replaceAccessorFixer(fixer, call.matcher, "toHaveCount"),
|
|
2560
2744
|
// insert "await" to before "expect()"
|
|
2561
2745
|
fixer.insertTextBefore(node, "await ")
|
|
2562
2746
|
];
|
|
2563
2747
|
},
|
|
2564
2748
|
messageId: "useToHaveCount",
|
|
2565
|
-
node:
|
|
2749
|
+
node: call.matcher
|
|
2566
2750
|
});
|
|
2567
2751
|
}
|
|
2568
2752
|
};
|
|
@@ -2592,16 +2776,16 @@ var init_prefer_to_have_length = __esm({
|
|
|
2592
2776
|
"use strict";
|
|
2593
2777
|
init_ast();
|
|
2594
2778
|
init_fixer();
|
|
2595
|
-
|
|
2779
|
+
init_parseFnCall();
|
|
2596
2780
|
prefer_to_have_length_default = {
|
|
2597
2781
|
create(context) {
|
|
2598
2782
|
return {
|
|
2599
2783
|
CallExpression(node) {
|
|
2600
|
-
const
|
|
2601
|
-
if (
|
|
2784
|
+
const call = parseFnCall(context, node);
|
|
2785
|
+
if (call?.type !== "expect" || !equalityMatchers.has(call.matcherName)) {
|
|
2602
2786
|
return;
|
|
2603
2787
|
}
|
|
2604
|
-
const [argument] =
|
|
2788
|
+
const [argument] = call.args;
|
|
2605
2789
|
if (argument?.type !== "MemberExpression" || !isPropertyAccessor(argument, "length")) {
|
|
2606
2790
|
return;
|
|
2607
2791
|
}
|
|
@@ -2614,11 +2798,11 @@ var init_prefer_to_have_length = __esm({
|
|
|
2614
2798
|
argument.range[1]
|
|
2615
2799
|
]),
|
|
2616
2800
|
// replace the current matcher with "toHaveLength"
|
|
2617
|
-
replaceAccessorFixer(fixer,
|
|
2801
|
+
replaceAccessorFixer(fixer, call.matcher, "toHaveLength")
|
|
2618
2802
|
];
|
|
2619
2803
|
},
|
|
2620
2804
|
messageId: "useToHaveLength",
|
|
2621
|
-
node:
|
|
2805
|
+
node: call.matcher
|
|
2622
2806
|
});
|
|
2623
2807
|
}
|
|
2624
2808
|
};
|
|
@@ -2659,7 +2843,7 @@ var init_prefer_web_first_assertions = __esm({
|
|
|
2659
2843
|
"src/rules/prefer-web-first-assertions.ts"() {
|
|
2660
2844
|
"use strict";
|
|
2661
2845
|
init_ast();
|
|
2662
|
-
|
|
2846
|
+
init_parseFnCall();
|
|
2663
2847
|
methods3 = {
|
|
2664
2848
|
getAttribute: {
|
|
2665
2849
|
matcher: "toHaveAttribute",
|
|
@@ -2705,24 +2889,26 @@ var init_prefer_web_first_assertions = __esm({
|
|
|
2705
2889
|
create(context) {
|
|
2706
2890
|
return {
|
|
2707
2891
|
CallExpression(node) {
|
|
2708
|
-
const
|
|
2709
|
-
if (
|
|
2892
|
+
const call = parseFnCall(context, node);
|
|
2893
|
+
if (call?.type !== "expect")
|
|
2894
|
+
return;
|
|
2895
|
+
const expect = findParent(call.head.node, "CallExpression");
|
|
2896
|
+
if (!expect)
|
|
2710
2897
|
return;
|
|
2711
|
-
const arg = dereference(context,
|
|
2898
|
+
const arg = dereference(context, call.args[0]);
|
|
2712
2899
|
if (!arg || arg.type !== "AwaitExpression" || arg.argument.type !== "CallExpression" || arg.argument.callee.type !== "MemberExpression") {
|
|
2713
2900
|
return;
|
|
2714
2901
|
}
|
|
2715
|
-
if (!supportedMatchers.has(
|
|
2902
|
+
if (!supportedMatchers.has(call.matcherName))
|
|
2716
2903
|
return;
|
|
2717
2904
|
const method = getStringValue(arg.argument.callee.property);
|
|
2718
2905
|
const methodConfig = methods3[method];
|
|
2719
2906
|
if (!methodConfig)
|
|
2720
2907
|
return;
|
|
2721
|
-
const
|
|
2722
|
-
const notModifier = expectCall.modifiers.find(
|
|
2908
|
+
const notModifier = call.modifiers.find(
|
|
2723
2909
|
(mod) => getStringValue(mod) === "not"
|
|
2724
2910
|
);
|
|
2725
|
-
const isFalsy = methodConfig.type === "boolean" && (!!
|
|
2911
|
+
const isFalsy = methodConfig.type === "boolean" && (!!call.matcherArgs.length && isBooleanLiteral(call.matcherArgs[0], false) || call.matcherName === "toBeFalsy");
|
|
2726
2912
|
const isInverse = methodConfig.inverse ? notModifier || isFalsy : notModifier && isFalsy;
|
|
2727
2913
|
const newMatcher = +!!notModifier ^ +isFalsy && methodConfig.inverse || methodConfig.matcher;
|
|
2728
2914
|
const { callee } = arg.argument;
|
|
@@ -2736,7 +2922,7 @@ var init_prefer_web_first_assertions = __esm({
|
|
|
2736
2922
|
const methodEnd = methodArgs.length ? methodArgs.at(-1).range[1] + 1 : callee.property.range[1] + 2;
|
|
2737
2923
|
const fixes = [
|
|
2738
2924
|
// Add await to the expect call
|
|
2739
|
-
fixer.insertTextBefore(
|
|
2925
|
+
fixer.insertTextBefore(expect, "await "),
|
|
2740
2926
|
// Remove the await keyword
|
|
2741
2927
|
fixer.replaceTextRange(
|
|
2742
2928
|
[arg.range[0], arg.argument.range[0]],
|
|
@@ -2753,23 +2939,23 @@ var init_prefer_web_first_assertions = __esm({
|
|
|
2753
2939
|
fixes.push(fixer.removeRange([notRange[0], notRange[1] + 1]));
|
|
2754
2940
|
}
|
|
2755
2941
|
if (!methodConfig.inverse && !notModifier && isFalsy) {
|
|
2756
|
-
fixes.push(fixer.insertTextBefore(matcher, "not."));
|
|
2942
|
+
fixes.push(fixer.insertTextBefore(call.matcher, "not."));
|
|
2757
2943
|
}
|
|
2758
|
-
fixes.push(fixer.replaceText(matcher, newMatcher));
|
|
2759
|
-
const [matcherArg] =
|
|
2944
|
+
fixes.push(fixer.replaceText(call.matcher, newMatcher));
|
|
2945
|
+
const [matcherArg] = call.matcherArgs ?? [];
|
|
2760
2946
|
if (matcherArg && isBooleanLiteral(matcherArg)) {
|
|
2761
2947
|
fixes.push(fixer.remove(matcherArg));
|
|
2762
2948
|
} else if (methodConfig.prop && matcherArg) {
|
|
2763
2949
|
const propArg = methodConfig.prop;
|
|
2764
2950
|
const variable = getStringValue(matcherArg);
|
|
2765
|
-
const
|
|
2766
|
-
fixes.push(fixer.replaceText(matcherArg,
|
|
2951
|
+
const args = `{ ${propArg}: ${variable} }`;
|
|
2952
|
+
fixes.push(fixer.replaceText(matcherArg, args));
|
|
2767
2953
|
}
|
|
2768
2954
|
const hasOtherArgs = !!methodArgs.filter(
|
|
2769
2955
|
(arg2) => !isBooleanLiteral(arg2)
|
|
2770
2956
|
).length;
|
|
2771
2957
|
if (methodArgs) {
|
|
2772
|
-
const range = matcher.range;
|
|
2958
|
+
const range = call.matcher.range;
|
|
2773
2959
|
const stringArgs = methodArgs.map((arg2) => getRawValue(arg2)).concat(hasOtherArgs ? "" : []).join(", ");
|
|
2774
2960
|
fixes.push(
|
|
2775
2961
|
fixer.insertTextAfterRange(
|
|
@@ -2781,7 +2967,7 @@ var init_prefer_web_first_assertions = __esm({
|
|
|
2781
2967
|
return fixes;
|
|
2782
2968
|
},
|
|
2783
2969
|
messageId: "useWebFirstAssertion",
|
|
2784
|
-
node
|
|
2970
|
+
node: expect
|
|
2785
2971
|
});
|
|
2786
2972
|
}
|
|
2787
2973
|
};
|
|
@@ -2809,6 +2995,7 @@ var init_require_hook = __esm({
|
|
|
2809
2995
|
"src/rules/require-hook.ts"() {
|
|
2810
2996
|
"use strict";
|
|
2811
2997
|
init_ast();
|
|
2998
|
+
init_parseFnCall();
|
|
2812
2999
|
isNullOrUndefined = (node) => {
|
|
2813
3000
|
return node.type === "Literal" && node.value === null || isIdentifier(node, "undefined");
|
|
2814
3001
|
};
|
|
@@ -2848,7 +3035,7 @@ var init_require_hook = __esm({
|
|
|
2848
3035
|
};
|
|
2849
3036
|
return {
|
|
2850
3037
|
CallExpression(node) {
|
|
2851
|
-
if (!
|
|
3038
|
+
if (!isTypeOfFnCall(context, node, ["describe"]) || node.arguments.length < 2) {
|
|
2852
3039
|
return;
|
|
2853
3040
|
}
|
|
2854
3041
|
const [, testFn] = node.arguments;
|
|
@@ -2896,17 +3083,23 @@ var init_require_soft_assertions = __esm({
|
|
|
2896
3083
|
"src/rules/require-soft-assertions.ts"() {
|
|
2897
3084
|
"use strict";
|
|
2898
3085
|
init_ast();
|
|
3086
|
+
init_parseFnCall();
|
|
2899
3087
|
require_soft_assertions_default = {
|
|
2900
3088
|
create(context) {
|
|
2901
3089
|
return {
|
|
2902
3090
|
CallExpression(node) {
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
3091
|
+
const call = parseFnCall(context, node);
|
|
3092
|
+
if (call?.type !== "expect" || call.modifiers.some((m) => {
|
|
3093
|
+
const name = getStringValue(m);
|
|
3094
|
+
return name === "soft" || name === "poll";
|
|
3095
|
+
})) {
|
|
3096
|
+
return;
|
|
2909
3097
|
}
|
|
3098
|
+
context.report({
|
|
3099
|
+
fix: (fixer) => fixer.insertTextAfter(call.head.node, ".soft"),
|
|
3100
|
+
messageId: "requireSoft",
|
|
3101
|
+
node: call.head.node
|
|
3102
|
+
});
|
|
2910
3103
|
}
|
|
2911
3104
|
};
|
|
2912
3105
|
},
|
|
@@ -2927,13 +3120,54 @@ var init_require_soft_assertions = __esm({
|
|
|
2927
3120
|
}
|
|
2928
3121
|
});
|
|
2929
3122
|
|
|
3123
|
+
// src/rules/require-to-throw-message.ts
|
|
3124
|
+
var require_to_throw_message_default;
|
|
3125
|
+
var init_require_to_throw_message = __esm({
|
|
3126
|
+
"src/rules/require-to-throw-message.ts"() {
|
|
3127
|
+
"use strict";
|
|
3128
|
+
init_ast();
|
|
3129
|
+
init_parseFnCall();
|
|
3130
|
+
require_to_throw_message_default = {
|
|
3131
|
+
create(context) {
|
|
3132
|
+
return {
|
|
3133
|
+
CallExpression(node) {
|
|
3134
|
+
const call = parseFnCall(context, node);
|
|
3135
|
+
if (call?.type !== "expect")
|
|
3136
|
+
return;
|
|
3137
|
+
if (call.matcherArgs.length === 0 && ["toThrow", "toThrowError"].includes(call.matcherName) && !call.modifiers.some((nod) => getStringValue(nod) === "not")) {
|
|
3138
|
+
context.report({
|
|
3139
|
+
data: { matcherName: call.matcherName },
|
|
3140
|
+
messageId: "addErrorMessage",
|
|
3141
|
+
node: call.matcher
|
|
3142
|
+
});
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
};
|
|
3146
|
+
},
|
|
3147
|
+
meta: {
|
|
3148
|
+
docs: {
|
|
3149
|
+
category: "Best Practices",
|
|
3150
|
+
description: "Require a message for `toThrow()`",
|
|
3151
|
+
recommended: false,
|
|
3152
|
+
url: "https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/require-to-throw-message.md"
|
|
3153
|
+
},
|
|
3154
|
+
messages: {
|
|
3155
|
+
addErrorMessage: "Add an error message to {{ matcherName }}()"
|
|
3156
|
+
},
|
|
3157
|
+
schema: [],
|
|
3158
|
+
type: "suggestion"
|
|
3159
|
+
}
|
|
3160
|
+
};
|
|
3161
|
+
}
|
|
3162
|
+
});
|
|
3163
|
+
|
|
2930
3164
|
// src/rules/require-top-level-describe.ts
|
|
2931
3165
|
var require_top_level_describe_default;
|
|
2932
3166
|
var init_require_top_level_describe = __esm({
|
|
2933
3167
|
"src/rules/require-top-level-describe.ts"() {
|
|
2934
3168
|
"use strict";
|
|
2935
|
-
init_ast();
|
|
2936
3169
|
init_misc();
|
|
3170
|
+
init_parseFnCall();
|
|
2937
3171
|
require_top_level_describe_default = {
|
|
2938
3172
|
create(context) {
|
|
2939
3173
|
const { maxTopLevelDescribes } = {
|
|
@@ -2944,7 +3178,10 @@ var init_require_top_level_describe = __esm({
|
|
|
2944
3178
|
let describeCount = 0;
|
|
2945
3179
|
return {
|
|
2946
3180
|
CallExpression(node) {
|
|
2947
|
-
|
|
3181
|
+
const call = parseFnCall(context, node);
|
|
3182
|
+
if (!call)
|
|
3183
|
+
return;
|
|
3184
|
+
if (call.type === "describe") {
|
|
2948
3185
|
describeCount++;
|
|
2949
3186
|
if (describeCount === 1) {
|
|
2950
3187
|
topLevelDescribeCount++;
|
|
@@ -2957,15 +3194,15 @@ var init_require_top_level_describe = __esm({
|
|
|
2957
3194
|
}
|
|
2958
3195
|
}
|
|
2959
3196
|
} else if (!describeCount) {
|
|
2960
|
-
if (
|
|
3197
|
+
if (call.type === "test") {
|
|
2961
3198
|
context.report({ messageId: "unexpectedTest", node: node.callee });
|
|
2962
|
-
} else if (
|
|
3199
|
+
} else if (call.type === "hook") {
|
|
2963
3200
|
context.report({ messageId: "unexpectedHook", node: node.callee });
|
|
2964
3201
|
}
|
|
2965
3202
|
}
|
|
2966
3203
|
},
|
|
2967
3204
|
"CallExpression:exit"(node) {
|
|
2968
|
-
if (
|
|
3205
|
+
if (isTypeOfFnCall(context, node, ["describe"])) {
|
|
2969
3206
|
describeCount--;
|
|
2970
3207
|
}
|
|
2971
3208
|
}
|
|
@@ -3001,23 +3238,121 @@ var init_require_top_level_describe = __esm({
|
|
|
3001
3238
|
}
|
|
3002
3239
|
});
|
|
3003
3240
|
|
|
3004
|
-
// src/rules/valid-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3241
|
+
// src/rules/valid-describe-callback.ts
|
|
3242
|
+
var paramsLocation, valid_describe_callback_default;
|
|
3243
|
+
var init_valid_describe_callback = __esm({
|
|
3244
|
+
"src/rules/valid-describe-callback.ts"() {
|
|
3245
|
+
"use strict";
|
|
3246
|
+
init_ast();
|
|
3247
|
+
init_parseFnCall();
|
|
3248
|
+
paramsLocation = (params) => {
|
|
3249
|
+
const [first] = params;
|
|
3250
|
+
const last = params[params.length - 1];
|
|
3251
|
+
return {
|
|
3252
|
+
end: last.loc.end,
|
|
3253
|
+
start: first.loc.start
|
|
3254
|
+
};
|
|
3255
|
+
};
|
|
3256
|
+
valid_describe_callback_default = {
|
|
3257
|
+
create(context) {
|
|
3258
|
+
return {
|
|
3259
|
+
CallExpression(node) {
|
|
3260
|
+
const call = parseFnCall(context, node);
|
|
3261
|
+
if (call?.type !== "describe")
|
|
3262
|
+
return;
|
|
3263
|
+
if (node.arguments.length < 1) {
|
|
3264
|
+
return context.report({
|
|
3265
|
+
loc: node.loc,
|
|
3266
|
+
messageId: "nameAndCallback"
|
|
3267
|
+
});
|
|
3268
|
+
}
|
|
3269
|
+
const [, callback] = node.arguments;
|
|
3270
|
+
if (!callback) {
|
|
3271
|
+
context.report({
|
|
3272
|
+
loc: paramsLocation(node.arguments),
|
|
3273
|
+
messageId: "nameAndCallback"
|
|
3274
|
+
});
|
|
3275
|
+
return;
|
|
3276
|
+
}
|
|
3277
|
+
if (!isFunction(callback)) {
|
|
3278
|
+
context.report({
|
|
3279
|
+
loc: paramsLocation(node.arguments),
|
|
3280
|
+
messageId: "secondArgumentMustBeFunction"
|
|
3281
|
+
});
|
|
3282
|
+
return;
|
|
3283
|
+
}
|
|
3284
|
+
if (callback.async) {
|
|
3285
|
+
context.report({
|
|
3286
|
+
messageId: "noAsyncDescribeCallback",
|
|
3287
|
+
node: callback
|
|
3288
|
+
});
|
|
3289
|
+
}
|
|
3290
|
+
if (call.members.every((s) => getStringValue(s) !== "each") && callback.params.length) {
|
|
3291
|
+
context.report({
|
|
3292
|
+
loc: paramsLocation(callback.params),
|
|
3293
|
+
messageId: "unexpectedDescribeArgument"
|
|
3294
|
+
});
|
|
3295
|
+
}
|
|
3296
|
+
if (callback.body.type === "CallExpression") {
|
|
3297
|
+
context.report({
|
|
3298
|
+
messageId: "unexpectedReturnInDescribe",
|
|
3299
|
+
node: callback
|
|
3300
|
+
});
|
|
3301
|
+
}
|
|
3302
|
+
if (callback.body.type === "BlockStatement") {
|
|
3303
|
+
callback.body.body.forEach((node2) => {
|
|
3304
|
+
if (node2.type === "ReturnStatement") {
|
|
3305
|
+
context.report({
|
|
3306
|
+
messageId: "unexpectedReturnInDescribe",
|
|
3307
|
+
node: node2
|
|
3308
|
+
});
|
|
3309
|
+
}
|
|
3310
|
+
});
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
};
|
|
3314
|
+
},
|
|
3315
|
+
meta: {
|
|
3316
|
+
docs: {
|
|
3317
|
+
category: "Possible Errors",
|
|
3318
|
+
description: "Enforce valid `describe()` callback",
|
|
3319
|
+
recommended: true,
|
|
3320
|
+
url: "https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/valid-describe-callback.md"
|
|
3321
|
+
},
|
|
3322
|
+
messages: {
|
|
3323
|
+
nameAndCallback: "Describe requires name and callback arguments",
|
|
3324
|
+
noAsyncDescribeCallback: "No async describe callback",
|
|
3325
|
+
secondArgumentMustBeFunction: "Second argument must be function",
|
|
3326
|
+
unexpectedDescribeArgument: "Unexpected argument(s) in describe callback",
|
|
3327
|
+
unexpectedReturnInDescribe: "Unexpected return statement in describe callback"
|
|
3328
|
+
},
|
|
3329
|
+
schema: [],
|
|
3330
|
+
type: "problem"
|
|
3331
|
+
}
|
|
3010
3332
|
};
|
|
3011
3333
|
}
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3334
|
+
});
|
|
3335
|
+
|
|
3336
|
+
// src/rules/valid-expect.ts
|
|
3337
|
+
var findTopMostMemberExpression, valid_expect_default;
|
|
3015
3338
|
var init_valid_expect = __esm({
|
|
3016
3339
|
"src/rules/valid-expect.ts"() {
|
|
3017
3340
|
"use strict";
|
|
3018
3341
|
init_ast();
|
|
3019
3342
|
init_misc();
|
|
3020
|
-
|
|
3343
|
+
init_parseFnCall();
|
|
3344
|
+
findTopMostMemberExpression = (node) => {
|
|
3345
|
+
let topMostMemberExpression = node;
|
|
3346
|
+
let parent = getParent(node);
|
|
3347
|
+
while (parent) {
|
|
3348
|
+
if (parent.type !== "MemberExpression") {
|
|
3349
|
+
break;
|
|
3350
|
+
}
|
|
3351
|
+
topMostMemberExpression = parent;
|
|
3352
|
+
parent = parent.parent;
|
|
3353
|
+
}
|
|
3354
|
+
return topMostMemberExpression;
|
|
3355
|
+
};
|
|
3021
3356
|
valid_expect_default = {
|
|
3022
3357
|
create(context) {
|
|
3023
3358
|
const options = {
|
|
@@ -3029,32 +3364,70 @@ var init_valid_expect = __esm({
|
|
|
3029
3364
|
const maxArgs = Math.max(options.minArgs, options.maxArgs);
|
|
3030
3365
|
return {
|
|
3031
3366
|
CallExpression(node) {
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
context.report({ messageId: "matcherNotFound", node });
|
|
3037
|
-
} else {
|
|
3038
|
-
const result = isMatcherCalled(node);
|
|
3039
|
-
if (!result.called) {
|
|
3367
|
+
const call = parseFnCallWithReason(context, node);
|
|
3368
|
+
if (typeof call === "string") {
|
|
3369
|
+
const reportingNode = node.parent?.type === "MemberExpression" ? findTopMostMemberExpression(node.parent).property : node;
|
|
3370
|
+
if (call === "matcher-not-found") {
|
|
3040
3371
|
context.report({
|
|
3041
|
-
messageId: "
|
|
3042
|
-
node:
|
|
3372
|
+
messageId: "matcherNotFound",
|
|
3373
|
+
node: reportingNode
|
|
3043
3374
|
});
|
|
3375
|
+
return;
|
|
3044
3376
|
}
|
|
3377
|
+
if (call === "matcher-not-called") {
|
|
3378
|
+
context.report({
|
|
3379
|
+
messageId: isSupportedAccessor(reportingNode) && modifiers.has(getStringValue(reportingNode)) ? "matcherNotFound" : "matcherNotCalled",
|
|
3380
|
+
node: reportingNode
|
|
3381
|
+
});
|
|
3382
|
+
}
|
|
3383
|
+
if (call === "modifier-unknown") {
|
|
3384
|
+
context.report({
|
|
3385
|
+
messageId: "modifierUnknown",
|
|
3386
|
+
node: reportingNode
|
|
3387
|
+
});
|
|
3388
|
+
return;
|
|
3389
|
+
}
|
|
3390
|
+
return;
|
|
3391
|
+
} else if (call?.type !== "expect") {
|
|
3392
|
+
return;
|
|
3045
3393
|
}
|
|
3046
|
-
|
|
3394
|
+
const expect = findParent(call.head.node, "CallExpression");
|
|
3395
|
+
if (!expect)
|
|
3396
|
+
return;
|
|
3397
|
+
if (expect.arguments.length < minArgs) {
|
|
3398
|
+
const expectLength = getStringValue(call.head.node).length;
|
|
3399
|
+
const loc = {
|
|
3400
|
+
end: {
|
|
3401
|
+
column: expect.loc.start.column + expectLength + 1,
|
|
3402
|
+
line: expect.loc.start.line
|
|
3403
|
+
},
|
|
3404
|
+
start: {
|
|
3405
|
+
column: expect.loc.start.column + expectLength,
|
|
3406
|
+
line: expect.loc.start.line
|
|
3407
|
+
}
|
|
3408
|
+
};
|
|
3047
3409
|
context.report({
|
|
3048
3410
|
data: getAmountData(minArgs),
|
|
3411
|
+
loc,
|
|
3049
3412
|
messageId: "notEnoughArgs",
|
|
3050
|
-
node
|
|
3413
|
+
node: expect
|
|
3051
3414
|
});
|
|
3052
3415
|
}
|
|
3053
|
-
if (
|
|
3416
|
+
if (expect.arguments.length > maxArgs) {
|
|
3417
|
+
const { start } = expect.arguments[maxArgs].loc;
|
|
3418
|
+
const { end } = expect.arguments.at(-1).loc;
|
|
3419
|
+
const loc = {
|
|
3420
|
+
end: {
|
|
3421
|
+
column: end.column,
|
|
3422
|
+
line: end.line
|
|
3423
|
+
},
|
|
3424
|
+
start
|
|
3425
|
+
};
|
|
3054
3426
|
context.report({
|
|
3055
3427
|
data: getAmountData(maxArgs),
|
|
3428
|
+
loc,
|
|
3056
3429
|
messageId: "tooManyArgs",
|
|
3057
|
-
node
|
|
3430
|
+
node: expect
|
|
3058
3431
|
});
|
|
3059
3432
|
}
|
|
3060
3433
|
}
|
|
@@ -3095,12 +3468,265 @@ var init_valid_expect = __esm({
|
|
|
3095
3468
|
}
|
|
3096
3469
|
});
|
|
3097
3470
|
|
|
3471
|
+
// src/rules/valid-expect-in-promise.ts
|
|
3472
|
+
var isPromiseChainCall, isTestCaseCallWithCallbackArg, isPromiseMethodThatUsesValue, isValueAwaitedInElements, isValueAwaitedInArguments, getLeftMostCallExpression, isValueAwaitedOrReturned, findFirstBlockBodyUp, isDirectlyWithinTestCaseCall, isVariableAwaitedOrReturned, valid_expect_in_promise_default;
|
|
3473
|
+
var init_valid_expect_in_promise = __esm({
|
|
3474
|
+
"src/rules/valid-expect-in-promise.ts"() {
|
|
3475
|
+
"use strict";
|
|
3476
|
+
init_ast();
|
|
3477
|
+
init_parseFnCall();
|
|
3478
|
+
isPromiseChainCall = (node) => {
|
|
3479
|
+
if (node.type === "CallExpression" && node.callee.type === "MemberExpression" && isSupportedAccessor(node.callee.property)) {
|
|
3480
|
+
if (node.arguments.length === 0) {
|
|
3481
|
+
return false;
|
|
3482
|
+
}
|
|
3483
|
+
switch (getStringValue(node.callee.property)) {
|
|
3484
|
+
case "then":
|
|
3485
|
+
return node.arguments.length < 3;
|
|
3486
|
+
case "catch":
|
|
3487
|
+
case "finally":
|
|
3488
|
+
return node.arguments.length < 2;
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
return false;
|
|
3492
|
+
};
|
|
3493
|
+
isTestCaseCallWithCallbackArg = (context, node) => {
|
|
3494
|
+
const jestCallFn = parseFnCall(context, node);
|
|
3495
|
+
if (jestCallFn?.type !== "test") {
|
|
3496
|
+
return false;
|
|
3497
|
+
}
|
|
3498
|
+
const isJestEach = jestCallFn.members.some(
|
|
3499
|
+
(s) => getStringValue(s) === "each"
|
|
3500
|
+
);
|
|
3501
|
+
if (isJestEach && node.callee.type !== "TaggedTemplateExpression") {
|
|
3502
|
+
return true;
|
|
3503
|
+
}
|
|
3504
|
+
const [, callback] = node.arguments;
|
|
3505
|
+
const callbackArgIndex = Number(isJestEach);
|
|
3506
|
+
return callback && isFunction(callback) && callback.params.length === 1 + callbackArgIndex;
|
|
3507
|
+
};
|
|
3508
|
+
isPromiseMethodThatUsesValue = (node, identifier) => {
|
|
3509
|
+
const name = getStringValue(identifier);
|
|
3510
|
+
if (node.argument == null)
|
|
3511
|
+
return false;
|
|
3512
|
+
if (node.argument.type === "CallExpression" && node.argument.arguments.length > 0) {
|
|
3513
|
+
const nodeName = getNodeName(node.argument);
|
|
3514
|
+
if (["Promise.all", "Promise.allSettled"].includes(nodeName)) {
|
|
3515
|
+
const [firstArg] = node.argument.arguments;
|
|
3516
|
+
if (firstArg.type === "ArrayExpression" && firstArg.elements.some((nod) => nod && isIdentifier(nod, name))) {
|
|
3517
|
+
return true;
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3520
|
+
if (["Promise.resolve", "Promise.reject"].includes(nodeName) && node.argument.arguments.length === 1) {
|
|
3521
|
+
return isIdentifier(node.argument.arguments[0], name);
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
return isIdentifier(node.argument, name);
|
|
3525
|
+
};
|
|
3526
|
+
isValueAwaitedInElements = (name, elements) => {
|
|
3527
|
+
for (const element of elements) {
|
|
3528
|
+
if (element?.type === "AwaitExpression" && isIdentifier(element.argument, name)) {
|
|
3529
|
+
return true;
|
|
3530
|
+
}
|
|
3531
|
+
if (element?.type === "ArrayExpression" && isValueAwaitedInElements(name, element.elements)) {
|
|
3532
|
+
return true;
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
return false;
|
|
3536
|
+
};
|
|
3537
|
+
isValueAwaitedInArguments = (name, call) => {
|
|
3538
|
+
let node = call;
|
|
3539
|
+
while (node) {
|
|
3540
|
+
if (node.type === "CallExpression") {
|
|
3541
|
+
if (isValueAwaitedInElements(name, node.arguments)) {
|
|
3542
|
+
return true;
|
|
3543
|
+
}
|
|
3544
|
+
node = node.callee;
|
|
3545
|
+
}
|
|
3546
|
+
if (node.type !== "MemberExpression") {
|
|
3547
|
+
break;
|
|
3548
|
+
}
|
|
3549
|
+
node = node.object;
|
|
3550
|
+
}
|
|
3551
|
+
return false;
|
|
3552
|
+
};
|
|
3553
|
+
getLeftMostCallExpression = (call) => {
|
|
3554
|
+
let leftMostCallExpression = call;
|
|
3555
|
+
let node = call;
|
|
3556
|
+
while (node) {
|
|
3557
|
+
if (node.type === "CallExpression") {
|
|
3558
|
+
leftMostCallExpression = node;
|
|
3559
|
+
node = node.callee;
|
|
3560
|
+
}
|
|
3561
|
+
if (node.type !== "MemberExpression") {
|
|
3562
|
+
break;
|
|
3563
|
+
}
|
|
3564
|
+
node = node.object;
|
|
3565
|
+
}
|
|
3566
|
+
return leftMostCallExpression;
|
|
3567
|
+
};
|
|
3568
|
+
isValueAwaitedOrReturned = (context, identifier, body) => {
|
|
3569
|
+
const name = getStringValue(identifier);
|
|
3570
|
+
for (const node of body) {
|
|
3571
|
+
if (node.range[0] <= identifier.range[0]) {
|
|
3572
|
+
continue;
|
|
3573
|
+
}
|
|
3574
|
+
if (node.type === "ReturnStatement") {
|
|
3575
|
+
return isPromiseMethodThatUsesValue(node, identifier);
|
|
3576
|
+
}
|
|
3577
|
+
if (node.type === "ExpressionStatement") {
|
|
3578
|
+
if (node.expression.type === "CallExpression") {
|
|
3579
|
+
if (isValueAwaitedInArguments(name, node.expression)) {
|
|
3580
|
+
return true;
|
|
3581
|
+
}
|
|
3582
|
+
const leftMostCall = getLeftMostCallExpression(node.expression);
|
|
3583
|
+
const call = parseFnCall(context, node.expression);
|
|
3584
|
+
if (call?.type === "expect" && leftMostCall.arguments.length > 0 && isIdentifier(leftMostCall.arguments[0], name)) {
|
|
3585
|
+
if (call.members.some((m) => {
|
|
3586
|
+
const v = getStringValue(m);
|
|
3587
|
+
return v === "resolves" || v === "rejects";
|
|
3588
|
+
})) {
|
|
3589
|
+
return true;
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
if (node.expression.type === "AwaitExpression" && isPromiseMethodThatUsesValue(node.expression, identifier)) {
|
|
3594
|
+
return true;
|
|
3595
|
+
}
|
|
3596
|
+
if (node.expression.type === "AssignmentExpression") {
|
|
3597
|
+
if (isIdentifier(node.expression.left, name) && getNodeName(node.expression.right)?.startsWith(`${name}.`) && isPromiseChainCall(node.expression.right)) {
|
|
3598
|
+
continue;
|
|
3599
|
+
}
|
|
3600
|
+
break;
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
if (node.type === "BlockStatement" && isValueAwaitedOrReturned(context, identifier, node.body)) {
|
|
3604
|
+
return true;
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
return false;
|
|
3608
|
+
};
|
|
3609
|
+
findFirstBlockBodyUp = (node) => {
|
|
3610
|
+
let parent = node;
|
|
3611
|
+
while (parent) {
|
|
3612
|
+
if (parent.type === "BlockStatement") {
|
|
3613
|
+
return parent.body;
|
|
3614
|
+
}
|
|
3615
|
+
parent = getParent(parent);
|
|
3616
|
+
}
|
|
3617
|
+
throw new Error(
|
|
3618
|
+
`Could not find BlockStatement - please file a github issue at https://github.com/playwright-community/eslint-plugin-playwright`
|
|
3619
|
+
);
|
|
3620
|
+
};
|
|
3621
|
+
isDirectlyWithinTestCaseCall = (context, node) => {
|
|
3622
|
+
let parent = node;
|
|
3623
|
+
while (parent) {
|
|
3624
|
+
if (isFunction(parent)) {
|
|
3625
|
+
parent = parent.parent;
|
|
3626
|
+
return parent?.type === "CallExpression" && isTypeOfFnCall(context, parent, ["test"]);
|
|
3627
|
+
}
|
|
3628
|
+
parent = getParent(parent);
|
|
3629
|
+
}
|
|
3630
|
+
return false;
|
|
3631
|
+
};
|
|
3632
|
+
isVariableAwaitedOrReturned = (context, variable) => {
|
|
3633
|
+
const body = findFirstBlockBodyUp(variable);
|
|
3634
|
+
if (!isIdentifier(variable.id)) {
|
|
3635
|
+
return true;
|
|
3636
|
+
}
|
|
3637
|
+
return isValueAwaitedOrReturned(context, variable.id, body);
|
|
3638
|
+
};
|
|
3639
|
+
valid_expect_in_promise_default = {
|
|
3640
|
+
create(context) {
|
|
3641
|
+
let inTestCaseWithDoneCallback = false;
|
|
3642
|
+
const chains = [];
|
|
3643
|
+
return {
|
|
3644
|
+
CallExpression(node) {
|
|
3645
|
+
if (isTestCaseCallWithCallbackArg(context, node)) {
|
|
3646
|
+
inTestCaseWithDoneCallback = true;
|
|
3647
|
+
return;
|
|
3648
|
+
}
|
|
3649
|
+
if (isPromiseChainCall(node)) {
|
|
3650
|
+
chains.unshift(false);
|
|
3651
|
+
return;
|
|
3652
|
+
}
|
|
3653
|
+
if (chains.length > 0 && isTypeOfFnCall(context, node, ["expect"])) {
|
|
3654
|
+
chains[0] = true;
|
|
3655
|
+
}
|
|
3656
|
+
},
|
|
3657
|
+
"CallExpression:exit"(node) {
|
|
3658
|
+
if (inTestCaseWithDoneCallback) {
|
|
3659
|
+
if (isTypeOfFnCall(context, node, ["test"])) {
|
|
3660
|
+
inTestCaseWithDoneCallback = false;
|
|
3661
|
+
}
|
|
3662
|
+
return;
|
|
3663
|
+
}
|
|
3664
|
+
if (!isPromiseChainCall(node)) {
|
|
3665
|
+
return;
|
|
3666
|
+
}
|
|
3667
|
+
const hasExpectCall = chains.shift();
|
|
3668
|
+
if (!hasExpectCall) {
|
|
3669
|
+
return;
|
|
3670
|
+
}
|
|
3671
|
+
const { parent } = findTopMostCallExpression(node);
|
|
3672
|
+
if (!parent || !isDirectlyWithinTestCaseCall(context, parent)) {
|
|
3673
|
+
return;
|
|
3674
|
+
}
|
|
3675
|
+
switch (parent.type) {
|
|
3676
|
+
case "VariableDeclarator": {
|
|
3677
|
+
if (isVariableAwaitedOrReturned(context, parent)) {
|
|
3678
|
+
return;
|
|
3679
|
+
}
|
|
3680
|
+
break;
|
|
3681
|
+
}
|
|
3682
|
+
case "AssignmentExpression": {
|
|
3683
|
+
if (parent.left.type === "Identifier" && isValueAwaitedOrReturned(
|
|
3684
|
+
context,
|
|
3685
|
+
parent.left,
|
|
3686
|
+
findFirstBlockBodyUp(parent)
|
|
3687
|
+
)) {
|
|
3688
|
+
return;
|
|
3689
|
+
}
|
|
3690
|
+
break;
|
|
3691
|
+
}
|
|
3692
|
+
case "ExpressionStatement":
|
|
3693
|
+
break;
|
|
3694
|
+
case "ReturnStatement":
|
|
3695
|
+
case "AwaitExpression":
|
|
3696
|
+
default:
|
|
3697
|
+
return;
|
|
3698
|
+
}
|
|
3699
|
+
context.report({
|
|
3700
|
+
messageId: "expectInFloatingPromise",
|
|
3701
|
+
node: parent
|
|
3702
|
+
});
|
|
3703
|
+
}
|
|
3704
|
+
};
|
|
3705
|
+
},
|
|
3706
|
+
meta: {
|
|
3707
|
+
docs: {
|
|
3708
|
+
category: "Best Practices",
|
|
3709
|
+
description: "Require promises that have expectations in their chain to be valid",
|
|
3710
|
+
recommended: true,
|
|
3711
|
+
url: "https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/valid-expect-in-promise.md"
|
|
3712
|
+
},
|
|
3713
|
+
messages: {
|
|
3714
|
+
expectInFloatingPromise: "This promise should either be returned or awaited to ensure the expects in its chain are called"
|
|
3715
|
+
},
|
|
3716
|
+
schema: [],
|
|
3717
|
+
type: "suggestion"
|
|
3718
|
+
}
|
|
3719
|
+
};
|
|
3720
|
+
}
|
|
3721
|
+
});
|
|
3722
|
+
|
|
3098
3723
|
// src/rules/valid-title.ts
|
|
3099
3724
|
var doesBinaryExpressionContainStringNode, quoteStringValue, compileMatcherPattern, compileMatcherPatterns, MatcherAndMessageSchema, valid_title_default;
|
|
3100
3725
|
var init_valid_title = __esm({
|
|
3101
3726
|
"src/rules/valid-title.ts"() {
|
|
3102
3727
|
"use strict";
|
|
3103
3728
|
init_ast();
|
|
3729
|
+
init_parseFnCall();
|
|
3104
3730
|
doesBinaryExpressionContainStringNode = (binaryExp) => {
|
|
3105
3731
|
if (isStringNode(binaryExp.right)) {
|
|
3106
3732
|
return true;
|
|
@@ -3154,9 +3780,8 @@ var init_valid_title = __esm({
|
|
|
3154
3780
|
const mustMatchPatterns = compileMatcherPatterns(mustMatch ?? {});
|
|
3155
3781
|
return {
|
|
3156
3782
|
CallExpression(node) {
|
|
3157
|
-
const
|
|
3158
|
-
|
|
3159
|
-
if (!isDescribe && !isTest) {
|
|
3783
|
+
const call = parseFnCall(context, node);
|
|
3784
|
+
if (call?.type !== "test" && call?.type !== "describe") {
|
|
3160
3785
|
return;
|
|
3161
3786
|
}
|
|
3162
3787
|
const [argument] = node.arguments;
|
|
@@ -3167,7 +3792,7 @@ var init_valid_title = __esm({
|
|
|
3167
3792
|
if (argument.type === "BinaryExpression" && doesBinaryExpressionContainStringNode(argument)) {
|
|
3168
3793
|
return;
|
|
3169
3794
|
}
|
|
3170
|
-
if (!(
|
|
3795
|
+
if (!(call.type === "describe" && ignoreTypeOfDescribeName || call.type === "test" && ignoreTypeOfTestName) && argument.type !== "TemplateLiteral") {
|
|
3171
3796
|
context.report({
|
|
3172
3797
|
loc: argument.loc,
|
|
3173
3798
|
messageId: "titleMustBeString"
|
|
@@ -3176,10 +3801,10 @@ var init_valid_title = __esm({
|
|
|
3176
3801
|
return;
|
|
3177
3802
|
}
|
|
3178
3803
|
const title = getStringValue(argument);
|
|
3179
|
-
const functionName =
|
|
3804
|
+
const functionName = call.type;
|
|
3180
3805
|
if (!title) {
|
|
3181
3806
|
context.report({
|
|
3182
|
-
data: { functionName },
|
|
3807
|
+
data: { functionName: call.type },
|
|
3183
3808
|
messageId: "emptyTitle",
|
|
3184
3809
|
node
|
|
3185
3810
|
});
|
|
@@ -3358,8 +3983,11 @@ var require_src = __commonJS({
|
|
|
3358
3983
|
init_prefer_web_first_assertions();
|
|
3359
3984
|
init_require_hook();
|
|
3360
3985
|
init_require_soft_assertions();
|
|
3986
|
+
init_require_to_throw_message();
|
|
3361
3987
|
init_require_top_level_describe();
|
|
3988
|
+
init_valid_describe_callback();
|
|
3362
3989
|
init_valid_expect();
|
|
3990
|
+
init_valid_expect_in_promise();
|
|
3363
3991
|
init_valid_title();
|
|
3364
3992
|
var index = {
|
|
3365
3993
|
configs: {},
|
|
@@ -3404,8 +4032,11 @@ var require_src = __commonJS({
|
|
|
3404
4032
|
"prefer-web-first-assertions": prefer_web_first_assertions_default,
|
|
3405
4033
|
"require-hook": require_hook_default,
|
|
3406
4034
|
"require-soft-assertions": require_soft_assertions_default,
|
|
4035
|
+
"require-to-throw-message": require_to_throw_message_default,
|
|
3407
4036
|
"require-top-level-describe": require_top_level_describe_default,
|
|
4037
|
+
"valid-describe-callback": valid_describe_callback_default,
|
|
3408
4038
|
"valid-expect": valid_expect_default,
|
|
4039
|
+
"valid-expect-in-promise": valid_expect_in_promise_default,
|
|
3409
4040
|
"valid-title": valid_title_default
|
|
3410
4041
|
}
|
|
3411
4042
|
};
|
|
@@ -3432,7 +4063,9 @@ var require_src = __commonJS({
|
|
|
3432
4063
|
"playwright/no-wait-for-selector": "warn",
|
|
3433
4064
|
"playwright/no-wait-for-timeout": "warn",
|
|
3434
4065
|
"playwright/prefer-web-first-assertions": "error",
|
|
4066
|
+
"playwright/valid-describe-callback": "error",
|
|
3435
4067
|
"playwright/valid-expect": "error",
|
|
4068
|
+
"playwright/valid-expect-in-promise": "error",
|
|
3436
4069
|
"playwright/valid-title": "error"
|
|
3437
4070
|
}
|
|
3438
4071
|
};
|