Testing custom Apollo hooks with React Testing Library
Tags: react, testing, hooks, tutorial
Published: 2020-03-29 01:04:17

---
title: Testing custom Apollo hooks with React Testing Library
published: true
description: Learn how to test a custom Apollo Query hook using React Testing Library.
tags: react, testing, hooks, tutorial
---
The other day, checking my code, I found a graphQL query that was repeating in many places. So I decided to put that query into a custom hook. That was the easy part, the hard part was to know how to test it. This is how I did it:

****
For this tutorial, we will be using this [Public GraphQL API for information about countries](https://github.com/trevorblades/countries) to fetch the country’s names and codes. This is the query: 

```graphql
query {
  countries {
    name
    code
  }
}
```

Now it’s time to create our custom hook, which it’s pretty straightforward.
The custom hook has two duties, the first one is to fetch the list of countries and the second one is to concatenate the country’s name and code.

```javascript
/**
 * Custom hook to fecth a list of countries
 *
 * @export
 * @param {Object} [options={}] Apollo Query Options
 * @returns {Object} Object with the the countries, loading, and error variables.
 */
export default function useCountries(queryOptions = {}) {
  const { loading, error, data } = useQuery(COUNTRIES, queryOptions);
  const countries = useMemo(() => {
    if (data) {
      return data.countries.map(country => `${country.name} - ${country.code}`);
    }
  }, [data]);
  return { loading, error, countries };
}
```

**Let’s see it in action**
```javascript
import React from "react";
import useCountries from "./hooks/useCountries";
import "./styles.css";

export default function App() {
  const { loading, error, countries } = useCountries();

  function renderCountryList(country, index) {
    return (
      <div className="list-item" key={index}>
        {country}
      </div>
    );
  }

  if (loading) {
    return <h2>Loading countries</h2>;
  }

  if (error) {
    return <h2>Uppps! There was an error</h2>;
  }

  return (
    <div className="App">
      <h1>List of Countries</h1>
      {countries.map(renderCountryList)}
    </div>
  );
}

```
{% codesandbox testing-custom-apollo-hook-ihkcb %}

## How to test it
Now comes the fun part, how to test that hook. We will be using [React Testing Library](https://github.com/testing-library/react-testing-library), [@apollo/react-testing](https://www.npmjs.com/package/@apollo/react-testing) to mock our Apollo Provider, and [react-hooks-testing-library
](https://github.com/testing-library/react-hooks-testing-library)

Let's start by creating our test cases and our mocked responses. We will be testing when it gets the list of countries successfully and when there is an error.

```javascript
import React from "react";
import useCountries, { COUNTRIES } from "./useCountries";

describe("useCountries custom hook", () => {
  // :: DATA :: 
  const mexico = {
    name: "Mexico",
    code: "MX"
  };
  const argentina = {
    name: "Argentina",
    code: "AR"
  };
  const portugal = {
    name: "Portugal",
    code: "PT"
  };

  // :: MOCKS :: 
  const countriesQueryMock = {
    request: {
      query: COUNTRIES
    },
    result: {
      data: {
        countries: [argentina, mexico, portugal]
      }
    }
  };

  const countriesQueryErrorMock = {
    request: {
      query: COUNTRIES
    },
    error: new Error("Ohh Ohh!")
  };


  it("should return an array of countries", async () => {});

  it("should return error when request fails", async () => {});
});

```
### First test case
The first test case checks that our hook returns an array of countries.

If you read the documentation of [react-hooks-testing-library
](https://github.com/testing-library/react-hooks-testing-library#readme), you know that we have to wrap our hook in renderHook:

```javascript
const { result, waitForNextUpdate } = renderHook(() => useCountries());
```
But because we are using **useQuery** from Apollo inside our hook, we need to use **MockedProvider** to wrap **renderHook** and Mock the responses. We can use the wrapper option for **renderHook** to do that.
```javascript
// Apollo Mocked Provider Wrapper
const wrapper = ({ children }) => (
  <MockedProvider>
    {children}
  </MockedProvider>
);

const { result, waitForNextUpdate } = renderHook(() => useCountries(), {
  wrapper
});
```
Because we will be using that code in both of our test cases, we can move it into a function

```javascript
function getHookWrapper(mocks = []) {
  const wrapper = ({ children }) => (
    <MockedProvider mocks={mocks} addTypename={false}>
      {children}
    </MockedProvider>
  );
  const { result, waitForNextUpdate } = renderHook(() => useCountries(), {
  wrapper
  });
  // Test the initial state of the request
  expect(result.current.loading).toBeTruthy();
  expect(result.current.error).toBeUndefined();
  expect(result.current.countries).toBeUndefined();
  return { result, waitForNextUpdate };
}
```
Now we test the first case.
```javascript
 it("should return an array of countries", async () => {
  const { result, waitForNextUpdate } = getHookWrapper([countriesQueryMock]);
  // Wait for the results
  await waitForNextUpdate();
  // We access the hook result using result.current
  expect(result.current.loading).toBeFalsy();
  expect(result.current.error).toBeUndefined();
  expect(result.current.countries).toEqual([
    `${argentina.name} - ${argentina.code}`,
    `${mexico.name} - ${mexico.code}`,
    `${portugal.name} - ${portugal.code}`
  ]);
});
```


### Second test case
The second test case it's pretty similar, but now we test when there's an error.

```javascript
it("should return error when request fails", async () => {
  // Similar to the first case, but now we use countriesQueryErrorMock
  const { result, waitForNextUpdate } = getHookWrapper([
    countriesQueryErrorMock
  ]);
  await waitForNextUpdate();
  expect(result.current.loading).toBeFalsy();
  expect(result.current.error).toBeTruthy();
  expect(result.current.countries).toBeUndefined();
});
```

As you can see, it's not that hard once you know how to do it. [Here is the code](https://codesandbox.io/s/testing-custom-apollo-hook-077e9) in case you need it.

Thanks for reading.