require-data-selectors.js 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. 'use strict'
  2. module.exports = {
  3. meta: {
  4. docs: {
  5. description: 'Use data-* attributes to provide context to your selectors and insulate them from CSS or JS changes https://docs.cypress.io/guides/references/best-practices.html#Selecting-Elements',
  6. category: 'Possible Errors',
  7. recommended: false,
  8. url: 'https://docs.cypress.io/guides/references/best-practices.html#Selecting-Elements',
  9. },
  10. schema: [],
  11. messages: {
  12. unexpected: 'use data-* attribute selectors instead of classes or tag names',
  13. },
  14. },
  15. create (context) {
  16. return {
  17. CallExpression (node) {
  18. if (isCallingCyGet(node) && !isDataArgument(node)) {
  19. context.report({ node, messageId: 'unexpected' })
  20. }
  21. },
  22. }
  23. },
  24. }
  25. function isCallingCyGet (node) {
  26. return node.callee.type === 'MemberExpression' &&
  27. node.callee.object.type === 'Identifier' &&
  28. node.callee.object.name === 'cy' &&
  29. node.callee.property.type === 'Identifier' &&
  30. node.callee.property.name === 'get'
  31. }
  32. function isDataArgument (node) {
  33. return node.arguments.length > 0 &&
  34. (
  35. (node.arguments[0].type === 'Literal' && isAliasOrDataSelector(String(node.arguments[0].value))) ||
  36. (node.arguments[0].type === 'TemplateLiteral' && isAliasOrDataSelector(String(node.arguments[0].quasis[0].value.cooked)))
  37. )
  38. }
  39. function isAliasOrDataSelector (selector) {
  40. return ['[data-', '@'].some(function (validValue) {
  41. return selector.startsWith(validValue)
  42. })
  43. }