Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing debounced method in React with Enzyme

//Component
import _ from 'lodash';

constructor(props) {
  super(props);
  this.onScroll = _.debounce(::this.onScroll, 100);
}

onScroll() {
  //some code
}

//Test
it('onScroll', () => {
  const component = shallow(<Component />);
  component.instance().onScroll(); //Dosn't call method 
})

I use enzyme for render component, and lodash for debounce. How to call component.instance().onScroll()?

like image 929
Vadym Petryshyn Avatar asked Oct 17 '22 22:10

Vadym Petryshyn


1 Answers

TL;DR; use lolex to advance in time while mocking timers for testing _.debounce

I was ready to describe several ways to mock timers with jest by useFakeTimers and advanceTimersByTime. But it did not work.

After some time I've found it works with _.throttle but not _.debounce. And then I've found issue reported in Jest's repo. Also there is dedicated bug report "_.debounce breaks fake timers" and I don't see it's resolved(ignore its status and check last comments there).

According to veeeeery detailed explanation _.debounce not just put setTimeout but also checks time difference. So we should mock also Date.now that Jest's jest.runOnlyPendingTimers or jest.advanceTimersByTime don't do.

So for simple component like

function Debounced({onClick}) {
    return <button onClick={_debounce(onClick,500)}>Click Me</button>;  
}

next test has passed:

let clock = lolex.install();
const onClick = jest.fn();
const wrapper = shallow(<Debounced onClick={onClick} />);
const button = wrapper.find('button').at(0);

button.simulate('click');
button.simulate('click');
button.simulate('click');

clock.tick(510);
expect(onClick).toHaveBeenCalledTimes(1);
clock.uninstall();

PS for sure you could run lolex.install() and clock.uninstall() in beforeEach/afterEach

like image 61
skyboyer Avatar answered Oct 21 '22 07:10

skyboyer