10

I'm using React Test Renderer with Jest to test my React Native app.

Here is a simple code example of what I'm doing:

it('renders one text', () => {
  const text = 'bar';
  const instance = renderer.create(
    <View>
      <Text testID="foo">{text}</Text>
    </View>
  ).root;
  expect(instance.findAllByProps({ testID: 'foo' }).length).toEqual(1);
});

it('renders two texts', () => {
  const text = 'bar';
  const instance = renderer.create(
    <View>
      <Text testID="foo">{text}</Text>
      <Text testID="foo">{text}</Text>
    </View>
  ).root;
  expect(instance.findAllByProps({ testID: 'foo' }).length).toEqual(2);
});

The first test fails saying:

Expected: 1
Received: 2

And the second test also fails:

Expected: 2
Received: 4

Why does react test renderer using findAllByProps find double the instances?

PS: As a sanity check I also tried findByProps which works:

it('renders one text', () => {
  const text = 'bar';
  const instance = renderer.create(
    <View>
      <Text testID="foo">{text}</Text>
    </View>
  ).root;
  expect(instance.findByProps({ testID: 'foo' }).props.children).toEqual(text);
});
J. Hesters
  • 13,117
  • 31
  • 133
  • 249

2 Answers2

8

There is unresolved issue on react-native

Currently the only work-around is:

const findAllByTestID = (instance) => instance.findAll(el => el.props.testID === 'foo' && el.type === 'Text');

expect(findAllByTestID(instance).length).toEqual(2);
Ilarion Halushka
  • 2,083
  • 18
  • 13
  • 1
    Thank you for linking the issue. Very frustrating that Facebook ignores this. – J. Hesters Apr 23 '19 at 11:10
  • for some components it doesn't work. for example if I wanted to find TouchableOpacity then I had to modify code a bit: const findAllByTestID = (instance) => instance.findAll(el => el.props.testID === 'foo' && el.type.displayName === 'TouchableOpacity'); expect(findAllByTestID(instance).length).toEqual(2); – Jan Tumanov Jun 03 '20 at 05:11
1

I've encountered the same issue when testing ReactJS component.

I've taken a deeper look into it and it turns out that under certain conditions findAllByProps may return two TestInstances matching the query, however those do not represent the same entity. The first entity represents the props passed to the component, the second the actual component with it's whole structure and props applied.

In my case I had been querying for components with a certain className. Typically the constructed component would have it's className made of several aggregated classes (the ones we pass via props and ones we apply internally), however I had mocked the component and the mock used only the class which was passed via props. This way I ended up with two entities having the same single-word className, the first simply stored the props and className was one of them, the second represented the mock which handled the property by passing it directly to the element making it's className equal to the props.className.

I found that mechanism out by serialising the TestInstance object to a JSON.

Yyyeey
  • 55
  • 9