I am using jest and react-testing-library to write tests for my react application. In the application, I have a context provider that contains the state across most of the application. In my tests, I need to mock one state variable in context provider and leave one alone, but I'm not sure how to do this.
AppContext.tsx
const empty = (): void => {};
export const emptyApi: ApiList = {
setStep: empty,
callUsers: empty,
}
export const defaultState: StateList = {
userList = [],
step = 0,
}
const AppContext = createContext<ContextProps>({ api: emptyApi, state: defaultState });
export const AppContextProvider: React.FC<Props> = props => {
const [stepNum, setStepNum] = React.useState(0);
const [users, setUsers] = useState<User[]>([]);
const api: ApiList = {
setStep: setStepNum,
callUsers: callUsers,
}
const state: Statelist = {
userList: users,
step: stepNum,
}
const callUsers = () => {
const usersResponse = ... // call users api - invoked somewhere else in application
setUsers(userResponse);
}
return <AppContext.Provider value={{ api, state}}>{children}</AppContext.Provider>;
}
export default AppContext
In _app.tsx
import { AppContextProvider } from '../src/context/AppContext';
import { AppProps } from 'next/app';
import { NextPage } from 'next';
const app: NextPage<AppProps> = props => {
const { Component, pageProps } = props;
return (
<React.Fragment>
<AppContextProvider>
<Component {...pageProps}
</AppContextProvider>
</React.Fragment>
)
}
export default app
the component that uses AppContext progress.tsx
import AppContext from './context/AppContext';
const progress: React.FC<Props> = props => {
const { state: appState, api: appApi } = useContext(AppContext);
const { userList, step } = appState;
const { setStep } = appApi;
return (
<div>
<Name />
{step > 0 && <Date /> }
{step > 1 && <UserStep list={userList} /> }
{step > 2 && <Address />
</div>
)
}
export default progress
users is data that comes in from an API which I would like to mock. This data is shown in progress.tsx. stepNum controls the display of subcomponents in progress.tsx. It is incremented after a step is completed, once incremented, the next step will show.
In my test, I have tried the following for rendering - progress.test.tsx
import progress from './progress'
import AppContext, { emptyApi, defaultState } from './context/AppContext'
import { render } from "@testing-library/react"
describe('progress', () => ({
const api = emptyApi;
const state = defaultState;
it('should go through the steps', () => ({
state.usersList = {...}
render(
<AppContext.Provider value={{api, state}}>
<progress />
</AppContext.Provider>
)
// interact with screen...
// expect(...)
})
})
However, when I set up the context provider like that in the test, I can set the userList to whatever I want, but it'll also override the setStep state hook so in the component, it won't update the state. Is it possible to mock only the users variable inside of AppContext with jest, but leave users hook alone?