React-Testing-Library - useReducer dispatch not updating tested components state

Viewed 687

I have a component that calls a useApi custom hook. In the custom hook it fetches data from the API an then performs a dispatch action that updates the app state with the data fetched from the API. In my test I'm spying on my 'get' api call and mocking a return value. I'm also mocking my dispatch function and ensuring it's being called with the proper action/data. All of that succeeds, but my component does not reflect the state update.

WorkflowList.test.js

test('Workflow list loads on mount', async () => {
    let myComponent;
    const apiSpy = jest.spyOn(api, 'get').mockReturnValue({ ...mock.workflow });
    const dispatch = jest.fn();


    await act(async () => {
        myComponent = render(
            <GlobalContext.Provider
                value={{
                    ...mock.initial,
                    dispatch,
                }}
            >
                <ThemeProvider theme={light}>
                    <Router history={history}>
                        <WorkflowList />
                    </Router>
                </ThemeProvider>
            </GlobalContext.Provider>
        )
    });
    await expect(apiSpy).toHaveBeenCalled(); <--- Passes
    await expect(dispatch).toHaveBeenCalledWith({ <--- Passes
        type: 'LIST_WORKFLOWS',
        result: { ...mock.workflow },
    });

    expect(screen.getByText('Test Workflow 1')).toBeInTheDocument(); <--- Fails
});

The dispatch call doesn't seem to be updating my components state. One this that does work is if I rerender the component and then manually put in the new workflow in my Providers 'value' property. But, that doesn't seem right, it seems like I should be able to run my mock.workflow through and have it update the component.

WorkflowList.js

const WorkflowList = () => {
    const classes = useStyles();
    const { workflow } = useContext(GlobalContext);
    const { loading, get } = useApi();

    const listWorkflows = async () => {
        await get({
            endpoint: '/strategy/strategy',
            success: 'LIST_WORKFLOWS',
            fail: 'LIST_WORKFLOWS_FAILED'
        });
    };

    // Fetch data and then dispatch a state update depending on success or fail
    useMemo(() => {
        listWorkflows();
    }, []);

    return (
        <Page
            className={classes.root}
            title="Workflows"
        >
            <Grid
                container
                spacing={3}
            >
                <Grid
                    item
                    xs={12}
                >
                    <Header listWorkflows={listWorkflows} />
                </Grid>
                {
                    !loading &&
                    <>
                        <Grid
                            item
                            xs={12}
                        >
                            <Search
                                config={{
                                    title: "Workflows",
                                    subject: "workflow",
                                    data: Object.values(workflow.list.data),
                                    filters: ["name", "description"],
                                }}
                            />
                        </Grid>
                        <Grid
                            item
                            xs={12}
                        >
                            <WorkflowCard />
                        </Grid>
                    </>
                }
                {
                    loading &&
                    <ProgressSpinner message={'Loading Workflows...'} />
                }
            </Grid>
        </Page>
    );
};

export default WorkflowList;
0 Answers
Related