« Previous Tutorial Next Tutorial »

All right, now that we understand how linting works, let’s go over the rest of our app and find any more errors that need to be resolved. Opening every single file in our app in Sublime to look for linting errors would be an exercise in frustration. It’d also be a tremendous waste of time, because ESLint can be run from the command line and told to look at any or all of the files in our app at the same time.

To do this, we need to—hang on, I’m gonna blow your mind—do some installing. I know it seems like every single step of the way here involves installing a bunch of stuff, but the reason for that is because I’m portioning this out into bite-sized pieces. If I were doing a normal app setup for myself, I’d install all of this stuff right at the start, before writing a line of code, and then be done with it. Actually, there are even generators you can use to automate a lot of this stuff when putting together a new app, although you often have to deal with other people’s defaults and preferences, which can be mildly annoying.

Anyway, for right now let’s get to it. We need to install ESLint and its various dependencies globally if we want to run from the command line, so do that first:

yarn global add eslint-config-airbnb@15.0.1 eslint@^3.19.0 eslint-plugin-jsx-a11y@^5.0.1 eslint-plugin-import@^2.2.0 eslint-plugin-react@^7.0.1

Now we’re going to add a plugin to lint our jest tests, which will also allow us to preempt ESLint yelling at us because variables like “describe” and “it” in those tests are not defined in the same file. We start that process by typing the following and hitting enter:

yarn add --dev eslint-plugin-jest@20.0.3

and then add it globally, too:

yarn global add eslint-plugin-jest@20.0.3

OK, cool. Now we can lint our entire app. “BUT WAIT,” you may be thinking. “Does this mean we’re going to lint the literally tens of thousands of files in our node_modules folder? Because that seems like an apocalyptically bad idea!”

It is, and we’re not going to do that. ESLint is smart, and it automatically ignores node_modules. We could also tell it to ignore other files by setting up a .eslintignore file, but we’ll get to that another time.

To finish our installation, we need to tweak .eslintrc, so open that file up. It should look like this:

{
  "extends": "airbnb",
  "rules": {
    "no-unused-vars": ["error", { "argsIgnorePattern": "next" }]
  }
}

We need to make it jest-aware, so add the following lines below the “extends” block, but above the “rules” block:

  "plugins": [ "jest" ],
  "env": {
    "jest/globals": true
  },

This is telling ESLint to use the Jest plugin, and also to be aware of Jest’s various globals, like “describe” and “it” so that it doesn’t report them as undefined variables. Our final ESLint file should look like this:

{
  "extends": "airbnb",
  "plugins": [ "jest" ],
  "env": {
    "jest/globals": true
  },
  "rules": {
    "no-unused-vars": ["error", { "argsIgnorePattern": "next" }]
  }
}

OK, now we want to set up a script to run our linter. Open package.json and, in the scripts section, add the following:

"lint": "eslint ."

Make sure to add a comma at the end of the “test” line or your json will be broken and your scripts won’t run. Now back to our terminal or command prompt, and let’s try it out. Just type:

yarn lint

There we go! A whole list of files with linting errors. You might also notice the second-to-last line, which says we got an error with an exit code of 1. This is somewhat misleading: ESLint returned an exit code of 1 because it found errors, but it didn’t actually cause any errors itself. In other words, you can safely ignore this line. In the event that you ran your script and no files had linting errors, ESLint would return 0 and this error would go away.

All right, there are six files which need some help. Think we can run through them real quickly? Let’s give it a shot.

Start with app.js and let's just tell ESLint to ignore that favicon line, like this:

const favicon = require('serve-favicon'); // eslint-disable-line

Save that file and open up models/users.js. We need to fix line 1 by adding a new line (this is to keep require blocks separate, even if they’re only a single line). We also need a trailing comma at the end of our object. The final file should look like this:

const mongoose = require('mongoose');

const Schema = mongoose.Schema;
const passportLocalMongoose = require('passport-local-mongoose');

const User = new Schema({
  username: String,
  firstName: String,
  lastName: String,
});

User.plugin(passportLocalMongoose);

module.exports = mongoose.model('User', User);

Now open up api/index.js. This one’s easy: just an empty line after the require. It should look like this:

const express = require('express');

const router = express.Router();

module.exports = router;

/api/users.js has a few issues, too, so open that up. Again, we need a new line after our require statement.

Line 8’s error is interesting. In AirBnB’s opinion, functions should always return something (a JavaScript function with no return value automatically returns undefined, but undefined doesn’t qualify as “something”). The way to fix this is by adding a return at the beginning of our two res lines. Then we fix our improperly spaced if statement on line 9, and all we have left to do is add a new line at the end of the file. It’ll look like this:

const express = require('express');

const router = express.Router();

const User = require('../../models/user');

/ GET User List. /
router.get('/list', (req, res, next) => {
  User.find((err, users) => {
    if (err) {
      return res.send(err);
    }
    return res.json(users);
  });
});

module.exports = router;

Our last two files are easy. Open /api/users.test.js and unpad the block by deleting lines 6 and 9, and add a blank line at the end. It should look like this:

// Access supertest module functionality under the variable name "request"
const request = require('supertest');

// Top level of this test suite: the entire user API
describe('The User API', () => {
  // Specific test
  it('Returns a list of all users', async () => {
    // Connect to the server and get a response
    // Expect that response to be a 200 and serve JSON
    const res = await request('http://localhost:3000')
      .get('/api/users/list')
      .expect(200)
      .expect('Content-Type', /json/);

    // These expects are jest, not supertext
    // First, expect to get a result that is an array
    expect(Array.isArray(res.body)).toBe(true);
    // Second, expect the array to have something in it
    expect(res.body.length).toBeGreaterThan(0);
    // Third, expect the username of the first returned user to be Administrator
    expect(res.body[0].username).toBe('administrator');
  });
});

And then open /routes/index.js and add a new line under the require statement and a new line at the end, giving us this:

const express = require('express');

const router = express.Router();

/ GET home page. /
router.get('/', (req, res, next) => {
  res.render('index', { title: 'MusicList Alpha' });
});

module.exports = router;

That should be it. Make sure all of those files are saved, return to your terminal or command prompt, and type:

yarn lint

Again. There we go. Zero linting errors. Our code is lint-free and ready for a night on the town. In the next tutorial, we’re going to finally start talking React! See you there.

« Previous Tutorial Next Tutorial »