Skip to content

Commit b6ff623

Browse files
authored
fix: text editor opening blank with no images (#492)
* fix: pasting and images only insert at beginning * fix: add image click not showing gallery * chore: increase code coverage * fix: empty string when no srcs need updates * fix: assest to static in raw editor
1 parent fc3cd9a commit b6ff623

File tree

11 files changed

+133
-82
lines changed

11 files changed

+133
-82
lines changed

src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ export const ExplanationWidget = ({
1616
intl,
1717
}) => {
1818
const { editorRef, refReady, setEditorRef } = prepareEditorRef();
19-
const solutionContent = replaceStaticWithAsset({
20-
initialContent: settings?.solutionExplanation || '',
19+
const initialContent = settings?.solutionExplanation || '';
20+
const newContent = replaceStaticWithAsset({
21+
initialContent,
2122
learningContextId,
2223
});
24+
const solutionContent = newContent || initialContent;
2325
if (!refReady) { return null; }
2426
return (
2527
<div className="tinyMceWidget mt-4 text-primary-500">

src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.test.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable react/prop-types */
21
import React from 'react';
32
import { shallow } from '@edx/react-unit-test-utils';
43
import { formatMessage } from '../../../../../../testUtils';
@@ -24,11 +23,11 @@ jest.mock('../../../../../data/redux', () => ({
2423
}));
2524

2625
jest.mock('../../../../../sharedComponents/TinyMceWidget/hooks', () => ({
26+
...jest.requireActual('../../../../../sharedComponents/TinyMceWidget/hooks'),
2727
prepareEditorRef: jest.fn(() => ({
2828
refReady: true,
2929
setEditorRef: jest.fn().mockName('prepareEditorRef.setEditorRef'),
3030
})),
31-
replaceStaticWithAsset: jest.fn(() => 'This is my solution'),
3231
}));
3332

3433
describe('SolutionWidget', () => {

src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ export const QuestionWidget = ({
1616
intl,
1717
}) => {
1818
const { editorRef, refReady, setEditorRef } = prepareEditorRef();
19-
const questionContent = replaceStaticWithAsset({
20-
initialContent: question,
19+
const initialContent = question;
20+
const newContent = replaceStaticWithAsset({
21+
initialContent,
2122
learningContextId,
2223
});
24+
const questionContent = newContent || initialContent;
2325
if (!refReady) { return null; }
2426
return (
2527
<div className="tinyMceWidget">

src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.test.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable react/prop-types */
21
import React from 'react';
32
import { shallow } from '@edx/react-unit-test-utils';
43
import { formatMessage } from '../../../../../../testUtils';
@@ -29,11 +28,11 @@ jest.mock('../../../../../data/redux', () => ({
2928
}));
3029

3130
jest.mock('../../../../../sharedComponents/TinyMceWidget/hooks', () => ({
31+
...jest.requireActual('../../../../../sharedComponents/TinyMceWidget/hooks'),
3232
prepareEditorRef: jest.fn(() => ({
3333
refReady: true,
3434
setEditorRef: jest.fn().mockName('prepareEditorRef.setEditorRef'),
3535
})),
36-
replaceStaticWithAsset: jest.fn(() => 'This is my question'),
3736
}));
3837

3938
describe('QuestionWidget', () => {

src/editors/containers/TextEditor/__snapshots__/index.test.jsx.snap

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,52 @@ exports[`TextEditor snapshots renders as expected with default behavior 1`] = `
191191
</div>
192192
</EditorContainer>
193193
`;
194+
195+
exports[`TextEditor snapshots renders static images with relative paths 1`] = `
196+
<EditorContainer
197+
getContent={
198+
{
199+
"getContent": {
200+
"editorRef": {
201+
"current": {
202+
"value": "something",
203+
},
204+
},
205+
"showRawEditor": false,
206+
},
207+
}
208+
}
209+
onClose={[MockFunction props.onClose]}
210+
returnFunction={null}
211+
>
212+
<div
213+
className="editor-body h-75 overflow-auto"
214+
>
215+
<Toast
216+
onClose={[MockFunction hooks.nullMethod]}
217+
show={false}
218+
>
219+
<FormattedMessage
220+
defaultMessage="Error: Could Not Load Text Content"
221+
description="Error Message Dispayed When HTML content fails to Load"
222+
id="authoring.texteditor.load.error"
223+
/>
224+
</Toast>
225+
<[object Object]
226+
editorContentHtml="eDiTablE Text with <img src="/asset+org+run+type@[email protected]" />"
227+
editorRef={
228+
{
229+
"current": {
230+
"value": "something",
231+
},
232+
}
233+
}
234+
editorType="text"
235+
height="100%"
236+
initializeEditor={[MockFunction args.intializeEditor]}
237+
minHeight={500}
238+
setEditorRef={[MockFunction hooks.prepareEditorRef.setEditorRef]}
239+
/>
240+
</div>
241+
</EditorContainer>
242+
`;

src/editors/containers/TextEditor/index.jsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ export const TextEditor = ({
3232
intl,
3333
}) => {
3434
const { editorRef, refReady, setEditorRef } = prepareEditorRef();
35-
const editorContent = blockValue ? replaceStaticWithAsset({
36-
initialContent: blockValue.data.data,
35+
const initialContent = blockValue ? blockValue.data.data : '';
36+
const newContent = replaceStaticWithAsset({
37+
initialContent,
3738
learningContextId,
38-
}) : '';
39+
});
40+
const editorContent = newContent || initialContent;
3941

4042
if (!refReady) { return null; }
4143

src/editors/containers/TextEditor/index.test.jsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ jest.mock('./hooks', () => ({
2525
}));
2626

2727
jest.mock('../../sharedComponents/TinyMceWidget/hooks', () => ({
28+
...jest.requireActual('../../sharedComponents/TinyMceWidget/hooks'),
2829
prepareEditorRef: jest.fn(() => ({
2930
editorRef: { current: { value: 'something' } },
3031
refReady: true,
3132
setEditorRef: jest.fn().mockName('hooks.prepareEditorRef.setEditorRef'),
3233
})),
33-
replaceStaticWithAsset: jest.fn(() => 'eDiTablE Text'),
3434
}));
3535

3636
jest.mock('react', () => {
@@ -88,6 +88,13 @@ describe('TextEditor', () => {
8888
test('renders as expected with default behavior', () => {
8989
expect(shallow(<TextEditor {...props} />).snapshot).toMatchSnapshot();
9090
});
91+
test('renders static images with relative paths', () => {
92+
const updatedProps = {
93+
...props,
94+
blockValue: { data: { data: 'eDiTablE Text with <img src="/static/img.jpg" />' } },
95+
};
96+
expect(shallow(<TextEditor {...updatedProps} />).snapshot).toMatchSnapshot();
97+
});
9198
test('not yet loaded, Spinner appears', () => {
9299
expect(shallow(<TextEditor {...props} blockFinished={false} />).snapshot).toMatchSnapshot();
93100
});

src/editors/sharedComponents/RawEditor/__snapshots__/index.test.jsx.snap

Lines changed: 0 additions & 52 deletions
This file was deleted.

src/editors/sharedComponents/RawEditor/index.jsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
33
import { Alert } from '@openedx/paragon';
44

55
import CodeEditor from '../CodeEditor';
6+
import { setAssetToStaticUrl } from '../TinyMceWidget/hooks';
67

78
function getValue(content) {
89
if (!content) { return null; }
@@ -15,7 +16,8 @@ export const RawEditor = ({
1516
content,
1617
lang,
1718
}) => {
18-
const value = getValue(content);
19+
const value = getValue(content) || '';
20+
const staticUpdate = setAssetToStaticUrl({ editorValue: value });
1921

2022
return (
2123
<div>
@@ -27,8 +29,9 @@ export const RawEditor = ({
2729
{ value ? (
2830
<CodeEditor
2931
innerRef={editorRef}
30-
value={value}
32+
value={staticUpdate}
3133
lang={lang}
34+
data-testid="code-editor"
3235
/>
3336
) : null}
3437

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
import React from 'react';
2-
import { shallow } from '@edx/react-unit-test-utils';
2+
import { render, screen } from '@testing-library/react';
3+
import { IntlProvider } from '@edx/frontend-platform/i18n';
4+
import '@testing-library/jest-dom/extend-expect';
35

46
import { RawEditor } from '.';
57

8+
jest.unmock('@openedx/paragon');
9+
10+
const renderComponent = (props) => render(
11+
<IntlProvider locale="en">
12+
<RawEditor {...props} />
13+
</IntlProvider>,
14+
);
615
describe('RawEditor', () => {
716
const defaultProps = {
817
editorRef: {
918
current: {
1019
value: 'Ref Value',
1120
},
1221
},
13-
content: { data: { data: 'eDiTablE Text' } },
22+
content: { data: { data: 'eDiTablE Text HtmL' } },
1423
lang: 'html',
1524
};
1625
const xmlProps = {
@@ -19,7 +28,7 @@ describe('RawEditor', () => {
1928
value: 'Ref Value',
2029
},
2130
},
22-
content: { data: { data: 'eDiTablE Text' } },
31+
content: { data: { data: 'eDiTablE Text XMl' } },
2332
lang: 'xml',
2433
};
2534
const noContentProps = {
@@ -33,13 +42,39 @@ describe('RawEditor', () => {
3342
width: { width: '80%' },
3443
};
3544

36-
test('renders as expected with default behavior', () => {
37-
expect(shallow(<RawEditor {...defaultProps} />).snapshot).toMatchSnapshot();
45+
it('renders as expected with default behavior', () => {
46+
renderComponent(defaultProps);
47+
expect(screen.getByRole('alert')).toBeVisible();
48+
49+
expect(screen.getByText('eDiTablE Text HtmL')).toBeVisible();
3850
});
39-
test('renders as expected with lang equal to xml', () => {
40-
expect(shallow(<RawEditor {...xmlProps} />).snapshot).toMatchSnapshot();
51+
52+
it('updates the assets to static srcs', () => {
53+
const updatedProps = {
54+
...defaultProps,
55+
content: 'pick <img src="/asset-v1:org+run+term+type@[email protected]" /> or <img src="/assets/courseware/v1/hash/asset-v1:org+run+term+type@asset+block/img2.jpeg" />',
56+
};
57+
renderComponent(updatedProps);
58+
expect(screen.getByText('"/static/img.jpeg"')).toBeVisible();
59+
60+
expect(screen.getByText('"/static/img2.jpeg"')).toBeVisible();
61+
62+
expect(screen.queryByText('"/asset-v1:org+run+term+type@[email protected]"')).toBeNull();
63+
64+
expect(screen.queryByText('"/assets/courseware/v1/hash/asset-v1:org+run+term+type@asset+block/img2.jpeg"')).toBeNull();
4165
});
42-
test('renders as expected with content equal to null', () => {
43-
expect(shallow(<RawEditor {...noContentProps} />).snapshot).toMatchSnapshot();
66+
67+
it('renders as expected with lang equal to xml', () => {
68+
renderComponent(xmlProps);
69+
expect(screen.queryByRole('alert')).toBeNull();
70+
71+
expect(screen.getByText('eDiTablE Text XMl')).toBeVisible();
72+
});
73+
74+
it('renders as expected with content equal to null', () => {
75+
renderComponent(noContentProps);
76+
expect(screen.getByRole('alert')).toBeVisible();
77+
78+
expect(screen.queryByTestId('code-editor')).toBeNull();
4479
});
4580
});

0 commit comments

Comments
 (0)