Eslint rule for avoid 'contain' in assertions throws 'Should have 1 error but had 0' error

Viewed 1241

I'm creating new rule to avoid using 'contain' in 'should' assertion. I've used 'yo eslint:plugin' and then 'yo eslint:rule' to create structure. Now trying to write a rule. Unfortunately after npm test I'm getting AssertionError [ERR_ASSERTION]: Should have 1 error but had 0: [].

lib/rules/no-contain-assertion.js

module.exports = {
  meta: {
    docs: {
      description:
        "Rule to flag use of should.('contain') in tests, preventing tests with non strict assertion being committed accidentally",
      category: "StrictAssertion",
      recommended: false
    },
    fixable: null, // or "code" or "whitespace"
    schema: [
      // fill in your schema
    ]
  },

  create: function(context) {
    return {
      StrictAssertion(node) {
        if (node.object.name === 'should' && node.arguments[0] === 'contain') {
          context.report({
            node,
            message: `Don't use ${node}(${node.arguments[0]})`,
          });
        }
      }
    };
  }
};

tests/lib/rules/no-contain-assertion.js

var ruleTester = new RuleTester();
ruleTester.run("no-contain-assertion", rule, {

    valid: [
        "should('have.text')"
    ],

    invalid: [
        {
            code: "should('contain')",
            errors: [{
                message: "Don't use 'contain' in assertion!",
                type: "StrictAssertion"
            }]
        }
    ]
});
2 Answers

I know that it's might too late to answer the question but I'm developing an ESLint plugin nowadays so I was getting this problem. I resolved this problem by adding babel-eslint to the project.

  • Add babel-eslint
  • Configure .eslintrc.js
$ npm install eslint babel-eslint --save-dev
# or
$ yarn add eslint babel-eslint -D
module.exports = {
  parser: "babel-eslint",
};

The problem is that you should not have this:

return {
  StrictAssertion(node) {

StrictAssertion is not an AST type (at least AFAIAA).

What you want for matching should('contain') is CallExpression.

The AST types are defined by each parser (though they should adhere to ESTree and only some experimental JavaScript features tend to have different names in different parsers, e.g., babel-eslint currently uses ExperimentalRestProperty while Espree, the default parser of ESLint (used unless your config adds parser), uses RestElement).

So you can consult the docs for the parser you are using to find out more. ESLint itself gives a brief description of AST.

However, I find that learning how JavaScript maps to AST can most easily be done by using a tool like ASTExplorer which allows you to see an AST tree for the JavaScript code you supply. If you use the "Transform" feature with "ESLint 4" (yes, it is behind the current version of 7, but still very useful), you can even debug your rule right there.

Besides using bare AST types, you can use full ESLint selectors (which are really esquery expressions), allowing you to match similarly to CSS selectors, e.g., specifying in a single expression that you want your rule to find the child of a specific parent type only. In your case, rather than just using CallExpression and then filtering node by properties, you can create a selector which directly matches all your requirements, i.e., CallExpression[callee.name="should"] > Literal[value="contain"]. You can look at the AST Explorer for this: https://astexplorer.net/#/gist/3770fc3a0d869a55f88797b3228994af/3e63f6b3b74f0123cdd107b134f4c9f4a4387f1a to see it in action.

(Btw, you might want to consider submitting your rule if you complete it to https://github.com/ihordiachenko/eslint-plugin-chai-friendly which offers related rules, though not that one or maybe to https://github.com/Turbo87/eslint-plugin-chai-expect which has a rule against inner literals but currently only for expect.) I neglected to notice you were speaking of Cypress' should not Chai's. But the rest of the above is still accurate/relevant (and maybe eslint-plugin-cypress would be a good place for the rule instead).

Related