0

I have a React application to be tested. The application uses the useReducer()-Pattern and creates a dispatch function. As it´s neiter easy nor useful to assert on the state directly, I want to do my asserts against the input values of the dispatch function.

As I can´t spy on the dispatch function directly because it´s just a local function inside of a function component, my plan is to spy on the React.useReducer and mock it in a way that it returns a mocked dispatch function I can assert on.

I made a minimal example of this.

This is the component to be tested:


interface IState {
    name : string
}

interface IAction {
    type: "fetched data" | "manual update"
    newName : string
}

const TestRedcuerComponent: React.FC<ITestComponentProps> = (props) => {
  
    const { name } = props;

    const initState  = { name: name};

    const handleUpdates = (state : IState, action : IAction) : IState => {
        console.log("handle updates was called with " + action.newName);
        return { name : action.newName };
    }
    

    const [state, dispatch] = React.useReducer(handleUpdates, initState);

    React.useEffect(() => {
     // In the real application, data like newName is fetched here and then passed to dispatch

     //I´m interested in the input values of this function   
     dispatch({type: "fetched data", newName: "Max"});
    }, [])

    return (<div>

    </div>)
}

export default TestRedcuerComponent;

This is how I test on it:

it("react specific test", async () => {

const mockedDispatcherFunction = jest.fn();

jest
   //see information on why caller below
  .spyOn(caller, 'useReducer')
  .mockImplementationOnce((initialState, initializer) => [initialState, mockedDispatcherFunction]);

render(<TestReducerComponent name = { "Peter" }></TestReducerComponent>)

expect(mockedDispatcherFunction).toHaveBeenCalledWith({type: 'fetched data', initValues: {newName: "Max"} });


 });

However, my mockedDispatcherFunction is never called.

Why I used caller? I used barrel imports to be able to reexport the use-Reducer Function because otherwise I cannot redefine the property. (See: https://pyk.sh/tutorials/how-to-fix-cannot-redefine-property-x-typeerror-in-jest/)

My caller-Module looks like this:

import { useReducer } from "react";

const caller = {useReducer}

export default caller;

Ali Navidi
  • 693
  • 1
  • 5
  • 18
  • Spying on `useReducer` is still *technically* spying on "state" and/or spying on internal implementation details. It looks like you are using React-Testing-Library. If this is the case then you should be inspecting/asserting on what the update to `state` does to the rendered UI, e.g. if `state` is a name and is rendered. – Drew Reese Jun 28 '23 at 06:43
  • React testing library is used later in a specific test case that is about rendering of the ui from the state as it includes a lot of logic as well, which will be tested in other test cases. Please just take this test case as given. – Feuerschinken Jun 28 '23 at 06:55
  • I feel I may have been misunderstood. I'm saying it's a testing anti-pattern to spy and assert on this internal implementation detail. – Drew Reese Jun 28 '23 at 07:11

0 Answers0