UNPKG

eslint-plugin-testing-library

Version:

ESLint plugin to follow best practices and anticipate common mistakes when writing tests with Testing Library

112 lines (111 loc) 4.72 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RULE_NAME = void 0; const utils_1 = require("@typescript-eslint/utils"); const create_testing_library_rule_1 = require("../create-testing-library-rule"); const node_utils_1 = require("../node-utils"); const utils_2 = require("../utils"); exports.RULE_NAME = 'no-node-access'; const userEventInstanceNames = new Set(); exports.default = (0, create_testing_library_rule_1.createTestingLibraryRule)({ name: exports.RULE_NAME, meta: { type: 'problem', docs: { description: 'Disallow direct Node access', recommendedConfig: { dom: 'error', angular: 'error', react: 'error', vue: 'error', svelte: 'error', marko: 'error', }, }, messages: { noNodeAccess: 'Avoid direct Node access. Prefer using the methods from Testing Library.', }, schema: [ { type: 'object', properties: { allowContainerFirstChild: { type: 'boolean', }, }, }, ], }, defaultOptions: [ { allowContainerFirstChild: false, }, ], create(context, [{ allowContainerFirstChild = false }], helpers) { function showErrorForNodeAccess(node) { if (!helpers.isTestingLibraryImported(true)) { return; } const propertyName = utils_1.ASTUtils.isIdentifier(node.property) ? node.property.name : null; if (propertyName && utils_2.ALL_RETURNING_NODES.some((allReturningNode) => allReturningNode === propertyName)) { if (allowContainerFirstChild && propertyName === 'firstChild') { return; } if (utils_1.ASTUtils.isIdentifier(node.object) && node.object.name === 'props') { return; } context.report({ node, loc: node.property.loc.start, messageId: 'noNodeAccess', }); } } return { CallExpression(node) { const { callee } = node; const property = (0, node_utils_1.isMemberExpression)(callee) ? callee.property : null; const object = (0, node_utils_1.isMemberExpression)(callee) ? callee.object : null; const propertyName = utils_1.ASTUtils.isIdentifier(property) ? property.name : null; const objectName = utils_1.ASTUtils.isIdentifier(object) ? object.name : null; const isEventHandlerMethod = utils_2.EVENT_HANDLER_METHODS.some((method) => method === propertyName); const hasUserEventInstanceName = userEventInstanceNames.has(objectName !== null && objectName !== void 0 ? objectName : ''); const testingLibraryFn = (0, utils_2.resolveToTestingLibraryFn)(node, context); if (!testingLibraryFn && isEventHandlerMethod && !hasUserEventInstanceName) { context.report({ node, loc: property === null || property === void 0 ? void 0 : property.loc.start, messageId: 'noNodeAccess', }); } }, VariableDeclarator(node) { const { init, id } = node; if (!(0, node_utils_1.isCallExpression)(init)) { return; } if (!(0, node_utils_1.isMemberExpression)(init.callee) || !utils_1.ASTUtils.isIdentifier(init.callee.object)) { return; } const testingLibraryFn = (0, utils_2.resolveToTestingLibraryFn)(init, context); if (init.callee.object.name === (testingLibraryFn === null || testingLibraryFn === void 0 ? void 0 : testingLibraryFn.local) && utils_1.ASTUtils.isIdentifier(init.callee.property) && init.callee.property.name === 'setup' && utils_1.ASTUtils.isIdentifier(id)) { userEventInstanceNames.add(id.name); } }, 'ExpressionStatement MemberExpression': showErrorForNodeAccess, 'VariableDeclarator MemberExpression': showErrorForNodeAccess, }; }, });