@checkdigit/eslint-plugin 7.6.0-PR.75-4751 → 7.6.0-PR.75-a611

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.
@@ -1,517 +0,0 @@
1
- // agent/no-supertest.ts
2
-
3
- /*
4
- * Copyright (c) 2021-2024 Check Digit, LLC
5
- *
6
- * This code is licensed under the MIT license (see LICENSE.txt for details).
7
- */
8
-
9
- import { strict as assert } from 'node:assert';
10
-
11
- import { AST_NODE_TYPES, ESLintUtils, TSESTree } from '@typescript-eslint/utils';
12
- import type { Scope, ScopeManager, Variable } from '@typescript-eslint/scope-manager';
13
- import type { SourceCode } from '@typescript-eslint/utils/ts-eslint';
14
-
15
- import {
16
- getEnclosingFunction,
17
- getEnclosingScopeNode,
18
- getEnclosingStatement,
19
- getParent,
20
- isUsedInArrayOrAsArgument,
21
- } from '../library/ts-tree';
22
- import getDocumentationUrl from '../get-documentation-url';
23
- import { getIndentation } from '../library/format';
24
- import { analyzeResponseReferences } from './response-reference';
25
- import { getResponseBodyRetrievalText, getResponseHeadersRetrievalText, getResponseStatusRetrievalText } from './fetch';
26
-
27
- export const ruleId = 'no-supertest';
28
-
29
- interface FixtureCallInformation {
30
- rootNode:
31
- | TSESTree.AwaitExpression
32
- | TSESTree.ReturnStatement
33
- | TSESTree.VariableDeclaration
34
- | TSESTree.CallExpression
35
- | TSESTree.ExpressionStatement;
36
- fixtureNode: TSESTree.AwaitExpression | TSESTree.CallExpression;
37
- variableDeclaration?: TSESTree.VariableDeclaration;
38
- variableAssignment?: TSESTree.ExpressionStatement;
39
- assertions?: TSESTree.Expression[][];
40
- inlineStatementNode?: TSESTree.Node;
41
- inlineBodyReference?: TSESTree.MemberExpression;
42
- inlineStatusReference?: TSESTree.MemberExpression;
43
- inlineHeadersReference?: TSESTree.MemberExpression;
44
- }
45
-
46
- // recursively analyze the fixture/supertest call chain to collect information of request/response
47
- // eslint-disable-next-line sonarjs/cognitive-complexity
48
- function analyzeFixtureCall(call: TSESTree.CallExpression, results: FixtureCallInformation, sourceCode: SourceCode) {
49
- const parent = getParent(call);
50
- assert.ok(parent, 'parent should exist for fixture/supertest call node');
51
-
52
- let nextCall;
53
- if (parent.type === AST_NODE_TYPES.ReturnStatement) {
54
- // direct return, no variable declaration or await
55
- results.fixtureNode = call;
56
- results.rootNode = parent;
57
- } else if (
58
- parent.type === AST_NODE_TYPES.ArrayExpression ||
59
- parent.type === AST_NODE_TYPES.CallExpression ||
60
- parent.type === AST_NODE_TYPES.ArrowFunctionExpression
61
- ) {
62
- // direct return, no variable declaration or await
63
- results.fixtureNode = call;
64
- results.rootNode = call;
65
- } else if (parent.type === AST_NODE_TYPES.AwaitExpression) {
66
- results.fixtureNode = call;
67
- const enclosingStatement = getEnclosingStatement(parent);
68
- assert.ok(enclosingStatement);
69
- const awaitParent = getParent(parent);
70
- if (awaitParent?.type === AST_NODE_TYPES.MemberExpression) {
71
- results.rootNode = parent;
72
- results.inlineStatementNode = enclosingStatement;
73
- if (awaitParent.property.type === AST_NODE_TYPES.Identifier && awaitParent.property.name === 'body') {
74
- results.inlineBodyReference = awaitParent;
75
- }
76
- if (
77
- awaitParent.property.type === AST_NODE_TYPES.Identifier &&
78
- (awaitParent.property.name === 'status' || awaitParent.property.name === 'statusCode')
79
- ) {
80
- results.inlineStatusReference = awaitParent;
81
- }
82
- if (
83
- awaitParent.property.type === AST_NODE_TYPES.Identifier &&
84
- (awaitParent.property.name === 'header' || awaitParent.property.name === 'headers')
85
- ) {
86
- results.inlineHeadersReference = awaitParent;
87
- }
88
- } else if (enclosingStatement.type === AST_NODE_TYPES.VariableDeclaration) {
89
- results.variableDeclaration = enclosingStatement;
90
- results.rootNode = enclosingStatement;
91
- } else if (
92
- enclosingStatement.type === AST_NODE_TYPES.ExpressionStatement &&
93
- enclosingStatement.expression.type === AST_NODE_TYPES.AssignmentExpression
94
- ) {
95
- results.variableAssignment = enclosingStatement;
96
- results.rootNode = enclosingStatement;
97
- } else {
98
- results.rootNode = parent;
99
- }
100
- } else if (parent.type === AST_NODE_TYPES.MemberExpression && parent.property.type === AST_NODE_TYPES.Identifier) {
101
- if (parent.property.name === 'expect') {
102
- // supertest assertions
103
- const assertionCall = getParent(parent);
104
- assert.ok(assertionCall && assertionCall.type === AST_NODE_TYPES.CallExpression);
105
- results.assertions = [...(results.assertions ?? []), assertionCall.arguments as TSESTree.Expression[]];
106
- nextCall = assertionCall;
107
- }
108
- } else {
109
- throw new Error(`Unexpected expression in fixture/supertest call ${sourceCode.getText(parent)}.`);
110
- }
111
- if (nextCall) {
112
- analyzeFixtureCall(nextCall, results, sourceCode);
113
- }
114
- }
115
-
116
- // eslint-disable-next-line sonarjs/cognitive-complexity
117
- function createResponseAssertions(
118
- fixtureCallInformation: FixtureCallInformation,
119
- sourceCode: SourceCode,
120
- responseVariableName: string,
121
- destructuringResponseHeadersVariable: Variable | undefined,
122
- ) {
123
- let statusAssertion: string | undefined;
124
- const nonStatusAssertions: string[] = [];
125
- for (const expectArguments of fixtureCallInformation.assertions ?? []) {
126
- if (expectArguments.length === 1) {
127
- const [assertionArgument] = expectArguments;
128
- assert.ok(assertionArgument);
129
- if (
130
- (assertionArgument.type === AST_NODE_TYPES.MemberExpression &&
131
- assertionArgument.object.type === AST_NODE_TYPES.Identifier &&
132
- assertionArgument.object.name === 'StatusCodes') ||
133
- assertionArgument.type === AST_NODE_TYPES.Literal ||
134
- sourceCode.getText(assertionArgument).includes('StatusCodes.')
135
- ) {
136
- // status code assertion
137
- statusAssertion = `assert.equal(${responseVariableName}.status, ${sourceCode.getText(assertionArgument)})`;
138
- } else if (assertionArgument.type === AST_NODE_TYPES.ArrowFunctionExpression) {
139
- // callback assertion using arrow function
140
- let functionBody = sourceCode.getText(assertionArgument.body);
141
-
142
- const [originalResponseArgument] = assertionArgument.params;
143
- assert.ok(originalResponseArgument?.type === AST_NODE_TYPES.Identifier);
144
- const originalResponseArgumentName = originalResponseArgument.name;
145
- if (originalResponseArgumentName !== responseVariableName) {
146
- functionBody = functionBody.replace(
147
- new RegExp(`\\b${originalResponseArgumentName}\\b`, 'ug'),
148
- responseVariableName,
149
- );
150
- }
151
- nonStatusAssertions.push(`assert.doesNotThrow(()=>${functionBody})`);
152
- } else if (assertionArgument.type === AST_NODE_TYPES.Identifier) {
153
- // callback assertion using function reference
154
- nonStatusAssertions.push(
155
- `assert.doesNotThrow(()=>${sourceCode.getText(assertionArgument)}(${responseVariableName}))`,
156
- );
157
- } else if (
158
- assertionArgument.type === AST_NODE_TYPES.ObjectExpression ||
159
- assertionArgument.type === AST_NODE_TYPES.CallExpression
160
- ) {
161
- // body deep equal assertion
162
- nonStatusAssertions.push(
163
- `assert.deepEqual(await ${responseVariableName}.json(), ${sourceCode.getText(assertionArgument)})`,
164
- );
165
- } else {
166
- throw new Error(`Unexpected Supertest assertion argument: ".expect(${sourceCode.getText(assertionArgument)})`);
167
- }
168
- } else if (expectArguments.length === 2) {
169
- // header assertion
170
- const [headerName, headerValue] = expectArguments;
171
- assert.ok(headerName && headerValue);
172
- const headersReference =
173
- destructuringResponseHeadersVariable !== undefined
174
- ? destructuringResponseHeadersVariable.name
175
- : `${responseVariableName}.headers`;
176
- if (headerValue.type === AST_NODE_TYPES.Literal && headerValue.value instanceof RegExp) {
177
- nonStatusAssertions.push(
178
- `assert.ok(${headersReference}.get(${sourceCode.getText(headerName)}).match(${sourceCode.getText(headerValue)}))`,
179
- );
180
- } else {
181
- nonStatusAssertions.push(
182
- `assert.equal(${headersReference}.get(${sourceCode.getText(headerName)}), ${sourceCode.getText(headerValue)})`,
183
- );
184
- }
185
- }
186
- }
187
- return {
188
- statusAssertion,
189
- nonStatusAssertions,
190
- };
191
- }
192
-
193
- function getResponseVariableNameToUse(
194
- supertestFunctionName: string,
195
- scopeManager: ScopeManager,
196
- fixtureCallInformation: FixtureCallInformation,
197
- scopeVariablesMap: Map<Scope, string[]>,
198
- ) {
199
- if (fixtureCallInformation.variableAssignment) {
200
- assert.ok(
201
- fixtureCallInformation.variableAssignment.expression.type === AST_NODE_TYPES.AssignmentExpression &&
202
- fixtureCallInformation.variableAssignment.expression.left.type === AST_NODE_TYPES.Identifier,
203
- );
204
- return fixtureCallInformation.variableAssignment.expression.left.name;
205
- }
206
-
207
- if (fixtureCallInformation.variableDeclaration) {
208
- const firstDeclaration = fixtureCallInformation.variableDeclaration.declarations[0];
209
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
210
- if (firstDeclaration !== undefined && firstDeclaration.id.type === AST_NODE_TYPES.Identifier) {
211
- return firstDeclaration.id.name;
212
- }
213
- }
214
-
215
- const enclosingScopeNode = getEnclosingScopeNode(fixtureCallInformation.rootNode);
216
- scopeManager.getDeclaredVariables(fixtureCallInformation.rootNode);
217
- assert.ok(enclosingScopeNode);
218
- const scope = scopeManager.acquire(enclosingScopeNode);
219
- assert.ok(scope !== null);
220
- let scopeVariables = scopeVariablesMap.get(scope);
221
- if (!scopeVariables) {
222
- scopeVariables = [...scope.set.keys()];
223
- scopeVariablesMap.set(scope, scopeVariables);
224
- }
225
-
226
- let responseVariableCounter = 0;
227
- let responseVariableNameToUse;
228
- while (responseVariableNameToUse === undefined) {
229
- responseVariableNameToUse = `${supertestFunctionName}Response${responseVariableCounter === 0 ? '' : responseVariableCounter.toString()}`;
230
- if (scopeVariables.includes(responseVariableNameToUse)) {
231
- responseVariableNameToUse = undefined;
232
- }
233
- responseVariableCounter++;
234
- }
235
- scopeVariables.push(responseVariableNameToUse);
236
- return responseVariableNameToUse;
237
- }
238
-
239
- function isResponseBodyRedefinition(responseBodyReference: TSESTree.MemberExpression): boolean {
240
- const parent = getParent(responseBodyReference);
241
- return parent?.type === AST_NODE_TYPES.VariableDeclarator && parent.id.type === AST_NODE_TYPES.Identifier;
242
- }
243
-
244
- const createRule = ESLintUtils.RuleCreator((name) => getDocumentationUrl(name));
245
-
246
- const rule: ESLintUtils.RuleModule<'unknownError' | 'preferNativeFetch'> = createRule({
247
- name: ruleId,
248
- meta: {
249
- type: 'suggestion',
250
- docs: {
251
- description: 'Transform supertest assersions to regular node assertions.',
252
- url: getDocumentationUrl(ruleId),
253
- },
254
- messages: {
255
- preferNativeFetch: 'Transform supertest assersions to regular node assertions.',
256
- unknownError: 'Unknown error occurred in file "{{fileName}}": {{ error }}.',
257
- },
258
- fixable: 'code',
259
- schema: [],
260
- },
261
- defaultOptions: [],
262
- // eslint-disable-next-line max-lines-per-function
263
- create(context) {
264
- const sourceCode = context.sourceCode;
265
- const scopeManager = sourceCode.scopeManager;
266
- assert.ok(scopeManager !== null);
267
- const scopeVariablesMap = new Map<Scope, string[]>();
268
-
269
- return {
270
- // eslint-disable-next-line max-lines-per-function
271
- 'CallExpression[callee.property.name="expect"]': (
272
- supertestCall: TSESTree.CallExpression,
273
- // eslint-disable-next-line sonarjs/cognitive-complexity
274
- ) => {
275
- try {
276
- assert.ok(supertestCall.callee.type === AST_NODE_TYPES.MemberExpression);
277
- if (
278
- supertestCall.callee.object.type !== AST_NODE_TYPES.CallExpression ||
279
- (supertestCall.callee.object.callee.type === AST_NODE_TYPES.MemberExpression &&
280
- supertestCall.callee.object.callee.property.type === AST_NODE_TYPES.Identifier &&
281
- supertestCall.callee.object.callee.property.name === 'expect')
282
- ) {
283
- // skip nested expect call chain, only focus on the first expect call
284
- return;
285
- }
286
- if (
287
- supertestCall.callee.object.callee.type === AST_NODE_TYPES.MemberExpression &&
288
- supertestCall.callee.object.callee.object.type === AST_NODE_TYPES.MemberExpression &&
289
- supertestCall.callee.object.callee.object.object.type === AST_NODE_TYPES.Identifier &&
290
- supertestCall.callee.object.callee.object.object.name === 'fixture' &&
291
- supertestCall.callee.object.callee.object.property.type === AST_NODE_TYPES.Identifier &&
292
- supertestCall.callee.object.callee.object.property.name === 'api'
293
- ) {
294
- // skip nested expect calls, only focus on the top level
295
- return;
296
- }
297
-
298
- const fullSupertestFunctionName = sourceCode.getText(supertestCall.callee.object.callee);
299
- const supertestFunctionName = fullSupertestFunctionName.split('.').pop();
300
- assert.ok(supertestFunctionName !== undefined);
301
-
302
- if (isUsedInArrayOrAsArgument(supertestCall) || getEnclosingFunction(supertestCall)?.async === false) {
303
- // skip and leave it to "fetch-then" rule to handle it because no "await" can be used here
304
- return;
305
- }
306
-
307
- const indentation = getIndentation(supertestCall, sourceCode);
308
-
309
- const fixtureCallInformation = {} as FixtureCallInformation;
310
- const fixtureFunction = supertestCall.callee.object;
311
- analyzeFixtureCall(fixtureFunction, fixtureCallInformation, sourceCode);
312
- fixtureCallInformation.assertions?.flat().map((ass) => sourceCode.getText(ass));
313
-
314
- const {
315
- variable: responseVariable,
316
- bodyReferences: responseBodyReferences,
317
- // headersReferences: responseHeadersReferences,
318
- statusReferences: responseStatusReferences,
319
- destructuringBodyVariable: destructuringResponseBodyVariable,
320
- destructuringHeadersVariable: destructuringResponseHeadersVariable,
321
- destructuringStatusVariable: destructuringResponseStatusVariable,
322
- } = analyzeResponseReferences(fixtureCallInformation.variableDeclaration, scopeManager);
323
-
324
- const responseVariableNameToUse = getResponseVariableNameToUse(
325
- supertestFunctionName,
326
- scopeManager,
327
- fixtureCallInformation,
328
- scopeVariablesMap,
329
- );
330
-
331
- const isResponseBodyVariableRedefinitionNeeded =
332
- destructuringResponseBodyVariable !== undefined ||
333
- fixtureCallInformation.inlineBodyReference !== undefined ||
334
- (responseBodyReferences.length > 0 && !responseBodyReferences.some(isResponseBodyRedefinition));
335
- const redefineResponseBodyVariableName = `${responseVariableNameToUse}Body`;
336
-
337
- const isResponseStatusVariableRedefinitionNeeded =
338
- destructuringResponseStatusVariable !== undefined ||
339
- fixtureCallInformation.inlineStatusReference !== undefined;
340
- const redefineResponseStatusVariableName = `${responseVariableNameToUse}Status`;
341
-
342
- const isResponseHeadersVariableRedefinitionNeeded =
343
- (destructuringResponseHeadersVariable !== undefined &&
344
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
345
- (destructuringResponseHeadersVariable as TSESTree.ObjectPattern).type === AST_NODE_TYPES.ObjectPattern) ||
346
- fixtureCallInformation.inlineHeadersReference !== undefined;
347
- const redefineResponseHeadersVariableName = `${responseVariableNameToUse}Headers`;
348
-
349
- const isResponseVariableRedefinitionNeeded =
350
- (fixtureCallInformation.variableAssignment === undefined &&
351
- responseVariable === undefined &&
352
- fixtureCallInformation.assertions !== undefined) ||
353
- isResponseBodyVariableRedefinitionNeeded ||
354
- isResponseStatusVariableRedefinitionNeeded ||
355
- isResponseHeadersVariableRedefinitionNeeded;
356
-
357
- const responseBodyHeadersVariableRedefineLines = isResponseVariableRedefinitionNeeded
358
- ? [
359
- // eslint-disable-next-line no-nested-ternary
360
- ...(destructuringResponseBodyVariable
361
- ? [
362
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
363
- `${fixtureCallInformation.variableDeclaration?.kind ?? 'const'} ${(destructuringResponseBodyVariable as TSESTree.ObjectPattern).type === AST_NODE_TYPES.ObjectPattern ? sourceCode.getText(destructuringResponseBodyVariable as TSESTree.ObjectPattern) : (destructuringResponseBodyVariable as Variable).name} = ${getResponseBodyRetrievalText(responseVariableNameToUse)}`,
364
- ]
365
- : isResponseBodyVariableRedefinitionNeeded
366
- ? [
367
- `const ${redefineResponseBodyVariableName} = ${getResponseBodyRetrievalText(responseVariableNameToUse)}`,
368
- ]
369
- : []),
370
- // eslint-disable-next-line no-nested-ternary
371
- ...(destructuringResponseStatusVariable
372
- ? [
373
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
374
- `${fixtureCallInformation.variableDeclaration?.kind ?? 'const'} ${(destructuringResponseStatusVariable as TSESTree.ObjectPattern).type === AST_NODE_TYPES.ObjectPattern ? sourceCode.getText(destructuringResponseStatusVariable as TSESTree.ObjectPattern) : (destructuringResponseStatusVariable as Variable).name} = ${getResponseStatusRetrievalText(responseVariableNameToUse)}`,
375
- ]
376
- : isResponseStatusVariableRedefinitionNeeded
377
- ? [
378
- `const ${redefineResponseStatusVariableName} = ${getResponseStatusRetrievalText(responseVariableNameToUse)}`,
379
- ]
380
- : []),
381
- // eslint-disable-next-line no-nested-ternary
382
- ...(destructuringResponseHeadersVariable
383
- ? // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
384
- (destructuringResponseHeadersVariable as TSESTree.ObjectPattern).type ===
385
- AST_NODE_TYPES.ObjectPattern
386
- ? (destructuringResponseHeadersVariable as TSESTree.ObjectPattern).properties.map((property) => {
387
- assert.ok(property.type === AST_NODE_TYPES.Property);
388
- assert.ok(property.value.type === AST_NODE_TYPES.Identifier);
389
- // eslint-disable-next-line sonarjs/no-nested-template-literals
390
- return `${fixtureCallInformation.variableDeclaration?.kind ?? 'const'} ${property.value.name} = ${getResponseHeadersRetrievalText(responseVariableNameToUse)}.get(${property.key.type === AST_NODE_TYPES.Literal ? sourceCode.getText(property.key) : `'${sourceCode.getText(property.key)}'`})`;
391
- })
392
- : [
393
- `${fixtureCallInformation.variableDeclaration?.kind ?? 'const'} ${(destructuringResponseHeadersVariable as Variable).name} = ${getResponseHeadersRetrievalText(responseVariableNameToUse)}`,
394
- ]
395
- : isResponseHeadersVariableRedefinitionNeeded
396
- ? [
397
- `const ${redefineResponseHeadersVariableName} = ${getResponseHeadersRetrievalText(responseVariableNameToUse)}`,
398
- ]
399
- : []),
400
- ]
401
- : [];
402
-
403
- const { statusAssertion, nonStatusAssertions } = createResponseAssertions(
404
- fixtureCallInformation,
405
- sourceCode,
406
- responseVariableNameToUse,
407
- destructuringResponseHeadersVariable as Variable | undefined,
408
- );
409
-
410
- // add variable declaration if needed
411
- const fetchCallText = sourceCode.getText(fixtureFunction);
412
- const fetchStatementText = !isResponseVariableRedefinitionNeeded
413
- ? fetchCallText
414
- : `${fixtureCallInformation.variableDeclaration?.kind ?? 'const'} ${responseVariableNameToUse} = await ${fetchCallText}`;
415
-
416
- const nodeToReplace = isResponseVariableRedefinitionNeeded
417
- ? fixtureCallInformation.rootNode
418
- : fixtureCallInformation.fixtureNode;
419
- const appendingAssignmentAndAssertionText = [
420
- '',
421
- ...(statusAssertion !== undefined ? [statusAssertion] : []),
422
- ...responseBodyHeadersVariableRedefineLines,
423
- ...nonStatusAssertions,
424
- ].join(`;\n${indentation}`);
425
-
426
- context.report({
427
- node: supertestCall,
428
- messageId: 'preferNativeFetch',
429
-
430
- *fix(fixer) {
431
- if (fixtureCallInformation.inlineStatementNode) {
432
- const preInlineDeclaration = [
433
- fetchStatementText,
434
- `${appendingAssignmentAndAssertionText};\n${indentation}`,
435
- ].join(``);
436
- yield fixer.insertTextBefore(fixtureCallInformation.inlineStatementNode, preInlineDeclaration);
437
- } else {
438
- yield fixer.replaceText(nodeToReplace, fetchStatementText);
439
-
440
- const needEndingSemiColon = sourceCode.getText(nodeToReplace).endsWith(';');
441
- yield fixer.insertTextAfter(
442
- nodeToReplace,
443
- needEndingSemiColon ? `${appendingAssignmentAndAssertionText};` : appendingAssignmentAndAssertionText,
444
- );
445
- }
446
-
447
- // handle response body references
448
- for (const responseBodyReference of responseBodyReferences) {
449
- yield fixer.replaceText(
450
- responseBodyReference,
451
- isResponseBodyVariableRedefinitionNeeded || !isResponseBodyRedefinition(responseBodyReference)
452
- ? redefineResponseBodyVariableName
453
- : getResponseBodyRetrievalText(responseVariableNameToUse),
454
- );
455
- }
456
- if (fixtureCallInformation.inlineBodyReference) {
457
- yield fixer.replaceText(fixtureCallInformation.inlineBodyReference, redefineResponseBodyVariableName);
458
- }
459
-
460
- // // handle response headers references
461
- // for (const responseHeadersReference of responseHeadersReferences) {
462
- // const parent = getParent(responseHeadersReference);
463
- // assert.ok(parent);
464
- // let headerName;
465
- // if (parent.type === AST_NODE_TYPES.MemberExpression) {
466
- // const headerNameNode = parent.property;
467
- // headerName = parent.computed
468
- // ? sourceCode.getText(headerNameNode)
469
- // : `'${sourceCode.getText(headerNameNode)}'`;
470
- // } else if (parent.type === AST_NODE_TYPES.CallExpression) {
471
- // const headerNameNode = parent.arguments[0];
472
- // headerName = sourceCode.getText(headerNameNode);
473
- // }
474
- // assert.ok(headerName !== undefined);
475
- // yield fixer.replaceText(parent, `${responseVariableNameToUse}.headers.get(${headerName})`);
476
- // }
477
-
478
- // convert response.statusCode to response.status
479
- for (const responseStatusReference of responseStatusReferences) {
480
- if (
481
- responseStatusReference.property.type === AST_NODE_TYPES.Identifier &&
482
- responseStatusReference.property.name === 'statusCode'
483
- ) {
484
- yield fixer.replaceText(responseStatusReference.property, `status`);
485
- }
486
- }
487
-
488
- // handle direct return statement without await, e.g. "return fixture.api.get(...);"
489
- if (
490
- fixtureCallInformation.rootNode.type === AST_NODE_TYPES.ReturnStatement &&
491
- fixtureCallInformation.assertions !== undefined
492
- ) {
493
- yield fixer.insertTextAfter(
494
- fixtureCallInformation.rootNode,
495
- `\n${indentation}return ${responseVariableNameToUse};`,
496
- );
497
- }
498
- },
499
- });
500
- } catch (error) {
501
- // eslint-disable-next-line no-console
502
- console.error(`Failed to apply ${ruleId} rule for file "${context.filename}":`, error);
503
- context.report({
504
- node: supertestCall,
505
- messageId: 'unknownError',
506
- data: {
507
- fileName: context.filename,
508
- error: error instanceof Error ? error.toString() : JSON.stringify(error),
509
- },
510
- });
511
- }
512
- },
513
- };
514
- },
515
- });
516
-
517
- export default rule;