Merge pull request #354 from open-craft/farhaan/bb-7522-fix-spinner-for-video

feat: Add loading spinner to the video upload page
This commit is contained in:
kenclary
2023-06-30 11:10:50 -04:00
committed by GitHub
8 changed files with 511 additions and 440 deletions

View File

@@ -370,6 +370,45 @@ export const replaceTranscript = ({ newFile, newFilename, language }) => (dispat
}));
};
export const uploadVideo = ({ supportedFiles, setLoadSpinner, postUploadRedirect }) => (dispatch) => {
const data = { files: [] };
setLoadSpinner(true);
supportedFiles.forEach((file) => {
data.files.push({
file_name: file.name,
content_type: file.type,
});
});
dispatch(requests.uploadVideo({
data,
onSuccess: async (response) => {
const { files } = response.data;
await Promise.all(Object.values(files).map(async (fileObj) => {
const fileName = fileObj.file_name;
const edxVideoId = fileObj.edx_video_id;
const uploadUrl = fileObj.upload_url;
const uploadFile = supportedFiles.find((file) => file.name === fileName);
if (!uploadFile) {
console.error(`Could not find file object with name "${fileName}" in supportedFiles array.`);
return;
}
const formData = new FormData();
formData.append('uploaded-file', uploadFile);
await fetch(uploadUrl, {
method: 'PUT',
body: formData,
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then(() => postUploadRedirect(edxVideoId))
.catch((error) => console.error('Error uploading file:', error));
}));
setLoadSpinner(false);
},
}));
};
export default {
loadVideoData,
determineVideoSources,
@@ -382,4 +421,5 @@ export default {
updateTranscriptLanguage,
replaceTranscript,
uploadHandout,
uploadVideo,
};

View File

@@ -32,6 +32,7 @@ jest.mock('./requests', () => ({
checkTranscriptsForImport: (args) => ({ checkTranscriptsForImport: args }),
importTranscript: (args) => ({ importTranscript: args }),
fetchVideoFeatures: (args) => ({ fetchVideoFeatures: args }),
uploadVideo: (args) => ({ uploadVideo: args }),
}));
jest.mock('../../../utils', () => ({
@@ -669,3 +670,79 @@ describe('video thunkActions', () => {
});
});
});
describe('uploadVideo', () => {
let dispatch;
let setLoadSpinner;
let postUploadRedirect;
let dispatchedAction;
const supportedFiles = [
new File(['content1'], 'file1.mp4', { type: 'video/mp4' }),
new File(['content2'], 'file2.mov', { type: 'video/quicktime' }),
];
beforeEach(() => {
dispatch = jest.fn((action) => ({ dispatch: action }));
setLoadSpinner = jest.fn();
postUploadRedirect = jest.fn();
jest.resetAllMocks();
jest.restoreAllMocks();
});
it('dispatch uploadVideo action with right data', async () => {
const data = {
files: [
{ file_name: 'file1.mp4', content_type: 'video/mp4' },
{ file_name: 'file2.mov', content_type: 'video/quicktime' },
],
};
thunkActions.uploadVideo({ supportedFiles, setLoadSpinner, postUploadRedirect })(dispatch);
[[dispatchedAction]] = dispatch.mock.calls;
expect(dispatchedAction.uploadVideo).not.toEqual(undefined);
expect(setLoadSpinner).toHaveBeenCalled();
expect(dispatchedAction.uploadVideo.data).toEqual(data);
});
it('should call fetch with correct arguments for each file', async () => {
const mockResponseData = { success: true };
const mockFetchResponse = Promise.resolve({ data: mockResponseData });
global.fetch = jest.fn().mockImplementation(() => mockFetchResponse);
const response = {
files: [
{ file_name: 'file1.mp4', upload_url: 'http://example.com/put_video1' },
{ file_name: 'file2.mov', upload_url: 'http://example.com/put_video2' },
],
};
const mockRequestResponse = { data: response };
thunkActions.uploadVideo({ supportedFiles, setLoadSpinner, postUploadRedirect })(dispatch);
[[dispatchedAction]] = dispatch.mock.calls;
dispatchedAction.uploadVideo.onSuccess(mockRequestResponse);
expect(fetch).toHaveBeenCalledTimes(2);
response.files.forEach(({ upload_url: uploadUrl }, index) => {
expect(fetch.mock.calls[index][0]).toEqual(uploadUrl);
});
supportedFiles.forEach((file, index) => {
expect(fetch.mock.calls[index][1].body.get('uploaded-file')).toBe(file);
});
});
it('should log an error if file object is not found in supportedFiles array', () => {
const mockResponseData = { success: true };
const mockFetchResponse = Promise.resolve({ data: mockResponseData });
global.fetch = jest.fn().mockImplementation(() => mockFetchResponse);
const response = {
files: [
{ file_name: 'file2.gif', upload_url: 'http://example.com/put_video2' },
],
};
const mockRequestResponse = { data: response };
const spyConsoleError = jest.spyOn(console, 'error');
thunkActions.uploadVideo({ supportedFiles: [supportedFiles[0]], setLoadSpinner, postUploadRedirect })(dispatch);
dispatchedAction.uploadVideo.onSuccess(mockRequestResponse);
expect(spyConsoleError).toHaveBeenCalledWith('Could not find file object with name "file2.gif" in supportedFiles array.');
});
});