test: replacing snapshot tests with RTL tests part 5 (#2143)
* test: replacing snapshot tests with rtl tests part 5 * test: removig extra tests * test: snaps update * test: adding import shorthand and turning tests into ts * docs: clarify which line the comment is about --------- Co-authored-by: Braden MacDonald <braden@opencraft.com>
This commit is contained in:
committed by
GitHub
parent
96df339be5
commit
cba4e684ab
@@ -11,6 +11,9 @@ module.exports = createConfig('jest', {
|
||||
],
|
||||
moduleNameMapper: {
|
||||
'^lodash-es$': 'lodash',
|
||||
// This alias is for any code in the src directory that wants to avoid '../../' style relative imports:
|
||||
'^@src/(.*)$': '<rootDir>/src/$1',
|
||||
// This alias is used for plugins in the plugins/ folder only.
|
||||
'^CourseAuthoring/(.*)$': '<rootDir>/src/$1',
|
||||
},
|
||||
modulePathIgnorePatterns: [
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
// @ts-check
|
||||
import React from 'react';
|
||||
import { shallow } from '@edx/react-unit-test-utils';
|
||||
import EditorContainer from './EditorContainer';
|
||||
import { mockWaffleFlags } from '../data/apiHooks.mock';
|
||||
|
||||
mockWaffleFlags();
|
||||
|
||||
const mockPathname = '/editor/';
|
||||
jest.mock('react-router-dom', () => ({
|
||||
...jest.requireActual('react-router-dom'), // use actual for all non-hook parts
|
||||
useParams: () => ({
|
||||
blockId: 'company-id1',
|
||||
blockType: 'html',
|
||||
}),
|
||||
useLocation: () => ({
|
||||
pathname: mockPathname,
|
||||
}),
|
||||
useSearchParams: () => [{
|
||||
get: () => 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd',
|
||||
}],
|
||||
}));
|
||||
|
||||
jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
...jest.requireActual('@edx/frontend-platform/i18n'),
|
||||
useIntl: () => ({
|
||||
formatMessage: (message) => message.defaultMessage,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('react-redux', () => ({
|
||||
...jest.requireActual('react-redux'),
|
||||
useSelector: () => ({
|
||||
useReactMarkdownEditor: true, // or false depending on the test
|
||||
}),
|
||||
}));
|
||||
|
||||
const props = { learningContextId: 'cOuRsEId' };
|
||||
|
||||
describe('Editor Container', () => {
|
||||
describe('snapshots', () => {
|
||||
test('rendering correctly with expected Input', () => {
|
||||
expect(shallow(<EditorContainer {...props} />).snapshot).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
94
src/editors/EditorContainer.test.tsx
Normal file
94
src/editors/EditorContainer.test.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import React from 'react';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import {
|
||||
render, screen, initializeMocks, fireEvent, act,
|
||||
} from '@src/testUtils';
|
||||
import EditorContainer from './EditorContainer';
|
||||
import { mockWaffleFlags } from '../data/apiHooks.mock';
|
||||
import editorCmsApi from './data/services/cms/api';
|
||||
|
||||
mockWaffleFlags();
|
||||
|
||||
const mockPathname = '/editor/';
|
||||
jest.mock('react-router-dom', () => ({
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useParams: () => ({
|
||||
blockId: 'block-v1:Org+TS100+24+type@fake+block@123456fake',
|
||||
blockType: 'fake',
|
||||
}),
|
||||
useLocation: () => ({
|
||||
pathname: mockPathname,
|
||||
}),
|
||||
useSearchParams: () => [{
|
||||
get: () => 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd',
|
||||
}],
|
||||
}));
|
||||
|
||||
jest.mock('react-redux', () => ({
|
||||
...jest.requireActual('react-redux'),
|
||||
useSelector: () => ({
|
||||
useReactMarkdownEditor: true, // or false depending on the test
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mock this plugins component:
|
||||
jest.mock('frontend-components-tinymce-advanced-plugins', () => ({ a11ycheckerCss: '' }));
|
||||
// Always mock out the "fetch course images" endpoint:
|
||||
jest.spyOn(editorCmsApi, 'fetchCourseImages').mockImplementation(async () => ( // eslint-disable-next-line
|
||||
{ data: { assets: [], start: 0, end: 0, page: 0, pageSize: 50, totalCount: 0 } }
|
||||
));
|
||||
// Mock out the 'get ancestors' API:
|
||||
jest.spyOn(editorCmsApi, 'fetchByUnitId').mockImplementation(async () => ({
|
||||
status: 200,
|
||||
data: {
|
||||
ancestors: [{
|
||||
id: 'block-v1:Org+TS100+24+type@vertical+block@parent',
|
||||
display_name: 'You-Knit? The Test Unit',
|
||||
category: 'vertical',
|
||||
has_children: true,
|
||||
}],
|
||||
},
|
||||
}));
|
||||
jest.mock('../library-authoring/LibraryBlock', () => ({
|
||||
LibraryBlock: jest.fn(() => (<div>Advanced Editor Iframe</div>)),
|
||||
}));
|
||||
|
||||
const props = { learningContextId: 'cOuRsEId' };
|
||||
|
||||
describe('EditorContainer', () => {
|
||||
beforeEach(() => {
|
||||
initializeMocks();
|
||||
jest.spyOn(editorCmsApi, 'fetchBlockById').mockImplementationOnce(async () => (
|
||||
{
|
||||
status: 200,
|
||||
data: {
|
||||
display_name: 'Fake Un-editable Block', category: 'fake', metadata: {}, data: '',
|
||||
},
|
||||
}
|
||||
));
|
||||
});
|
||||
|
||||
test('render component', () => {
|
||||
render(<EditorContainer {...props} />);
|
||||
expect(screen.getByText('View in Library')).toBeInTheDocument();
|
||||
expect(screen.getByText('Advanced Editor Iframe')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should call onClose param when receiving "cancel-clicked" message', () => {
|
||||
const onCloseMock = jest.fn();
|
||||
render(<EditorContainer {...props} onClose={onCloseMock} />);
|
||||
const messageEvent = new MessageEvent('message', {
|
||||
data: {
|
||||
type: 'xblock-event',
|
||||
eventName: 'cancel',
|
||||
},
|
||||
origin: getConfig().STUDIO_BASE_URL,
|
||||
});
|
||||
|
||||
act(() => {
|
||||
window.dispatchEvent(messageEvent);
|
||||
});
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Discard Changes and Exit' }));
|
||||
expect(onCloseMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,69 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Editor Container snapshots rendering correctly with expected Input 1`] = `
|
||||
<div
|
||||
className="editor-page"
|
||||
>
|
||||
<AlertMessage
|
||||
actions={
|
||||
[
|
||||
<ForwardRef
|
||||
as={
|
||||
{
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"defaultProps": {
|
||||
"as": "a",
|
||||
"className": undefined,
|
||||
"destination": undefined,
|
||||
"externalLinkAlternativeText": undefined,
|
||||
"externalLinkTitle": undefined,
|
||||
"isInline": false,
|
||||
"onClick": undefined,
|
||||
"showLaunchIcon": true,
|
||||
"target": "_self",
|
||||
"variant": "default",
|
||||
},
|
||||
"propTypes": {
|
||||
"as": [Function],
|
||||
"children": [Function],
|
||||
"className": [Function],
|
||||
"destination": [Function],
|
||||
"externalLinkAlternativeText": [Function],
|
||||
"externalLinkTitle": [Function],
|
||||
"isInline": [Function],
|
||||
"onClick": [Function],
|
||||
"showLaunchIcon": [Function],
|
||||
"target": [Function],
|
||||
"variant": [Function],
|
||||
},
|
||||
"render": [Function],
|
||||
}
|
||||
}
|
||||
destination="/library/lib:Axim:TEST/components?usageKey=lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fdd"
|
||||
disabled={false}
|
||||
rel="noopener noreferrer"
|
||||
showLaunchIcon={true}
|
||||
target="_blank"
|
||||
>
|
||||
View in Library
|
||||
</ForwardRef>,
|
||||
]
|
||||
}
|
||||
className="m-3"
|
||||
description="Edits made here will only be reflected in this course. These edits may be overridden later if updates are accepted."
|
||||
icon={[Function]}
|
||||
show={true}
|
||||
title="Editing Content from a Library"
|
||||
variant="warning"
|
||||
/>
|
||||
<EditorPage
|
||||
blockId="company-id1"
|
||||
blockType="html"
|
||||
courseId="cOuRsEId"
|
||||
lmsEndpointUrl="http://localhost:18000"
|
||||
onClose={null}
|
||||
returnFunction={null}
|
||||
studioEndpointUrl="http://localhost:18010"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Collapsible, Icon, IconButton } from '@openedx/paragon';
|
||||
import { ExpandLess, ExpandMore, InfoOutline } from '@openedx/paragon/icons';
|
||||
|
||||
@@ -20,40 +20,41 @@ const CollapsibleFormWidget = ({
|
||||
subtitle,
|
||||
title,
|
||||
fontSize,
|
||||
// injected
|
||||
intl,
|
||||
}) => (
|
||||
<Collapsible.Advanced
|
||||
className="collapsible-card rounded mx-4 my-3 px-4 text-primary-500"
|
||||
defaultOpen
|
||||
open={isError || undefined}
|
||||
>
|
||||
<Collapsible.Trigger
|
||||
className="collapsible-trigger d-flex border-0 align-items-center pt-4 p-0"
|
||||
style={{ justifyContent: 'unset' }}
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<Collapsible.Advanced
|
||||
className="collapsible-card rounded mx-4 my-3 px-4 text-primary-500"
|
||||
defaultOpen
|
||||
open={isError || undefined}
|
||||
>
|
||||
<Collapsible.Visible whenClosed className="p-0 pb-3">
|
||||
<div className="d-flex flex-column flex-grow-1">
|
||||
<Collapsible.Trigger
|
||||
className="collapsible-trigger d-flex border-0 align-items-center pt-4 p-0"
|
||||
style={{ justifyContent: 'unset' }}
|
||||
>
|
||||
<Collapsible.Visible whenClosed className="p-0 pb-3">
|
||||
<div className="d-flex flex-column flex-grow-1">
|
||||
<div className="d-flex flex-grow-1 w-75 x-small">{title}</div>
|
||||
{subtitle ? <div className={`${fontSize} mb-4 mt-3`}>{subtitle}</div> : <div className="mb-4" />}
|
||||
</div>
|
||||
<div className="d-flex flex-row align-self-start">
|
||||
{isError && <Icon className="alert-icon" src={InfoOutline} />}
|
||||
<IconButton alt={intl.formatMessage(messages.expandAltText)} src={ExpandMore} iconAs={Icon} variant="dark" />
|
||||
</div>
|
||||
</Collapsible.Visible>
|
||||
<Collapsible.Visible whenOpen>
|
||||
<div className="d-flex flex-grow-1 w-75 x-small">{title}</div>
|
||||
{subtitle ? <div className={`${fontSize} mb-4 mt-3`}>{subtitle}</div> : <div className="mb-4" />}
|
||||
</div>
|
||||
<div className="d-flex flex-row align-self-start">
|
||||
{isError && <Icon className="alert-icon" src={InfoOutline} />}
|
||||
<IconButton alt={intl.formatMessage(messages.expandAltText)} src={ExpandMore} iconAs={Icon} variant="dark" />
|
||||
</div>
|
||||
</Collapsible.Visible>
|
||||
<Collapsible.Visible whenOpen>
|
||||
<div className="d-flex flex-grow-1 w-75 x-small">{title}</div>
|
||||
<div className="align-self-start">
|
||||
<IconButton alt={intl.formatMessage(messages.collapseAltText)} src={ExpandLess} iconAs={Icon} variant="dark" />
|
||||
</div>
|
||||
</Collapsible.Visible>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Body className={`collapsible-body rounded px-0 ${fontSize} pb-4`}>
|
||||
{children}
|
||||
</Collapsible.Body>
|
||||
</Collapsible.Advanced>
|
||||
);
|
||||
<div className="align-self-start">
|
||||
<IconButton alt={intl.formatMessage(messages.collapseAltText)} src={ExpandLess} iconAs={Icon} variant="dark" />
|
||||
</div>
|
||||
</Collapsible.Visible>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Body className={`collapsible-body rounded px-0 ${fontSize} pb-4`}>
|
||||
{children}
|
||||
</Collapsible.Body>
|
||||
</Collapsible.Advanced>
|
||||
);
|
||||
};
|
||||
|
||||
CollapsibleFormWidget.defaultProps = {
|
||||
subtitle: null,
|
||||
@@ -66,9 +67,6 @@ CollapsibleFormWidget.propTypes = {
|
||||
subtitle: PropTypes.node,
|
||||
title: PropTypes.node.isRequired,
|
||||
fontSize: PropTypes.string,
|
||||
// injected
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export const CollapsibleFormWidgetInternal = CollapsibleFormWidget; // For testing only
|
||||
export default injectIntl(CollapsibleFormWidget);
|
||||
export default CollapsibleFormWidget;
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'CourseAuthoring/editors/setupEditorTest';
|
||||
import React from 'react';
|
||||
import { shallow } from '@edx/react-unit-test-utils';
|
||||
|
||||
import { formatMessage } from '../../../../../testUtils';
|
||||
import { CollapsibleFormWidgetInternal as CollapsibleFormWidget } from './CollapsibleFormWidget';
|
||||
|
||||
describe('CollapsibleFormWidget', () => {
|
||||
const props = {
|
||||
isError: false,
|
||||
subtitle: 'SuBTItle',
|
||||
title: 'tiTLE',
|
||||
// inject
|
||||
intl: { formatMessage },
|
||||
};
|
||||
describe('render', () => {
|
||||
const testContent = (<p>Some test string</p>);
|
||||
test('snapshots: renders as expected with default props', () => {
|
||||
expect(
|
||||
shallow(<CollapsibleFormWidget {...props}>{testContent}</CollapsibleFormWidget>).snapshot,
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
test('snapshots: renders with open={true} when there is error', () => {
|
||||
expect(
|
||||
shallow(<CollapsibleFormWidget {...props} isError>{testContent}</CollapsibleFormWidget>).snapshot,
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
render, screen, initializeMocks,
|
||||
} from '@src/testUtils';
|
||||
import CollapsibleFormWidget from './CollapsibleFormWidget';
|
||||
|
||||
describe('CollapsibleFormWidget', () => {
|
||||
const props = {
|
||||
isError: false,
|
||||
subtitle: 'Sample subtitle',
|
||||
title: 'Sample title',
|
||||
fontSize: 'x-small',
|
||||
};
|
||||
const testContent = (<p>Some test string</p>);
|
||||
|
||||
beforeEach(() => {
|
||||
initializeMocks();
|
||||
});
|
||||
|
||||
test('renders component', () => {
|
||||
render(<CollapsibleFormWidget {...props}>{testContent}</CollapsibleFormWidget>);
|
||||
expect(screen.getByText('Sample title')).toBeInTheDocument();
|
||||
expect(screen.getByText('Some test string')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DurationWidget render snapshots: renders as expected with default props 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize="x-small"
|
||||
subtitle="Custom: 00:00:00"
|
||||
title="Duration"
|
||||
@@ -60,5 +60,5 @@ exports[`DurationWidget render snapshots: renders as expected with default props
|
||||
Total: 00:00:00
|
||||
</span>
|
||||
</div>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`HandoutWidget snapshots snapshots: renders as expected with default props 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize="x-small"
|
||||
isError={true}
|
||||
subtitle="None"
|
||||
@@ -60,11 +60,11 @@ exports[`HandoutWidget snapshots snapshots: renders as expected with default pro
|
||||
/>
|
||||
</Button>
|
||||
</Stack>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
exports[`HandoutWidget snapshots snapshots: renders as expected with handout 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize="x-small"
|
||||
isError={true}
|
||||
subtitle="sOMeUrl "
|
||||
@@ -159,7 +159,7 @@ exports[`HandoutWidget snapshots snapshots: renders as expected with handout 1`]
|
||||
id="authoring.videoeditor.handout.handoutHelpMessage"
|
||||
/>
|
||||
</Stack>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
exports[`HandoutWidget snapshots snapshots: renders as expected with isLibrary true 1`] = `null`;
|
||||
|
||||
@@ -3,8 +3,7 @@ import { connect, useDispatch } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
FormattedMessage,
|
||||
injectIntl,
|
||||
intlShape,
|
||||
useIntl,
|
||||
} from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
ActionRow,
|
||||
@@ -22,12 +21,11 @@ import { LicenseLevel, LicenseNames, LicenseTypes } from '../../../../../../data
|
||||
const LicenseSelector = ({
|
||||
license,
|
||||
level,
|
||||
// injected
|
||||
intl,
|
||||
// redux
|
||||
courseLicenseType,
|
||||
updateField,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const { levelDescription } = hooks.determineText({ level });
|
||||
const onLicenseChange = hooks.onSelectLicense({ dispatch: useDispatch() });
|
||||
const ref = React.useRef();
|
||||
@@ -74,8 +72,6 @@ const LicenseSelector = ({
|
||||
LicenseSelector.propTypes = {
|
||||
license: PropTypes.string.isRequired,
|
||||
level: PropTypes.string.isRequired,
|
||||
// injected
|
||||
intl: intlShape.isRequired,
|
||||
// redux
|
||||
courseLicenseType: PropTypes.string.isRequired,
|
||||
updateField: PropTypes.func.isRequired,
|
||||
@@ -90,4 +86,4 @@ export const mapDispatchToProps = (dispatch) => ({
|
||||
});
|
||||
|
||||
export const LicenseSelectorInternal = LicenseSelector; // For testing only
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(LicenseSelector));
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(LicenseSelector);
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import 'CourseAuthoring/editors/setupEditorTest';
|
||||
import React from 'react';
|
||||
import { shallow } from '@edx/react-unit-test-utils';
|
||||
|
||||
import { formatMessage } from '../../../../../../testUtils';
|
||||
import { actions, selectors } from '../../../../../../data/redux';
|
||||
import { LicenseSelectorInternal as LicenseSelector, mapStateToProps, mapDispatchToProps } from './LicenseSelector';
|
||||
|
||||
jest.mock('react', () => {
|
||||
const updateState = jest.fn();
|
||||
return {
|
||||
...jest.requireActual('react'),
|
||||
updateState,
|
||||
useContext: jest.fn(() => ({ license: ['error.license', jest.fn().mockName('error.setLicense')] })),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('react-redux', () => {
|
||||
const dispatchFn = jest.fn();
|
||||
return {
|
||||
...jest.requireActual('react-redux'),
|
||||
dispatch: dispatchFn,
|
||||
useDispatch: jest.fn(() => dispatchFn),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../../../../../data/redux', () => ({
|
||||
actions: {
|
||||
video: {
|
||||
updateField: jest.fn().mockName('actions.video.updateField'),
|
||||
},
|
||||
},
|
||||
selectors: {
|
||||
video: {
|
||||
courseLicenseType: jest.fn(state => ({ courseLicenseType: state })),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe('LicenseSelector', () => {
|
||||
const props = {
|
||||
intl: { formatMessage },
|
||||
license: 'all-rights-reserved',
|
||||
level: 'course',
|
||||
courseLicenseType: 'all-rights-reserved',
|
||||
updateField: jest.fn().mockName('args.updateField'),
|
||||
};
|
||||
describe('snapshots', () => {
|
||||
test('snapshots: renders as expected with default props', () => {
|
||||
expect(
|
||||
shallow(<LicenseSelector {...props} />).snapshot,
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
test('snapshots: renders as expected with library level', () => {
|
||||
expect(
|
||||
shallow(<LicenseSelector {...props} level="library" />).snapshot,
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
test('snapshots: renders as expected with block level', () => {
|
||||
expect(
|
||||
shallow(<LicenseSelector {...props} level="block" />).snapshot,
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
test('snapshots: renders as expected with no license', () => {
|
||||
expect(
|
||||
shallow(<LicenseSelector {...props} license="" />).snapshot,
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('mapStateToProps', () => {
|
||||
const testState = { A: 'pple', B: 'anana', C: 'ucumber' };
|
||||
test('courseLicenseType from video.courseLicenseType', () => {
|
||||
expect(
|
||||
mapStateToProps(testState).courseLicenseType,
|
||||
).toEqual(selectors.video.courseLicenseType(testState));
|
||||
});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
const dispatch = jest.fn();
|
||||
test('updateField from actions.video.updateField', () => {
|
||||
expect(mapDispatchToProps.updateField).toEqual(dispatch(actions.video.updateField));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
render, fireEvent, screen, initializeMocks,
|
||||
} from '@src/testUtils';
|
||||
import { LicenseSelectorInternal } from './LicenseSelector';
|
||||
import * as hooks from './hooks';
|
||||
|
||||
jest.mock('./hooks', () => ({
|
||||
determineText: jest.fn(() => ({ levelDescription: 'Test level description' })),
|
||||
onSelectLicense: jest.fn(() => jest.fn()),
|
||||
}));
|
||||
|
||||
const LicenseTypes = {
|
||||
select: 'select',
|
||||
allRightsReserved: 'All Rights Reserved',
|
||||
creativeCommons: 'Creative Commons',
|
||||
};
|
||||
const LicenseLevel = { course: 'course', video: 'video' };
|
||||
|
||||
describe('LicenseSelectorInternal', () => {
|
||||
const updateField = jest.fn();
|
||||
const onLicenseChange = jest.fn();
|
||||
const props = {
|
||||
license: LicenseTypes.select,
|
||||
level: LicenseLevel.video,
|
||||
courseLicenseType: LicenseTypes.select,
|
||||
updateField,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
initializeMocks();
|
||||
(hooks.onSelectLicense as jest.Mock).mockReturnValue(onLicenseChange);
|
||||
(hooks.determineText as jest.Mock).mockReturnValue({ levelDescription: 'Test level description' });
|
||||
});
|
||||
|
||||
it('renders select with correct options and default value', () => {
|
||||
render(<LicenseSelectorInternal {...props} />);
|
||||
const select = screen.getByRole('combobox');
|
||||
expect(select).toBeInTheDocument();
|
||||
expect((select as HTMLSelectElement).value).toBe(props.license);
|
||||
expect(screen.getByText(LicenseTypes.allRightsReserved)).toBeInTheDocument();
|
||||
expect(screen.getByText(LicenseTypes.creativeCommons)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('disables select when level is course', () => {
|
||||
render(<LicenseSelectorInternal {...props} level={LicenseLevel.course} />);
|
||||
expect(screen.getByRole('combobox')).toBeDisabled();
|
||||
});
|
||||
|
||||
it('shows delete button when level is not course', () => {
|
||||
render(<LicenseSelectorInternal {...props} />);
|
||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show delete button when level is course', () => {
|
||||
render(<LicenseSelectorInternal {...props} level={LicenseLevel.course} />);
|
||||
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onLicenseChange when select changes', () => {
|
||||
render(<LicenseSelectorInternal {...props} />);
|
||||
fireEvent.change(screen.getByRole('combobox'), { target: { value: LicenseTypes.select } });
|
||||
expect(onLicenseChange).toHaveBeenCalledWith(LicenseTypes.select);
|
||||
});
|
||||
|
||||
it('calls updateField and resets select when delete button clicked', () => {
|
||||
render(<LicenseSelectorInternal {...props} />);
|
||||
fireEvent.click(screen.getByRole('button'));
|
||||
expect(updateField).toHaveBeenCalledWith({ licenseType: '', licenseDetails: {} });
|
||||
});
|
||||
|
||||
it('renders level description', () => {
|
||||
render(<LicenseSelectorInternal {...props} />);
|
||||
expect(screen.getByText('Test level description')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders border when license is not select', () => {
|
||||
const { container } = render(<LicenseSelectorInternal {...props} license={LicenseTypes.allRightsReserved} />);
|
||||
expect(container.querySelector('.border-primary-100')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render border when license is select', () => {
|
||||
const { container } = render(<LicenseSelectorInternal {...props} license={LicenseTypes.select} />);
|
||||
expect(container.querySelector('.border-primary-100')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,203 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LicenseSelector snapshots snapshots: renders as expected with block level 1`] = `
|
||||
<Fragment>
|
||||
<ActionRow>
|
||||
<Form.Control
|
||||
as="select"
|
||||
className="w-100 m-0 p-0"
|
||||
defaultValue="all-rights-reserved"
|
||||
disabled={false}
|
||||
floatingLabel="License Type"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<option
|
||||
hidden={true}
|
||||
>
|
||||
Select
|
||||
</option>
|
||||
<option
|
||||
value="all-rights-reserved"
|
||||
>
|
||||
All Rights Reserved
|
||||
</option>
|
||||
<option
|
||||
value="creative-commons"
|
||||
>
|
||||
Creative Commons
|
||||
</option>
|
||||
</Form.Control>
|
||||
<Fragment>
|
||||
<ActionRow.Spacer />
|
||||
<IconButtonWithTooltip
|
||||
iconAs="Icon"
|
||||
onClick={[Function]}
|
||||
tooltipContent={
|
||||
<FormattedMessage
|
||||
defaultMessage="Clear and apply the course-level license"
|
||||
description="Message presented to user for action to delete license selection"
|
||||
id="authoring.videoeditor.license.deleteLicenseSelection"
|
||||
/>
|
||||
}
|
||||
tooltipPlacement="top"
|
||||
/>
|
||||
</Fragment>
|
||||
</ActionRow>
|
||||
<div
|
||||
className="x-small mt-3"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="This license is set specifically for this video"
|
||||
description="Helper text for license type when choosing for a spcific video"
|
||||
id="authoring.videoeditor.license.defaultLevelDescription.helperText"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="border-primary-100 mt-3 border-bottom"
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`LicenseSelector snapshots snapshots: renders as expected with default props 1`] = `
|
||||
<Fragment>
|
||||
<ActionRow>
|
||||
<Form.Control
|
||||
as="select"
|
||||
className="w-100 m-0 p-0"
|
||||
defaultValue="all-rights-reserved"
|
||||
disabled={true}
|
||||
floatingLabel="License Type"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<option
|
||||
hidden={true}
|
||||
>
|
||||
Select
|
||||
</option>
|
||||
<option
|
||||
value="all-rights-reserved"
|
||||
>
|
||||
All Rights Reserved
|
||||
</option>
|
||||
<option
|
||||
value="creative-commons"
|
||||
>
|
||||
Creative Commons
|
||||
</option>
|
||||
</Form.Control>
|
||||
</ActionRow>
|
||||
<div
|
||||
className="x-small mt-3"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="This license currently set at the course level"
|
||||
description="Helper text for license type when using course license"
|
||||
id="authoring.videoeditor.license.courseLevelDescription.helperText"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="border-primary-100 mt-3 border-bottom"
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`LicenseSelector snapshots snapshots: renders as expected with library level 1`] = `
|
||||
<Fragment>
|
||||
<ActionRow>
|
||||
<Form.Control
|
||||
as="select"
|
||||
className="w-100 m-0 p-0"
|
||||
defaultValue="all-rights-reserved"
|
||||
disabled={false}
|
||||
floatingLabel="License Type"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<option
|
||||
hidden={true}
|
||||
>
|
||||
Select
|
||||
</option>
|
||||
<option
|
||||
value="all-rights-reserved"
|
||||
>
|
||||
All Rights Reserved
|
||||
</option>
|
||||
<option
|
||||
value="creative-commons"
|
||||
>
|
||||
Creative Commons
|
||||
</option>
|
||||
</Form.Control>
|
||||
<Fragment>
|
||||
<ActionRow.Spacer />
|
||||
<IconButtonWithTooltip
|
||||
iconAs="Icon"
|
||||
onClick={[Function]}
|
||||
tooltipContent={
|
||||
<FormattedMessage
|
||||
defaultMessage="Clear and apply the course-level license"
|
||||
description="Message presented to user for action to delete license selection"
|
||||
id="authoring.videoeditor.license.deleteLicenseSelection"
|
||||
/>
|
||||
}
|
||||
tooltipPlacement="top"
|
||||
/>
|
||||
</Fragment>
|
||||
</ActionRow>
|
||||
<div
|
||||
className="x-small mt-3"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="This license currently set at the library level"
|
||||
description="Helper text for license type when using library license"
|
||||
id="authoring.videoeditor.license.libraryLevelDescription.helperText"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="border-primary-100 mt-3 border-bottom"
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`LicenseSelector snapshots snapshots: renders as expected with no license 1`] = `
|
||||
<Fragment>
|
||||
<ActionRow>
|
||||
<Form.Control
|
||||
as="select"
|
||||
className="w-100 m-0 p-0"
|
||||
defaultValue=""
|
||||
disabled={true}
|
||||
floatingLabel="License Type"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<option
|
||||
hidden={true}
|
||||
>
|
||||
Select
|
||||
</option>
|
||||
<option
|
||||
value="all-rights-reserved"
|
||||
>
|
||||
All Rights Reserved
|
||||
</option>
|
||||
<option
|
||||
value="creative-commons"
|
||||
>
|
||||
Creative Commons
|
||||
</option>
|
||||
</Form.Control>
|
||||
</ActionRow>
|
||||
<div
|
||||
className="x-small mt-3"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="This license currently set at the course level"
|
||||
description="Helper text for license type when using course license"
|
||||
id="authoring.videoeditor.license.courseLevelDescription.helperText"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="border-primary-100 mt-3 border-bottom"
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -1,7 +1,8 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LicenseWidget snapshots snapshots: renders as expected with default props 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize=""
|
||||
subtitle={
|
||||
<div>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
@@ -25,7 +26,7 @@ exports[`LicenseWidget snapshots snapshots: renders as expected with default pro
|
||||
gap={4}
|
||||
>
|
||||
<Fragment>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<[object Object]
|
||||
level="course"
|
||||
license="all-rights-reserved"
|
||||
/>
|
||||
@@ -64,11 +65,12 @@ exports[`LicenseWidget snapshots snapshots: renders as expected with default pro
|
||||
</Button>
|
||||
</Fragment>
|
||||
</Stack>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
exports[`LicenseWidget snapshots snapshots: renders as expected with isLibrary true 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize=""
|
||||
subtitle={
|
||||
<div>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
@@ -92,7 +94,7 @@ exports[`LicenseWidget snapshots snapshots: renders as expected with isLibrary t
|
||||
gap={4}
|
||||
>
|
||||
<Fragment>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<[object Object]
|
||||
level="library"
|
||||
license="all-rights-reserved"
|
||||
/>
|
||||
@@ -114,11 +116,12 @@ exports[`LicenseWidget snapshots snapshots: renders as expected with isLibrary t
|
||||
/>
|
||||
</Fragment>
|
||||
</Stack>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
exports[`LicenseWidget snapshots snapshots: renders as expected with licenseType defined 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize=""
|
||||
subtitle={
|
||||
<div>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
@@ -142,7 +145,7 @@ exports[`LicenseWidget snapshots snapshots: renders as expected with licenseType
|
||||
gap={4}
|
||||
>
|
||||
<Fragment>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<[object Object]
|
||||
level="block"
|
||||
license="all-rights-reserved"
|
||||
/>
|
||||
@@ -164,5 +167,5 @@ exports[`LicenseWidget snapshots snapshots: renders as expected with licenseType
|
||||
/>
|
||||
</Fragment>
|
||||
</Stack>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
@@ -7,7 +7,7 @@ exports[`SocialShareWidget rendered with videoSharingEnabled false with videoSha
|
||||
exports[`SocialShareWidget rendered with videoSharingEnabled false with videoSharingEnabledForCourse and isLibrary false and videoSharingEnabledForAll true should return null 1`] = `null`;
|
||||
|
||||
exports[`SocialShareWidget rendered with videoSharingEnabled true and allowVideoSharing value equals false should have subtitle with text that reads Enabled 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize="x-small"
|
||||
subtitle="Disabled"
|
||||
title="Social Sharing"
|
||||
@@ -42,11 +42,11 @@ exports[`SocialShareWidget rendered with videoSharingEnabled true and allowVideo
|
||||
Learn more about social sharing
|
||||
</Hyperlink>
|
||||
</div>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
exports[`SocialShareWidget rendered with videoSharingEnabled true and allowVideoSharing value equals true should have subtitle with text that reads Enabled 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize="x-small"
|
||||
subtitle="Enabled"
|
||||
title="Social Sharing"
|
||||
@@ -81,5 +81,5 @@ exports[`SocialShareWidget rendered with videoSharingEnabled true and allowVideo
|
||||
Learn more about social sharing
|
||||
</Hyperlink>
|
||||
</div>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
exports[`ThumbnailWidget snapshots snapshots: renders as expected where thumbnail uploads are allowed 1`] = `null`;
|
||||
|
||||
exports[`ThumbnailWidget snapshots snapshots: renders as expected where videoId is valid 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize="x-small"
|
||||
isError={true}
|
||||
subtitle="Yes"
|
||||
@@ -38,11 +38,11 @@ exports[`ThumbnailWidget snapshots snapshots: renders as expected where videoId
|
||||
tooltipPlacement="top"
|
||||
/>
|
||||
</Stack>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
exports[`ThumbnailWidget snapshots snapshots: renders as expected where videoId is valid and no thumbnail 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize="x-small"
|
||||
isError={true}
|
||||
subtitle="None"
|
||||
@@ -106,11 +106,11 @@ exports[`ThumbnailWidget snapshots snapshots: renders as expected where videoId
|
||||
/>
|
||||
</Button>
|
||||
</Stack>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
exports[`ThumbnailWidget snapshots snapshots: renders as expected with a thumbnail provided 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize="x-small"
|
||||
isError={true}
|
||||
subtitle="Yes"
|
||||
@@ -148,7 +148,7 @@ exports[`ThumbnailWidget snapshots snapshots: renders as expected with a thumbna
|
||||
thumbnail={true}
|
||||
/>
|
||||
</Stack>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
exports[`ThumbnailWidget snapshots snapshots: renders as expected with default props 1`] = `null`;
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import 'CourseAuthoring/editors/setupEditorTest';
|
||||
import React from 'react';
|
||||
import { shallow } from '@edx/react-unit-test-utils';
|
||||
import { Button, IconButton } from '@openedx/paragon';
|
||||
|
||||
import { thunkActions } from '../../../../../../data/redux';
|
||||
import { ImportTranscriptCardInternal as ImportTranscriptCard, mapDispatchToProps, mapStateToProps } from './ImportTranscriptCard';
|
||||
|
||||
jest.mock('react', () => ({
|
||||
...jest.requireActual('react'),
|
||||
useContext: jest.fn(() => ({ transcripts: ['error.transcripts', jest.fn().mockName('error.setTranscripts')] })),
|
||||
}));
|
||||
|
||||
jest.mock('../../../../../../data/redux', () => ({
|
||||
thunkActions: {
|
||||
video: {
|
||||
importTranscript: jest.fn().mockName('thunkActions.video.importTranscript'),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe('ImportTranscriptCard', () => {
|
||||
const props = {
|
||||
setOpen: jest.fn().mockName('setOpen'),
|
||||
importTranscript: jest.fn().mockName('args.importTranscript'),
|
||||
};
|
||||
let el;
|
||||
describe('snapshots', () => {
|
||||
test('snapshots: renders as expected with default props', () => {
|
||||
expect(
|
||||
shallow(<ImportTranscriptCard {...props} />).snapshot,
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('behavior inspection', () => {
|
||||
beforeEach(() => {
|
||||
el = shallow(<ImportTranscriptCard {...props} />);
|
||||
});
|
||||
test('close behavior is linked to IconButton', () => {
|
||||
expect(el.instance.findByType(IconButton)[0]
|
||||
.props.onClick).toBeDefined();
|
||||
});
|
||||
test('import behavior is linked to Button onClick', () => {
|
||||
expect(el.instance.findByType(Button)[0]
|
||||
.props.onClick).toEqual(props.importTranscript);
|
||||
});
|
||||
});
|
||||
describe('mapStateToProps', () => {
|
||||
it('returns an empty object', () => {
|
||||
expect(mapStateToProps()).toEqual({});
|
||||
});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
test('updateField from thunkActions.video.importTranscript', () => {
|
||||
expect(mapDispatchToProps.importTranscript).toEqual(thunkActions.video.importTranscript);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
render, screen, fireEvent, initializeMocks,
|
||||
} from '@src/testUtils';
|
||||
import { ImportTranscriptCardInternal as ImportTranscriptCard } from './ImportTranscriptCard';
|
||||
|
||||
jest.mock('../../../../../../data/redux', () => ({
|
||||
thunkActions: {
|
||||
video: {
|
||||
importTranscript: jest.fn().mockName('thunkActions.video.importTranscript'),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe('ImportTranscriptCard (RTL)', () => {
|
||||
const mockSetOpen = jest.fn();
|
||||
const mockImportTranscript = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
initializeMocks();
|
||||
});
|
||||
|
||||
it('renders header, message, and button', () => {
|
||||
render(
|
||||
<ImportTranscriptCard setOpen={mockSetOpen} importTranscript={mockImportTranscript} />,
|
||||
);
|
||||
expect(screen.getByText('Import transcript from YouTube?')).toBeInTheDocument();
|
||||
expect(screen.getByText('We found transcript for this video on YouTube. Would you like to import it now?')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Import Transcript' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls setOpen(false) when close IconButton is clicked', () => {
|
||||
const { container } = render(
|
||||
<ImportTranscriptCard setOpen={mockSetOpen} importTranscript={mockImportTranscript} />,
|
||||
);
|
||||
const closeButton = container.querySelector('.btn-icon-primary');
|
||||
expect(closeButton).toBeInTheDocument();
|
||||
fireEvent.click(closeButton!);
|
||||
expect(mockSetOpen).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('calls importTranscript when import button is clicked', () => {
|
||||
render(
|
||||
<ImportTranscriptCard setOpen={mockSetOpen} importTranscript={mockImportTranscript} />,
|
||||
);
|
||||
const importBtn = screen.getByRole('button', { name: 'Import Transcript' });
|
||||
fireEvent.click(importBtn);
|
||||
expect(mockImportTranscript).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,98 +1,82 @@
|
||||
import 'CourseAuthoring/editors/setupEditorTest';
|
||||
import React from 'react';
|
||||
import { shallow } from '@edx/react-unit-test-utils';
|
||||
import {
|
||||
render, fireEvent, screen, initializeMocks,
|
||||
} from 'CourseAuthoring/testUtils';
|
||||
import { TranscriptInternal, hooks } from './Transcript';
|
||||
|
||||
import * as module from './Transcript';
|
||||
jest.mock('./TranscriptActionMenu', () => jest.fn(() => <div>TranscriptActionMenu</div>));
|
||||
jest.mock('./LanguageSelector', () => jest.fn(() => <div>LanguageSelector</div>));
|
||||
|
||||
import { MockUseState } from '../../../../../../testUtils';
|
||||
const defaultProps = {
|
||||
index: 0,
|
||||
language: '',
|
||||
transcriptUrl: undefined,
|
||||
deleteTranscript: jest.fn(),
|
||||
};
|
||||
|
||||
const Transcript = module.TranscriptInternal;
|
||||
|
||||
jest.mock('./LanguageSelector', () => 'LanguageSelector');
|
||||
jest.mock('./TranscriptActionMenu', () => 'TranscriptActionMenu');
|
||||
|
||||
describe('Transcript Component', () => {
|
||||
describe('state hooks', () => {
|
||||
const state = new MockUseState(module.hooks);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
describe('state hooks', () => {
|
||||
state.testGetter(state.keys.inDeleteConfirmation);
|
||||
});
|
||||
|
||||
describe('setUpDeleteConfirmation hook', () => {
|
||||
beforeEach(() => {
|
||||
state.mock();
|
||||
});
|
||||
afterEach(() => {
|
||||
state.restore();
|
||||
});
|
||||
test('inDeleteConfirmation: state values', () => {
|
||||
expect(module.hooks.setUpDeleteConfirmation().inDeleteConfirmation).toEqual(false);
|
||||
});
|
||||
test('inDeleteConfirmation setters: launch', () => {
|
||||
module.hooks.setUpDeleteConfirmation().launchDeleteConfirmation();
|
||||
expect(state.setState[state.keys.inDeleteConfirmation]).toHaveBeenCalledWith(true);
|
||||
});
|
||||
test('inDeleteConfirmation setters: cancel', () => {
|
||||
module.hooks.setUpDeleteConfirmation().cancelDelete();
|
||||
expect(state.setState[state.keys.inDeleteConfirmation]).toHaveBeenCalledWith(false);
|
||||
});
|
||||
});
|
||||
describe('TranscriptInternal', () => {
|
||||
const cancelDelete = jest.fn();
|
||||
const deleteTranscript = jest.fn();
|
||||
jest.spyOn(hooks, 'setUpDeleteConfirmation').mockReturnValue({
|
||||
inDeleteConfirmation: false,
|
||||
launchDeleteConfirmation: deleteTranscript,
|
||||
cancelDelete,
|
||||
});
|
||||
|
||||
describe('component', () => {
|
||||
describe('component', () => {
|
||||
const props = {
|
||||
index: 'sOmenUmBer',
|
||||
language: 'lAnG',
|
||||
deleteTranscript: jest.fn().mockName('thunkActions.video.deleteTranscript'),
|
||||
};
|
||||
afterAll(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
test('snapshots: renders as expected with default props: dont show confirm delete', () => {
|
||||
jest.spyOn(module.hooks, 'setUpDeleteConfirmation').mockImplementationOnce(() => ({
|
||||
inDeleteConfirmation: false,
|
||||
launchDeleteConfirmation: jest.fn().mockName('launchDeleteConfirmation'),
|
||||
cancelDelete: jest.fn().mockName('cancelDelete'),
|
||||
}));
|
||||
expect(
|
||||
shallow(<Transcript {...props} />).snapshot,
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
test('snapshots: renders as expected with default props: dont show confirm delete, language is blank so delete is shown instead of action menu', () => {
|
||||
jest.spyOn(module.hooks, 'setUpDeleteConfirmation').mockImplementationOnce(() => ({
|
||||
inDeleteConfirmation: false,
|
||||
launchDeleteConfirmation: jest.fn().mockName('launchDeleteConfirmation'),
|
||||
cancelDelete: jest.fn().mockName('cancelDelete'),
|
||||
}));
|
||||
expect(
|
||||
shallow(<Transcript {...props} language="" />).snapshot,
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
test('snapshots: renders as expected with default props: show confirm delete', () => {
|
||||
jest.spyOn(module.hooks, 'setUpDeleteConfirmation').mockImplementationOnce(() => ({
|
||||
inDeleteConfirmation: true,
|
||||
launchDeleteConfirmation: jest.fn().mockName('launchDeleteConfirmation'),
|
||||
cancelDelete: jest.fn().mockName('cancelDelete'),
|
||||
}));
|
||||
expect(
|
||||
shallow(<Transcript {...props} />).snapshot,
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
test('snapshots: renders as expected with transcriptUrl', () => {
|
||||
jest.spyOn(module.hooks, 'setUpDeleteConfirmation').mockImplementationOnce(() => ({
|
||||
inDeleteConfirmation: false,
|
||||
launchDeleteConfirmation: jest.fn().mockName('launchDeleteConfirmation'),
|
||||
cancelDelete: jest.fn().mockName('cancelDelete'),
|
||||
}));
|
||||
expect(
|
||||
shallow(<Transcript {...props} transcriptUrl="url" />).snapshot,
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
beforeEach(() => {
|
||||
initializeMocks();
|
||||
});
|
||||
|
||||
it('renders ActionRow and LanguageSelector when not in delete confirmation', () => {
|
||||
render(<TranscriptInternal {...defaultProps} />);
|
||||
expect(screen.getByText('LanguageSelector')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders TranscriptActionMenu when language is not empty', () => {
|
||||
const props = { language: 'en', transcriptUrl: 'url' };
|
||||
render(<TranscriptInternal {...defaultProps} {...props} />);
|
||||
expect(screen.getByText('TranscriptActionMenu')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls launchDeleteConfirmation when IconButton is clicked', () => {
|
||||
render(<TranscriptInternal {...defaultProps} />);
|
||||
fireEvent.click(screen.getByRole('button'));
|
||||
expect(deleteTranscript).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders delete confirmation card when inDeleteConfirmation is true', () => {
|
||||
jest.spyOn(hooks, 'setUpDeleteConfirmation').mockReturnValue({
|
||||
inDeleteConfirmation: true,
|
||||
launchDeleteConfirmation: jest.fn(),
|
||||
cancelDelete,
|
||||
});
|
||||
render(<TranscriptInternal {...defaultProps} />);
|
||||
expect(screen.getByText('Delete this transcript?')).toBeInTheDocument();
|
||||
expect(screen.getByText('Are you sure you want to delete this transcript?')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls cancelDelete when cancel button is clicked', () => {
|
||||
jest.spyOn(hooks, 'setUpDeleteConfirmation').mockReturnValue({
|
||||
inDeleteConfirmation: true,
|
||||
launchDeleteConfirmation: jest.fn(),
|
||||
cancelDelete,
|
||||
});
|
||||
render(<TranscriptInternal {...defaultProps} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Cancel' }));
|
||||
expect(cancelDelete).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls deleteTranscript and cancelDelete when confirm delete is clicked', () => {
|
||||
jest.spyOn(hooks, 'setUpDeleteConfirmation').mockReturnValue({
|
||||
inDeleteConfirmation: true,
|
||||
launchDeleteConfirmation: jest.fn(),
|
||||
cancelDelete,
|
||||
});
|
||||
const props = { language: 'es', deleteTranscript };
|
||||
render(<TranscriptInternal {...defaultProps} {...props} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Delete' }));
|
||||
expect(deleteTranscript).toHaveBeenCalledWith({ language: 'es' });
|
||||
expect(cancelDelete).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ImportTranscriptCard snapshots snapshots: renders as expected with default props 1`] = `
|
||||
<Stack
|
||||
className="border rounded border-primary-200 p-4"
|
||||
gap={3}
|
||||
>
|
||||
<ActionRow
|
||||
className="h5"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Import transcript from YouTube?"
|
||||
description="Header for import transcript card"
|
||||
id="authoring.videoEditor.transcripts.importCard.header"
|
||||
/>
|
||||
<ActionRow.Spacer />
|
||||
<IconButton
|
||||
iconAs="Icon"
|
||||
onClick={[Function]}
|
||||
src={[MockFunction icons.Close]}
|
||||
/>
|
||||
</ActionRow>
|
||||
<FormattedMessage
|
||||
defaultMessage="We found transcript for this video on YouTube. Would you like to import it now?"
|
||||
description="Message for import transcript card asking user if they want to import transcript"
|
||||
id="authoring.videoEditor.transcrtipts.importCard.message"
|
||||
/>
|
||||
<Button
|
||||
onClick={[MockFunction args.importTranscript]}
|
||||
size="sm"
|
||||
variant="outline-primary"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Import Transcript"
|
||||
description="Label for youTube import transcript button"
|
||||
id="authoring.videoEditor.transcripts.importButton.label"
|
||||
/>
|
||||
</Button>
|
||||
</Stack>
|
||||
`;
|
||||
@@ -1,103 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Transcript Component component component snapshots: renders as expected with default props: dont show confirm delete 1`] = `
|
||||
<Fragment>
|
||||
<ActionRow>
|
||||
<LanguageSelector
|
||||
language="lAnG"
|
||||
title="sOmenUmBer"
|
||||
/>
|
||||
<ActionRow.Spacer />
|
||||
<TranscriptActionMenu
|
||||
index="sOmenUmBer"
|
||||
language="lAnG"
|
||||
launchDeleteConfirmation={[MockFunction launchDeleteConfirmation]}
|
||||
/>
|
||||
</ActionRow>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`Transcript Component component component snapshots: renders as expected with default props: dont show confirm delete, language is blank so delete is shown instead of action menu 1`] = `
|
||||
<Fragment>
|
||||
<ActionRow>
|
||||
<LanguageSelector
|
||||
language=""
|
||||
title="sOmenUmBer"
|
||||
/>
|
||||
<ActionRow.Spacer />
|
||||
<IconButton
|
||||
iconAs="Icon"
|
||||
onClick={[Function]}
|
||||
/>
|
||||
</ActionRow>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`Transcript Component component component snapshots: renders as expected with default props: show confirm delete 1`] = `
|
||||
<Fragment>
|
||||
<Card
|
||||
className="mb-2"
|
||||
>
|
||||
<Card.Header
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Delete this transcript?"
|
||||
description="Title for Warning which allows users to select next step in the process of deleting a transcript"
|
||||
id="authoring.videoeditor.transcripts.deleteConfirmationTitle"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Card.Body>
|
||||
<Card.Section>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to delete this transcript?"
|
||||
description="Warning which allows users to select next step in the process of deleting a transcript"
|
||||
id="authoring.videoeditor.transcripts.deleteConfirmationMessage"
|
||||
/>
|
||||
</Card.Section>
|
||||
<Card.Footer>
|
||||
<Button
|
||||
className="mb-2 mb-sm-0"
|
||||
onClick={[MockFunction cancelDelete]}
|
||||
variant="tertiary"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Cancel"
|
||||
description="Label For Button, which allows users to stop the process of deleting a transcript"
|
||||
id="authoring.videoeditor.transcripts.cancelDeleteLabel"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
className="mb-2 mb-sm-0"
|
||||
onClick={[Function]}
|
||||
variant="danger"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Delete"
|
||||
description="Label For Button, which allows users to confirm the process of deleting a transcript"
|
||||
id="authoring.videoeditor.transcripts.confirmDeleteLabel"
|
||||
/>
|
||||
</Button>
|
||||
</Card.Footer>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`Transcript Component component component snapshots: renders as expected with transcriptUrl 1`] = `
|
||||
<Fragment>
|
||||
<ActionRow>
|
||||
<LanguageSelector
|
||||
language="lAnG"
|
||||
title="sOmenUmBer"
|
||||
/>
|
||||
<ActionRow.Spacer />
|
||||
<TranscriptActionMenu
|
||||
index="sOmenUmBer"
|
||||
language="lAnG"
|
||||
launchDeleteConfirmation={[MockFunction launchDeleteConfirmation]}
|
||||
transcriptUrl="url"
|
||||
/>
|
||||
</ActionRow>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -1,8 +1,9 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`VideoSourceWidget snapshots snapshots: renders as expected with default props 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize="x-small"
|
||||
subtitle={null}
|
||||
title="Video source"
|
||||
>
|
||||
<ErrorAlert
|
||||
@@ -154,12 +155,13 @@ exports[`VideoSourceWidget snapshots snapshots: renders as expected with default
|
||||
id="authoring.videoeditor.videoSource.fallbackVideo.addButtonLabel"
|
||||
/>
|
||||
</Button>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
exports[`VideoSourceWidget snapshots snapshots: renders as expected with videoSharingEnabledForCourse=true 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
<CollapsibleFormWidget
|
||||
fontSize="x-small"
|
||||
subtitle={null}
|
||||
title="Video source"
|
||||
>
|
||||
<ErrorAlert
|
||||
@@ -311,5 +313,5 @@ exports[`VideoSourceWidget snapshots snapshots: renders as expected with videoSh
|
||||
id="authoring.videoeditor.videoSource.fallbackVideo.addButtonLabel"
|
||||
/>
|
||||
</Button>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
</CollapsibleFormWidget>
|
||||
`;
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CollapsibleFormWidget render snapshots: renders as expected with default props 1`] = `
|
||||
<Advanced
|
||||
className="collapsible-card rounded mx-4 my-3 px-4 text-primary-500"
|
||||
defaultOpen={true}
|
||||
>
|
||||
<Trigger
|
||||
className="collapsible-trigger d-flex border-0 align-items-center pt-4 p-0"
|
||||
style={
|
||||
{
|
||||
"justifyContent": "unset",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Visible
|
||||
className="p-0 pb-3"
|
||||
whenClosed={true}
|
||||
>
|
||||
<div
|
||||
className="d-flex flex-column flex-grow-1"
|
||||
>
|
||||
<div
|
||||
className="d-flex flex-grow-1 w-75 x-small"
|
||||
>
|
||||
tiTLE
|
||||
</div>
|
||||
<div
|
||||
className=" mb-4 mt-3"
|
||||
>
|
||||
SuBTItle
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="d-flex flex-row align-self-start"
|
||||
>
|
||||
<IconButton
|
||||
alt="Expand"
|
||||
iconAs="Icon"
|
||||
variant="dark"
|
||||
/>
|
||||
</div>
|
||||
</Visible>
|
||||
<Visible
|
||||
whenOpen={true}
|
||||
>
|
||||
<div
|
||||
className="d-flex flex-grow-1 w-75 x-small"
|
||||
>
|
||||
tiTLE
|
||||
</div>
|
||||
<div
|
||||
className="align-self-start"
|
||||
>
|
||||
<IconButton
|
||||
alt="Collapse"
|
||||
iconAs="Icon"
|
||||
variant="dark"
|
||||
/>
|
||||
</div>
|
||||
</Visible>
|
||||
</Trigger>
|
||||
<Body
|
||||
className="collapsible-body rounded px-0 pb-4"
|
||||
>
|
||||
<p>
|
||||
Some test string
|
||||
</p>
|
||||
</Body>
|
||||
</Advanced>
|
||||
`;
|
||||
|
||||
exports[`CollapsibleFormWidget render snapshots: renders with open={true} when there is error 1`] = `
|
||||
<Advanced
|
||||
className="collapsible-card rounded mx-4 my-3 px-4 text-primary-500"
|
||||
defaultOpen={true}
|
||||
open={true}
|
||||
>
|
||||
<Trigger
|
||||
className="collapsible-trigger d-flex border-0 align-items-center pt-4 p-0"
|
||||
style={
|
||||
{
|
||||
"justifyContent": "unset",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Visible
|
||||
className="p-0 pb-3"
|
||||
whenClosed={true}
|
||||
>
|
||||
<div
|
||||
className="d-flex flex-column flex-grow-1"
|
||||
>
|
||||
<div
|
||||
className="d-flex flex-grow-1 w-75 x-small"
|
||||
>
|
||||
tiTLE
|
||||
</div>
|
||||
<div
|
||||
className=" mb-4 mt-3"
|
||||
>
|
||||
SuBTItle
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="d-flex flex-row align-self-start"
|
||||
>
|
||||
<Icon
|
||||
className="alert-icon"
|
||||
/>
|
||||
<IconButton
|
||||
alt="Expand"
|
||||
iconAs="Icon"
|
||||
variant="dark"
|
||||
/>
|
||||
</div>
|
||||
</Visible>
|
||||
<Visible
|
||||
whenOpen={true}
|
||||
>
|
||||
<div
|
||||
className="d-flex flex-grow-1 w-75 x-small"
|
||||
>
|
||||
tiTLE
|
||||
</div>
|
||||
<div
|
||||
className="align-self-start"
|
||||
>
|
||||
<IconButton
|
||||
alt="Collapse"
|
||||
iconAs="Icon"
|
||||
variant="dark"
|
||||
/>
|
||||
</div>
|
||||
</Visible>
|
||||
</Trigger>
|
||||
<Body
|
||||
className="collapsible-body rounded px-0 pb-4"
|
||||
>
|
||||
<p>
|
||||
Some test string
|
||||
</p>
|
||||
</Body>
|
||||
</Advanced>
|
||||
`;
|
||||
@@ -4,7 +4,7 @@
|
||||
"outDir": "dist",
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"*": ["*"]
|
||||
"@src/*": ["./*"],
|
||||
}
|
||||
},
|
||||
"include": ["*.js", ".eslintrc.js", "src/**/*", "plugins/**/*"],
|
||||
|
||||
@@ -4,6 +4,8 @@ const { createConfig } = require('@openedx/frontend-build');
|
||||
const config = createConfig('webpack-dev', {
|
||||
resolve: {
|
||||
alias: {
|
||||
// Within this app, we can use '@src/foo instead of relative URLs like '../../../foo'
|
||||
'@src': path.resolve(__dirname, 'src/'),
|
||||
// Plugins can use 'CourseAuthoring' as an import alias for this app:
|
||||
CourseAuthoring: path.resolve(__dirname, 'src/'),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user