0

I am new to testing, creating simple component with counter state and useState react hook that increment the counter when a button is clicked:

Component:

const Counter= () => {
    const[counter, setCounter] = useState(0);

    const handleClick=() => {
        setCounter(counter + 1);
    }

    return (
        <div>
            <h2>{counter}</h2>
            <button onClick={handleClick} id="button">increment</button>
        </div>
    )
}

Counter.test.js:

it('increment counter correctly', () => {
    let wrapper = shallow(<Counter/>);
    const counter  = wrapper.find('h2');
    const button = wrapper.find('button');
    button.simulate('click')
    console.log(counter.text()) // 0
})

Logging counter.text() after simulating button click print 0 instead of 1; and when i tried to spy on useState, i got the same problem:

it('increment counter correctlry', () => {
    let wrapper = shallow(<Card />);
    const setState = jest.fn();
    const useStateSpy = jest.spyOn(React, 'useState');

    useStateSpy.mockImplementation((init) => [init, setState]);
     const button = wrapper.find("button")
     button.simulate('click');
     expect(setState).toHaveBeenCalledWith(1);
})

This test fails and i get this error after running the test:

Expected: 1
Number of calls: 0

What am i doing wrong??

5
  • 1
    I think console.log(counter.text()) gives the wrong answer because you obtain that reference before updating the counter. Try moving that statement until after the button is clicked. Commented Oct 1, 2020 at 21:27
  • 1
    Also, your spy breaks the hook because it doesn't actually update the counter value. Your mock setState is a no-op. If you're going to mock useState, you'll need a persistent reference to an array that you can then mutate inside your test. Otherwise, even if the component is flawless, it will fail the test because it's relying on a broken impl of useState. Commented Oct 1, 2020 at 21:31
  • @Tom the statement is already after simulating the button click, can you give me some demo code of how to fix mocking useState?? Commented Oct 1, 2020 at 21:41
  • 1
    It turns out that implementing a mock version of React's setState hook is pretty hard. Don't do it. Try doing wrapper.find('h2') after you do the click. And you may need to wrap the click inside of RTL's act. Commented Oct 2, 2020 at 23:13
  • @Tom, some people advised me to migrate to react-testing library as Enzyme is hard to handle Commented Oct 3, 2020 at 2:14

1 Answer 1

1

In enzyme v3, you should re-find the h2 shallow wrapper after you trigger the click handler. Then you will get the new h2 shallow wrapper reference which contains the latest value of counter. Check migration-from-2-to-3.html#calling-props-after-a-state-change for more info.

E.g.

Counter.jsx:

import React, { useState } from 'react';

export const Counter = () => {
  const [counter, setCounter] = useState(0);

  const handleClick = () => {
    setCounter(counter + 1);
  };

  return (
    <div>
      <h2>{counter}</h2>
      <button onClick={handleClick} id="button">
        increment
      </button>
    </div>
  );
};

Counter.text.jsx:

import { shallow } from 'enzyme';
import React from 'react';
import { Counter } from './Counter';

describe('64148085', () => {
  it('increment counter correctly', () => {
    const wrapper = shallow(<Counter />);
    const button = wrapper.find('button');
    button.simulate('click');
    expect(wrapper.find('h2').text()).toBe('1');
  });
});

unit test result with coverage report

 PASS  src/stackoverflow/64148085/Counter.test.tsx
  64148085
    ✓ increment counter correctly (12ms)

-------------|----------|----------|----------|----------|-------------------|
File         |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-------------|----------|----------|----------|----------|-------------------|
All files    |      100 |      100 |      100 |      100 |                   |
 counter.tsx |      100 |      100 |      100 |      100 |                   |
-------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.472s, estimated 12s
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.