react-test-renderer: is possible to test lifecycle functions?

Created on 26 Aug 2018  路  10Comments  路  Source: facebook/react

Do you want to request a feature or report a bug?

Question

What is the current behavior?

I am trying to use react-test-renderer and I notice that the lifecycles methods (ex: componentDidMount) need to be fired manually - rendered.getInstance().componentDidMount(), what solves my problem but reveals an other: I want to use shallow render, to test only the component under test, but then react-test-renderer/shallow API is minimal for rendering.

What is the expected behavior?

I was expecting that react-test-renderer would support testing my component reaction to the different lifecycles and be capable to use shallow rendering. Is there some way to use react-test-renderer in this scenario? Or is better I move to another library like enzyme?

Test Renderer Question

Most helpful comment

Test renderer has no opinions about whether your code is synchronous or asynchronous. Just like ReactDOM doesn't care about this.

But as I am using create function from react-test-renderer I need to get the re-render version from my component, what I think is not possible

When you call setState your component will re-render. Both with ReactDOM and with test renderer.

All 10 comments

You shouldn't need to fire lifecycle hooks manually with react-test-renderer. Can you share an example please?

I was expecting that react-test-renderer would support testing my component reaction to the different lifecycles and be capable to use shallow rendering.

I don't understand what this means.

Test renderer and shallow renderer are two different renderers. What does it mean for test renderer to "support" shallow rendering? Again, a complete example would help. It's not clear what you're asking.

@gaearon here an example: https://codesandbox.io/s/ypl36k1491

My second test fails, because I don't know how to get the component updated state after the componentDidMount re-render. Is possible to get the re-render state with react-test-renderer?

I think you might be misunderstanding why the test fails.

You don't need to call componentDidMount yourself. React already does it.

However, you have a setTimeout inside componentDidMount. The test won't wait for that (tests are synchronous by default). So you're asserting before that setTimeout callback has fired.

Normally, depending on what you actually want to test, you could mock setTimeout, mock your data fetching layer, or do something else.

@gaearon thanks, now I understood.

The setTimeout is to exemplify my real scenario, where my componendDidMount call an asynchronous function, so to my test succeeded I need to wait for the asynchronous execution. For sure the mock could solves this problem (googling I just found examples using mocks), but what I want to know, if there is not way to do an asynchronous test with react-test-renderer.

@FabricioFFC handling asynchronous code in tests will be the responsibility of the test runner you're using (e.g. Jest, Mocha, Jasmine, etc.). If you're using Jest check out the Testing Asynchronous Code docs page.

@aweary I must be confusing something. But as I am using create function from react-test-renderer I need to get the re-render version from my component, what I think is not possible, because it seems react-test-renderer is intended to synchronous testing, so if I need to test some async function, I need to mock it to turn it synchronous.

Sorry if I am missing something. I know mocking will solve my problem, but I want to know if there is an alternative to make an integration test with my component and my data fetch layer.

Test renderer has no opinions about whether your code is synchronous or asynchronous. Just like ReactDOM doesn't care about this.

But as I am using create function from react-test-renderer I need to get the re-render version from my component, what I think is not possible

When you call setState your component will re-render. Both with ReactDOM and with test renderer.

But how I test componentDidUpdate? Please help me!

@VCuzmin if you need to mock/stub anything happening inside a lifecycle method, then you'll need to mock that specific API. Let's say cDU is calling a function from a separate module, then you could mock on that with jest.mock(). Another case might be where you want to prevent the cDM from setting state, for example, to emulate the before mount state:

const mock = jest.spyOn(TestComponent.prototype, 'setState').mockImplementation(noop);
[...]
// your assertion here
mock.restoreMock()

Of course this changes behavior, but for such cases, spyOn can be restored and the rest of your tests should then be isolated from this change in the "effect".

Was this page helpful?
0 / 5 - 0 ratings