---
title: Testing Your Style With ESLint and Mocha
teaser: Use ESLint and Mocha to generate tests for the style of your codebase.
tags: javascript,style,web
author: Blake Williams
published_on: 2016-05-04
---

I've been working on a front-end application that uses [ESLint] for linting and
Mocha as our testing framework. We've tried a few solutions to integrate linting
into our workflow but it can easily be ignored. To make sure linting errors were
given the attention they deserved we decided to turn linting errors into test
failures.

[ESLint]: http://eslint.org

## Generating tests

ESLint provides all the tools we need to lint our files and get the
results back directly in JavaScript.

To get started, create a file called called `eslint-test.js` in your test
directory.

The first thing we need to do is collect an array of file paths we want to lint
and get the results from ESLint after telling it our environment information and
to use our `.eslintrc`.

```javascript
// eslint-test.js
import glob from 'glob';
import { CLIEngine } from 'eslint';
import { assert } from 'chai';

const paths = glob.sync('./+(app|test)/**/*.js');
const engine = new CLIEngine({
  envs: ['node', 'mocha'],
  useEslintrc: true,
});

const results = engine.executeOnFiles(paths).results;
```

Now that we have the results we can define our `describe` block and generate
tests in that block. Let's add that to the end of our `eslint-test.js` file.

```javascript
describe('ESLint', function() {
  results.forEach((result) => generateTest(result));
});
```

For each result we want to extract the `filePath` and `messages`. `filePath`
will be used to generate a good test name. We'll use `messages` to check if we
have any messages and if we do, we fail the test with a well formatted reason
built from `messages`.

```javascript
function generateTest(result) {
  const { filePath, messages } = result;

  it(`validates ${filePath}`, function() {
    if (messages.length > 0) {
      assert.fail(false, true, formatMessages(messages));
    }
  });
}
```

Finally we can loop over each of the messages and generate a failure message
telling us the line number, column number, failure message, and the ESLint rule
name.

```javascript
function formatMessages(messages) {
  const errors = messages.map((message) => {
    return `${message.line}:${message.column} ${message.message.slice(0, -1)} - ${message.ruleId}\n`;
  });

  return `\n${errors.join('')}`;
}
```

Here's the test generator code all together:

```javascript
import glob from 'glob';
import { CLIEngine } from 'eslint';
import { assert } from 'chai';

const paths = glob.sync('./+(app|test)/**/*.js');
const engine = new CLIEngine({
  envs: ['node', 'mocha'],
  useEslintrc: true,
});

const results = engine.executeOnFiles(paths).results;

describe('ESLint', function() {
  results.forEach((result) => generateTest(result));
});

function generateTest(result) {
  const { filePath, messages } = result;

  it(`validates ${filePath}`, function() {
    if (messages.length > 0) {
      assert.fail(false, true, formatMessages(messages));
    }
  });
}

function formatMessages(messages) {
  const errors = messages.map((message) => {
    return `${message.line}:${message.column} ${message.message.slice(0, -1)} - ${message.ruleId}\n`;
  });

  return `\n${errors.join('')}`;
}
```

## The results

Now that we have our ESLint test generator we can run our test suite and see it
in action.

    $ mocha
      1) ESLint validates ./app/index.js
         AssertionError:
    44:35 Missing semicolon - semi

It works! Our failure tells us the failure's file, line number, column number,
and linting error!

## Conclusion

This combined with GitHub's [required checks] can make it much harder to merge
code with poor style in your application. You can also take this same idea and
apply it to other tools or linters like [Hound].

[required checks]: https://github.com/blog/2051-protected-branches-and-required-status-checks
[Hound]: https://houndci.com/
