Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 713
J. Hesters Avatar asked Dec 03 '18 08:12

J. Hesters


People also ask

Can I manually trigger a state change when testing using react testing library?

You can not do that with RTL. You are not supposed to interact with the internals of your components.

How do you test select options in react testing library?

Here's how you can do it: // highlight-start jest. mock("react-select", () => ({ options, value, onChange }) => { function handleChange(event) { const option = options. find( (option) => option.


1 Answers

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.

like image 146
fgkolf Avatar answered Oct 09 '22 10:10

fgkolf