react-nativereact-native-testing-library

Why doesn't ref.current.focus() work when running tests via the @testing-library/react-native libary?


I'm attempting to write some tests for my react native app. A component in my app focuses a TextInput after a parent Pressable receives a press. I'm using a ref to identify and focus the TextInput element.

My desired functionality works just fine when running my app through expo, but my test is failing because it seems that the onFocus event is not being called.

Why isn't ref.current.focus() being called when running tests via the @testing-library/react-native library?

Here's my code:

Foo.js

import {Pressable, TextInput} from "react-native";
import {useRef} from "react";

const Foo = (props) => {
    const inputRef = useRef()

    return (
        <Pressable testID={"pressable"} onPress={() => inputRef.current.focus()}>
            <TextInput ref={inputRef} testID={"input"} onFocus={props.onFocus} />
        </Pressable>
    )
}

export default Foo;

Foo.test.js

import { render, screen, fireEvent } from '@testing-library/react-native';
import Foo from "./foo";

test('onFocus is called after press', () => {
    const mockFocus = jest.fn();
    render(<Foo onFocus={mockFocus} />)
    // fireEvent(screen.getByTestId("input"), 'focus');
    fireEvent.press(screen.getByTestId("pressable"));
    expect(mockFocus).toHaveBeenCalled()
});

This test fails with the following message:

Error: expect(jest.fn()).toHaveBeenCalled()

Expected number of calls: >= 1
Received number of calls:    0

Solution

  • I created an issue on the RNTL GitHub page and received a response from a contributor. Copying and pasting here for easy reference for anyone who might stumble upon this thread.

    This is expected as React Test Renderer which we use for rendering does not support refs. Check #1006 for more details.

    Since the behaviour of focus() triggering onFocus event would probably involve roundtrip to native side (from JS side), then you actually cannot test such behaviour using RNTL as we do not run native code (see here for details).

    That leaves you with following options:

    1. Call fireEvent.focus to manually trigger onFocus on relevant TextInput. Recommended in case focus assertion would be a part of a step in a bigger test.
    2. Use createNodeMock to pass ref creating function to render method, More details here. Recommended in case you just want to assert pressing button triggers onFocus.