React-native-testing-library: Alert.alert

Created on 14 Aug 2019  路  6Comments  路  Source: callstack/react-native-testing-library

Looking for a way to test Alert.alert 'onPress' is that even possible?

feature request

Most helpful comment

sure, use jest.spyOn(Alert, 'alert')

All 6 comments

sure, use jest.spyOn(Alert, 'alert')

But then the code coverage for onPress is going to be zero....

If you call fireEvent.press, the onPress handler should be called. And jest.spyOn doesn't change implementation by default, so all the code inside will be called

I couldn't get fireEvent.press to work for me. I ended up with this helper function for testing alerts (WARNING!! Not thoroughly tested yet):

/* global jest */
import {Alert, AlertButton} from 'react-native';

interface MockAlertActions {
  pressAlertButton(text: string): Promise<void>;
}

type MockedCall = Readonly<[string, string, ReadonlyArray<AlertButton>]>;

export default function spyOnAlert(): MockAlertActions {
  jest.spyOn(Alert, 'alert');

  let dismissedCalls: ReadonlyArray<MockedCall> = [];
  return {
    async pressAlertButton(text: string): Promise<void> {
      const unhandledCalls = Alert.alert.mock.calls.slice();
      dismissedCalls.forEach(call => {
        // Only want to remove the first instance in case there are multiple identical calls
        const index = unhandledCalls.indexOf(call);
        dismissedCalls = dismissedCalls.filter((_, i) => i !== index);
      });
      if (unhandledCalls.length === 0) {
        throw new Error('No pending calls to alert');
      }
      const mostRecentCall = unhandledCalls[unhandledCalls.length - 1];
      // TODO: Handle default button case, when no buttons provided
      const targetButton = mostRecentCall[2].find(
        (button: AlertButton) => button.text === text
      );
      if (!targetButton) {
        throw new Error(`No button with text ${text}`);
      }
      if (targetButton.onPress) {
        await targetButton.onPress();
      }
      dismissedCalls = [...dismissedCalls, mostRecentCall];
    }
  };
}

Which you would use like so:

const { pressAlertButton } = spyOnAlert();

const rendered = render(<MyComponent />);

await act(async () => {
  await fireEvent.press(rendered.getByLabelText('DELETE'));
  await pressAlertButton('Yes, delete this item');
});

@danielholmes nice workaround!

If you call fireEvent.press, the onPress handler should be called. And jest.spyOn doesn't change implementation by default, so all the code inside will be called

@thymikee does this library provide a better way of simulating interaction with react-native alerts than what Daniel posted? I'm doing something like Alert.alert.mocks.call[0][2][1].onPress() which does not feel very friendly either

@sbalay Alert is a native module. fireEvent only supports native views/components that exist in a view hierarchy.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

maitriyogin picture maitriyogin  路  7Comments

mym0404 picture mym0404  路  11Comments

ghost picture ghost  路  7Comments

acollazomayer picture acollazomayer  路  3Comments

thymikee picture thymikee  路  9Comments