Building & Testing React Hooks with NPM
Tags: react, typescript, npm, tutorial
Published: 2023-09-12 07:46:48


## Table of Contents

1. [Introduction](#introduction)
2. [Setting Up the Project](#setting-up-the-project)
3. [Rollup Configuration](#rollup-configuration)
4. [Create Our Hook](#create-our-hook)
5. [Testing](#testing)
6. [Conclusion](#conclusion)

#Introduction

This tutorial aims to guide you through setting up an NPM package specifically designed for React projects. You'll learn how to create and test a custom hook as well.

Links:

[Previous NPM tutorial](https://dev.to/martinpersson/create-and-publish-your-first-npm-package-a-comprehensive-guide-3l0a)

[Repo for this tutorial](https://github.com/Mumma6/react-hook-tutorial)

**What you will learn:**

- **NPM Package Setup:** Steps to create an NPM package for React projects or custom component libraries.
- **Custom Form Hook Creation:** How to build a simple but extensible custom hook.
- **Testing in React:** Utilize Jest and React Testing Library to test React components and hooks.

This tutorial builds upon a previous guide where we created a basic NPM package. If you haven't checked that out yet, you might want to start [there](https://dev.to/martinpersson/create-and-publish-your-first-npm-package-a-comprehensive-guide-3l0a).


#Setting up the project

Firstly, ensure you have Node and npm installed. To kickstart your project, clone the starter code from the GitHub repository:

`git clone https://github.com/Mumma6/npm-package-tutorial`

Navigate into the project directory:

`cd npm-package-tutorial/`

After you've cloned the starter code, you'll want to set up your own GitHub repository. Here is how to do that:

1. **Create a New Repository on GitHub:**
    - Go to your GitHub account and create a new repository.
    - Do not initialize the new repository with a README, `.gitignore`, or license. This empty repository will be linked to your local project.

2. **Change the Remote URL:**
    - Open your terminal and navigate to your local project directory.
    - Type `git remote -v` to list the current configured remote repository for your fork.
    - Run `git remote set-url origin YOUR-NEW-REPOSITORY-URL.git` to change the repository URL to your newly created repository.

3. **Verify the Remote URL:**
    - Again, run `git remote -v` to verify that the remote URL has been updated.

4. **Push to New Repository:**
    - Run `git push -u origin main` (or `git push -u origin master` depending on your default branch name) to push your local code to your own GitHub repository.


After these steps, your local repository will be linked to your new GitHub repository, and you can start making commits and pushing changes.

> **Note:** If you plan to publish this package, make sure to change the name in your `package.json` to avoid conflicts with existing packages.

##Install Dependencies

Install React and React DOM. We'll use version 17 to maintain compatibility with React Testing Library:

`npm i react@17 react-dom@17 @types/react@17 @types/react-dom@17`

##Rollup Configuration

Update your Rollup configuration to include React and React DOM as external dependencies:

```Typescript
const typescript = require("rollup-plugin-typescript2")
const pkg = require("./package.json")

module.exports = {
  input: 'src/index.ts',
  output: [
    {
      file: pkg.main,
      format: 'cjs',
      exports: 'named',
      sourcemap: true,
      strict: false
    }
  ],
  plugins: [
    typescript()
  ],
  external: ['react', 'react-dom']
}
```

##Create our hook

Let's create our custom form hook. For simplicity, the hook will be minimal:

In you index.ts file create this.

```Typescript
import { useState } from "react"

export function useForm(formData: any) {
  const [values, setValues] = useState(formData)

  return {
    values,
    setValues,
  }
}
```

##Testing

For testing we are going to use Jest and React Testing Library. 

**Jest**

Jest is a popular testing framework in the JavaScript ecosystem that comes with a lot of features out-of-the-box, like mocking, assertions, and snapshot testing. It's widely used in the React community, partly because create-react-app includes it by default.

**React Testing Library**

React Testing Library is built on top of Jest and provides a set of utilities to test React components. It encourages better testing practices and makes it easier to find elements and interact with them in a way that resembles how the end-user would.

**Testing Hooks with @testing-library/react-hooks**

While React Testing Library primarily focuses on React components, @testing-library/react-hooks is an extension that allows us to test React hooks in isolation from the components that use them. This is particularly useful for your tutorial since you're building a hook.

**The renderHook and act Functions**

In our test example, we use two primary functions: renderHook and act.

- **renderHook:** This function "renders" your hook in a testing environment, much like render does for components. It returns an object that contains the hook's return value, among other things.
- **act:** When you need to interact with your hook (for example, to change a state variable), wrap those interactions in an act function to ensure that all updates related to these actions have been processed and applied to the DOM before you make any assertions.

To test our hook, install the required testing libraries:

`npm i @testing-library/react-hooks @testing-library/jest-dom jest-environment-jsdom`

Create a file called setupTests.ts and add the following line:

```Typescript
import "@testing-library/jest-dom"
```

Update your Jest configuration to include the new environment and setup file:

```Typescript
module.exports = {
  preset: 'ts-jest',
  testMatch: ["**/__tests__/**/*.test.ts"],
  testEnvironment: 'jest-environment-jsdom',
  setupFilesAfterEnv: ['./setupTests.ts'],
};
```

Now, create a folder called `__tests__` and add a test file `index.test.ts` with the following content:

```Typescript
import { renderHook, act } from "@testing-library/react-hooks"
import { useForm } from "../src/index"

describe("useFormHook", () => {
  test("should update form values", () => {
    const { result } = renderHook(() => useForm({ name: "", email: "" }))

    act(() => {
      result.current.setValues({ name: "John", email: "john@example.com" })
    })

    expect(result.current.values).toEqual({ name: "John", email: "john@example.com" })
  })
})
```

You can now run the test with `npm test`

#Conclusion

Congratulations on making it to the end of this tutorial! You've successfully built an NPM package tailored for React projects, complete with a custom hook. Not only did you develop the hook, but you also ensured its robustness by writing tests using Jest and React Testing Library. This not only amplifies the quality of your package but also provides peace of mind when integrating it into larger, more complex systems.

What's more, your package is now ready for publishing on NPM, opening up the possibility for other developers to make use of your work in their projects. If you're unsure about how to publish your package, you can refer back to my previous [guide](https://dev.to/martinpersson/create-and-publish-your-first-npm-package-a-comprehensive-guide-3l0a#publishing-the-package) for a detailed walk-through on publishing it to NPM.

As a next step, you might consider adding more features to your custom hook, or perhaps even expand it into a full-fledged React component library. The possibilities are endless, and the foundations laid in this tutorial will serve you well as you continue on your journey in React development.