diff --git a/lib/rules/no-node-access.ts b/lib/rules/no-node-access.ts index b0362886..9bc3a713 100644 --- a/lib/rules/no-node-access.ts +++ b/lib/rules/no-node-access.ts @@ -22,8 +22,6 @@ export const RULE_NAME = 'no-node-access'; export type MessageIds = 'noNodeAccess'; export type Options = [{ allowContainerFirstChild: boolean }]; -const userEventInstanceNames = new Set(); - export default createTestingLibraryRule({ name: RULE_NAME, meta: { @@ -62,6 +60,8 @@ export default createTestingLibraryRule({ ], create(context, [{ allowContainerFirstChild = false }], helpers) { + const userEventInstanceNames = new Set(); + function showErrorForNodeAccess(node: TSESTree.MemberExpression) { // This rule is so aggressive that can cause tons of false positives outside test files when Aggressive Reporting // is enabled. Because of that, this rule will skip this mechanism and report only if some Testing Library package @@ -169,6 +169,26 @@ export default createTestingLibraryRule({ userEventInstanceNames.add(id.name); } }, + AssignmentExpression(node: TSESTree.AssignmentExpression) { + if ( + ASTUtils.isIdentifier(node.left) && + isCallExpression(node.right) && + isMemberExpression(node.right.callee) && + ASTUtils.isIdentifier(node.right.callee.object) + ) { + const testingLibraryFn = resolveToTestingLibraryFn( + node.right, + context + ); + if ( + node.right.callee.object.name === testingLibraryFn?.local && + ASTUtils.isIdentifier(node.right.callee.property) && + node.right.callee.property.name === 'setup' + ) { + userEventInstanceNames.add(node.left.name); + } + } + }, 'ExpressionStatement MemberExpression': showErrorForNodeAccess, 'VariableDeclarator MemberExpression': showErrorForNodeAccess, }; diff --git a/tests/lib/rules/no-node-access.test.ts b/tests/lib/rules/no-node-access.test.ts index eb5906d3..41c29b16 100644 --- a/tests/lib/rules/no-node-access.test.ts +++ b/tests/lib/rules/no-node-access.test.ts @@ -219,6 +219,43 @@ ruleTester.run(RULE_NAME, rule, { const buttonText = screen.getByText('submit'); userEvt.click(buttonText); + `, + }, + { + code: ` + import { screen } from '${testingFramework}'; + import userEvent from '@testing-library/user-event'; + + describe('Testing', () => { + let user; + + beforeEach(() => { + user = userEvent.setup(); + }); + + it('test 1', async () => { + await user.click(screen.getByRole('button')); + }); + }); + `, + }, + { + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` + // case: custom module set but not imported using ${testingFramework} (aggressive reporting limited) + import { screen, userEvent } from 'test-utils'; + + describe('Testing', () => { + let user; + + beforeEach(() => { + user = userEvent.setup(); + }); + + it('test 1', async () => { + await user.click(screen.getByRole('button')); + }); + }); `, }, {