Search code examples
javascriptreact-nativejestjsreact-native-testing-libraryreact-native-ui-kitten

Finding the buttons on the screen that have no text for the test


I am trying to write the tests for the NavBar component (using react-native-testing-library) that has several buttons that are basically just icons (using ui-kitten for react native). So I can't get these buttons by text (as there is none) but other methods didn't work for me either (like adding accesibilityLabel or testID and then getting by the label text / getting by test ID). Any ideas what I am doing wrong?

// NavBar.tsx
import React from 'react';
import {View, StyleSheet} from 'react-native';
import {HomeBtn, SaveBtn} from '../components/buttons';
import UserSignOut from './UserSignOut';

const NavBar = ({
  navigation,
  pressHandlers,
}) => {
  return (
    <View style={styles.navBar}>
      <View>
        <HomeBtn navigation={navigation} />
        <SaveBtn pressHandler={pressHandlers?.saveBtn ?? undefined} />
      </View>
      <UserSignOut />
    </View>
  );
};
export default NavBar;

// HomeBtn.tsx
import React from 'react';
import {Button} from '@ui-kitten/components';
import {HomeIcon} from '../shared/icons';
import styles from './Btn.style';

export const HomeBtn = ({navigation}: any) => {
  return (
    <Button
      accesibilityLabel="home button"
      style={styles.button}
      accessoryLeft={props => HomeIcon(props, styles.icon)}
      onPress={() => navigation.navigate('Home')}
    />
  );
};

// NavBar.test.tsx
import React from 'react';
import {render, screen} from '@testing-library/react-native';
import * as eva from '@eva-design/eva';
import {RootSiblingParent} from 'react-native-root-siblings';
import {EvaIconsPack} from '@ui-kitten/eva-icons';
import {ApplicationProvider, IconRegistry} from '@ui-kitten/components';
import NavBar from '../../containers/NavBar';

describe('NavBar', () => {
  const navBarContainer = (
    <RootSiblingParent>
      <IconRegistry icons={EvaIconsPack} />
      <ApplicationProvider {...eva} theme={eva.light}>
        <NavBar />
      </ApplicationProvider>
    </RootSiblingParent>
  );
  it('should render the buttons', async () => {
    render(navBarContainer);
    // this test fails (nothing is found with this accesibility label)
    await screen.findByLabelText('home button');
  });
});


Solution

  • Query predicate

    The recommended solution would be to use:

    getByRole('button', { name: "home button" })
    

    As it will require both the button role, as well as check accessibilityLabel with name option.

    Alternative, but slightly less expressive way would be to use:

    getByLabelText('home button')
    

    This query will only check accessibilityLabel prop, which also should work fine.

    Why is query not matching

    Since you're asking why the query is not working, that depends on your test setup. It seems that you should be able to use sync getBy* query and do not need to await findBy* query, as the HomeBtn should be rendered without waiting for any async action.

    What might prevent that test from working could be incorrect mocking of any of the wrapping components: RootSiblingParent, ApplicationProvider, they might be "consuming" children prop without rendering it. In order to diagnose the issue you can use debug() function from RNTL to inspect the current state of rendered components. You can also run your tests on render(<NavBar />) to verify that.