MCO
MCO

Reputation: 314

JEST to test react components

I am following the tutorial on jest on how to test my component, and am wondering if I am missing anything. I am trying to test my weatherApp.js whose sole purpose is to display information from my TemperatureData.jswith a color from my colorize.js

export default class Weather extends React.Component {
    constructor(props) {
        super(props);
        this.state = {temp: undefined}}
    componentDidMount() {temperatureData().then(temp => {this.setState({temp: temp})})
    }
    render() {
        const temperature = this.state.temp;
        return <>{this.state.temp === undefined ?<somegraph />:<p style={{ color: colorize(temperature) }} id="temperature">{temperature}</p>}</>
    }
}

Here is what I have to test this application, I'm not sure if i need to test anything else or what else im missing, any input appreciated.

describe("<WeatherApp> component test", () => {
  test("displays data from temperature data", async () => {
    const mockedTemp = "something irrelevant";
    temperatureData.mockImplementation(() => {
      return Promise.resolve(mockedTemp)
    })
    const weatherComponent = render(<WeatherApp />);
    expect(temperatureData).toHaveBeenCalled()
    await wait(() => {
      const paragraph = weatherComponent.getByText(mockedTemp)
      //console.log(paragraph)
      expect(paragraph).toBeInTheDocument()
      expect(paragraph).toBeDefined()
    });
  })
})

I am not sure if i should test to see if the correct color is returned based on my temperature input as i have a separate unit test for my colorize file...

Upvotes: 0

Views: 276

Answers (2)

Ben
Ben

Reputation: 5646

Whether your unit-test is sufficient depends on what you define as the critical criteria for your component. If it is critically important to ensure the temperature is displayed in the correct color, you should probably test that. However, as you said, you have a separate test for the colorize function, so that may be enough. If that gives you confidence that it will work there is no need to test it again in the weatherApp.js

Those decisions are relatively subjective, and one of the reasons unit-testing is challenging - there are relatively few prescriptive answers as far as what to test. For some better guidance, this is a pretty good read on the subject.

There are, however, ways of structuring your components that facilitate easier unit testing, and in that regard I have a suggestion for changing the way your component is built since really, I think, what you care about is that:

  • The WeatherApp component displays colorized temperature data

Right? You don't really care that it calls the API...the data could come from anywhere. And you don't really care that it calls the colorize function...only that there is a color applied. Testing those details only makes your unit-test brittle, meaning for instance that you will have to update the unit-test definition if your API changes.

Instead, make the WeatherApp component stateless and presentational. Use a parent component to handle:

  1. Calling the API
  2. Calculating the color
  3. Rendering the WeatherApp
class ParentComponent extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        temp: undefined,
        color: undefined,
      }
    }

    componentDidMount() {
      temperatureData().then(temp => {
        this.setState({
          temp: temp
          color: colorize(temp)
        })
      })
    }

  render(
    return (
      <WeatherApp temp={this.state.temp} color={this.state.color} />
    )
  )
}

Then your test looks something like this instead:

describe("<WeatherApp> component test", () => {
  test("displays data from temperature data", () => {
    const mockedTemp = "something irrelevant";

    const weatherComponent = render(<WeatherApp temp={mockedTemp} />);

    const paragraph = weatherComponent.getByText(mockedTemp)
    expect(paragraph).toBeInTheDocument()
  })
})

You could include the color there in the test, or not...up to you.

Since you can test all 3 units (temp/color/weatherApp) that make up the parent component separately, you can be relatively confident that the parent component will work. You also have an added bonus of not needing to write any asynchronous code in the unit-test.

Upvotes: 1

aquinq
aquinq

Reputation: 1448

You can configure jest to report test coverage information, by adding --coverage=true option to your test command line :

jest --coverage=true

Test coverage will give you a first hint of what's missing in your tests.

For example, if you forgot to test a conditional rendering based on a ternary operator (which is the case here, you don't test that if this.state.temp is undefined, <somegraph /> should be displayed), the coverage report (something like this) will give you the uncovered lines, which is a great indicator to know if you forgot to test some basic logic of your component.

However, test coverage might not be aware of some more subtil logic, like side effects or css styling etc.. Sometimes you'll need to think a bit further for testing more specific logic in your components.

I suggest you start by making sure you don't have uncovered lines by looking at coverage report. Hope it will help !

Upvotes: 1

Related Questions