17

I have the following code:

const App = () => {
    return (
        <Provider store={store}>
            <PersistGate persistor={persistor} loading={<Text>Loading!</Text>}>
                <ConnectedRootComponent />
            </PersistGate>
        </Provider>
    );
};

export default App;

which uses redux-persist to rehydrate state, and before this is complete, it will show what's sitting in the loading property. I have a Jest test (just the default one that comes with react native out of the box):

it('renders without crashing', () => {
  const rendered = renderer.create(<App />).toJSON();
  console.log("Rendering: " + JSON.stringify(rendered));
  expect(rendered).toBeTruthy();
});

but although the test passes I see that the actions that persist/PERSIST and persist/REHYDRATE are still occurring, and the value printed to the console in the test (the rendered output) is:

{
    "type": "Text",
    "props": {
        "accessible": true,
        "allowFontScaling": true,
        "ellipsizeMode": "tail"
    },
    "children": ["Loading!"]
}

What I want to do is wait until redux-persist has completed hydration, and then check the rendered value. How can I do this?

skyboyer
  • 22,209
  • 7
  • 57
  • 64
user4184113
  • 976
  • 2
  • 11
  • 29
  • 1
    You can provide a callback to **persistStore**, which will be called when rehydration is finished. You might have to modify the test case accordingly. Please refer https://github.com/rt2zz/redux-persist#persiststorestore-config-callback – dhruv soni Jun 16 '18 at 14:31

4 Answers4

4
import React from 'react';
import App, {persistor} from '../App';

import renderer from 'react-test-renderer';

it('renders without crashing', (done) => {
  const appRendered = renderer.create(<App />);
  persistor.subscribe(function(){
      const rendered = appRendered.toJSON();
      console.log("Rendering: " + JSON.stringify(rendered));
      expect(rendered).toBeTruthy();
      done();
  });
});

you just need to export the persistor from App file and then use the above code to test. it works perfectly, i have tested.

You can notice that persistor object can subscribe with a callback, which gets executed when the redux store has rehydrated.

Inus Saha
  • 1,918
  • 11
  • 17
3

You could mock PersistGate to always return props.children, then your test can check the rendered value.

Here's how to create the mock:

jest.mock('redux-persist/integration/react', () => ({
  PersistGate: props => props.children,
}))

Credits.

Jordan Enev
  • 16,904
  • 3
  • 42
  • 67
1

You may ignore persist while testing with

jest.mock('redux-persist/integration/react', () => ({
  PersistGate: props => props.children,
}))
jest.mock('redux-persist', () => ({
  ...jest.requireActual('redux-persist'),
  persistReducer: jest.fn().mockImplementation((config, reducer) => reducer),
}));
0

The other solutions work for me but here's what I ended up using.

TL;DR

In your <PersistGate /> add a loading component and wait for it to be removed in your tests

await waitForElementToBeRemoved(() => screen.getByText('Loading...'));

Full explanation

So in my code I have a <Text /> component that will be displayed while redux-persist is hydrating

<StoreProvider store={setupStore()}>
  <PersistGate loading={<Text>Loading...</Text>} persistor={persistor}>
    {children}
  </PersistGate>
</StoreProvider>

now in my test suite, it will wait for the component to be removed before continuing

it('should render correctly', async () => {
  render(<App />);

  await waitForElementToBeRemoved(() => screen.getByText('Loading...'));

  const headline = screen.getByText("Welcome to the App!");
  expect(headline).toBeTruthy();
});
Eric Aya
  • 69,473
  • 35
  • 181
  • 253