364

I'm attempting to use the ESLint linter with the Jest testing framework.

Jest tests run with some globals like jest, which I'll need to tell the linter about; but the tricky thing is the directory structure, with Jest the tests are embedded with the source code in __tests__ folders, so the directory structure looks something like:

src
    foo
        foo.js
        __tests__
            fooTest.js
    bar
        bar.js
        __tests__
            barTest.js

Normally, I'd have all my tests under a single dir, and I could just add an .eslintrc file there to add the globals... but I certainly don't want to add a .eslintrc file to every single __test__ dir.

For now, I've just added the test globals to the global .eslintrc file, but since that means I could now reference jest in non-testing code, that doesn't seem like the "right" solution.

Is there a way to get eslint to apply rules based on some pattern based on the directory name, or something like that?

Retsam
  • 30,909
  • 11
  • 68
  • 90
  • 1
    This is a bit too brute force for an actual answer, but you could have a separate linting task that manually uses an`eslint-test` file with a glob, e.g. `eslint **/__tests__/*.js -c eslint-test.yml`. That said, I don't think there's much danger of a `jest` or `beforeEach` global leaking out into production code ;) – Nick Tomlin Jul 27 '15 at 19:52

13 Answers13

880

The docs show you are now able to add:

"env": {
    "jest/globals": true
}

To your .eslintrc which will add all the jest related things to your environment, eliminating the linter errors/warnings.

You may need to include plugins: ["jest"] to your esconfig, and add the eslint-plugin-jest plugin if it still isn't working.

Dave Cooper
  • 10,494
  • 4
  • 30
  • 50
  • 33
    With this method the usage of "describe" or "it" outside of files that match the "*.test.js" or "__tests__/*.js" pattern will not result in linting errors. Is there any way to achieve this? – n1ru4l May 09 '17 at 17:21
  • 9
    @l0rin you could add a `.eslintrc` file that extend you default `.eslintrc` in your `__tests__` folder. If you have same problem as OP (multiple test folders), then you can generate those `.eslintrc` with a template and a tiny bash script (something like`ls **/__tests/ | xargs cp templates/.eslintrc`) – Ulysse BN Jul 22 '17 at 19:11
  • 2
    related link [here](https://eslint.org/docs/user-guide/configuring#specifying-environments) – devonj Jan 25 '18 at 09:20
  • 4
    Is this still accurate? The docs specifically say `"jest/globals": true` rather than `"jest": true`. – Kevin Ghadyani Sep 21 '20 at 20:57
  • @Sawtaytoes good spot. I have updated the answer accordingly :) – Dave Cooper Sep 22 '20 at 07:47
  • 3
    To be clear, you have to include `plugins": ["jest"]` to your esconfig, and add the eslint-plugin-jest plugin. – Stealth Rabbi Aug 12 '21 at 11:46
96

ESLint supports this as of version >= 4:

/*
.eslintrc.js
*/
const ERROR = 2;
const WARN = 1;

module.exports = {
  extends: "eslint:recommended",
  env: {
    es6: true
  },
  overrides: [
    {
      files: [
        "**/*.test.js"
      ],
      env: {
        jest: true // now **/*.test.js files' env has both es6 *and* jest
      },
      // Can't extend in overrides: https://github.com/eslint/eslint/issues/8813
      // "extends": ["plugin:jest/recommended"]
      plugins: ["jest"],
      rules: {
        "jest/no-disabled-tests": "warn",
        "jest/no-focused-tests": "error",
        "jest/no-identical-title": "error",
        "jest/prefer-to-have-length": "warn",
        "jest/valid-expect": "error"
      }
    }
  ],
};

Here is a workaround (from another answer on here, vote it up!) for the "extend in overrides" limitation of eslint config :

overrides: [
  Object.assign(
    {
      files: [ '**/*.test.js' ],
      env: { jest: true },
      plugins: [ 'jest' ],
    },
    require('eslint-plugin-jest').configs.recommended
  )
]

From https://github.com/eslint/eslint/issues/8813#issuecomment-320448724

Zachary Ryan Smith
  • 2,688
  • 1
  • 20
  • 30
  • 4
    Thank you, this is totally the right solution for this question, as it actually answers it. worked for me! – sra Mar 21 '18 at 18:13
  • 1
    This is great! With updating my ESLint to version >= 4 and adding a `"files"` and `"env"` object to `"overrides"` in `eslint.rc` I no longer have to worry about Jest specific syntax passing linting outside of the testing files. – Chunky Chunk Jun 14 '18 at 22:46
  • 1
    Excellent solution and also works for other frameworks (jasmine) when you have a non-standard folder structure. – Elliot Nelson Dec 23 '18 at 23:09
  • 3
    I'm the guy who wrote the accepted answer - this answer is much better than mine! Although at the time I wrote my answer, it was the only way to solve this problem well. – Dave Cooper May 17 '19 at 12:58
  • 8
    ESLint now supports extending in overrides – Nick McCurdy Nov 08 '19 at 20:52
32

You can also set the test env in your test file as follows:

/* eslint-env jest */

describe(() => {
  /* ... */
})
mkg20001
  • 171
  • 1
  • 10
HaNdTriX
  • 28,732
  • 11
  • 78
  • 85
20

To complete Zachary's answer, here is a workaround for the "extend in overrides" limitation of eslint config :

overrides: [
  Object.assign(
    {
      files: [ '**/*.test.js' ],
      env: { jest: true },
      plugins: [ 'jest' ],
    },
    require('eslint-plugin-jest').configs.recommended
  )
]

From https://github.com/eslint/eslint/issues/8813#issuecomment-320448724

Ricovitch
  • 2,278
  • 1
  • 21
  • 28
14

As of 2021, I think the correct way or at least the one that works is to install @types/jest and eslint-plugin-jest:

npm i -D eslint-plugin-jest @types/jest

And adding the Jest plugin into .eslintrc.js with the overrides instruction mentioned by @Loren:

module.exports = {
  ...
  plugins: ["jest"],
  ...
  overrides: [
    {
      files: ["**/*.test.js"],
      env: { "jest/globals": true },
      plugins: ["jest"],
      extends: ["plugin:jest/recommended"],
    },
  ],
  ...
};

This way you get linting errors in your source files as well as in test files, but in test files you don't get linting errors for test and other Jest's functions, but you will get them in your source files as they will appear as undefined there.

tonix
  • 6,671
  • 13
  • 75
  • 136
  • 1
    Many solutions purposed to put `"jest/globals": true` but it seems to make Eslint to stop working properly in other js files. But this solution is working flawlessly for me. It allows eslint to lint `.test` and `.js` files properly. – wael32gh Feb 09 '22 at 10:38
  • you can update a file rule to `"**/*.test.[j|t]s"` – belykh Nov 22 '22 at 23:04
12

I solved the problem REF

Run

# For Yarn
yarn add eslint-plugin-jest -D

# For NPM
npm i eslint-plugin-jest -D

And then add in your .eslintrc file

{
    "extends": ["airbnb","plugin:jest/recommended"],
}
Raz Luvaton
  • 3,166
  • 4
  • 21
  • 36
Brance Lee
  • 131
  • 1
  • 4
5

First install eslint-plugin-jest

Running:

yarn add eslint-plugin-jest

or

npm install eslint-plugin-jest

Then edit .eslintrc.json

{
   "env":{
     "jest": true
   }
}
MatthewMartin
  • 32,326
  • 33
  • 105
  • 164
Vander
  • 51
  • 1
  • 3
4

Add environment only for __tests__ folder

You could add a .eslintrc.yml file in your __tests__ folders, that extends you basic configuration:

extends: <relative_path to .eslintrc>
env:
    jest: true

If you have only one __tests__folder, this solution is the best since it scope jest environment only where it is needed.

Dealing with many test folders

If you have more test folders (OPs case), I'd still suggest to add those files. And if you have tons of those folders can add them with a simple zsh script:

#!/usr/bin/env zsh

for folder in **/__tests__/ ;do
    count=$(($(tr -cd '/' <<< $folder | wc -c)))
    echo $folder : $count
    cat <<EOF > $folder.eslintrc.yml
extends: $(printf '../%.0s' {1..$count}).eslintrc
env:
    jest: true
EOF
done

This script will look for __tests__ folders and add a .eslintrc.yml file with to configuration shown above. This script has to be launched within the folder containing your parent .eslintrc.

Ulysse BN
  • 10,116
  • 7
  • 54
  • 82
  • .eslintrc.yml to set second folder to be listed, super nice! To stop indexing it and avoid error messages, you can also set `"ignorePatterns": ["tests/*"]` in eslintrc file – vintagexav Feb 02 '23 at 17:07
4

some of the answers assume you have eslint-plugin-jest installed, however without needing to do that, you can simply do this in your .eslintrc file, add:

  "globals": {
    "jest": true,
  }
4

As of ESLint V 6 (released in late 2019), you can use extends in the glob based config as follows:

    "overrides": [
      {
        "files": ["*.test.js"],
        "env": {
          "jest": true
        },
        "plugins": ["jest"],
        "extends": ["plugin:jest/recommended"]
      }
    ]
Loren
  • 9,783
  • 4
  • 39
  • 49
2

Pattern based configs are scheduled for 2.0.0 release of ESLint. For now, however, you will have to create two separate tasks (as mentioned in the comments). One for tests and one for the rest of the code and run both of them, while providing different .eslintrc files.

P.S. There's a jest environment coming in the next release of ESLint, it will register all of the necessary globals.

Ilya Volodin
  • 10,929
  • 2
  • 45
  • 48
2

I got it running after spending some time trying out different options. Hope this helps anyone else getting stuck.

.eslintrc.json (in root project folder):

{
    "env": {
        "browser": true,
        "es2021": true,
        "jest/globals": true
    },
    "extends": [
        "standard",
        "plugin:jest/all"
    ],
    "parser": "@babel/eslint-parser",
    "parserOptions": {
        "ecmaVersion": 12,
        "sourceType": "module"
    },
    "rules": {
        "jest/no-hooks": [
            "error",
            {
                "allow": [
                    "afterEach",
                    "beforeEach"
                ]
            }
        ]
    },
    "plugins": [
        "jest"
    ]
}

Empty .babelrc (in root project folder):

{}

.package.json (in root project folder):

{
  "scripts": {
    "test": "jest",
    "lint": "npx eslint --format=table .",
    "lintfix": "npx eslint --fix ."
  },
  "devDependencies": {
    "@babel/core": "^7.15.0",
    "@babel/eslint-parser": "^7.15.0",
    "aws-sdk-mock": "^5.2.1",
    "eslint": "^7.32.0",
    "eslint-config-standard": "^16.0.3",
    "eslint-plugin-import": "^2.24.0",
    "eslint-plugin-jest": "^24.4.0",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^5.1.0",
    "jest": "^27.0.6"
  }
}

VS Code settings.xml (editor configuration: enables auto fix on save + babel parser):

    "eslint.alwaysShowStatus": true,
    "eslint.format.enable": true,
    "eslint.lintTask.enable": true,
    "eslint.options": {
        "parser": "@babel/eslint-parser"
    },
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
    },
    "eslint.validate": [
        "javascript"
    ]
Andrei
  • 2,282
  • 26
  • 35
-11

In your .eslintignore file add the following value:

**/__tests__/

This should ignore all instances of the __tests__ directory and their children.

Retsam
  • 30,909
  • 11
  • 68
  • 90
  • 5
    That's not quite what I want, I don't want to ignore the test files, I still want to lint them, I just want to figure out how to specify the necessary options to lint them correctly. – Retsam Jul 26 '15 at 04:00
  • 3
    Very bad idea, eslint helps in all code - including test code. – Daniel Kmak Mar 13 '18 at 11:10