loading...
Cover image for Don't commit focused tests

Don't commit focused tests

timdeschryver profile image Tim Deschryver Originally published at timdeschryver.dev ・3 min read

Follow me on Twitter at @tim_deschryver | Subscribe to the Newsletter | Originally published on timdeschryver.dev.


We've all done it, committing a focused test. Most of the time this won't be spotted during a review, and this might lead to bigger problems. So... how can this be prevented?

Visual Studio Code extension

Last week, Dzhavat Ushev created the Test Focus Highlighter Visual Studio Code extension which highlights focused tests.

Warnings are shown for focused tests

Neat right?! But this doesn't prevent us from committing tests, for this we have to take it a step further.

TSLint

For projects that are using TSLint, the built-in ban rule can be used to ban the usage of specific functions or global methods. I didn't know this existed, but Maxime Robert pointed me to it.

This ban rule can be configured in the tslint.json file.

{
  "rules": {
    "ban": [
      true,
      { "name": ["describe", "only"], "message": "don't focus tests" },
      { "name": "fdescribe", "message": "don't focus tests" },
      { "name": ["it", "only"], "message": "don't focus tests" },
      { "name": "fit", "message": "don't focus tests" },
      { "name": ["test", "only"], "message": "don't focus tests" },
      { "name": "ftest", "message": "don't focus tests" }
    ]
  }
}

ESLint

eslint-plugin-ban

Sadly, for ESLint there isn't a built-in rule but there are options. Inspired by the TSLint ban rule, there's an ESLint ban rule that is created by the community. It has the same configuration and behaves the same way as the TSLint version.

This ban rule can be configured in the .eslintrc.json file.

{
  "rules": {
    "ban/ban": [
      true,
      { "name": ["describe", "only"], "message": "don't focus tests" },
      { "name": "fdescribe", "message": "don't focus tests" },
      { "name": ["it", "only"], "message": "don't focus tests" },
      { "name": "fit", "message": "don't focus tests" },
      { "name": ["test", "only"], "message": "don't focus tests" },
      { "name": "ftest", "message": "don't focus tests" }
    ]
  }
}

eslint-plugin-jest

The second option, if you're using Jest, is to use the eslint-plugin-jest ESLint plugin. This plugin has a set of options and one of these is no-focused-tests. You can enable the rule specifically, use the "all configuration", or the "recommended configuration".

{
  "extends": ["plugin:jest/recommended"]
}

Pre-commit hook

After this post was released, Netanel Basal shared a third option by using a pre-commit hook.
This will prevent a user from committing a focused test.

For this method, you have to (1) create the hook, and (2) enable the hook with for example husky.

const { execSync } = require('child_process')
const chalk = require('chalk')

/** Map of forbidden words and their match regex */
const words = {
  fit: '\\s*fit\\(',
  fdescribe: '\\s*fdescribe\\(',
  debugger: '(debugger);?',
}
let status = 0
for (let word of Object.keys(words)) {
  const matchRegex = words[word]
  const gitCommand = `git diff --staged -G"${matchRegex}" --name-only`
  const badFiles = execSync(gitCommand).toString()
  const filesAsArray = badFiles.split('\n')
  const tsFileRegex = /\.ts$/
  const onlyTsFiles = filesAsArray.filter(file => tsFileRegex.test(file.trim()))
  if (onlyTsFiles.length) {
    status = 1
    console.log(
      chalk.bgRed.black.bold(`The following files contains '${word}' in them:`),
    )
    console.log(chalk.bgRed.black(onlyTsFiles.join('\n')))
  }
}
process.exit(status)
"husky": {
  "hooks": {
    "pre-commit": "node hooks/pre-commit.js",
  }
}

For an example, you can take a look at the Transloco library.
Thanks Netanel!

Conclusion

Using the Visual Studio Code extension helps you to spot focused tests, but doesn't prevent that these tests are committed. Using a linter helps to spot these focused tests (or skipped tests).
Linting your project during a continuous integration run will give you a warning or will throw an error (depending on how it's configured) to prevent an accidental commit.

Happy linting!


Follow me on Twitter at @tim_deschryver | Subscribe to the Newsletter | Originally published on timdeschryver.dev.

Posted on by:

timdeschryver profile

Tim Deschryver

@timdeschryver

NgRx team member - Writer for AngularInDepth

Discussion

markdown guide