90

In my Chai tests I often find myself wanting to use their assertions that are something like .to.be.empty, .to.be.true e.t.c., because I find them to be cleaner to read than .to.be.length(1) or .to.be.equal(true). However, this breaks my linter (I'm using default Airbnb linting).

I could use the // disable-eslint-line syntax, but then I'd have to add it to every single line that reads like that and that seems tedious.

I've also read about the DirtyChai library, but that would require me to go back through my entire testing library adding brackets to them all which seems like something I shouldn't have to do simply to get my linter to pass something it should probably be OK with in the first place.

Does anyone know a nicer way to handle this than the ways I've outlined above?

d4nyll
  • 11,811
  • 6
  • 54
  • 68
Ben Hare
  • 4,365
  • 5
  • 27
  • 44

6 Answers6

103

You can disable the rule for the entire file using eslint-disable at the top of the file in question:

/* eslint-disable no-unused-expressions */
expect(someTrueValue).to.be.true; 

However, adding this at the top of every test file can be tedious. To disable this rule for all relevant files, you can:

  1. Put a new .eslintc configuration file in the same directory as your test files, configured to disable that rule. This allows you to use the default configuration for all other rules while ignoring that rule specifically only on files in that folder. ESLint calls this Configuration Cascading.

    {
        "rules": {
            "no-unused-expressions": "off"
        }
    }
    
  2. Use the overrides key in your main .eslintrc file to disable rules for groups of files with glob pattern matching:

    {
        "overrides": [
            {
                "files": ["*.test.js", "*.spec.js"],
                "rules": {
                    "no-unused-expressions": "off"
                }
            }
        ]
    }
    

This also allows you to disable other rules which become troublesome in testing, such as no-underscore-dangle when using rewire.

Nick Bartlett
  • 4,865
  • 2
  • 24
  • 37
  • That's a really cool feature (the Configuration Cascading) I didn't know about eslint thanks! Not the perfect solution to what I'd like, as I'd love for it to only care about those specific use cases, but suffices for what I'm trying to do. – Ben Hare Jun 12 '16 at 18:29
  • Why is this answer about `no-underscore-dangle`? Can you explain what to put in .eslintrc to answer op's original question? – Jim May 07 '18 at 15:11
39

Just found another option using Relative Glob Patterns:

In your .eslintrc file:

"overrides": [
    {
        "files": "*.test.js",
        "rules": {
          "no-unused-expressions": "off"
        }
    }
]
Walter Tross
  • 12,237
  • 2
  • 40
  • 64
jonalvarezz
  • 739
  • 6
  • 4
36

I've made a small plugin called eslint-plugin-chai-friendly that overrides the default no-unused-expressions rule and makes it friendly towards chai. The modified rule ignores the expect and should statements while keeping default behavior for everything else.

Ihor Diachenko
  • 468
  • 4
  • 6
  • 5
    +1. This should be the accepted answer because it means you don't have to turn off the rule for the entire test file (so you still get the benefits of the rule when it applies). Thanks for the plugin! – Jules Dupont Feb 06 '18 at 15:54
  • 1
    If you're writing typescript, there's now an equivalent plugin on npm for tslint: `tslint-no-unused-expression-chai`. – GaryO May 06 '19 at 14:54
5

Combining jonalvarezz's answer with Ihor Diachenko's answer gave me exactly what I wanted:

npm install --save-dev eslint-plugin-chai-friendly

// .eslintrc.js
module.exports = {
  // ...
  plugins: ['chai-friendly'],
  overrides: [{
    files: '*.test.js',
    rules: {
      'no-unused-expressions': 'off',
      'chai-friendly/no-unused-expressions': 'error',
    },
  }],
  // ...
}

This way, the no-unused-expression rule will only be overridden in *.test.js files AND a no-unused-expression rule will still be in place to catch any unused expressions in the test files that are unrelated to chai.

Iman Mahmoudinasab
  • 6,861
  • 4
  • 44
  • 68
Scott Rudiger
  • 1,224
  • 12
  • 16
  • 1
    Great idea. Shouldn't the second rule in your code sample be enabled though? i. e. `'chai-friendly/no-unused-expressions': 2` – dmudro Nov 05 '18 at 17:14
  • You are correct. I looked back at my code and I have it as `chai-friendly/no-unused-expressions': 'error'`. Feel free to submit an edit, or if not I'll do it in a few days. – Scott Rudiger Nov 06 '18 at 18:40
3

In case anyone is stumbling upon this today, I had the same issue and found this solution on eslint documentation. In your eslint configuration file, you can specify one or several environments, which will predefine global variables for this environment. For us, it'd be mocha, and you'd configure like this in your .eslintrc.json:

{
    "env": {
        "mocha": true
    },
    ...
    ...
    ...
}

As a result, it will remove all false positive about mocha describe, it, beforeEach, etc. without needing to completely disable eslint or completely disable any specific rule.

Tested with ESLint v.4.11 and mocha 5.0

Pierre-Adrien
  • 2,836
  • 29
  • 30
  • 3
    That's the right thing to do. In my experience the Chai assertion would still fail though as Chai and Mocha are two different things so you want to take care of it separately. Scott's answer above seems to be the most efficient fix for Chai. – dmudro Nov 07 '18 at 20:43
  • 3
    This does not answer the question, which is about Chai's `should()` and `assert` methods. – GrayedFox Feb 21 '19 at 09:16
0

I had this issue with tslint and solved it by simply moving the rule for unused expressions down one level. My ./tslint.json has all the other rules I care about, then I made ./src/tslint.json that just looks like

{
    "rules": {
        "no-unused-expression": true
    },
    "extends": "../tslint.json"
}

tslint automatically checks for a config file in every level as it descends the tree (with --project or using the VSCode extension) so this means that my tests (under ./test/) have all the other rules applied, but no-unused-expression only applies to files under ./src/.

Coderer
  • 25,844
  • 28
  • 99
  • 154