For some reason, my Jest mock is not being invoked. All relevant bits of logic are indeed being accessed/invoked and, in fact, if I pass a handler of my own--something like () => { console.log('blah') }
--it will indeed be invoked and I see the console.log
in my terminal. Does anyone know why expect(mockOnSuccess).toHaveBeenCalled()
and expect(mockOnFailure).toHaveBeenCalled()
are returning false despite the fact that I know the handler is being invoked?
// file-upload.tsx
import { useDropzone } from 'react-dropzone';
import type {
DropzoneOptions as ComponentProps,
FileRejection,
} from 'react-dropzone';
export function FileUpload({
maxSize = 100000000,
onSuccess,
onFailure,
}: FileUploadDropzoneProps) {
const { getRootProps, getInputProps } = useDropzone({
validator,
accept,
onDropAccepted: (acceptedFiles) => {
onSuccess(acceptedFiles);
},
onDropRejected: (fileRejections) => {
onFailure(fileRejections);
},
});
return (
<div {...getRootProps()}>
<input
{...getInputProps()}
data-testid='file-upload'
/>
<p className='border-dashed'>
Drag 'n' drop some files here, or click to select files
</p>
</div>
);
function validator(file: File) {
if (fileSizeIsTooLarge(file)) {
return {
code: 'file-too-large',
message: `File size is larger than ${maxSize}`,
};
}
return null;
}
function fileSizeIsTooLarge(file: File) {
return maxSize && file.size > maxSize;
}
}
/* Accepted file types */
const accept = {
'text/csv': [],
'application/vnd.ms-excel': [],
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': [],
'application/vnd.openxmlformats-officedocument.spreadsheetml.template': [],
'application/vnd.ms-excel.sheet.macroEnabled.12': [],
'application/vnd.ms-excel.template.macroEnabled.12': [],
'application/vnd.ms-excel.addin.macroEnabled.12': [],
'application/vnd.ms-excel.sheet.binary.macroEnabled.12': [],
};
type FileUploadDropzoneProps = Partial<Pick<ComponentProps, 'maxSize'>> & {
onSuccess: (files: File[]) => void;
onFailure: (files: FileRejection[]) => void;
};
// file-upload.test.tsx
import '@testing-library/jest-dom';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { FileUpload } from '../';
describe('FileUpload', () => {
const mockOnSuccess = jest.fn();
const mockOnFailure = jest.fn();
afterEach(() => {
mockOnSuccess.mockReset();
mockOnFailure.mockReset();
});
describe('In general', () => {
test('It should render', () => {
render(
<FileUpload
onSuccess={mockOnSuccess}
onFailure={mockOnFailure}
/>,
);
expect(
screen.getByText(
"Drag 'n' drop some files here, or click to select files",
),
).toBeInTheDocument();
});
});
describe('When the uploaded file is accepted', () => {
test('It should invoke the onSuccess handler', async () => {
const maxSize = 100000000;
render(
<FileUpload
onSuccess={mockOnSuccess}
onFailure={mockOnFailure}
maxSize={maxSize}
/>,
);
const validFile = createMockFile('file.csv', maxSize, 'text/csv');
const input = screen.getByTestId('file-upload');
fireEvent.drop(input, { target: { files: [validFile] } });
await waitFor(() => {
expect(mockOnSuccess).toHaveBeenCalled();
expect(mockOnFailure).not.toHaveBeenCalledWith([validFile]);
});
});
});
describe('Failure scenarios', () => {
test('The onFailure handler should be invoked if the file is too large', async () => {
const maxSize = 100000000;
const overMaxSize = 100000001;
render(
<FileUpload
onSuccess={mockOnSuccess}
onFailure={mockOnFailure}
maxSize={maxSize}
/>,
);
const invalidFile = createMockFile('file.txt', overMaxSize, 'text/plain');
const input = screen.getByTestId('file-upload');
fireEvent.drop(input, { target: { files: [invalidFile] } });
await waitFor(() => {
expect(mockOnSuccess).not.toHaveBeenCalled();
expect(mockOnFailure).toHaveBeenCalled();
});
});
/*
test('It should not allow inappropriate file types', () => {
const maxSize = 100000000;
render(
<FileUpload
onSuccess={mockOnSuccess}
onFailure={mockOnFailure}
maxSize={maxSize}
/>,
);
const invalidFile = createMockFile('file.csv', maxSize, 'text/plain');
const input = screen.getByTestId('file-upload');
fireEvent.drop(input, { target: { files: [invalidFile] } });
expect(mockOnSuccess).not.toHaveBeenCalled();
expect(mockOnFailure).toHaveBeenCalled();
});
*/
});
});
function createMockFile(name: string, size: number, mimeType: string) {
const blob = new Blob(['a'.repeat(size)], { type: mimeType });
return new File([blob], name, { type: mimeType });
}
Error:
FileUpload › When the uploaded file is accepted › It should invoke the onSuccess handler
thrown: "Exceeded timeout of 5000 ms for a test.
Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
32 |
33 | describe('When the uploaded file is accepted', () => {
> 34 | test('It should invoke the onSuccess handler', async () => {
| ^
35 | const maxSize = 100000000;
36 | render(
37 | <FileUpload
at src/lib/components/__tests__/file-upload.test.tsx:34:5
at src/lib/components/__tests__/file-upload.test.tsx:33:3
at Object.<anonymous> (src/lib/components/__tests__/file-upload.test.tsx:7:1)
● FileUpload › Failure scenarios › The onFailure handler should be invoked if the file is too large
thrown: "Exceeded timeout of 5000 ms for a test.
Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
54 |
55 | describe('Failure scenarios', () => {
> 56 | test('The onFailure handler should be invoked if the file is too large', async () => {
| ^
57 | const maxSize = 100000000;
58 | const overMaxSize = 100000001;
59 | render(
at src/lib/components/__tests__/file-upload.test.tsx:56:5
at src/lib/components/__tests__/file-upload.test.tsx:55:3
at Object.<anonymous> (src/lib/components/__tests__/file-upload.test.tsx:7:1)
Test Suites: 1 failed, 1 total
Tests: 2 failed, 1 passed, 3 total
Snapshots: 0 total
Time: 18.756 s
Ran all test suites.
```