Integration Tests with Relay

sibelius

Sibelius Seraphini

Posted on March 21, 2023

Integration Tests with Relay

What to test in the frontend? 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

const App = () => {
  const response = useLazyLoadQuery<AppQuery>(
    graphql`
      query AppQuery {
        me {
          name
        }
      }
    `,
    {},
    {},
  );

  return (
    <span>{response.me.name}</span>
  )
}
Enter fullscreen mode Exit fullscreen mode

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.

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

const environment = createMockEnvironment();
Enter fullscreen mode Exit fullscreen mode

We then render our component using @testing/library

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

render(<App />);
Enter fullscreen mode Exit fullscreen mode

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

assertOperation(environment, 'AppQuery', {});
Enter fullscreen mode Exit fullscreen mode

We can resolve/mock the request like this:

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

resolveMostRecentOperation(environment, mockResolvers);
Enter fullscreen mode Exit fullscreen mode

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

await waitLoading();
Enter fullscreen mode Exit fullscreen mode

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

assertNoPendingOperations(environment);
Enter fullscreen mode Exit fullscreen mode

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

expect(screen.getByText('Woovi')).toBeTruthy();
Enter fullscreen mode Exit fullscreen mode

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

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);
};
Enter fullscreen mode Exit fullscreen mode

resolveMostRecentOperation - mock the most recent operation

export const resolveMostRecentOperation = (
  environment: RelayMockEnvironment,
  customMockResolvers: MockResolvers,
) => {
  act(() => {
    environment.mock.resolveMostRecentOperation((operation) => {     
      return MockPayloadGenerator.generate(operation, customMockResolvers);
    });
  });
};
Enter fullscreen mode Exit fullscreen mode

waitLoading - await loading element to be removed

export const waitLoading = async () => {
  await waitForElementToBeRemoved(screen.queryByTestId('loading'), {
    timeout: 20000,
  });
}
Enter fullscreen mode Exit fullscreen mode

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 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!


Photo by Roman Mager on Unsplash

💖 💪 🙅 🚩
sibelius
Sibelius Seraphini

Posted on March 21, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Integration Tests with Relay
testing Integration Tests with Relay

March 21, 2023