1. 29
    Run Linting, Tests and Prettier in git Hooks with Husky
    5m 41s

Run Linting, Tests and Prettier in git Hooks with Husky

Andy Van Slaars
InstructorAndy Van Slaars

Share this video with your friends

Send Tweet
Published 4 years ago
Updated 3 years ago

With the ability to run unit tests, automatic code formatting and linting, we should avoid ever committing code that does not adhere to our project standards or breaks our tests. In this lesson, we'll install and configure the Husky npm package and enforce these checks before a git commit is allowed.

Instructor: [00:01] Our project has Prettier, ESLint, and Jest all configured, so we can ensure we're creating consistently-formatted, well-tested, high quality code. Let's ensure that all tests and linting rules pass, and our code is properly formatted before any new code can be committed to Git.

[00:15] We'll start by running npm i -d to save as a dev dependency, Husky. With that installed, let's go into our package.json and configure it. Husky is going to have its own configuration in our package.json, so I'm going to create a Husky key at the top level.

[00:34] That's going to get an object. We're going to define a section in here called hooks. Then we want to define the key for the pre-commit hook. That's going to be pre-commit. Then we can give this a value. This'll be a script that runs.

[00:53] Let's start with npm run lint. We'll save that. Now, I'm going to come into my app.js file, and I'm going to do something that will cause a lint error. I'm just going to add a new constant. I'll call it A. I'm going to assign it a value A, and I'm not going to do anything with it.

[01:10] I'm going to save this, and if I do an npm run lint, we'll see that our linter fails, because we have a value that's never used. Now that I know I have a linting error, what I expect to happen is, if I add this file, and then try to commit it to Git, that commit should fail.

[01:30] In my terminal, I'm going to do a git add source/app.js. If I run a git status, we will see that I have one file that's been modified and ready to commit. I'm going to do a git commit -m, and this should fail. We'll see that we get an error here.

[01:58] If I scroll up, it's our linting error that we expected. We'll see that Husky is running that pre-commit script. If I do a git status, we're right back where we were before I attempted to commit. We know a linting error will fail our commit.

[02:17] I'm going to come in here, and I'm going to remove this code that causes that error in the first place. I'll save that. I would also like committing to fail if our tests aren't all passing. I'm going to come into our app.spec.js, and I'm going to add a second test that just always fails.

[02:38] Here, we'll just expect true to be false, so this test can never pass. We'll just verify that by running npm test. We have our failing test. Now, I'm going to come back into package.json, and I'm going to update this pre-commit script to run npm run lint.

[03:00] Then I'm also, with the double ampersand, if the linting passes, then I'm going to run npm run test. I can save that, and I'll go back down into my terminal here. If I do a git status, we'll see that we have some new modified files, but we still have a file ready to be committed.

[03:23] We can run this experiment again without doing anything else. We'll do a git commit -m. This should fail. We can see that our test is failing. It ran lint. Lint passed, then it ran Jest. Our test failed. If we look at our git status, our commit never happened.

[03:53] Now, we know that our pre-commit hook will also fail if our test fails. I can come into app.spec, and I can remove this test that's always going to fail. The last thing we need to add is automatically formatting our code using our Prettier settings.

[04:07] I'm going to go into package.json, and I'm going to update this script. I'm going to add this one to the beginning, because it's going to run pretty fast. I'm going to add pretty quick. I'm going to pass it the --staged flag, and then use the double ampersands to run lint, and then test after that.

[04:26] This is only going to apply to staged files, things that we've added to git that are about to be committed. This is what we're worried about here, is those staged files. I'm going to save this, and I'm going to go back into app.js.

[04:39] I'm going to mess up my formatting. Now, I have turned off my automatic format on save setting in my editor so that I can save this file. Now, I'm going to back down into the terminal. At this point, we expect everything to pass.

[04:52] Down here, I'm going to just add everything that we've changed. Then I'm going to git commit. This commit says that we added Husky, with pre-commit hooks. We'll see that our file has been formatted. It also ran all of our lint checks.

[05:21] It ran our tests. If we look at our git status, we'll see that we've successfully made our commit. Now, we can't commit without our test passing, all the linting rules being cleared up. It'll automatically format anything that hasn't been formatted by our editor, or by running our format script.

Felipe
Felipe
~ 3 years ago

In the test file from the Transcript says 'if'. if('Fails', () => { expect(true).toBe(false) }) Salute.

Miguel Palomera
Miguel Palomera
~ 3 years ago

Due to I am using google prettier setup eslint was overriding the prettier output hence I was unable to commit. The solution was to use this package

npm i -D eslint-config-prettier

Then, add eslint-config-prettier to the "extends" array in your .eslintrc file. Make sure to put it last, so it gets the chance to override other configs.

{ "extends": [ "some-other-config-you-use", "prettier" ] }

cfsnsalazar
cfsnsalazar
~ 3 years ago

I am getting this error when trying to set up the pre-commit hook :

internal/modules/cjs/loader.js:626
    throw err;
    ^

Error: Cannot find module './v1'
Require stack:
- /Users/cfsnsalazar/node_modules/npm/node_modules/uuid/index.js
- /Users/cfsnsalazar/node_modules/npm/lib/utils/metrics.js
- /Users/cfsnsalazar/node_modules/npm/lib/npm.js
- /Users/cfsnsalazar/node_modules/npm/bin/npm-cli.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:623:15)
    at Function.Module._load (internal/modules/cjs/loader.js:527:27)
    at Module.require (internal/modules/cjs/loader.js:681:19)
    at require (internal/modules/cjs/helpers.js:16:16)
    at Object.<anonymous> (/Users/cfsnsalazar/node_modules/npm/node_modules/uuid/index.js:1:10)
    at Module._compile (internal/modules/cjs/loader.js:774:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:785:10)
    at Module.load (internal/modules/cjs/loader.js:641:32)
    at Function.Module._load (internal/modules/cjs/loader.js:556:12)
    at Module.require (internal/modules/cjs/loader.js:681:19) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/Users/cfsnsalazar/node_modules/npm/node_modules/uuid/index.js',
    '/Users/cfsnsalazar/node_modules/npm/lib/utils/metrics.js',
    '/Users/cfsnsalazar/node_modules/npm/lib/npm.js',
    '/Users/cfsnsalazar/node_modules/npm/bin/npm-cli.js'
  ]
}
husky > pre-commit hook failed (add --no-verify to bypass)```
cfsnsalazar
cfsnsalazar
~ 3 years ago

If I do not use my script , the pre-commit hook works "pre-commit": "eslint ./"