feat: video editor fix to disappearing transcript (#178)
* feat: video editor fix to disappearing transcript
This commit is contained in:
@@ -1,70 +1,19 @@
|
||||
import { actions } from '../../../../../../data/redux';
|
||||
import { isEdxVideo } from '../../../../../../data/services/cms/api';
|
||||
|
||||
/**
|
||||
* updateVideoId({ dispatch })({e, source})
|
||||
* updateVideoId takes the current onBlur event, the current object of the video
|
||||
* source, and dispatch method, and updates the redux value for all the fields to
|
||||
* their default values except videoId, fallbackVideos, and handouts.
|
||||
* @param {event} e - object for onBlur event
|
||||
* @param {func} dispatch - redux dispatch method
|
||||
* @param {object} source - object for the Video Source field functions and values
|
||||
*/
|
||||
export const updateVideoId = ({ dispatch }) => ({ e, source }) => {
|
||||
if (source.local !== '') {
|
||||
if (source.formValue !== e.target.value) {
|
||||
source.onBlur(e);
|
||||
let videoId;
|
||||
let videoSource;
|
||||
if (isEdxVideo(source.local)) {
|
||||
videoId = source.local;
|
||||
videoSource = '';
|
||||
} else if (source.local.includes('youtu.be') || source.local.includes('youtube')) {
|
||||
videoId = '';
|
||||
videoSource = source.local;
|
||||
} else {
|
||||
videoId = '';
|
||||
videoSource = source.local;
|
||||
}
|
||||
dispatch(actions.video.updateField({
|
||||
videoId,
|
||||
videoSource,
|
||||
allowVideoDownloads: false,
|
||||
thumbnail: null,
|
||||
transcripts: [],
|
||||
allowTranscriptDownloads: false,
|
||||
showTranscriptByDefault: false,
|
||||
duration: {
|
||||
startTime: '00:00:00',
|
||||
stopTime: '00:00:00',
|
||||
total: '00:00:00',
|
||||
},
|
||||
licenseType: null,
|
||||
}));
|
||||
}
|
||||
}
|
||||
export const sourceHooks = ({ dispatch }) => ({
|
||||
updateVideoURL: (e) => dispatch(actions.video.updateField({ videoSource: e.target.value })),
|
||||
updateVideoId: (e) => dispatch(actions.video.updateField({ videoId: e.target.value })),
|
||||
});
|
||||
|
||||
export const fallbackHooks = ({ fallbackVideos, dispatch }) => ({
|
||||
addFallbackVideo: () => dispatch(actions.video.updateField({ fallbackVideos: [...fallbackVideos, ''] })),
|
||||
deleteFallbackVideo: (videoUrl) => {
|
||||
const updatedFallbackVideos = fallbackVideos.splice(fallbackVideos.indexOf(videoUrl), 1);
|
||||
dispatch(actions.video.updateField({ fallbackVideos: updatedFallbackVideos }));
|
||||
},
|
||||
});
|
||||
|
||||
export default {
|
||||
sourceHooks,
|
||||
fallbackHooks,
|
||||
};
|
||||
|
||||
/**
|
||||
* deleteFallbackVideo({ fallbackVideos, dispatch })(videoUrl)
|
||||
* deleteFallbackVideo takes the current array of fallback videos, string of
|
||||
* deleted video URL and dispatch method, and updates the redux value for
|
||||
* fallbackVideos.
|
||||
* @param {array} fallbackVideos - array of current fallback videos
|
||||
* @param {func} dispatch - redux dispatch method
|
||||
* @param {string} videoUrl - string of the video URL for the fallabck video that needs to be deleted
|
||||
*/
|
||||
export const deleteFallbackVideo = ({ fallbackVideos, dispatch }) => (videoUrl) => {
|
||||
const updatedFallbackVideos = [];
|
||||
let firstOccurence = true;
|
||||
fallbackVideos.forEach(item => {
|
||||
if (item === videoUrl && firstOccurence) {
|
||||
firstOccurence = false;
|
||||
} else {
|
||||
updatedFallbackVideos.push(item);
|
||||
}
|
||||
});
|
||||
dispatch(actions.video.updateField({ fallbackVideos: updatedFallbackVideos }));
|
||||
};
|
||||
|
||||
export default { deleteFallbackVideo };
|
||||
|
||||
@@ -6,6 +6,7 @@ jest.mock('react-redux', () => {
|
||||
const dispatchFn = jest.fn();
|
||||
return {
|
||||
...jest.requireActual('react-redux'),
|
||||
useSelector: jest.fn(),
|
||||
dispatch: dispatchFn,
|
||||
useDispatch: jest.fn(() => dispatchFn),
|
||||
};
|
||||
@@ -20,78 +21,61 @@ jest.mock('../../../../../../data/redux', () => ({
|
||||
}));
|
||||
|
||||
describe('VideoEditorHandout hooks', () => {
|
||||
describe('updateVideoId', () => {
|
||||
const sourceEdxVideo = {
|
||||
onBlur: jest.fn(),
|
||||
local: '06b15030-7df0-4e70-b979-326e02dbcbe0',
|
||||
};
|
||||
const sourceYouTube = {
|
||||
onBlur: jest.fn(),
|
||||
local: 'youtu.be',
|
||||
};
|
||||
const sourceHtml5Source = {
|
||||
onBlur: jest.fn(),
|
||||
local: 'sOMEranDomfILe.mp4',
|
||||
};
|
||||
const mockState = {
|
||||
videoId: '',
|
||||
videoSource: '',
|
||||
allowVideoDownloads: false,
|
||||
thumbnail: null,
|
||||
transcripts: [],
|
||||
allowTranscriptDownloads: false,
|
||||
showTranscriptByDefault: false,
|
||||
duration: {
|
||||
startTime: '00:00:00',
|
||||
stopTime: '00:00:00',
|
||||
total: '00:00:00',
|
||||
},
|
||||
licenseType: null,
|
||||
};
|
||||
it('returns dispatches updateField action with default state and edxVideo Id', () => {
|
||||
hooks.updateVideoId({ dispatch })({ e: { target: { value: sourceEdxVideo.local } }, source: sourceEdxVideo });
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
actions.video.updateField({
|
||||
...mockState,
|
||||
videoId: sourceEdxVideo.local,
|
||||
}),
|
||||
);
|
||||
let hook;
|
||||
|
||||
describe('sourceHooks', () => {
|
||||
const e = { target: { value: 'soMEvALuE' } };
|
||||
beforeEach(() => {
|
||||
hook = hooks.sourceHooks({ dispatch });
|
||||
});
|
||||
it('returns dispatches updateField action with default state and YouTube video', () => {
|
||||
hooks.updateVideoId({ dispatch })({
|
||||
e: { target: { value: sourceYouTube.local } },
|
||||
source: sourceYouTube,
|
||||
describe('updateVideoURL', () => {
|
||||
it('dispatches updateField action with new videoSource', () => {
|
||||
hook.updateVideoURL(e);
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
actions.video.updateField({
|
||||
videoSource: e.target.value,
|
||||
}),
|
||||
);
|
||||
});
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
actions.video.updateField({
|
||||
...mockState,
|
||||
}),
|
||||
);
|
||||
});
|
||||
it('returns dispatches updateField action with default state and html5source video', () => {
|
||||
hooks.updateVideoId({ dispatch })({
|
||||
e: { target: { value: sourceHtml5Source.local } },
|
||||
source: sourceHtml5Source,
|
||||
describe('updateVideoId', () => {
|
||||
it('dispatches updateField action with new videoId', () => {
|
||||
hook.updateVideoId(e);
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
actions.video.updateField({
|
||||
videoId: e.target.value,
|
||||
}),
|
||||
);
|
||||
});
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
actions.video.updateField({
|
||||
...mockState,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteFallbackVideo', () => {
|
||||
describe('fallbackHooks', () => {
|
||||
const videoUrl = 'sOmERAndoMuRl1';
|
||||
const fallbackVideos = ['sOmERAndoMuRl1', 'sOmERAndoMuRl2', 'sOmERAndoMuRl1', ''];
|
||||
const updatedFallbackVideos = ['sOmERAndoMuRl2', 'sOmERAndoMuRl1', ''];
|
||||
it('returns dispatches updateField action with updatedFallbackVideos', () => {
|
||||
hooks.deleteFallbackVideo({ fallbackVideos, dispatch })(videoUrl);
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
actions.video.updateField({
|
||||
fallbackVideos: updatedFallbackVideos,
|
||||
}),
|
||||
);
|
||||
beforeEach(() => {
|
||||
hook = hooks.fallbackHooks({ fallbackVideos, dispatch });
|
||||
});
|
||||
describe('addFallbackVideo', () => {
|
||||
it('dispatches updateField action with updated array appended by a new empty element', () => {
|
||||
hook.addFallbackVideo();
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
actions.video.updateField({
|
||||
fallbackVideos: [...fallbackVideos, ''],
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('deleteFallbackVideo', () => {
|
||||
it('dispatches updateField action with updated array with videoUrl removed', () => {
|
||||
const updatedFallbackVideos = ['sOmERAndoMuRl2', 'sOmERAndoMuRl1', ''];
|
||||
hook.deleteFallbackVideo(videoUrl);
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
actions.video.updateField({
|
||||
fallbackVideos: updatedFallbackVideos,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import { connect, useDispatch } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import {
|
||||
Form,
|
||||
@@ -20,9 +19,8 @@ import {
|
||||
} from '@edx/frontend-platform/i18n';
|
||||
|
||||
import * as widgetHooks from '../hooks';
|
||||
import * as module from './hooks';
|
||||
import * as hooks from './hooks';
|
||||
import messages from './messages';
|
||||
import { actions } from '../../../../../../data/redux';
|
||||
|
||||
import CollapsibleFormWidget from '../CollapsibleFormWidget';
|
||||
|
||||
@@ -32,8 +30,6 @@ import CollapsibleFormWidget from '../CollapsibleFormWidget';
|
||||
export const VideoSourceWidget = ({
|
||||
// injected
|
||||
intl,
|
||||
// redux
|
||||
updateField,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
@@ -50,8 +46,11 @@ export const VideoSourceWidget = ({
|
||||
[widgetHooks.selectorKeys.allowVideoDownloads]: widgetHooks.genericWidget,
|
||||
},
|
||||
});
|
||||
const deleteFallbackVideo = module.deleteFallbackVideo({ fallbackVideos: fallbackVideos.formValue, dispatch });
|
||||
const updateVideoId = module.updateVideoId({ dispatch });
|
||||
const { updateVideoId, updateVideoURL } = hooks.sourceHooks({ dispatch });
|
||||
const {
|
||||
addFallbackVideo,
|
||||
deleteFallbackVideo,
|
||||
} = hooks.fallbackHooks({ fallbackVideos: fallbackVideos.formValue, dispatch });
|
||||
|
||||
return (
|
||||
<CollapsibleFormWidget
|
||||
@@ -63,7 +62,7 @@ export const VideoSourceWidget = ({
|
||||
<Form.Control
|
||||
floatingLabel={intl.formatMessage(messages.videoIdLabel)}
|
||||
onChange={videoId.onChange}
|
||||
onBlur={(e) => updateVideoId({ e, source: videoId })}
|
||||
onBlur={updateVideoId}
|
||||
value={videoId.local}
|
||||
/>
|
||||
<FormControlFeedback className="text-primary-300 mb-4">
|
||||
@@ -72,7 +71,7 @@ export const VideoSourceWidget = ({
|
||||
<Form.Control
|
||||
floatingLabel={intl.formatMessage(messages.videoUrlLabel)}
|
||||
onChange={source.onChange}
|
||||
onBlur={(e) => updateVideoId({ e, source })}
|
||||
onBlur={updateVideoURL}
|
||||
value={source.local}
|
||||
/>
|
||||
<FormControlFeedback className="text-primary-300">
|
||||
@@ -134,7 +133,7 @@ export const VideoSourceWidget = ({
|
||||
size="sm"
|
||||
iconBefore={Add}
|
||||
variant="link"
|
||||
onClick={() => updateField({ fallbackVideos: [...fallbackVideos.formValue, ''] })}
|
||||
onClick={() => addFallbackVideo()}
|
||||
>
|
||||
<FormattedMessage {...messages.addButtonLabel} />
|
||||
</Button>
|
||||
@@ -144,12 +143,6 @@ export const VideoSourceWidget = ({
|
||||
VideoSourceWidget.propTypes = {
|
||||
// injected
|
||||
intl: intlShape.isRequired,
|
||||
// redux
|
||||
updateField: PropTypes.func.isRequired,
|
||||
};
|
||||
export const mapStateToProps = () => ({});
|
||||
|
||||
export const mapDispatchToProps = (dispatch) => ({
|
||||
updateField: (stateUpdate) => dispatch(actions.video.updateField(stateUpdate)),
|
||||
});
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(VideoSourceWidget));
|
||||
export default injectIntl(VideoSourceWidget);
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
import React from 'react';
|
||||
import { dispatch } from 'react-redux';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { formatMessage } from '../../../../../../../testUtils';
|
||||
import { actions } from '../../../../../../data/redux';
|
||||
import { VideoSourceWidget, mapDispatchToProps } from '.';
|
||||
import { VideoSourceWidget } from '.';
|
||||
import * as hooks from './hooks';
|
||||
|
||||
jest.mock('../../../../../../data/redux', () => ({
|
||||
actions: {
|
||||
video: {
|
||||
updateField: jest.fn().mockName('actions.video.updateField'),
|
||||
},
|
||||
},
|
||||
selectors: {
|
||||
video: {
|
||||
videoSource: jest.fn(state => ({ videoSource: state })),
|
||||
videoId: jest.fn(state => ({ videoId: state })),
|
||||
fallbackVideos: jest.fn(state => ({ fallbackVideos: state })),
|
||||
allowVideoDownloads: jest.fn(state => ({ allowVideoDownloads: state })),
|
||||
},
|
||||
},
|
||||
}));
|
||||
jest.mock('react-redux', () => {
|
||||
const dispatchFn = jest.fn();
|
||||
return {
|
||||
...jest.requireActual('react-redux'),
|
||||
dispatch: dispatchFn,
|
||||
useDispatch: jest.fn(() => dispatchFn),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../hooks', () => ({
|
||||
selectorKeys: ['soMEkEy'],
|
||||
@@ -36,14 +30,21 @@ jest.mock('../hooks', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('./hooks', () => ({
|
||||
sourceHooks: jest.fn().mockReturnValue({
|
||||
updateVideoId: (args) => ({ updateVideoId: args }),
|
||||
updateVideoURL: (args) => ({ updateVideoURL: args }),
|
||||
}),
|
||||
fallbackHooks: jest.fn().mockReturnValue({
|
||||
addFallbackVideo: jest.fn().mockName('addFallbackVideo'),
|
||||
deleteFallbackVideo: jest.fn().mockName('deleteFallbackVideo'),
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('VideoSourceWidget', () => {
|
||||
const props = {
|
||||
error: {},
|
||||
title: 'tiTLE',
|
||||
// inject
|
||||
intl: { formatMessage },
|
||||
// redux
|
||||
updateField: jest.fn().mockName('args.updateField'),
|
||||
};
|
||||
|
||||
describe('snapshots', () => {
|
||||
@@ -53,10 +54,27 @@ describe('VideoSourceWidget', () => {
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
const dispatch = jest.fn();
|
||||
test('updateField from actions.video.updateField', () => {
|
||||
expect(mapDispatchToProps.updateField).toEqual(dispatch(actions.video.updateField));
|
||||
|
||||
describe('behavior inspection', () => {
|
||||
let el;
|
||||
let hook;
|
||||
beforeEach(() => {
|
||||
el = shallow(<VideoSourceWidget {...props} />);
|
||||
hook = hooks.sourceHooks({ dispatch });
|
||||
});
|
||||
test('updateVideoId is tied to id field onBlur', () => {
|
||||
const expected = hook.updateVideoId;
|
||||
expect(el
|
||||
// eslint-disable-next-line
|
||||
.children().at(0).children().at(0).children().at(0)
|
||||
.props().onBlur).toEqual(expected);
|
||||
});
|
||||
test('updateVideoURL is tied to url field onBlur', () => {
|
||||
const expected = hook.updateVideoURL;
|
||||
expect(el
|
||||
// eslint-disable-next-line
|
||||
.children().at(0).children().at(0).children().at(2)
|
||||
.props().onBlur).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,10 +11,10 @@ export const loadVideoData = () => (dispatch, getState) => {
|
||||
const courseLicenseData = state.app.courseDetails.data ? state.app.courseDetails.data : {};
|
||||
const studioView = state.app.studioView?.data?.html;
|
||||
const {
|
||||
videoSource,
|
||||
videoId,
|
||||
videoUrl,
|
||||
fallbackVideos,
|
||||
} = module.determineVideoSource({
|
||||
} = module.determineVideoSources({
|
||||
edxVideoId: rawVideoData.edx_video_id,
|
||||
youtubeId: rawVideoData.youtube_id_1_0,
|
||||
html5Sources: rawVideoData.html5_sources,
|
||||
@@ -27,7 +27,7 @@ export const loadVideoData = () => (dispatch, getState) => {
|
||||
});
|
||||
|
||||
dispatch(actions.video.load({
|
||||
videoSource,
|
||||
videoSource: videoUrl,
|
||||
videoId,
|
||||
fallbackVideos,
|
||||
allowVideoDownloads: rawVideoData.download_video,
|
||||
@@ -61,7 +61,7 @@ export const loadVideoData = () => (dispatch, getState) => {
|
||||
allowThumbnailUpload: response.data.allowThumbnailUpload,
|
||||
})),
|
||||
}));
|
||||
const youTubeId = parseYoutubeId(videoSource);
|
||||
const youTubeId = parseYoutubeId(videoUrl);
|
||||
if (youTubeId) {
|
||||
dispatch(requests.checkTranscriptsForImport({
|
||||
videoId,
|
||||
@@ -77,33 +77,23 @@ export const loadVideoData = () => (dispatch, getState) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const determineVideoSource = ({
|
||||
export const determineVideoSources = ({
|
||||
edxVideoId,
|
||||
youtubeId,
|
||||
html5Sources,
|
||||
}) => {
|
||||
// videoSource should be the edx_video_id, the youtube url or the first fallback url in that order.
|
||||
// If we are falling back to the first fallback url, remove it from the list of fallback urls for display.
|
||||
const youtubeUrl = `https://youtu.be/${youtubeId}`;
|
||||
const videoId = edxVideoId || '';
|
||||
let videoSource = '';
|
||||
let fallbackVideos = [];
|
||||
let videoUrl;
|
||||
let fallbackVideos;
|
||||
if (youtubeId) {
|
||||
// videoSource = youtubeUrl;
|
||||
// fallbackVideos = html5Sources;
|
||||
[videoSource, fallbackVideos] = [youtubeUrl, html5Sources];
|
||||
} else if (edxVideoId) {
|
||||
// fallbackVideos = html5Sources;
|
||||
fallbackVideos = html5Sources;
|
||||
[videoUrl, fallbackVideos] = [youtubeUrl, html5Sources];
|
||||
} else if (Array.isArray(html5Sources) && html5Sources[0]) {
|
||||
// videoSource = html5Sources[0];
|
||||
// fallbackVideos = html5Sources.slice(1);
|
||||
[videoSource, fallbackVideos] = [html5Sources[0], html5Sources.slice(1)];
|
||||
[videoUrl, fallbackVideos] = [html5Sources[0], html5Sources.slice(1)];
|
||||
}
|
||||
return {
|
||||
videoSource,
|
||||
videoId,
|
||||
fallbackVideos,
|
||||
videoId: edxVideoId,
|
||||
videoUrl: videoUrl || '',
|
||||
fallbackVideos: fallbackVideos || [],
|
||||
};
|
||||
};
|
||||
|
||||
@@ -343,7 +333,7 @@ export const replaceTranscript = ({ newFile, newFilename, language }) => (dispat
|
||||
|
||||
export default {
|
||||
loadVideoData,
|
||||
determineVideoSource,
|
||||
determineVideoSources,
|
||||
parseLicense,
|
||||
saveVideoData,
|
||||
uploadThumbnail,
|
||||
|
||||
@@ -99,8 +99,8 @@ describe('video thunkActions', () => {
|
||||
let dispatchedAction1;
|
||||
let dispatchedAction2;
|
||||
beforeEach(() => {
|
||||
jest.spyOn(thunkActions, thunkActionsKeys.determineVideoSource).mockReturnValue({
|
||||
videoSource: 'videOsOurce',
|
||||
jest.spyOn(thunkActions, thunkActionsKeys.determineVideoSources).mockReturnValue({
|
||||
videoUrl: 'videOsOurce',
|
||||
videoId: 'videOiD',
|
||||
fallbackVideos: 'fALLbACKvIDeos',
|
||||
});
|
||||
@@ -176,69 +176,69 @@ describe('video thunkActions', () => {
|
||||
}));
|
||||
});
|
||||
});
|
||||
describe('determineVideoSource', () => {
|
||||
describe('determineVideoSources', () => {
|
||||
const edxVideoId = 'EDxviDEoiD';
|
||||
const youtubeId = 'yOuTuBEiD';
|
||||
const youtubeUrl = `https://youtu.be/${youtubeId}`;
|
||||
const html5Sources = ['htmLOne', 'hTMlTwo', 'htMLthrEE'];
|
||||
describe('when there is an edx video id, youtube id and html5 sources', () => {
|
||||
it('returns the youtube id for video source and html5 sources for fallback videos', () => {
|
||||
expect(thunkActions.determineVideoSource({
|
||||
it('returns all three with the youtube id wrapped in url', () => {
|
||||
expect(thunkActions.determineVideoSources({
|
||||
edxVideoId,
|
||||
youtubeId,
|
||||
html5Sources,
|
||||
})).toEqual({
|
||||
videoSource: youtubeUrl,
|
||||
videoUrl: youtubeUrl,
|
||||
videoId: edxVideoId,
|
||||
fallbackVideos: html5Sources,
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when there is an edx video id', () => {
|
||||
describe('when there is only an edx video id', () => {
|
||||
it('returns the edx video id for video source', () => {
|
||||
expect(thunkActions.determineVideoSource({
|
||||
expect(thunkActions.determineVideoSources({
|
||||
edxVideoId,
|
||||
youtubeId: '',
|
||||
html5Sources: '',
|
||||
})).toEqual({
|
||||
videoSource: '',
|
||||
videoUrl: '',
|
||||
videoId: edxVideoId,
|
||||
fallbackVideos: '',
|
||||
fallbackVideos: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when there is no edx video id', () => {
|
||||
it('returns the youtube url for video source and html5 sources for fallback videos', () => {
|
||||
expect(thunkActions.determineVideoSource({
|
||||
expect(thunkActions.determineVideoSources({
|
||||
edxVideoId: '',
|
||||
youtubeId,
|
||||
html5Sources,
|
||||
})).toEqual({
|
||||
videoSource: youtubeUrl,
|
||||
videoUrl: youtubeUrl,
|
||||
videoId: '',
|
||||
fallbackVideos: html5Sources,
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when there is no edx video id and no youtube id', () => {
|
||||
it('returns the first html5 source for video source and the rest for fallback videos', () => {
|
||||
expect(thunkActions.determineVideoSource({
|
||||
it('returns the first html5 source for video url and the rest for fallback videos', () => {
|
||||
expect(thunkActions.determineVideoSources({
|
||||
edxVideoId: '',
|
||||
youtubeId: '',
|
||||
html5Sources,
|
||||
})).toEqual({
|
||||
videoSource: 'htmLOne',
|
||||
videoUrl: 'htmLOne',
|
||||
videoId: '',
|
||||
fallbackVideos: ['hTMlTwo', 'htMLthrEE'],
|
||||
});
|
||||
});
|
||||
it('returns the html5 source for video source and an array with 2 empty values for fallback videos', () => {
|
||||
expect(thunkActions.determineVideoSource({
|
||||
expect(thunkActions.determineVideoSources({
|
||||
edxVideoId: '',
|
||||
youtubeId: '',
|
||||
html5Sources: ['htmlOne'],
|
||||
})).toEqual({
|
||||
videoSource: 'htmlOne',
|
||||
videoUrl: 'htmlOne',
|
||||
videoId: '',
|
||||
fallbackVideos: [],
|
||||
});
|
||||
@@ -246,12 +246,12 @@ describe('video thunkActions', () => {
|
||||
});
|
||||
describe('when there is no edx video id, no youtube id and no html5 sources', () => {
|
||||
it('returns an empty string for video source and an array with 2 empty values for fallback videos', () => {
|
||||
expect(thunkActions.determineVideoSource({
|
||||
expect(thunkActions.determineVideoSources({
|
||||
edxVideoId: '',
|
||||
youtubeId: '',
|
||||
html5Sources: [],
|
||||
})).toEqual({
|
||||
videoSource: '',
|
||||
videoUrl: '',
|
||||
videoId: '',
|
||||
fallbackVideos: [],
|
||||
});
|
||||
|
||||
@@ -157,7 +157,7 @@ export const apiMethods = {
|
||||
youtubeId,
|
||||
} = module.processVideoIds({
|
||||
videoId: content.videoId,
|
||||
videoSource: content.videoSource,
|
||||
videoUrl: content.videoSource,
|
||||
fallbackVideos: content.fallbackVideos,
|
||||
});
|
||||
response = {
|
||||
@@ -217,21 +217,18 @@ export const loadImages = (rawImages) => camelizeKeys(rawImages).reduce(
|
||||
|
||||
export const processVideoIds = ({
|
||||
videoId,
|
||||
videoSource,
|
||||
videoUrl,
|
||||
fallbackVideos,
|
||||
edxVideoId,
|
||||
}) => {
|
||||
let newEdxVideoId = edxVideoId;
|
||||
let youtubeId = '';
|
||||
const html5Sources = [];
|
||||
|
||||
// overwrite videoId if source is changed.
|
||||
if (module.isEdxVideo(videoId)) {
|
||||
newEdxVideoId = videoId;
|
||||
} else if (module.parseYoutubeId(videoSource)) {
|
||||
youtubeId = module.parseYoutubeId(videoSource);
|
||||
} else if (videoSource) {
|
||||
html5Sources.push(videoSource);
|
||||
if (videoUrl) {
|
||||
if (module.parseYoutubeId(videoUrl)) {
|
||||
youtubeId = module.parseYoutubeId(videoUrl);
|
||||
} else {
|
||||
html5Sources.push(videoUrl);
|
||||
}
|
||||
}
|
||||
|
||||
if (fallbackVideos) {
|
||||
@@ -239,7 +236,7 @@ export const processVideoIds = ({
|
||||
}
|
||||
|
||||
return {
|
||||
edxVideoId: newEdxVideoId,
|
||||
edxVideoId: videoId,
|
||||
html5Sources,
|
||||
youtubeId,
|
||||
};
|
||||
|
||||
@@ -333,7 +333,8 @@ describe('cms api', () => {
|
||||
});
|
||||
describe('processVideoIds', () => {
|
||||
const edxVideoId = 'eDXviDEoid';
|
||||
const youtubeId = 'yOuTuBeID';
|
||||
const youtubeId = 'yOuTuBeUrL';
|
||||
const youtubeUrl = `https://youtu.be/${youtubeId}`;
|
||||
const html5Sources = [
|
||||
'sOuRce1',
|
||||
'sourCE2',
|
||||
@@ -341,15 +342,14 @@ describe('cms api', () => {
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
describe('if the videoSource is an edx video id', () => {
|
||||
describe('if there is a video id', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(api, 'isEdxVideo').mockReturnValue(true);
|
||||
jest.spyOn(api, 'parseYoutubeId').mockReturnValue(null);
|
||||
jest.spyOn(api, 'parseYoutubeId').mockReturnValue(youtubeId);
|
||||
});
|
||||
it('returns edxVideoId when there are no fallbackVideos', () => {
|
||||
expect(api.processVideoIds({
|
||||
edxVideoId,
|
||||
videoSource: '',
|
||||
videoUrl: '',
|
||||
fallbackVideos: [],
|
||||
videoId: edxVideoId,
|
||||
})).toEqual({
|
||||
@@ -360,42 +360,39 @@ describe('cms api', () => {
|
||||
});
|
||||
it('returns edxVideoId and html5Sources when there are fallbackVideos', () => {
|
||||
expect(api.processVideoIds({
|
||||
edxVideoId,
|
||||
videoSource: 'edxVideoId',
|
||||
videoUrl: youtubeUrl,
|
||||
fallbackVideos: html5Sources,
|
||||
videoId: edxVideoId,
|
||||
})).toEqual({
|
||||
edxVideoId,
|
||||
html5Sources,
|
||||
youtubeId: '',
|
||||
youtubeId,
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('if the videoSource is a youtube url', () => {
|
||||
describe('if there is a youtube url', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(api, 'isEdxVideo').mockReturnValue(false);
|
||||
jest.spyOn(api, 'parseYoutubeId').mockReturnValue(youtubeId);
|
||||
});
|
||||
it('returns youtubeId when there are no fallbackVideos', () => {
|
||||
expect(api.processVideoIds({
|
||||
edxVideoId,
|
||||
videoSource: edxVideoId,
|
||||
videoUrl: youtubeUrl,
|
||||
fallbackVideos: [],
|
||||
videoId: '',
|
||||
})).toEqual({
|
||||
edxVideoId,
|
||||
edxVideoId: '',
|
||||
html5Sources: [],
|
||||
youtubeId,
|
||||
});
|
||||
});
|
||||
it('returns youtubeId and html5Sources when there are fallbackVideos', () => {
|
||||
expect(api.processVideoIds({
|
||||
edxVideoId,
|
||||
videoSource: edxVideoId,
|
||||
videoUrl: youtubeUrl,
|
||||
fallbackVideos: html5Sources,
|
||||
videoId: '',
|
||||
})).toEqual({
|
||||
edxVideoId,
|
||||
edxVideoId: '',
|
||||
html5Sources,
|
||||
youtubeId,
|
||||
});
|
||||
@@ -408,24 +405,22 @@ describe('cms api', () => {
|
||||
});
|
||||
it('returns html5Sources when there are no fallbackVideos', () => {
|
||||
expect(api.processVideoIds({
|
||||
edxVideoId,
|
||||
videoSource: html5Sources[0],
|
||||
videoUrl: html5Sources[0],
|
||||
fallbackVideos: [],
|
||||
videoId: '',
|
||||
})).toEqual({
|
||||
edxVideoId,
|
||||
edxVideoId: '',
|
||||
html5Sources: [html5Sources[0]],
|
||||
youtubeId: '',
|
||||
});
|
||||
});
|
||||
it('returns html5Sources when there are fallbackVideos', () => {
|
||||
expect(api.processVideoIds({
|
||||
edxVideoId,
|
||||
videoSource: html5Sources[0],
|
||||
videoUrl: html5Sources[0],
|
||||
fallbackVideos: [html5Sources[1]],
|
||||
videoId: '',
|
||||
})).toEqual({
|
||||
edxVideoId,
|
||||
edxVideoId: '',
|
||||
html5Sources,
|
||||
youtubeId: '',
|
||||
});
|
||||
|
||||
@@ -287,3 +287,7 @@ export const fetchStudioView = ({ blockId, studioEndpointUrl }) => {
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const checkTranscriptsForImport = () => mockPromise({});
|
||||
|
||||
export const uploadTranscript = () => mockPromise({});
|
||||
|
||||
Reference in New Issue
Block a user