Search code examples
jestjsreact-testing-librarytesting-libraryreact-native-testing-library

getByText doesn't find element with the text


I am starting using jest to test simple component SysError.js in my React Native 0.68 app. SysError displays some message on screen when it is called (routed by react-navigation 6.x) and the jest test is to check if the page view does contain the message. The @testing-library/react-native used is v11.0.0

Here is the SysError.js:

import React, {useState, useContext, Component} from 'react';
import {Platform, Button, Text, TouchableOpacity, View } from 'react-native';

export default function SysError({route}) { //<<== routed by react-navigation
    const message = route.params.message ? JSON.stringify(route.params.message) : "";
    return (
        <View styles={{marginTop: 32, paddingHorizontal: 24, alignItems:"center", alignContent:"center"}}> 
            <Text>{route.params.message} System NOT available right now. Try again later</Text>
        </View>
    )
};

Here is the jest test:

import React from 'react';
import { render, cleanup } from "@testing-library/react-native";
import SysError from './SysError';

afterEach(cleanup);

it ('describe SysError page view with a message', () => {
    const route = {params: {message:"nnmm"}};
    const {toJSON, getByText} = render(<SysError route={route} />);
    const foundmsg = getByText("System NOT available right now");  //<<==this throws error
    expect(toJSON()).toMatchSnapshot();
    expect(foundmsg.props.children).toEqual("System NOT available right now");

})

To my surprise, there is an error:

  FAIL  src/components/app/SysError.test.js

  ● describe SysError page view with a message

    Unable to find an element with text: System NOT available right now

       9 |     const route = {params: {message:"nnmm"}};
      10 |     const {toJSON, getByText} = render(<SysError route={route} />);
    > 11 |     const foundmsg = getByText("System NOT available right now");
         |                      ^
      12 |     expect(toJSON()).toMatchSnapshot();
      13 |     expect(foundmsg.props.children).toEqual("System NOT available right now");
      14 |

      at Object.getByText (src/components/app/SysError.test.js:11:22)

However if the test code is changed to reg expression:

  const foundmsg = getByText(/System NOT available right now/i);

Then the error becomes:

expect(received).toEqual(expected) // deep equality

    Expected: "System NOT available right now"
    Received: ["nnmm", " System NOT available right now. Try again later"]

      11 |     const foundmsg = getByText(/System NOT available right now/i);
      12 |     expect(toJSON()).toMatchSnapshot();
    > 13 |     expect(foundmsg.props.children).toEqual("System NOT available right now");

Is there way re-code expect(foundmsg.props.children).toEqual("System NOT available right now"); and make it pass? I tried toEqual(/System NOT available right now/i) and it didn't work.


Solution

  • As the react-native testing library shows in the documentation examples the getByText query, if provided a string, will look for the exact match.

    That's the reason why on your first attempt the query is unable to find the element. As you found out, you can also provide a regex to look for partial match so on your second attempt the query is capable of finding the element.

    Now that you have the element:

    <Text>{route.params.message} System NOT available right now. Try again later</Text>
    

    You can see that it actually has two children: One for the dynamic part that prints the route.params.message and the other one for the static part.

    You can check both values in your test with:

    expect(foundmsg.props.children).toEqual(["nnmm", "System NOT available right now"]);
    

    If you only want to check that the static part is present you could also do:

    expect(foundmsg.props.children).toContain("System NOT available right now");