I have a component. It has a button. Upon pressing the button, I am changing the style of the button text (color) using setState function. When I am testing the changed component, the test is failing because the change happens asynchronously. I want to do something as is given here (https://testing-library.com/docs/dom-testing-library/api-async/)
const button = screen.getByRole('button', { name: 'Click Me' })
fireEvent.click(button)
await screen.findByText('Clicked once')
fireEvent.click(button)
await screen.findByText('Clicked twice')
But rather than waiting for the text to change. I want to wait for the text color to change. Thanks
This is the code for my button
<Button onPress = {() => {this.setState({state : 1});}}>
<Text style = {style}>Button Text</Text>
</Button>
So when this button is pressed. state is set to 1. And in render :
if(this.state.state === 1) style = style1
else style = style2;
But it can be seen from logs that render is called after the test checks for the styles. So How can I wait for the render to complete before checking if the font color has been changed?
Here is the testing code
test('The button text style changes after press', () => {
  const {getByText} = render(<Component/>);
  fireEvent.press(getByText('button'));
  expect(getByText('button')).toHaveStyle({
    color : '#ffffff'
  });
})
                It looks like you have a custom button, not a native button. I'm guessing your component is something like this:
import React from "react";
import {Text, TouchableOpacity} from "react-native";
const Button = ({pressHandler, children}) => (
  <TouchableOpacity onPress={pressHandler}>
    {children}
  </TouchableOpacity>
);
const ColorChangingButton = ({text}) => {
  const [color, setColor] = React.useState("red");
  const toggleColor = () => setTimeout(() => 
    setColor(color === "green" ? "red" : "green"), 1000
  );
  return (
    <Button pressHandler={toggleColor}>
      <Text style={{color}}>{text}</Text>
    </Button>
  );
};
export default ColorChangingButton;
If so, you can test it with waitFor as described here:
import React from "react";
import {
  fireEvent, 
  render,
  waitFor,
} from "@testing-library/react-native";
import ColorChangingButton from "../src/components/ColorChangingButton";
it("should change the button's text color", async () => {
  const text = "foobar";
  const {getByText} = render(<ColorChangingButton text={text} />);
  fireEvent.press(getByText(text));
  await waitFor(() => {
    expect(getByText(text)).toHaveStyle({color: "green"});
  });
});
For a native button which has rigid semantics for changing colors and doesn't accept children, instead using title="foo", a call to debug() shows that it expands to a few nested elements. You can use
const text = within(getByRole("button")).getByText(/./);
expect(text).toHaveStyle({color: "green"});
inside the waitFor callback to dip into the button's text child and wait for it to have the desired color.
I used the same packages/versions for this post as shown in React Testing Library: Test if Elements have been mapped/rendered.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With