Integration Tests with Relay
Tags: testing, relay, react
Published: 2023-03-21 11:15:13

[What to test in the frontend?](https://dev.to/woovi/what-to-test-in-the-frontend-50a) was a success.

In this article, I will show some practical examples of how to test Frontend when using React and Relay.

## Asserting and mocking GraphQL Requests using Relay

When testing a React app that uses Relay, we need to mock GraphQL requests that would be sent to our GraphQL server. We don't want to reach the real server, as we are doing integration tests, and e2e is very slow.

We prefer to reduce the scope of our test, and assume the GraphQL server will behave correctly, so we can focus on test frontend behavior.

Let's test this `App` component

```jsx
const App = () => {
  const response = useLazyLoadQuery<AppQuery>(
    graphql`
      query AppQuery {
        me {
          name
        }
      }
    `,
    {},
    {},
  );
  
  return (
    <span>{response.me.name}</span>
  )
}
```

This test will mock the `AppQuery` GraphQL request, it will await the request to be resolved by Relay, and it will finally assert the DOM has the value returned in the `me { name }` field.

Firstly, we need to create a mock environment, that will let us mock GraphQL requests easily.

```jsx
import { createMockEnvironment } from 'relay-test-utils';

const environment = createMockEnvironment();
```

We then render our component using `@testing/library` 

```jsx
import { render } from '@testing-library/react';

render(<App />);
```

Before asserting anything in the DOM, we need to assert and mock the `AppQuery` request

We can assert that `App` component made the `AppQuery` request like this

```jsx
assertOperation(environment, 'AppQuery', {});
```

We can resolve/mock the request like this:

```jsx
const mockResolvers = {
  User: () => ({ name: 'Woovi' }),
};

resolveMostRecentOperation(environment, mockResolvers);
```

We then await the loading View to be removed from the DOM, so we know the request was resolved

```jsx
await waitLoading();
```

We validate that there are no more pending requests to be mocked

```jsx
assertNoPendingOperations(environment);
```

And we finally assert the DOM has the value that was mocked in our request

```jsx
expect(screen.getByText('Woovi')).toBeTruthy();
```

## Relay test helpers
The above code uses some helpers to make testing Relay more declarative, lets show how they are implemented here:

*assertOperation* - assert operation name and variables
```jsx
type OperationType = {
  variables: Record<string, unknown>;
};

export const assertOperation = <T extends OperationType>(
  environment: RelayMockEnvironment,
  name: string,
  variables: T['variables'] = {},
) => {
  const queryOperation = environment.mock.getMostRecentOperation();

  const operationName = getOperationName(queryOperation);
  const operationVariables = getOperationVariables(queryOperation);

  expect(operationName).toBe(name);
  expect(operationVariables).toEqual(variables);
};
```

*resolveMostRecentOperation* - mock the most recent operation
```jsx
export const resolveMostRecentOperation = (
  environment: RelayMockEnvironment,
  customMockResolvers: MockResolvers,
) => {
  act(() => {
    environment.mock.resolveMostRecentOperation((operation) => {     
      return MockPayloadGenerator.generate(operation, customMockResolvers);
    });
  });
};
```

*waitLoading* - await loading element to be removed
```jsx
export const waitLoading = async () => {
  await waitForElementToBeRemoved(screen.queryByTestId('loading'), {
    timeout: 20000,
  });
}
```


## In Conclusion
Testing Frontend with React and Relay can add some complexity to your tests, but if you create declarative helpers it can be very intuitive and easy.

---
Woovi
[Woovi](https://www.woovi.com) is a Startup that enables shoppers to pay as they like. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.

If you want to work with us, we are [hiring](https://woovi.com/jobs/)!

---
Photo by <a href="https://unsplash.com/@roman_lazygeek?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Roman Mager</a> on <a href="https://unsplash.com/photos/5mZ_M06Fc9g?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>