Test a Component That Uses a React Context Consumer

Share this video with your friends

Send Tweet

Consuming a Context in a component can make it tricky to test, because it requires an invisible Provider outside the scope of the component being tested. In this lesson you’ll learn how to test a component that uses a Context Consumer.

Viktor Soroka
Viktor Soroka
~ 6 years ago

Decent content course Dave👍. One small improvement I think would be just to reuse the rendered container with beforeEach way. Anaway this not an deal as the course is not about testing.

andrewnaeve
andrewnaeve
~ 6 years ago

I wonder if this approach is testing the right thing. Why not provide the props that <MessageViewer /> needs to render, instead of basically testing that Context itself is passing those props? This sounds like the Redux equivalent of not testing Connect(), just testing the isolated component.

Dave Ceddia
Dave Ceddia(instructor)
~ 6 years ago

Viktor - I like the idea of extracting the rendering into beforeEach, but in this case the second test is passing a different value to the Provider (with the addition of the mockCallback). Maybe I could've extracted that out into a function. But yeah, I wanted to keep this focused on testing Context, not get into the weeds of refactoring tests anyway ;)

Andrew - I agree with you in general, but in this case, the component doesn't accept props. Since it has to get its values from Context, it has to be wrapped in a Provider. In the Redux case, usually you can export { TheComponent } as well as export default connect()(TheComponent) so you have a choice of which to test. In this case it's just the one MessageViewer and it requires Context to work. If it were broken out into MessageViewer (that took props) and ConnectedMessageViewer (that used context), then I think your approach would make sense.

Dave Ceddia
Dave Ceddia(instructor)
~ 6 years ago

Note: The 'before' code for this lesson is the code from the previous lesson.

Ming Hann Voon
Ming Hann Voon
~ 6 years ago

the back button test, for me it doesn't test anything at all, I felt it's not complete, because toBeCalledWith surely work, why would we event want to test it that way?

Dave Ceddia
Dave Ceddia(instructor)
~ 6 years ago

@Ming: The back button test mocks out the dependency (the onSelectEmail function) in order to test just the MessageViewer. It's a unit test, solely verifying that the MessageViewer's button is working properly -- that it calls its callback when clicked. But it draws the line there. It says, "I'm only testing MessageViewer; I don't care what happens after I call onSelectEmail."

You could instead (or additionally) write a test to verify that the screen actually changes when the button is clicked. That'd be more of an integration test, testing the combination of MessageViewer + EmailContext + MessageList, which is still useful and valid, but depends on more parts of the system and could make it harder to determine the root cause of a test failure.

Etenne-Joseph Charles
Etenne-Joseph Charles
~ 5 years ago

@Dave, amazing, what's your trick to import different things so fast ?

Etenne-Joseph Charles
Etenne-Joseph Charles
~ 5 years ago

@Dave, amazing, what's your trick to import different things so fast ? You seem to be going so fast, and I'm not sure how you do it, do you mind sharing ?

Dave Ceddia
Dave Ceddia(instructor)
~ 5 years ago

@Etenne-Joseph: Some of that is video editing, but a lot of it is from snippets I've set up in VSCode. A few of them are "ir" to import React from 'react', "i" to import a named thing, "id" to import a default from a file (where it assumes the variable will match the filename). So for example I can just type "i" <TAB> and then fill out the stuff in the braces, TAB again, and fill out the stuff in the quotes. Check out VSCode > Preferences > User Snippets to make your own.