test: replacing snapshot tests with RTL tests part 13 (#2233)

This commit is contained in:
jacobo-dominguez-wgu
2025-07-08 10:33:53 -06:00
committed by GitHub
parent c4f565bf76
commit 2fe24f39ac
14 changed files with 189 additions and 871 deletions

View File

@@ -1,165 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`HandoutWidget snapshots snapshots: renders as expected with default props 1`] = `
<CollapsibleFormWidget
fontSize="x-small"
isError={true}
subtitle="None"
title="Handout"
>
<ErrorAlert
dismissError={[Function]}
hideHeading={true}
isError={false}
>
<FormattedMessage
defaultMessage="Handout files must be 20 MB or less. Please resize the file and try again."
description="Message presented to user when handout file size is larger than 20 MB"
id="authoring.videoeditor.handout.error.fileSizeError"
/>
</ErrorAlert>
<UploadErrorAlert
message={
{
"defaultMessage": "Failed to upload handout. Please try again.",
"description": "Message presented to user when handout fails to upload",
"id": "authoring.videoeditor.handout.error.uploadHandoutError",
}
}
/>
<FileInput
fileInput={
{
"addFile": [Function],
"click": [Function],
"ref": {
"current": undefined,
},
}
}
/>
<Stack
gap={3}
>
<FormattedMessage
defaultMessage="Add a handout to accompany this video. Learners can download
this file by clicking "Download Handout" below the video."
description="Message displayed when uploading a handout"
id="authoring.videoeditor.handout.upload.addHandoutMessage"
/>
<Button
className="text-primary-500 font-weight-bold justify-content-start pl-0"
onClick={[Function]}
size="sm"
variant="link"
>
<FormattedMessage
defaultMessage="Upload Handout"
description="Label for upload button"
id="authoring.videoeditor.handout.upload.label"
/>
</Button>
</Stack>
</CollapsibleFormWidget>
`;
exports[`HandoutWidget snapshots snapshots: renders as expected with handout 1`] = `
<CollapsibleFormWidget
fontSize="x-small"
isError={true}
subtitle="sOMeUrl "
title="Handout"
>
<ErrorAlert
dismissError={[Function]}
hideHeading={true}
isError={false}
>
<FormattedMessage
defaultMessage="Handout files must be 20 MB or less. Please resize the file and try again."
description="Message presented to user when handout file size is larger than 20 MB"
id="authoring.videoeditor.handout.error.fileSizeError"
/>
</ErrorAlert>
<UploadErrorAlert
message={
{
"defaultMessage": "Failed to upload handout. Please try again.",
"description": "Message presented to user when handout fails to upload",
"id": "authoring.videoeditor.handout.error.uploadHandoutError",
}
}
/>
<FileInput
fileInput={
{
"addFile": [Function],
"click": [Function],
"ref": {
"current": undefined,
},
}
}
/>
<Stack
gap={3}
>
<ActionRow
className="border border-gray-300 rounded px-3 py-2"
>
sOMeUrl
<ActionRow.Spacer />
<Dropdown>
<Dropdown.Toggle
alt="Actions dropdown"
as="IconButton"
iconAs="Icon"
id="dropdown-toggle-with-iconbutton-video-transcript-widget"
variant="primary"
/>
<Dropdown.Menu
className="video_handout Action Menu"
>
<Dropdown.Item
key="handout-actions-replace"
onClick={[Function]}
>
<FormattedMessage
defaultMessage="Replace"
description="Message Presented To user for action to replace handout"
id="authoring.videoeditor.handout.replaceHandout"
/>
</Dropdown.Item>
<Dropdown.Item
key="handout-actions-download"
target="_blank"
>
<FormattedMessage
defaultMessage="Download"
description="Message Presented To user for action to download handout"
id="authoring.videoeditor.handout.downloadHandout"
/>
</Dropdown.Item>
<Dropdown.Item
key="handout-actions-delete"
onClick={[Function]}
>
<FormattedMessage
defaultMessage="Delete"
description="Message Presented To user for action to delete handout"
id="authoring.videoeditor.handout.deleteHandout"
/>
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</ActionRow>
<FormattedMessage
defaultMessage="Learners can download this file by clicking "Download Handout" below the video."
description="Message presented to user when a handout is present"
id="authoring.videoeditor.handout.handoutHelpMessage"
/>
</Stack>
</CollapsibleFormWidget>
`;
exports[`HandoutWidget snapshots snapshots: renders as expected with isLibrary true 1`] = `null`;

View File

@@ -1,81 +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 { HandoutWidgetInternal as HandoutWidget, mapStateToProps, mapDispatchToProps } from '.';
jest.mock('react', () => ({
...jest.requireActual('react'),
useContext: jest.fn(() => ({ handout: ['error.handout', jest.fn().mockName('error.setHandout')] })),
}));
jest.mock('../../../../../../data/redux', () => ({
actions: {
video: {
updateField: jest.fn().mockName('actions.video.updateField'),
},
},
selectors: {
video: {
getHandoutDownloadUrl: jest.fn(args => ({ getHandoutDownloadUrl: args })).mockName('selectors.video.getHandoutDownloadUrl'),
handout: jest.fn(state => ({ handout: state })),
},
app: {
isLibrary: jest.fn(args => ({ isLibrary: args })),
},
requests: {
isFailed: jest.fn(args => ({ isFailed: args })),
},
},
}));
describe('HandoutWidget', () => {
const props = {
subtitle: 'SuBTItle',
title: 'tiTLE',
intl: { formatMessage },
isLibrary: false,
handout: '',
getHandoutDownloadUrl: jest.fn().mockName('args.getHandoutDownloadUrl'),
updateField: jest.fn().mockName('args.updateField'),
};
describe('snapshots', () => {
test('snapshots: renders as expected with default props', () => {
expect(
shallow(<HandoutWidget {...props} />).snapshot,
).toMatchSnapshot();
});
test('snapshots: renders as expected with isLibrary true', () => {
expect(
shallow(<HandoutWidget {...props} isLibrary />).snapshot,
).toMatchSnapshot();
});
test('snapshots: renders as expected with handout', () => {
expect(
shallow(<HandoutWidget {...props} handout="sOMeUrl " />).snapshot,
).toMatchSnapshot();
});
});
describe('mapStateToProps', () => {
const testState = { A: 'pple', B: 'anana', C: 'ucumber' };
test('isLibrary from app.isLibrary', () => {
expect(
mapStateToProps(testState).isLibrary,
).toEqual(selectors.app.isLibrary(testState));
});
test('getHandoutDownloadUrl from video.getHandoutDownloadUrl', () => {
expect(
mapStateToProps(testState).getHandoutDownloadUrl,
).toEqual(selectors.video.getHandoutDownloadUrl(testState));
});
});
describe('mapDispatchToProps', () => {
const dispatch = jest.fn();
test('updateField from actions.video.updateField', () => {
expect(mapDispatchToProps.updateField).toEqual(dispatch(actions.video.updateField));
});
});
});

View File

@@ -0,0 +1,60 @@
import React from 'react';
import { render, screen, initializeMocks } from '@src/testUtils';
import { formatMessage } from '@src/editors/testUtils';
import { HandoutWidgetInternal as HandoutWidget } from '.';
jest.mock('@src/editors/data/redux', () => ({
actions: {
video: {
updateField: jest.fn().mockName('actions.video.updateField'),
},
},
selectors: {
video: {
getHandoutDownloadUrl: jest.fn(args => ({ getHandoutDownloadUrl: args })).mockName('selectors.video.getHandoutDownloadUrl'),
handout: jest.fn(state => ({ handout: state })),
},
app: {
isLibrary: jest.fn(args => ({ isLibrary: args })),
},
requests: {
isFailed: jest.fn(args => ({ isFailed: args })),
},
},
}));
describe('HandoutWidget', () => {
const props = {
intl: { formatMessage },
isLibrary: false,
handout: '',
isUploadError: false,
getHandoutDownloadUrl: jest.fn().mockName('args.getHandoutDownloadUrl'),
updateField: jest.fn().mockName('args.updateField'),
};
describe('renders', () => {
beforeEach(() => {
initializeMocks();
});
test('renders as expected with default props', () => {
render(<HandoutWidget {...props} />);
expect(screen.getByText('Handout')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Upload Handout' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Handout' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Collapse' })).toBeInTheDocument();
});
test('renders as expected with isLibrary true', () => {
const { container } = render(<HandoutWidget {...props} isLibrary />);
const reduxWrapper = container.firstChild;
expect(reduxWrapper?.textContent).toBe('');
expect(screen.queryByText('Handout')).not.toBeInTheDocument();
});
test('renders as expected with handout', () => {
const handoutUrl = 'sOMeUrl ';
render(<HandoutWidget {...props} handout={handoutUrl} />);
expect(screen.getByText('Handout')).toBeInTheDocument();
expect(screen.getByText(handoutUrl.trim())).toBeInTheDocument();
});
});
});

View File

@@ -1,20 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CodeEditor Component Snapshots Renders and calls Hooks 1`] = `
<div>
<div
id="CodeMirror"
/>
<Button
aria-label="Unescape HTML Literals"
onClick={[Function]}
variant="tertiary"
>
<FormattedMessage
defaultMessage="Unescape HTML Literals"
description="Label For escape special html charectars button"
id="authoring.texteditor.codeEditor.escapeHTMLButton"
/>
</Button>
</div>
`;

View File

@@ -1,53 +1,15 @@
import 'CourseAuthoring/editors/setupEditorTest';
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { EditorState } from '@codemirror/state';
import { EditorView } from '@codemirror/view';
import { html } from '@codemirror/lang-html';
import {
render, screen, initializeMocks, fireEvent,
} from '@src/testUtils';
import { formatMessage, MockUseState } from '../../testUtils';
import alphanumericMap from './constants';
import * as module from './index';
import { CodeEditorInternal as CodeEditor } from './index';
import * as hooks from './hooks';
const CodeEditor = module.CodeEditorInternal;
jest.mock('@codemirror/view');
jest.mock('react', () => ({
...jest.requireActual('react'),
useRef: jest.fn(val => ({ current: val })),
useEffect: jest.fn(),
useCallback: (cb, prereqs) => ({ cb, prereqs }),
}));
jest.mock('@codemirror/state', () => ({
...jest.requireActual('@codemirror/state'),
EditorState: {
create: jest.fn(),
},
}));
jest.mock('@codemirror/lang-html', () => ({
html: jest.fn(),
}));
jest.mock('@codemirror/lang-xml', () => ({
xml: jest.fn(),
}));
jest.mock('@codemirror/lang-markdown', () => ({
markdown: jest.fn(),
}));
jest.mock('codemirror', () => ({
basicSetup: 'bAsiCSetUp',
}));
const state = new MockUseState(hooks);
describe('CodeEditor', () => {
describe('Hooks', () => {
const state = new MockUseState(hooks);
beforeEach(() => {
jest.clearAllMocks();
});
@@ -103,30 +65,6 @@ describe('CodeEditor', () => {
expect(mockHideBtn).toHaveBeenCalled();
});
});
describe('createCodeMirrorDomNode', () => {
const props = {
ref: {
current: 'sOmEvAlUe',
},
lang: 'html',
initialText: 'sOmEhTmL',
upstreamRef: {
current: 'sOmEotHERvAlUe',
},
};
beforeEach(() => {
hooks.createCodeMirrorDomNode(props);
});
it('calls useEffect and sets up codemirror objects', () => {
const [cb, prereqs] = React.useEffect.mock.calls[0];
expect(prereqs).toStrictEqual([]);
cb();
expect(EditorState.create).toHaveBeenCalled();
expect(EditorView).toHaveBeenCalled();
expect(html).toHaveBeenCalled();
});
});
});
describe('xmlSyntaxChecker', () => {
@@ -165,11 +103,12 @@ describe('CodeEditor', () => {
});
describe('Component', () => {
describe('Snapshots', () => {
const mockHideBtn = jest.fn().mockName('mockHidebtn');
let props;
beforeAll(() => {
props = {
describe('renders', () => {
beforeEach(() => {
initializeMocks();
});
test('Renders and calls Hooks ', () => {
const props = {
intl: { formatMessage },
innerRef: {
current: 'sOmEvALUE',
@@ -177,16 +116,29 @@ describe('CodeEditor', () => {
lang: 'html',
value: 'mOcKhTmL',
};
const mockBtnRef = { current: null };
const mockDOMRef = { current: null };
const mockUseRef = jest.fn()
.mockImplementationOnce(() => mockDOMRef) // for DOMref
.mockImplementationOnce(() => mockBtnRef); // for btnRef
jest.spyOn(React, 'useRef').mockImplementation(mockUseRef);
const mockHideBtn = jest.fn();
jest.spyOn(hooks, 'prepareShowBtnEscapeHTML').mockImplementation(() => ({
showBtnEscapeHTML: true,
hideBtn: mockHideBtn,
}));
jest.spyOn(hooks, 'createCodeMirrorDomNode').mockImplementation(() => ({}));
});
afterAll(() => {
jest.clearAllMocks();
});
test('Renders and calls Hooks ', () => {
jest.spyOn(hooks, 'prepareShowBtnEscapeHTML').mockImplementation(() => ({ showBtnEscapeHTML: true, hideBtn: mockHideBtn }));
const mockEscapeHTMLSpecialChars = jest.fn();
jest.spyOn(hooks, 'escapeHTMLSpecialChars').mockImplementation(mockEscapeHTMLSpecialChars);
// Note: ref won't show up as it is not acutaly a DOM attribute.
expect(shallow(<CodeEditor {...props} />).snapshot).toMatchSnapshot();
render(<CodeEditor {...props} />);
expect(screen.getByRole('button', { name: 'Unescape HTML Literals' })).toBeInTheDocument();
expect(hooks.prepareShowBtnEscapeHTML).toHaveBeenCalled();
expect(hooks.createCodeMirrorDomNode).toHaveBeenCalled();
fireEvent.click(screen.getByRole('button', { name: 'Unescape HTML Literals' }));
expect(mockEscapeHTMLSpecialChars).toHaveBeenCalled();
});
});
});

View File

@@ -1,77 +0,0 @@
import 'CourseAuthoring/editors/setupEditorTest';
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { selectors } from '../../data/redux';
import { formatMessage } from '../../testUtils';
import { ErrorPageInternal as ErrorPage, mapStateToProps } from './ErrorPage';
jest.mock('../../data/redux', () => ({
selectors: {
app: {
unitUrl: jest.fn(state => ({ unitUrl: state })),
},
},
}));
describe('Editor Page', () => {
const emptyProps = {
learningContextId: null,
studioEndpointUrl: null,
intl: { formatMessage },
};
const passedProps = {
learningContextId: 'course-v1:edX+DemoX+Demo_Course',
studioEndpointUrl: 'fakeurl.com',
message: 'cUStomMEssagE',
intl: { formatMessage },
};
const unitData = {
data: {
ancestors: [{ id: 'SomeID' }],
},
};
describe('rendered with empty props', () => {
it('should only have one button (try again)', () => {
const wrapper = shallow(<ErrorPage {...emptyProps} />);
const buttonText = wrapper.instance.findByType('Button')[0].children[0].el;
expect(wrapper.snapshot).toMatchSnapshot();
expect(buttonText).toEqual('Try again');
});
});
describe('rendered with pass through props defined', () => {
const wrapper = shallow(<ErrorPage {...passedProps} />);
describe('shows two buttons', () => {
it('the first button should correspond to returning to the course outline', () => {
const firstButtonText = wrapper.instance.findByType('Button')[0].children[0].el;
const secondButtonText = wrapper.instance.findByType('Button')[1].children[0].el;
expect(wrapper.snapshot).toMatchSnapshot();
expect(firstButtonText).toEqual('Return to course outline');
expect(secondButtonText).toEqual('Try again');
});
it('the first button should correspond to returning to the unit page', () => {
const returnToUnitPageWrapper = shallow(<ErrorPage {...passedProps} unitData={unitData} />);
expect(returnToUnitPageWrapper.snapshot).toMatchSnapshot();
const firstButtonText = returnToUnitPageWrapper.instance.findByType('Button')[0].children[0].el;
const secondButtonText = returnToUnitPageWrapper.instance.findByType('Button')[1].children[0].el;
expect(returnToUnitPageWrapper.snapshot).toMatchSnapshot();
expect(firstButtonText).toEqual('Return to unit page');
expect(secondButtonText).toEqual('Try again');
});
});
it('should have custom message', () => {
const customMessageText = wrapper.instance.findByType('div')[0].children[0].children[0].el;
expect(wrapper.snapshot).toMatchSnapshot();
expect(customMessageText).toEqual('cUStomMEssagE');
});
});
describe('mapStateToProps() function', () => {
const testState = { A: 'pple', B: 'anana', C: 'ucumber' };
test('unitData should equal unitUrl from app.unitUrl', () => {
expect(
mapStateToProps(testState).unitData,
).toEqual(selectors.app.unitUrl(testState));
});
});
});

View File

@@ -0,0 +1,65 @@
import React from 'react';
import { render, screen, initializeMocks } from '@src/testUtils';
import { formatMessage } from '../../testUtils';
import { ErrorPageInternal as ErrorPage } from './ErrorPage';
jest.mock('../../data/redux', () => ({
selectors: {
app: {
unitUrl: jest.fn(state => ({ unitUrl: state })),
},
},
}));
describe('Editor Page', () => {
const emptyProps = {
learningContextId: 'course-v1:edX+DemoX+Demo_Course',
studioEndpointUrl: 'fakeurl.com',
intl: { formatMessage },
};
const passedProps = {
learningContextId: 'course-v1:edX+DemoX+Demo_Course',
studioEndpointUrl: 'fakeurl.com',
message: 'cUStomMEssagE',
intl: { formatMessage },
};
const unitData = {
data: {
ancestors: [{ id: 'SomeID' }],
},
};
beforeEach(() => {
initializeMocks();
});
describe('rendered with empty props', () => {
it('should only have one button (try again)', () => {
render(<ErrorPage {...emptyProps} />);
expect(screen.getByRole('button', { name: 'Try again' })).toBeInTheDocument();
});
});
describe('rendered with pass through props defined', () => {
describe('shows two buttons', () => {
it('the first button should correspond to returning to the course outline', () => {
render(<ErrorPage {...passedProps} />);
const firstButton = screen.getByRole('button', { name: 'Return to course outline' });
const secondButton = screen.getByRole('button', { name: 'Try again' });
expect(firstButton).toBeInTheDocument();
expect(secondButton).toBeInTheDocument();
});
it('the first button should correspond to returning to the unit page', () => {
render(<ErrorPage {...passedProps} unitData={unitData} />);
const firstButton = screen.getByRole('button', { name: 'Return to unit page' });
const secondButton = screen.getByRole('button', { name: 'Try again' });
expect(firstButton).toBeInTheDocument();
expect(secondButton).toBeInTheDocument();
});
});
it('should have custom message', () => {
render(<ErrorPage {...passedProps} />);
expect(screen.getByText('cUStomMEssagE')).toBeInTheDocument();
});
});
});

View File

@@ -1,196 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Editor Page rendered with empty props should only have one button (try again) 1`] = `
<Container
className="py-5 justify-content-center align-items-start text-center"
fluid={true}
>
<Row>
<Col>
<p
className="text-muted"
>
An unexpected error occurred. Please click the button below to refresh the page.
</p>
<Row
className="justify-content-center"
>
<Button
className="ml-2"
onClick={[Function]}
>
Try again
</Button>
</Row>
</Col>
</Row>
</Container>
`;
exports[`Editor Page rendered with pass through props defined should have custom message 1`] = `
<Container
className="py-5 justify-content-center align-items-start text-center"
fluid={true}
>
<Row>
<Col>
<p
className="text-muted"
>
An unexpected error occurred. Please click the button below to refresh the page.
</p>
<div
className="my-4"
role="alert"
>
<p>
cUStomMEssagE
</p>
</div>
<Row
className="justify-content-center"
>
<Button
className="mr-2"
onClick={[Function]}
variant="outline-primary"
>
Return to course outline
</Button>
<Button
className="ml-2"
onClick={[Function]}
>
Try again
</Button>
</Row>
</Col>
</Row>
</Container>
`;
exports[`Editor Page rendered with pass through props defined shows two buttons the first button should correspond to returning to the course outline 1`] = `
<Container
className="py-5 justify-content-center align-items-start text-center"
fluid={true}
>
<Row>
<Col>
<p
className="text-muted"
>
An unexpected error occurred. Please click the button below to refresh the page.
</p>
<div
className="my-4"
role="alert"
>
<p>
cUStomMEssagE
</p>
</div>
<Row
className="justify-content-center"
>
<Button
className="mr-2"
onClick={[Function]}
variant="outline-primary"
>
Return to course outline
</Button>
<Button
className="ml-2"
onClick={[Function]}
>
Try again
</Button>
</Row>
</Col>
</Row>
</Container>
`;
exports[`Editor Page rendered with pass through props defined shows two buttons the first button should correspond to returning to the unit page 1`] = `
<Container
className="py-5 justify-content-center align-items-start text-center"
fluid={true}
>
<Row>
<Col>
<p
className="text-muted"
>
An unexpected error occurred. Please click the button below to refresh the page.
</p>
<div
className="my-4"
role="alert"
>
<p>
cUStomMEssagE
</p>
</div>
<Row
className="justify-content-center"
>
<Button
className="mr-2"
onClick={[Function]}
variant="outline-primary"
>
Return to unit page
</Button>
<Button
className="ml-2"
onClick={[Function]}
>
Try again
</Button>
</Row>
</Col>
</Row>
</Container>
`;
exports[`Editor Page rendered with pass through props defined shows two buttons the first button should correspond to returning to the unit page 2`] = `
<Container
className="py-5 justify-content-center align-items-start text-center"
fluid={true}
>
<Row>
<Col>
<p
className="text-muted"
>
An unexpected error occurred. Please click the button below to refresh the page.
</p>
<div
className="my-4"
role="alert"
>
<p>
cUStomMEssagE
</p>
</div>
<Row
className="justify-content-center"
>
<Button
className="mr-2"
onClick={[Function]}
variant="outline-primary"
>
Return to unit page
</Button>
<Button
className="ml-2"
onClick={[Function]}
>
Try again
</Button>
</Row>
</Col>
</Row>
</Container>
`;

View File

@@ -1,50 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ExpandableTextArea snapshots renders as expected with default behavior 1`] = `
<Fragment>
<div
className="expandable-mce error"
>
<TinyMceWidget
editorContentHtml="text"
editorRef={
{
"current": {
"value": "something",
},
}
}
editorType="expandable"
placeholder={null}
setEditorRef={[MockFunction hooks.prepareEditorRef.setEditorRef]}
updateContent={[MockFunction]}
/>
</div>
</Fragment>
`;
exports[`ExpandableTextArea snapshots renders error message 1`] = `
<Fragment>
<div
className="expandable-mce error"
>
<TinyMceWidget
editorContentHtml="text"
editorRef={
{
"current": {
"value": "something",
},
}
}
editorType="expandable"
placeholder={null}
setEditorRef={[MockFunction hooks.prepareEditorRef.setEditorRef]}
updateContent={[MockFunction]}
/>
</div>
<div
className="text-danger-500 x-small"
/>
</Fragment>
`;

View File

@@ -28,7 +28,7 @@ const ExpandableTextArea = ({
</div>
{error && (
<div className="text-danger-500 x-small">
{props.errorMessage}
{errorMessage}
</div>
)}
</>

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { render, screen, initializeMocks } from '@src/testUtils';
import ExpandableTextArea from '.';
// Per https://github.com/tinymce/tinymce-react/issues/91 React unit testing in JSDOM is not supported by tinymce.
@@ -31,13 +31,27 @@ describe('ExpandableTextArea', () => {
error: false,
errorMessage: null,
};
describe('snapshots', () => {
beforeEach(() => {
initializeMocks();
});
describe('renders', () => {
test('renders as expected with default behavior', () => {
expect(shallow(<ExpandableTextArea {...props} />).snapshot).toMatchSnapshot();
const { container } = render(<ExpandableTextArea {...props} />);
expect(container.querySelector('TinyMceWidget')).toBeInTheDocument();
});
test('renders error message', () => {
const wrapper = shallow(<ExpandableTextArea {...props} error errorMessage="eRRormeSsaGE" />);
expect(wrapper.snapshot).toMatchSnapshot();
render(<ExpandableTextArea {...props} error errorMessage="eRRormeSsaGE" />);
expect(screen.getByText('eRRormeSsaGE')).toBeInTheDocument();
});
test('renders nothing when refReady is null', () => {
// eslint-disable-next-line global-require
jest.spyOn(require('../TinyMceWidget/hooks'), 'prepareEditorRef').mockReturnValue({
editorRef: { current: { value: 'something' } },
refReady: false,
setEditorRef: jest.fn().mockName('hooks.prepareEditorRef.setEditorRef'),
});
const { container } = render(<ExpandableTextArea {...props} />);
expect(container.firstChild?.textContent).toBe('');
});
});
});

View File

@@ -1,175 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ImageSettingsModal render snapshot 1`] = `
<BaseModal
bodyStyle={null}
close={[MockFunction props.close]}
confirmAction={
<Button
onClick={
{
"hooks.onSaveClick": {
"altText": {
"error": {
"dismiss": [MockFunction],
"show": true,
},
"isDecorative": false,
"value": "alternative Taxes",
},
"dimensions": {
"height": 13,
"width": 12,
},
"isDecorative": false,
"saveToEditor": [MockFunction props.saveToEditor],
},
}
}
variant="primary"
>
<FormattedMessage
defaultMessage="Save"
description="Label for save button."
id="authoring.texteditor.imagesettingsmodal.saveButtonLabel"
/>
</Button>
}
footerAction={null}
headerComponent={null}
hideCancelButton={false}
isFullscreenScroll={true}
isOpen={false}
size="lg"
title="Image Settings"
>
<ErrorAlert
dismissError={[MockFunction]}
hideHeading={true}
isError={true}
>
<FormattedMessage
defaultMessage="Enter alt text or specify that the image is decorative only."
description="Message presented to user when user attempts to save unaccepted altText configuration."
id="authoring.texteditor.imagesettingsmodal.error.altTextError"
/>
</ErrorAlert>
<Button
onClick={[MockFunction props.returnToSelector]}
size="inline"
variant="link"
>
<FormattedMessage
defaultMessage="Replace image"
description="Label for replace image button."
id="authoring.texteditor.imagesettingsmodal.replaceImageButtonLabel"
/>
</Button>
<br />
<div
className="d-flex flex-row m-2 img-settings-form-container"
>
<div
className="img-settings-thumbnail-container"
>
<Image
className="img-settings-thumbnail"
onError={
{
"hooks.dimensions.onImgLoad.callback": {
"selection": {
"altText": "AlTTExt",
"externalUrl": "ExtERNALurL",
"url": "UrL",
},
},
}
}
onLoad={
{
"hooks.dimensions.onImgLoad.callback": {
"selection": {
"altText": "AlTTExt",
"externalUrl": "ExtERNALurL",
"url": "UrL",
},
},
}
}
src="ExtERNALurL"
/>
</div>
<hr
className="h-100 bg-primary-200 m-0"
/>
<div
className="img-settings-form-controls"
>
<DimensionControls
onImgLoad={
[MockFunction hooks.dimensions.onImgLoad] {
"calls": [
[
{
"altText": "AlTTExt",
"externalUrl": "ExtERNALurL",
"url": "UrL",
},
],
[
{
"altText": "AlTTExt",
"externalUrl": "ExtERNALurL",
"url": "UrL",
},
],
],
"results": [
{
"type": "return",
"value": {
"hooks.dimensions.onImgLoad.callback": {
"selection": {
"altText": "AlTTExt",
"externalUrl": "ExtERNALurL",
"url": "UrL",
},
},
},
},
{
"type": "return",
"value": {
"hooks.dimensions.onImgLoad.callback": {
"selection": {
"altText": "AlTTExt",
"externalUrl": "ExtERNALurL",
"url": "UrL",
},
},
},
},
],
}
}
value={
{
"height": 13,
"width": 12,
}
}
/>
<AltTextControls
error={
{
"dismiss": [MockFunction],
"show": true,
}
}
isDecorative={false}
value="alternative Taxes"
/>
</div>
</div>
</BaseModal>
`;

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Button, Image } from '@openedx/paragon';
import { ArrowBackIos } from '@openedx/paragon/icons';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import './index.scss';
import * as hooks from './hooks';
@@ -29,9 +29,8 @@ const ImageSettingsModal = ({
returnToSelection,
saveToEditor,
selection,
// inject
intl,
}) => {
const intl = useIntl();
const altText = hooks.altTextHooks(selection.altText);
const dimensions = hooks.dimensionHooks(altText);
const onSaveClick = hooks.onSaveClick({
@@ -99,8 +98,5 @@ ImageSettingsModal.propTypes = {
externalUrl: PropTypes.string,
url: PropTypes.string,
}).isRequired,
// inject
intl: intlShape.isRequired,
};
export const ImageSettingsModalInternal = ImageSettingsModal; // For testing only
export default injectIntl(ImageSettingsModal);
export default ImageSettingsModal;

View File

@@ -1,9 +1,6 @@
import 'CourseAuthoring/editors/setupEditorTest';
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { formatMessage } from '../../../testUtils';
import { ImageSettingsModalInternal as ImageSettingsModal } from '.';
import { render, screen, initializeMocks } from '@src/testUtils';
import ImageSettingsModal from '.';
jest.mock('./AltTextControls', () => 'AltTextControls');
jest.mock('./DimensionControls', () => 'DimensionControls');
@@ -28,23 +25,21 @@ jest.mock('./hooks', () => ({
describe('ImageSettingsModal', () => {
const props = {
isOpen: false,
isOpen: true,
selection: {
altText: 'AlTTExt',
externalUrl: 'ExtERNALurL',
url: 'UrL',
},
// inject
intl: { formatMessage },
close: jest.fn().mockName('props.close'),
returnToSelection: jest.fn().mockName('props.returnToSelector'),
saveToEditor: jest.fn().mockName('props.saveToEditor'),
};
beforeEach(() => {
props.close = jest.fn().mockName('props.close');
props.saveToEditor = jest.fn().mockName('props.saveToEditor');
props.returnToSelection = jest.fn().mockName('props.returnToSelector');
initializeMocks();
});
describe('render', () => {
test('snapshot', () => {
expect(shallow(<ImageSettingsModal {...props} />).snapshot).toMatchSnapshot();
});
test('renders component', () => {
render(<ImageSettingsModal {...props} />);
expect(screen.getByText('Image Settings')).toBeInTheDocument();
});
});