Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test class components in react

I am trying some unit testing, I created a sandbox with a fake example https://codesandbox.io/s/wizardly-hooks-32w6l (in reality I have a form)

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { number: 0 };    
  }

  handleSubmit = (number1, number2) => {
    this.setState({ number: this.handleMultiply(number1, number2) })
  }

  handleMultiply = (number1, number2) => {
    return number1 * number2
  }

  render() {
    const { number } = this.state;

    return (
      <div className="App">
        <form onSubmit={e => this.handleSubmit(3, 7)}>       
          <input type="submit" name="Submit" value="Multiply" />
        </form>
        <Table number={number} />
      </div>
    );
  }
}

export default App;

So my initial idea was to try to test the multiply function. And did this, which obviously doesn't work

import App from "../src/App";

test("Multiply", function() {
  const expected = 21;
  const result = App.handleMultiply(3, 7);
  expect(result).toBe(expected);
});

I get

_App.default.handleMultiply is not a function

Is my approach right? If yes then how do I test the functions? Else, should I test from a user point of view instead of for internal functions (this is what I read)? Should I test for the output on the screen (I don't think this is reasonable)?

like image 657
user3808307 Avatar asked Jan 18 '20 02:01

user3808307


People also ask

How do I test my React components?

There are a few ways to test React components. Broadly, they divide into two categories: Rendering component trees in a simplified test environment and asserting on their output. Running a complete app in a realistic browser environment (also known as “end-to-end” tests).

Can we use React testing library for class component?

You can change your components as much as you want as long as they render the data the same way or the React in the same way if you after interactions such as filling in data or pressing a button for example. It's a lightweight solution for testing React components. It provides utility functions on top of react-dom .

Which of the given method from Jest are used to test React component?

test. js extension as when the tests are run using the npm test command, React automatically checks for all the file names with a . test extension and runs the tests.


Video Answer


1 Answers

You can use instance() method of enzyme to get the instance of React Component. Then, call handleMultiply method directly and make the assertion for it. Furthermore, if the handleMultiply method has a side-effect or very complicated calculations, you need to make a simple mocked return value for it. It will make an isolated test environment for handleSubmit method. This means handleSubmit method will not depend on the return value of the real implementation of handleMultiply method.

E.g.

app.jsx:

import React from 'react';
import { Table } from './table';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { number: 0 };
  }

  handleSubmit = (number1, number2) => {
    this.setState({ number: this.handleMultiply(number1, number2) });
  };

  handleMultiply = (number1, number2) => {
    return number1 * number2;
  };

  render() {
    const { number } = this.state;

    return (
      <div className="App">
        <form onSubmit={(e) => this.handleSubmit(3, 7)}>
          <input type="submit" name="Submit" value="Multiply" />
        </form>
        <Table number={number} />
      </div>
    );
  }
}

export default App;

table.jsx:

import React from 'react';

export const Table = ({ number: num }) => {
  return <div>table: {num}</div>;
};

app.test.jsx:

import App from './app';
import { shallow } from 'enzyme';

describe('59796928', () => {
  let wrapper;
  beforeEach(() => {
    wrapper = shallow(<App></App>);
  });
  describe('#handleSubmit', () => {
    it('should pass', () => {
      expect(wrapper.exists()).toBeTruthy();
      wrapper.find('form').simulate('submit');
      expect(wrapper.state()).toEqual({ number: 21 });
    });
  });
  describe('#handleMultiply', () => {
    it('should pass', () => {
      const comp = wrapper.instance();
      const actual = comp.handleMultiply(2, 10);
      expect(actual).toBe(20);
    });
  });
});

Unit test results with coverage report:

 PASS  src/stackoverflow/59796928/app.test.jsx (11.688s)
  59796928
    #handleSubmit
      ✓ should pass (16ms)
    #handleMultiply
      ✓ should pass (9ms)

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |    90.48 |      100 |    85.71 |    94.44 |                   |
 app.jsx   |      100 |      100 |      100 |      100 |                   |
 table.jsx |       50 |      100 |        0 |    66.67 |                 4 |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        13.936s

Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59796928

like image 61
slideshowp2 Avatar answered Oct 27 '22 11:10

slideshowp2