Home > Enterprise >  Test my react(button) component, mock function received 0 calls
Test my react(button) component, mock function received 0 calls

Time:04-20

Below is my script:

export interface InputProps {
    value: string;
    onSubmit: (value: string) => void;
    onChange: (value: string) => void;
}

const InputBox: React.FC<InputProps> = (props: InputProps) => {
    return (
        <InputWrapper>
            <InputField
                value={props.value}
                onSubmit={() => {
                    props.onSubmit;
                    console.log('onsubmit function is being called.');
                }}
                onChange={props.onChange}
                button={true}
            />
        </InputWrapper>
    );
};

Below is my test:

describe('<InputBox />', () => {
    const onSubmitMock = jest.fn();
    const onChangeMock = jest.fn();

const Test = <InputBox onSubmit={onSubmitMock} onChange={onChangeMock} value="test" />;

it('called onSubmitMock when click submit', () => {
    const { getAllByRole } = render(Test);
    fireEvent.click(getAllByRole('button'));
    expect(onSubmitMock).toHaveBeenCalled();
});

but it gives me error: Number of calls: 0

However, my onChange test is passed:

it('called onChangeMock when click submit', () => {
    const { getAllByRole } = render(Test);
    fireEvent.click(getAllByRole('button'));
    expect(onChangeMock).toHaveBeenCalled();
});

The only difference b/t onChange and onSubmit is I have an arrow function for the onSubmit property.

Question one, why can't I call the onSubmitMock like the onChangeMock?

I've also tried to make a function like below:

const handleSubmit = (): void => {
    props.onSubmit('a');
    if (inputRef.current) {
        inputRef.current.blur();
    }
    console.log('This is being called');
};

When I call it inside onSubmit prop

onSubmit={handleSubmit()}

It gives me an error like below:

Type 'void' is not assignable to type '(...args: any[]) => any'.

The expected type comes from property 'onSubmit' should be '(...args: any[]) => any'

So I change the code like this:

onSubmit={handleSubmit}

Now, it doesn't give me error. But if I get rid of the 'a' argument in the props.onSubmit('a'), same failed message in the jest, "received 0 call". However, if I randomly add a string value for it, it might broke the logic. Because this function will be called in other files. And the argument should be user input..

Any idea of this? Huge thank in advance

(PS: the onSubmitMock is not called in my jest test, BUT the real onSubmit is called whenever I hit the button. Because I can see 'onsubmit function is being called.' msg in the console every time I hit the button.)

CodePudding user response:

Question one, why can't I call the onSubmitMock like the onChangeMock?

For a function to get called, someone must call it. If you write the code props.onChange with no parentheses, then you are just referencing a function, not calling it. So with both props.onSubmit; and onChange={props.onChange}, the function will not get called. Not on this line of code anyway...

But the onChange prop is designed so that if you pass a reference of a function into it, then react guarantees that it will call the function for you, if and when the change event happens. So later on when the event happens, react calls props.onChange for you.

With the onSubmit function, you've also passed a function into it: the anonymous arrow function you wrote, who's text is:

() => {
  props.onSubmit;
  console.log('onsubmit function is being called.');
}

When the event happens, react will call that function. Inside your custom function you can do whatever you like, including calling props.onSubmit. But you will be calling it yourself, not asking react (or anything else) to call it for you, so to call it yourself you need props.onSubmit()

Question two [...]

It's not clear to me what code you had that was causing the type error. If you show the code that caused the error, i'll edit this question to answer that

CodePudding user response:

It seems you forgot to call the onSubmit callback function. Just add the missing parenthesis like this:

  onSubmit={() => {
    props.onSubmit();
  }}

If the console.log is not needed, then this should work:

  onSubmit={props.onSubmit}
  • Related