From ecec8dcde53abc423aff54209ddd8a26c79672fa Mon Sep 17 00:00:00 2001 From: Erin Zimmer Date: Fri, 30 Aug 2024 13:16:14 +1000 Subject: [PATCH] fix(prefer-importing-jest-globals): ensure imports aren't inserted in the middle of a statement --- .../prefer-importing-jest-globals.test.ts | 55 +++++++++++++++++++ src/rules/prefer-importing-jest-globals.ts | 22 +++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/rules/__tests__/prefer-importing-jest-globals.test.ts b/src/rules/__tests__/prefer-importing-jest-globals.test.ts index 19bc24b8b..33ff353fd 100644 --- a/src/rules/__tests__/prefer-importing-jest-globals.test.ts +++ b/src/rules/__tests__/prefer-importing-jest-globals.test.ts @@ -546,5 +546,60 @@ ruleTester.run('prefer-importing-jest-globals', rule, { }, ], }, + { + code: dedent` + console.log('hello'); + const onClick = jest.fn(); + describe("suite", () => { + test("foo"); + expect(onClick).toHaveBeenCalled(); + }) + `, + output: dedent` + console.log('hello'); + const { describe, expect, jest, test } = require('@jest/globals'); + const onClick = jest.fn(); + describe("suite", () => { + test("foo"); + expect(onClick).toHaveBeenCalled(); + }) + `, + errors: [ + { + endColumn: 21, + column: 17, + line: 2, + messageId: 'preferImportingJestGlobal', + }, + ], + }, + { + code: dedent` + console.log('hello'); + const onClick = jest.fn(); + describe("suite", () => { + test("foo"); + expect(onClick).toHaveBeenCalled(); + }) + `, + output: dedent` + import { describe, expect, jest, test } from '@jest/globals'; + console.log('hello'); + const onClick = jest.fn(); + describe("suite", () => { + test("foo"); + expect(onClick).toHaveBeenCalled(); + }) + `, + parserOptions: { sourceType: 'module' }, + errors: [ + { + endColumn: 21, + column: 17, + line: 2, + messageId: 'preferImportingJestGlobal', + }, + ], + }, ], }); diff --git a/src/rules/prefer-importing-jest-globals.ts b/src/rules/prefer-importing-jest-globals.ts index 9cce2d213..532a4bfaf 100644 --- a/src/rules/prefer-importing-jest-globals.ts +++ b/src/rules/prefer-importing-jest-globals.ts @@ -21,6 +21,22 @@ const createFixerImports = ( : `const { ${allImportsFormatted} } = require('@jest/globals');`; }; +const findInsertionPoint = (reportingNode: TSESTree.Node) => { + let currentNode = reportingNode; + + while ( + currentNode.parent && + currentNode.parent.type !== AST_NODE_TYPES.Program && + currentNode.parent.type !== AST_NODE_TYPES.VariableDeclaration + ) { + currentNode = currentNode.parent; + } + + return currentNode.parent?.type === AST_NODE_TYPES.VariableDeclaration + ? currentNode.parent + : reportingNode; +}; + const allJestFnTypes: JestFnType[] = [ 'hook', 'describe', @@ -158,8 +174,12 @@ export default createRule({ ); if (requireNode?.type !== AST_NODE_TYPES.VariableDeclaration) { + const insertBeforeNode = isModule + ? firstNode + : findInsertionPoint(reportingNode); + return fixer.insertTextBefore( - reportingNode, + insertBeforeNode, `${createFixerImports(isModule, functionsToImport)}\n`, ); }