Husky: Step by Step (Bite-size Article)
Tags: husky, jest, testing, beginners
Published: 2024-03-01 21:54:34

#Introduction
**Husky** is a tool for easily managing **Git hooks** in web development projects. Git hooks are features of Git that automatically execute custom scripts when specific events occur, such as before a commit or before a push, allowing the execution of specific scripts.

By using Husky, these hooks can be configured in the project's `package.json` file, making it easy to incorporate scripts that utilize hooks into the project. This facilitates efficient management of code quality maintenance tasks such as linting (checking syntax and adherence to style guides) and automated testing.

With Husky, it is possible to, for example, automatically execute code linting before commits or run tests before pushing. If any issues are found, the push can be aborted. This prevents low-quality code from being added to the repository and is particularly useful for preventing issues before they occur, especially in team development scenarios.

In this article, I will explain how to set up and use Husky in a React app, including practical examples. And this article aims to be an introductory step to learning Husky, focusing only on the basics and avoiding complex content.

##Tip: What is Lint?
In programming, **Lint** refers to tools that analyze code to identify syntax errors, style issues, potential bugs, and inefficiencies without executing the code.

For JavaScript, **ESLint** and **JSHint** are popular options.

Lint contributes to development efficiency and quality improvement by detecting syntax errors and other issues before code execution. For example, it can detect various problems such as undeclared variables, missing semicolons, unused variables, and incorrect operators used in equality comparisons.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2cuonu4dr3j04wc5s1h.png)


#Setup
In this article, I will introduce specific examples of utilizing Git hooks with Husky. We'll set up hooks in the `package.json` file to execute linting (static code analysis) before commits and run tests in the workflow.

First, run the following command in your terminal:

```shell
npx husky-init && npm install
```

And also, if you don't have eslint in your project, please install it.

Running this command generates the `.husky` directory and adds the Husky configuration to your `package.json` (the `.husky` directory is added to your project's root directory).

Next, we will configure the Git hooks. In the `package.json` file, we will set up scripts to be executed with Husky. In the example below, we configure a script to run linting on the `pre-commit` hook and a script to run tests on the `pre-push` hook.

```json
{
  "name": "your-project-name",
  "version": "1.0.0",
  "scripts": {
    "lint": "eslint . --fix",
    "test": "jest"
  },
  "husky": {
    "hooks": {
      "pre-commit": "npm run lint",
      "pre-push": "npm run test"
    }
  }
}
```

With this setup, the following actions are performed:

- Before commit (pre-commit): The `eslint . --fix command` is executed to lint all files in the project. If issues can be automatically fixed, they are corrected (otherwise, errors would be reported). If linting detects errors, the commit is aborted.
- Before pushing (pre-push): The Jest command is executed to run the project's test suite. If any tests fail, the push is aborted. By the way, I wrote a related article about testing with Jest and using `npm run test`, which you might find interesting. You can read it [here](https://dev.to/koshirok096/jest-step-by-step-bite-size-article-1i9o).

##Tip: .husky
I want to share a point where I stumbled personally. Depending on the environment, even if the `pre-commit` is configured as described above, the git commit might trigger `npm run test` instead of `npm run lint`, which happened in my environment, resulting in unintended behavior. In such cases, you can check the `pre-commit` configuration file in the **.husky** directory to see if it contains `npm run test`. Changing this to `npm run lint` might resolve the issue. Also, the behavior and configuration method may change depending on the version of Husky, so if things don't work as expected, it's advisable to do some research on your own.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3p8l3o2o6h4gwo3e9qnl.png)



#Using Husky

`npm run lint` command analyzes and checks your code against defined standards to determine if there are any issues, informing you of the results. The main purpose of this article is to automate this command to run every time you commit with Git.

After setting up as described above, executing the `git commit` or `git push` commands will automatically trigger the configured hooks. For example, if you attempt to commit code with inappropriate coding style, the `pre-commit` hook will execute linting, and if there are issues, the commit will be aborted. This process helps maintain code quality while streamlining the development process.

```js
// TextInput.js
import React, { useState } from 'react';

function TextInput({ onSave }) {
  const [inputValue, setInputValue] = useState('');

  const handleChange = (event) => {
    setInputValue(event.target.value);
  };

  const handleSubmit = () => {
    onSave(inputValue);
    setInputValue('');
  };

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={handleChange}
        placeholder="Enter text"
      />
      <button onClick={handleSubmit}>Save</button>
    </div>
  );
}

export default TextInput;
```

For instance, let's see a js file above. Since the code is syntactically correct, performing `git add` and `git commit` will trigger a lint check, but since no errors are found, you can proceed to push the code.

Next, let's look at an example where it fails.

```js
// TextInput.js
import React, { useState } from 'react';

function TextInput({ onSave }) {
  const [inputValue, setInputValue] = useState('');

  const handleChange = (event) => {
    setInputValue(event.target.value);
  // missing closing brace for handleChange
  const handleSubmit = () => {
    onSave(inputValue);
    setInputValue(''); 
  };

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={handleChange}
        placeholder="Enter text"
      />
      <button onClick={handleSubmit}>Save</button>
    </div>
  );
}

export default TextInput;
```
In this code, I intentionally removed a closing brace, causing the code not to function as intended. When you attempt `git add` and `git commit` in this state, lint will notify you of the error, preventing the commit from being made. In this way, linting processes help identify violations of coding standards and potential errors, serving as a valuable tool in team-based environments like Git to inform of potential issues in advance and prevent problems before they occur.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/scu8q07zoadix0xqg7ea.png)



##Tip: npm run lint vs npm run test
If you're a beginner in testing, you might not initially grasp the clear distinction between `npm run lint` and `npm run test` (I certainly didn't).

`npm run lint` and `npm run test` target different aspects of the software development process, serving distinct purposes. Here's a casual summary of what they entail:

###npm run lint

**☕️ Purpose**: Checks the style and syntax of your code. Linting points out violations of coding conventions and potential errors, helping maintain a consistent code style. In JS, primary tools include ESLint, JSHint, etc.

**❓ What it does**: Identifies unused variables, inconsistencies in indentation, presence or absence of trailing semicolons, use of undefined variables, etc. This enhances code readability and maintainability, establishing a consistent coding style across the project and preventing minor errors or deviations from best practices.

###npm run test

**☕️ Purpose**: Ensures the application functions correctly. Testing verifies that the code works as intended and confirms that existing features remain unbroken during refactoring or adding new functionality. Popular options include Jest, Mocha, Jasmine, etc.

**❓ What it does**: Conducts unit tests, integration tests, end-to-end tests, etc, at various levels of the application to guarantee its quality, allowing early detection of bugs when adding new features or modifying existing code.

---

Husky can be used in combination with both commands, but they can be utilized differently depending on the goal. If the objective is to maintain code quality and style, you should run `npm run lint`. If the goal is to verify the functionality and quality of the developing application, then `npm run test` is appropriate.

Depending on the situation, you can choose between these two tests.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tc62uxt0hxipcm562qpe.png)


#Conclusion
This article comes from what I've learned so far. I'm still learning, so sorry if some parts are unclear for you! But I hope it helps if you're studying testing.

Thank you for reading, happy coding!