React Native Testing Library doesn't find text even though its in debug
Asked Answered
I

1

11

I'm building a React Native application with TypeScript. I'm using React Native Testing Library for my component tests.

I have a simple component that renders two clickable icons and a text. It's a counter that can increment and decrement the number.

import React, { PureComponent } from "react";
import { Text, TouchableOpacity, View } from "react-native";
import { Button, Icon } from "react-native-elements";
import { getIconName } from "../../services/core";
import styles from "./styles";

export interface AmountButtonProps {
  amount: number;
  onDecrement: () => void;
  onIncrement: () => void;
  size: "small" | "large";
}

export class AmountButtons extends PureComponent<AmountButtonProps> {
  render() {
    const { amount, onDecrement, onIncrement, size } = this.props;
    const fontSize = size === "small" ? 14 : 26;
    const minusDisabled = amount <= 1;
    const plusDisabled = amount >= 25;
    return (
      <View style={styles.container}>
        <Icon
          containerStyle={[
            styles[size],
            styles.iconContainer,
            styles.minusIcon,
            minusDisabled && styles.disabled
          ]}
          onPress={onDecrement}
          type="ionicon"
          name={getIconName("remove")}
          disabled={minusDisabled}
          disabledStyle={[styles.iconDisabled, styles.disabled]}
          size={fontSize}
          component={TouchableOpacity}
        />
        <View style={[styles[size], styles.amountContainer, styles.iconContainer]}>
          <Text style={{ fontSize }}>{amount}</Text>
        </View>
        <Icon
          containerStyle={[
            styles[size],
            styles.iconContainer,
            styles.addIcon,
            plusDisabled && styles.disabled
          ]}
          onPress={onIncrement}
          type="ionicon"
          name={getIconName("add")}
          disabled={plusDisabled}
          disabledStyle={styles.iconDisabled}
          color="white"
          size={fontSize}
          component={TouchableOpacity}
        />
      </View>
    );
  }
}

export default AmountButtons;

I wanted to write a simple unit test to see if the user can see the amount. Here is what I wrote.

import React from "react";
import { debug, fireEvent, render } from "react-native-testing-library";
import { getIconName } from "../../services/core";
import AmountButtons, { AmountButtonProps } from "./AmountButtons";

const createTestProps = (props?: object): AmountButtonProps => ({
  amount: 1,
  onDecrement: jest.fn(),
  onIncrement: jest.fn(),
  size: "large",
  ...props
});

describe("AmountButtons", () => {
  const props = createTestProps();
  const { getByText, getByProps } = render(<AmountButtons {...props} />);

  it("displays the amount", () => {
    debug(<AmountButtons {...props} />);
    expect(getByText(props.amount.toString())).toBeDefined();
  });
});

The problem is this test throws the error:

● AmountButtons › displays the amount

    Component not found.

      18 |   it("displays the amount", () => {
      19 |     debug(<AmountButtons {...props} />);
    > 20 |     expect(getByText(props.amount.toString())).toBeDefined();
         |            ^
      21 |   });
      22 |
      23 |   it("calls onIncrement", () => {

      at Object.it (app/components/AmountButtons/AmountButtons.test.tsx:20:12)

Even though in the output of debug I can see the amount being rendered:

...
       }
      >
        <Text
          style={
            Object {
              "fontSize": 26,
            }
          }
        >
          1
        </Text>
      </View>
      <Themed.Icon
...

What is going on here? Why does React Testing Library not see this text? How can I test this?

Iolenta answered 3/12, 2018 at 8:28 Comment(0)
A
1

The problem is that rendering your component with RTL's render method does not happen in sync with the test case. So when the it block runs you can't be sure that this line of code

const { getByText, getByProps } = render(<AmountButtons {...props} />);

has run and getByText is bound properly.

In order to solve this you can:

  1. move rendering inside it block:
describe("AmountButtons", () => {
  const props = createTestProps();

  it("displays the amount", () => {
    const { getByText, getByProps } = render(<AmountButtons {...props} />);
    expect(getByText(props.amount.toString())).toBeDefined();
  });
});
  1. move rendering inside a beforeEach/before block:
describe("AmountButtons", () => {
  const props = createTestProps();
  let getByText, getByProps;

  beforeEach(() => {
    ({ getByText, getByProps }) = render(<AmountButtons {...props} />);
  })

  it("displays the amount", () => {
    expect(getByText(props.amount.toString())).toBeDefined();
  });
});

but in this case you have to keep in let variables all the getBy helpers.

Affixation answered 17/10, 2021 at 17:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.