After upgrading our live system from Node 6 to Node 8 I got super excited about acquiring the async/await capability, and was in that raving “async/await all the things!” mode. It was very satisfying to see the callbacks-heavy production and test code to practically halve in size. Not only was it less code now, but also the code structure got completely flat and trivial to follow.
Some things are harder to async/await than others. Today I faced the following problem.
I have a tiny React component which is a star rating
input. It highlights the prospective star rating
value on mouse hover, and sets the new value on mouse click. The prospective value is stored in the
state, which is updated on
mouseLeave DOM event. Then the
state.prospectiveValue is used to highlight the potential rating selection.
I don’t always write React components, but when I do, I test-drive them. Let me replay here my
state.prospectiveValue support implementation, driven by tests, in
Mocha. First, we mount the component with enzyme,
and fabricate some initial
done callback passed to
setState, to make sure that Mocha waits for the state change
to succeed before proceeding with each of
the test cases. Here’s the first one of them:
The test is red:
2 != 4. Let’s make it green, changing the React component code.
Well, the test is still red.
setState is asynchronous, and we have to pass it a callback, like we
beforeEach(), in order to wait for its conclusion. How can we possibly do that now? My
first thought was introducing a func prop
onSetStateDone, and passing it to all the
calls within the React component. Another option, which I learned about later, is overriding the
componentDidUpdate. Both ways
would require pyramids of callbacks to implement. Meh. Could that instead be a nail for my new shiny
async/await hammer? You bet!
Then, instead of
Resulting in the test code like this:
…And the test is now green. We can proceed test-driving.