Batman
Batman

Reputation: 6373

Component not rendering when testing with react-relay

I'm trying to test a component using React Relay and React Testing Library

// @flow
import { Suspense } from 'react';
import {
  RelayEnvironmentProvider,
  useLazyLoadQuery,
  graphql,
} from 'react-relay/hooks';
import { createMockEnvironment, MockPayloadGenerator } from 'relay-test-utils';
import { render, cleanup, screen, act } from '@testing-library/react';
import Banner from './Banner';
jest.mock('react-router-dom', () => ({
  useLocation: jest.fn(() => ({
    pathname: 'some-path',
  })),
}));
describe('<Banner>', () => {
  let mockEnvironment;
  const defaultMockResolver = {
    // We do not want a consistent return in this case since we want the default MockPayloadGenerator behavior for most fields
    // See https://relay.dev/docs/en/testing-relay-components#mock-resolver-context
    // eslint-disable-next-line consistent-return
    String(context) {
      if (context.name === 'viewer') {
        return {id: 111 };
      }
    },
  };
  beforeEach(() => {
    mockEnvironment = createMockEnvironment();
  });
  afterEach(cleanup);
  it('renders - snapshot', () => {
    mockEnvironment = createMockEnvironment();
    const RelayComponent = () => {
      const data = useLazyLoadQuery(
        graphql`
          query BannerTestQuery @relay_test_operation {
            viewer {
              # Spread the fragment you want to test here
              ...Banner_viewer
            }
          }
        `,
        {},
      );
      return <Banner viewer={data.myData} />;
    };
    render(
      <RelayEnvironmentProvider environment={mockEnvironment}>
        <Suspense fallback="Loading...">
          <RelayComponent />
        </Suspense>
      </RelayEnvironmentProvider>,
    );
    // expect(container.firstChild).toMatchSnapshot();
    act(() => {
      mockEnvironment.mock.resolveMostRecentOperation(operation =>
        MockPayloadGenerator.generate(operation, defaultMockResolver),
      );
    });
    screen.debug();
  });
});

The test however does not load the component with the mocked data but only returns the Suspense fallback

Upvotes: 2

Views: 1112

Answers (2)

Syed Muhammad Ahmad
Syed Muhammad Ahmad

Reputation: 438

Trying to add more detail here. Agree with Tassilo Singhammer answer. Before rendering, you need to invoke queueOperationResolver. Inside the queueOperationResolver you need to generate mock payload via MockPayloadGenerator. Here is the bear minimum example:

test('Data Render', () => {
    const environment = createMockEnvironment();

    environment.mock.queueOperationResolver((operation:any) =>
        MockPayloadGenerator.generate(operation),
      );
      
    const renderer = ReactTestRenderer.create( 
        <RelayEnvironmentProvider environment={environment}>
            <Suspense fallback={<div data-testid="loading">Loading... </div>}>
                <HelmetProvider>
                    <MemoryRouter>
                        <Home /> // Your component with the useLazyLoadQuery or a QueryRenderer
                    </MemoryRouter>
                </HelmetProvider>
            </Suspense>
      </RelayEnvironmentProvider>);

    // At this point operation will be resolved
    // and the data for a query will be available in the store
    expect(
        renderer.root.find(node => node.props['data-testid'] === 'yourButton'),
    ).toBeDefined();
  });

In my case, I need HelmetProvider and MemoryRouter. You may skip, if not needed. Here is the official documentation: https://relay.dev/docs/guides/testing-relay-components/#example-with-queueoperationresolver

Upvotes: 1

Tassilo Singhammer
Tassilo Singhammer

Reputation: 31

This actually works: https://githubmemory.com/repo/facebook/relay/issues/3276

It is important, that you call queueOperationResolver before rendering the component.

Upvotes: 1

Related Questions