'Test onClick of a button is called when there is no props passed down to it using testing library react and jest

I have a component for an upload button which calls the ref of an input when clicked:

import { useRef, FC } from 'react';
import Button from '@mui/lab/LoadingButton';

const UploadButton: FC<UploadButtonProps> = ({
  onFileChange,
  loading,
  text = 'Import File',
  accept = '.csv',
  disabled = false,
}) => {
  const inputRef = useRef<HTMLInputElement>(null);
  const onChange = ({ target }: { target: HTMLInputElement }) => {
    const { files } = target;
    const file = files?.[0];
    file && onFileChange?.(file);
    target.value = '';
  };
  return (
    <>
      <Button
        loading={loading}
        color="primary"
        variant="contained"
        disabled={disabled}
        onClick={() => {
          inputRef.current?.click();
        }}
      >
        {text}
      </Button>
      <input
        aria-label="hidden-upload-input"
        ref={inputRef}
        style={{
          display: 'none',
        }}
        type="file"
        accept={accept}
        required
        onChange={onChange}
      />
    </>
  );
};

export default UploadButton;

interface UploadButtonProps {
  onFileChange?: (file: File) => void;
  loading?: boolean;
  text?: string;
  accept?: string;
  disabled?: boolean;
}

I want to test that when button is clicked its onClick is called or inputRef.current.click is called but I don't know how. I assume that I need to spyOn the onClick prop somehow.

I tried something like this:

it('should call button onClick if being clicked',() => {
const upload = render(<UploadButton text="upload text" />);

const buttonClick = jest.spyOn(upload, 'onClick');

const button = screen.getByText('upload text');

fireEvent.click(button);

expect(button.onclick).toBeCalled();
});


Solution 1:[1]

as a workaround I ended up adding a console log in the onClick function and spyOn it

import { useRef, FC } from 'react';
import Button from '@mui/lab/LoadingButton';

const UploadButton: FC<UploadButtonProps> = ({
  onFileChange,
  loading,
  text = 'Import File',
  accept = '.csv',
  disabled = false,
}) => {
  const inputRef = useRef<HTMLInputElement>(null);
  const onChange = ({ target }: { target: HTMLInputElement }) => {
    const { files } = target;
    const file = files?.[0];
    file && onFileChange?.(file);
    target.value = '';
  };

  return (
    <>
      <Button
        loading={loading}
        color="primary"
        variant="contained"
        disabled={disabled}
        onClick={() => {
          inputRef.current?.click();
          console.log('upload');
        }}
      >
        {text}
      </Button>
      <input
        aria-label="hidden-upload-input"
        ref={inputRef}
        style={{
          display: 'none',
        }}
        type="file"
        accept={accept}
        required
        onChange={onChange}
      />
    </>
  );
};

export default UploadButton;

interface UploadButtonProps {
  onFileChange?: (file: File) => void;
  loading?: boolean;
  text?: string;
  accept?: string;
  disabled?: boolean;
}

and test it like this

  it('should call button onClick if being clicked', async () => {
    render(<UploadButton text="upload text" />);

    const spy = jest.spyOn(console, 'log');

    const button = screen.getByText('upload text');

    fireEvent.click(button);

    expect(spy).toBeCalled();
  });

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mohammad K.