@dabapps/django-s3-file-upload
Version:
Upload files from the browser to S3 - client side implementation
177 lines (130 loc) • 5.55 kB
text/typescript
import { mockPromiseAll } from './helpers/mock-promise-all';
jest.spyOn(Promise, 'all').mockImplementation(mockPromiseAll);
import { MockPromise } from './helpers/mock-promise';
import {
createActionSet,
createFileUploadAction,
FileAndACL,
FileUploadOptions,
} from '../src';
import { uploadFileWithLoading } from '../src/actions';
import * as requests from '../src/upload-file-to-s3';
describe('upload actions', () => {
const mockUploadFileToS3 = jest
.spyOn(requests, 'uploadFileToS3')
.mockImplementation(
(file: File | FileAndACL) =>
new MockPromise({ arguments: [file], thenCalls: [], catchCalls: [] })
);
beforeEach(() => {
mockPromiseAll.clear();
mockUploadFileToS3.mockClear();
});
describe('createFileUploadAction', () => {
const ACTION_SET = createActionSet('PROFILE_PICTURE_UPLOAD');
it('should create a thunk action creator', () => {
const actionCreator = createFileUploadAction(ACTION_SET);
expect(typeof actionCreator).toBe('function');
const action = actionCreator([]);
expect(typeof action).toBe('function');
});
it('should dispatch some actions, construct a request for each file, and return a promise', () => {
const dispatch = jest.fn();
const files = [new File([], 'file-1.jpg'), new File([], 'file-2.jpg')];
const actionCreator = createFileUploadAction(ACTION_SET);
const action = actionCreator(files);
const result = action(dispatch);
const { calls: dispatchCalls } = dispatch.mock;
expect(result instanceof MockPromise).toBe(true);
expect(dispatchCalls.length).toBe(3);
// Initially dispatch the begin action
expect(dispatchCalls[0]).toEqual([
{ type: ACTION_SET.BEGIN, payload: 2 },
]);
// Then dispatch a request action for each file
expect(dispatchCalls[1]).toEqual([{ type: ACTION_SET.REQUEST }]);
expect(dispatchCalls[2]).toEqual([{ type: ACTION_SET.REQUEST }]);
const { calls: promiseAllCalls } = mockPromiseAll;
expect(promiseAllCalls.length).toBe(1);
// List of file promises is only argument
expect(promiseAllCalls[0].arguments.length).toBe(1);
// Should be 2 file promises (one for each file)
expect(promiseAllCalls[0].arguments[0].length).toBe(2);
// Check that the array actually contains promises
expect(promiseAllCalls[0].arguments[0][0] instanceof MockPromise).toBe(
true
);
expect(promiseAllCalls[0].arguments[0][1] instanceof MockPromise).toBe(
true
);
});
it('should rethrow if the shouldRethrow option returns true', () => {
const mutableOptions: FileUploadOptions = {};
const actionCreator = createFileUploadAction(ACTION_SET, mutableOptions);
const action = actionCreator([]);
action(jest.fn());
const { calls: promiseAllCalls } = mockPromiseAll;
const { thenCalls, catchCalls } = promiseAllCalls[0];
expect(thenCalls.length).toBe(0);
expect(catchCalls.length).toBe(1);
const [onlyCatchCall] = catchCalls;
expect(onlyCatchCall.arguments.length).toBe(1);
const [callback] = onlyCatchCall.arguments;
expect(() => callback('an error')).not.toThrow();
mutableOptions.shouldRethrow = () => true;
expect(() => callback('an error')).toThrow('an error');
});
});
describe('uploadFileWithLoading', () => {
const ACTION_SET = createActionSet('PROFILE_PICTURE_UPLOAD');
it('calls uploadFileToS3 and returns a promise', () => {
const mockFile = new File([], 'file.png');
const result = uploadFileWithLoading(
ACTION_SET,
mockFile,
jest.fn()
) as MockPromise;
expect(requests.uploadFileToS3).toHaveBeenCalledTimes(1);
expect(requests.uploadFileToS3).toHaveBeenCalledWith(mockFile);
expect(result instanceof MockPromise).toBe(true);
});
it('should dispatch a request and success action (when successful)', () => {
const dispatch = jest.fn();
const result = uploadFileWithLoading(
ACTION_SET,
new File([], 'file.pdf'),
dispatch
) as MockPromise;
const { thenCalls } = result.call;
expect(thenCalls.length).toBe(1);
expect(thenCalls[0].arguments.length).toBe(1);
const [thenCallback] = thenCalls[0].arguments;
thenCallback('response data');
const { calls: dispatchCalls } = dispatch.mock;
expect(dispatchCalls.length).toBe(2);
expect(dispatchCalls[0]).toEqual([{ type: ACTION_SET.REQUEST }]);
expect(dispatchCalls[1]).toEqual([
{ type: ACTION_SET.SUCCESS, payload: 'response data' },
]);
});
it('should throw, and dispatch a request and failure action (when unsuccessful)', () => {
const dispatch = jest.fn();
const result = uploadFileWithLoading(
ACTION_SET,
new File([], 'file.pdf'),
dispatch
) as MockPromise;
const { catchCalls } = result.call;
expect(catchCalls.length).toBe(1);
expect(catchCalls[0].arguments.length).toBe(1);
const [catchCallback] = catchCalls[0].arguments;
expect(() => catchCallback('some error')).toThrow('some error');
const { calls: dispatchCalls } = dispatch.mock;
expect(dispatchCalls.length).toBe(2);
expect(dispatchCalls[0]).toEqual([{ type: ACTION_SET.REQUEST }]);
expect(dispatchCalls[1]).toEqual([
{ type: ACTION_SET.FAILURE, payload: 'some error' },
]);
});
});
});