Skip to content

How to test RefreshControl "pull-to-refresh" behavior? #809

@flo-sch

Description

@flo-sch

Environment

  • react-native: v0.65.1
  • jest: v27.1.0
  • @testing-library/react-native: v7.2.0

Ask your Question

I have a component running a GraphQL query (ApolloClient), and rendering a with a that triggers the query's refetch function:

// MyComponent.tsx
import React from 'react';
import { ActivityIndicator, RefreshControl, ScrollView, ScrollViewProps, Text } from 'react-native';
import { useQuery, gql } from '@apollo/client';

export const TEST_QUERY = gql`
  query TestQuery {
    test {
      placeholder
    }
  }
`;

export interface TestQueryResponse {
  test: {
    placeholder: string;
  };
}

const MyComponent: React.FC<ScrollViewProps> = (props) => {
  const { data, loading, refetch } = useQuery<TestQueryResponse>(TEST_QUERY);

  return (
    <ScrollView
      {...props}
      refreshControl={<RefreshControl refreshing={loading} onRefresh={refetch} />}
    >
      {loading ? (
        <ActivityIndicator accessibilityLabel='loading' />
      ) : data?.test ? (
        <Text>{data.test.placeholder}</Text>
      ) : null}
    </ScrollView>
  );
};

export default MyComponent;

Now, I would like to test the "refetch" behavior.
I thought I would try to fire a "refetch" event on the ScrollView:

// MyComponent.test.tsx
import 'react-native';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { fireEvent, render } from '@testing-library/react-native';

import MyComponent, { TEST_QUERY } from './MyComponent';

describe('MyComponent', () => {
  test('refetch the query when pulled', async () => {
    // I have setup a custom render method using <MockedProvider /> as a wrapper,
    // This is a simplified inline version of my case:
    const { findByText, getByTestId, getByA11yLabel } = render(
      <MockedProvider
        addTypename={false}
        mocks={[
          {
            request: {
              query: TEST_QUERY,
              variables: {},
            },
            result: {
              data: {
                test: {
                  placeholder: 'Hello World',
                },
              },
            },
          },
        ]}
      >
        <MyComponent testID='my-component' />
      </MockedProvider>,
    );

    // wait for initial query to be done loading
    await findByText('Hello World');

    // attempt to simulate a "pulling" event
    fireEvent(getByTestId('my-component'), 'refresh');
    // --> No handler function found for event: "refresh"

    // expect the <ActivityIndicator /> to be rendered
    expect(getByA11yLabel('loading')).toBeDefined();
  });
});

But this test case throws an error on the "fireEvent" line:

No handler function found for event: "refresh"

Am I doing something wrong with the API here?
Should I mock something specifically (like <RefreshControl /> itself for this scenario?
(or is there a better way to assert that behavior?)

I did not find a list of "events" that can be fired, but from what I understand of the fireEvent API, it seems to expect an onRefresh handler to exists on the target element.
Which indeed is not the case here, since the onRefresh handler is defined on the <RefreshControl /> component itself.

If the snippets are not enough, I am happy to provide a repository or such?

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions