You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
6.0 KiB
147 lines
6.0 KiB
"use strict"; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
exports.MAPPING_TO_USER_EVENT = exports.UserEventMethods = 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"); |
|
exports.RULE_NAME = 'prefer-user-event'; |
|
exports.UserEventMethods = [ |
|
'click', |
|
'dblClick', |
|
'type', |
|
'upload', |
|
'clear', |
|
'selectOptions', |
|
'deselectOptions', |
|
'tab', |
|
'hover', |
|
'unhover', |
|
'paste', |
|
]; |
|
exports.MAPPING_TO_USER_EVENT = { |
|
click: ['click', 'type', 'selectOptions', 'deselectOptions'], |
|
change: ['upload', 'type', 'clear', 'selectOptions', 'deselectOptions'], |
|
dblClick: ['dblClick'], |
|
input: ['type', 'upload', 'selectOptions', 'deselectOptions', 'paste'], |
|
keyDown: ['type', 'tab'], |
|
keyPress: ['type'], |
|
keyUp: ['type', 'tab'], |
|
mouseDown: ['click', 'dblClick', 'selectOptions', 'deselectOptions'], |
|
mouseEnter: ['hover', 'selectOptions', 'deselectOptions'], |
|
mouseLeave: ['unhover'], |
|
mouseMove: ['hover', 'unhover', 'selectOptions', 'deselectOptions'], |
|
mouseOut: ['unhover'], |
|
mouseOver: ['hover', 'selectOptions', 'deselectOptions'], |
|
mouseUp: ['click', 'dblClick', 'selectOptions', 'deselectOptions'], |
|
paste: ['paste'], |
|
pointerDown: ['click', 'dblClick', 'selectOptions', 'deselectOptions'], |
|
pointerEnter: ['hover', 'selectOptions', 'deselectOptions'], |
|
pointerLeave: ['unhover'], |
|
pointerMove: ['hover', 'unhover', 'selectOptions', 'deselectOptions'], |
|
pointerOut: ['unhover'], |
|
pointerOver: ['hover', 'selectOptions', 'deselectOptions'], |
|
pointerUp: ['click', 'dblClick', 'selectOptions', 'deselectOptions'], |
|
}; |
|
function buildErrorMessage(fireEventMethod) { |
|
const userEventMethods = exports.MAPPING_TO_USER_EVENT[fireEventMethod].map((methodName) => `userEvent.${methodName}`); |
|
return userEventMethods.join(', ').replace(/, ([a-zA-Z.]+)$/, ', or $1'); |
|
} |
|
const fireEventMappedMethods = Object.keys(exports.MAPPING_TO_USER_EVENT); |
|
exports.default = (0, create_testing_library_rule_1.createTestingLibraryRule)({ |
|
name: exports.RULE_NAME, |
|
meta: { |
|
type: 'suggestion', |
|
docs: { |
|
description: 'Suggest using `userEvent` over `fireEvent` for simulating user interactions', |
|
recommendedConfig: { |
|
dom: false, |
|
angular: false, |
|
react: false, |
|
vue: false, |
|
marko: false, |
|
}, |
|
}, |
|
messages: { |
|
preferUserEvent: 'Prefer using {{userEventMethods}} over fireEvent.{{fireEventMethod}}', |
|
}, |
|
schema: [ |
|
{ |
|
type: 'object', |
|
properties: { |
|
allowedMethods: { type: 'array' }, |
|
}, |
|
}, |
|
], |
|
}, |
|
defaultOptions: [{ allowedMethods: [] }], |
|
create(context, [options], helpers) { |
|
const { allowedMethods } = options; |
|
const createEventVariables = {}; |
|
const isfireEventMethodAllowed = (methodName) => !fireEventMappedMethods.includes(methodName) || |
|
allowedMethods.includes(methodName); |
|
const getFireEventMethodName = (callExpressionNode, node) => { |
|
if (!utils_1.ASTUtils.isIdentifier(callExpressionNode.callee) && |
|
!(0, node_utils_1.isMemberExpression)(callExpressionNode.callee)) { |
|
return node.name; |
|
} |
|
const secondArgument = callExpressionNode.arguments[1]; |
|
if (utils_1.ASTUtils.isIdentifier(secondArgument) && |
|
createEventVariables[secondArgument.name] !== undefined) { |
|
return createEventVariables[secondArgument.name]; |
|
} |
|
if (!(0, node_utils_1.isCallExpression)(secondArgument) || |
|
!helpers.isCreateEventUtil(secondArgument)) { |
|
return node.name; |
|
} |
|
if (utils_1.ASTUtils.isIdentifier(secondArgument.callee)) { |
|
return secondArgument.arguments[0] |
|
.value; |
|
} |
|
return secondArgument.callee |
|
.property.name; |
|
}; |
|
return { |
|
'CallExpression Identifier'(node) { |
|
if (!helpers.isFireEventMethod(node)) { |
|
return; |
|
} |
|
const closestCallExpression = (0, node_utils_1.findClosestCallExpressionNode)(node, true); |
|
if (!closestCallExpression) { |
|
return; |
|
} |
|
const fireEventMethodName = getFireEventMethodName(closestCallExpression, node); |
|
if (!fireEventMethodName || |
|
isfireEventMethodAllowed(fireEventMethodName)) { |
|
return; |
|
} |
|
context.report({ |
|
node: closestCallExpression.callee, |
|
messageId: 'preferUserEvent', |
|
data: { |
|
userEventMethods: buildErrorMessage(fireEventMethodName), |
|
fireEventMethod: fireEventMethodName, |
|
}, |
|
}); |
|
}, |
|
VariableDeclarator(node) { |
|
if (!(0, node_utils_1.isCallExpression)(node.init) || |
|
!helpers.isCreateEventUtil(node.init) || |
|
!utils_1.ASTUtils.isIdentifier(node.id)) { |
|
return; |
|
} |
|
let fireEventMethodName = ''; |
|
if ((0, node_utils_1.isMemberExpression)(node.init.callee) && |
|
utils_1.ASTUtils.isIdentifier(node.init.callee.property)) { |
|
fireEventMethodName = node.init.callee.property.name; |
|
} |
|
else if (node.init.arguments.length > 0) { |
|
fireEventMethodName = node.init.arguments[0] |
|
.value; |
|
} |
|
if (!isfireEventMethodAllowed(fireEventMethodName)) { |
|
createEventVariables[node.id.name] = fireEventMethodName; |
|
} |
|
}, |
|
}; |
|
}, |
|
});
|
|
|