diff --git a/src/containers/ResponseDisplay/PreviewDisplay.test.jsx b/src/containers/ResponseDisplay/PreviewDisplay.test.jsx
index ffa85c9..ca0da40 100644
--- a/src/containers/ResponseDisplay/PreviewDisplay.test.jsx
+++ b/src/containers/ResponseDisplay/PreviewDisplay.test.jsx
@@ -1,56 +1,66 @@
-import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-
+import { render } from '@testing-library/react';
+import { IntlProvider } from '@edx/frontend-platform/i18n';
import { FileTypes } from 'data/constants/files';
-import { FileRenderer } from 'components/FilePreview';
import { PreviewDisplay } from './PreviewDisplay';
-jest.mock('components/FilePreview', () => ({
- FileRenderer: () => 'FileRenderer',
-}));
+jest.unmock('@openedx/paragon');
+jest.unmock('react');
+jest.unmock('@edx/frontend-platform/i18n');
describe('PreviewDisplay', () => {
- describe('component', () => {
- const supportedTypes = Object.values(FileTypes);
- const props = {
- files: [
- ...supportedTypes.map((fileType, index) => ({
- name: `fake_file_${index}.${fileType}`,
- description: `file description ${index}`,
- downloadUrl: `/url-path/fake_file_${index}.${fileType}`,
- })),
- {
- name: 'bad_ext_fake_file.other',
- description: 'bad_ext file description',
- downloadUrl: 'bad_ext.other',
- },
- ],
+ const supportedTypes = Object.values(FileTypes);
+ const props = {
+ files: [
+ ...supportedTypes.map((fileType, index) => ({
+ name: `fake_file_${index}.${fileType}`,
+ description: `file description ${index}`,
+ downloadUrl: `/url-path/fake_file_${index}.${fileType}`,
+ })),
+ {
+ name: 'bad_ext_fake_file.other',
+ description: 'bad_ext file description',
+ downloadUrl: 'bad_ext.other',
+ },
+ ],
+ };
+
+ const renderWithIntl = (component) => render(
+
+ {component}
+ ,
+ );
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('renders preview display container', () => {
+ const { container } = renderWithIntl();
+ const previewDisplay = container.querySelector('.preview-display');
+ expect(previewDisplay).toBeInTheDocument();
+ });
+
+ it('renders empty container when no files provided', () => {
+ const { container } = renderWithIntl();
+ const previewDisplay = container.querySelector('.preview-display');
+ expect(previewDisplay).toBeInTheDocument();
+ expect(previewDisplay.children.length).toBe(0);
+ });
+
+ it('only renders supported file types', () => {
+ const { container } = renderWithIntl();
+ const previewDisplay = container.querySelector('.preview-display');
+ expect(previewDisplay.children.length).toBe(supportedTypes.length);
+ });
+
+ it('filters out unsupported file types', () => {
+ const unsupportedFile = {
+ name: 'unsupported.xyz',
+ description: 'unsupported file',
+ downloadUrl: '/unsupported.xyz',
};
- let el;
- beforeEach(() => {
- el = shallow();
- });
-
- describe('snapshot', () => {
- test('files render with props', () => {
- expect(el.snapshot).toMatchSnapshot();
- });
- test('files does not exist', () => {
- el = shallow();
- expect(el.snapshot).toMatchSnapshot();
- });
- });
-
- describe('component', () => {
- test('only renders compatible files', () => {
- const cards = el.instance.findByType(FileRenderer);
- expect(cards.length).toEqual(supportedTypes.length);
- cards.forEach((_, index) => {
- expect(
- cards[index].props.file,
- ).toEqual(props.files[index]);
- });
- });
- });
+ const { container } = renderWithIntl();
+ const previewDisplay = container.querySelector('.preview-display');
+ expect(previewDisplay.children.length).toBe(0);
});
});
diff --git a/src/containers/ResponseDisplay/SubmissionFiles.test.jsx b/src/containers/ResponseDisplay/SubmissionFiles.test.jsx
index 0025520..999f121 100644
--- a/src/containers/ResponseDisplay/SubmissionFiles.test.jsx
+++ b/src/containers/ResponseDisplay/SubmissionFiles.test.jsx
@@ -1,99 +1,104 @@
-import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-
+import { render, screen } from '@testing-library/react';
+import { IntlProvider } from '@edx/frontend-platform/i18n';
import { downloadAllLimit, downloadSingleLimit } from 'data/constants/files';
-
-import { formatMessage } from 'testUtils';
import { SubmissionFiles } from './SubmissionFiles';
-import messages from './messages';
-jest.mock('./components/FileNameCell', () => jest.fn().mockName('FileNameCell'));
-jest.mock('./components/FileExtensionCell', () => jest.fn().mockName('FileExtensionCell'));
-jest.mock('./components/FilePopoverCell', () => jest.fn().mockName('FilePopoverCell'));
-jest.mock('./FileDownload', () => 'FileDownload');
+jest.unmock('@openedx/paragon');
+jest.unmock('react');
+jest.unmock('@edx/frontend-platform/i18n');
+
+jest.mock('./components/FileNameCell', () => jest.fn(({ value }) =>
Name: {value}
));
+jest.mock('./components/FileExtensionCell', () => jest.fn(({ value }) => Extension: {value}
));
+jest.mock('./components/FilePopoverCell', () => jest.fn(() => Popover
));
+jest.mock('./FileDownload', () => jest.fn(({ files }) => Download {files.length} files
));
describe('SubmissionFiles', () => {
- describe('component', () => {
- const props = {
- files: [
- {
- name: 'some file name.jpg',
- description: 'description for the file',
- downloadURL: '/valid-url-wink-wink',
- size: 0,
- },
- {
- name: 'file number 2.jpg',
- description: 'description for this file',
- downloadURL: '/url-2',
- size: 0,
- },
- ],
- };
- let el;
- beforeEach(() => {
- el = shallow();
+ const defaultProps = {
+ files: [
+ {
+ name: 'some file name.jpg',
+ description: 'description for the file',
+ downloadURL: '/valid-url-wink-wink',
+ size: 100,
+ },
+ {
+ name: 'file number 2.jpg',
+ description: 'description for this file',
+ downloadURL: '/url-2',
+ size: 200,
+ },
+ ],
+ };
+
+ const renderWithIntl = (component) => render(
+
+ {component}
+ ,
+ );
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('behavior', () => {
+ it('displays submission files title with file count', () => {
+ renderWithIntl();
+ const title = screen.getByTestId('submission-files-title');
+ expect(title).toBeInTheDocument();
+ expect(title).toHaveTextContent(`Submission Files (${defaultProps.files.length})`);
});
- describe('snapshot', () => {
- test('files existed for props', () => {
- expect(el.snapshot).toMatchSnapshot();
- });
-
- test('files does not exist', () => {
- el = shallow();
-
- expect(el.snapshot).toMatchSnapshot();
- });
- test('files size exceed', () => {
- const files = props.files.map(file => ({ ...file, size: downloadSingleLimit + 1 }));
- el = shallow();
- expect(el.snapshot).toMatchSnapshot();
- });
+ it('renders file download component when files can be downloaded', () => {
+ renderWithIntl();
+ const downloadComponent = screen.getByTestId('file-download');
+ expect(downloadComponent).toBeInTheDocument();
+ expect(downloadComponent).toHaveTextContent('Download 2 files');
});
- describe('behavior', () => {
- test('title', () => {
- const titleEl = el.instance.findByTestId('submission-files-title')[0].children[0];
- expect(titleEl.el).toEqual(
- `${formatMessage(messages.submissionFiles)} (${props.files.length})`,
- );
- });
+ it('displays warning when individual file exceeds size limit', () => {
+ const largeFileProps = {
+ ...defaultProps,
+ files: [
+ { ...defaultProps.files[0], size: downloadSingleLimit + 1 },
+ defaultProps.files[1],
+ ],
+ };
+ renderWithIntl();
- describe('canDownload', () => {
- test('normal file size', () => {
- expect(el.instance.findByTestId('file-download')).toHaveLength(1);
- });
+ expect(screen.queryByTestId('file-download')).not.toBeInTheDocument();
+ const warningText = screen.getByTestId('exceed-download-text');
+ expect(warningText).toBeInTheDocument();
+ expect(warningText).toHaveTextContent('Exceeded the allow download size');
+ });
- test('one of the file exceed the limit', () => {
- const oneFileExceed = [{ ...props.files[0], size: downloadSingleLimit + 1 }, props.files[1]];
+ it('displays warning when total file size exceeds limit', () => {
+ const largeFileSize = (downloadAllLimit + 1) / 20;
+ const largeFilesProps = {
+ ...defaultProps,
+ files: Array(20).fill({
+ name: 'large file.jpg',
+ description: 'large file description',
+ downloadURL: '/large-file-url',
+ size: largeFileSize,
+ }),
+ };
+ renderWithIntl();
- oneFileExceed.forEach(file => expect(file.size < downloadAllLimit).toEqual(true));
+ expect(screen.queryByTestId('file-download')).not.toBeInTheDocument();
+ });
- el = shallow();
- expect(el.instance.findByTestId('file-download')).toHaveLength(0);
+ it('displays title only when no files are provided', () => {
+ const { container } = renderWithIntl();
+ const title = container.querySelector('.submission-files-title h3');
+ expect(title).toBeInTheDocument();
+ expect(title).toHaveTextContent('Submission Files (0)');
+ expect(screen.queryByTestId('file-download')).not.toBeInTheDocument();
+ });
- const warningEl = el.instance.findByTestId('exceed-download-text')[0];
- expect(warningEl.el.children[1]).toEqual(formatMessage(messages.exceedFileSize));
- });
-
- test('total file size exceed the limit', () => {
- const length = 20;
- const totalFilesExceed = new Array(length).fill({
- name: 'some file name.jpg',
- description: 'description for the file',
- downloadURL: '/valid-url-wink-wink',
- size: (downloadAllLimit + 1) / length,
- });
- totalFilesExceed.forEach(file => {
- expect(file.size < downloadAllLimit).toEqual(true);
- expect(file.size < downloadSingleLimit).toEqual(true);
- });
-
- el = shallow();
- expect(el.instance.findByTestId('file-download')).toHaveLength(0);
- });
- });
+ it('renders data table with correct file information', () => {
+ const { container } = renderWithIntl();
+ const dataTable = container.querySelector('.submission-files-table');
+ expect(dataTable).toBeInTheDocument();
});
});
});
diff --git a/src/containers/ResponseDisplay/__snapshots__/PreviewDisplay.test.jsx.snap b/src/containers/ResponseDisplay/__snapshots__/PreviewDisplay.test.jsx.snap
deleted file mode 100644
index cc82091..0000000
--- a/src/containers/ResponseDisplay/__snapshots__/PreviewDisplay.test.jsx.snap
+++ /dev/null
@@ -1,124 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`PreviewDisplay component snapshot files does not exist 1`] = `
-
-`;
-
-exports[`PreviewDisplay component snapshot files render with props 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
diff --git a/src/containers/ResponseDisplay/__snapshots__/SubmissionFiles.test.jsx.snap b/src/containers/ResponseDisplay/__snapshots__/SubmissionFiles.test.jsx.snap
deleted file mode 100644
index ad819a5..0000000
--- a/src/containers/ResponseDisplay/__snapshots__/SubmissionFiles.test.jsx.snap
+++ /dev/null
@@ -1,230 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`SubmissionFiles component snapshot files does not exist 1`] = `
-
-
-
- Submission Files (0)
-
-
-
-`;
-
-exports[`SubmissionFiles component snapshot files existed for props 1`] = `
-
-
-
-
-
- Submission Files (2)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`SubmissionFiles component snapshot files size exceed 1`] = `
-
-
-
-
-
- Submission Files (2)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Exceeded the allow download size
-
-
-
-
-
-
-
-`;
diff --git a/src/containers/ResponseDisplay/__snapshots__/index.test.jsx.snap b/src/containers/ResponseDisplay/__snapshots__/index.test.jsx.snap
deleted file mode 100644
index e2fabe0..0000000
--- a/src/containers/ResponseDisplay/__snapshots__/index.test.jsx.snap
+++ /dev/null
@@ -1,99 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`ResponseDisplay component snapshot file upload disable with valid response 1`] = `
-
-
-
- parsed html (sanitized (some text response here))
-
-
-
-`;
-
-exports[`ResponseDisplay component snapshot file upload disabled without response 1`] = `
-
-`;
-
-exports[`ResponseDisplay component snapshot file upload enable with valid response 1`] = `
-
-
-
-
-
- parsed html (sanitized (some text response here))
-
-
-
-`;
-
-exports[`ResponseDisplay component snapshot file upload enable without response 1`] = `
-
-`;
diff --git a/src/containers/ResponseDisplay/components/FileExtensionCell.test.jsx b/src/containers/ResponseDisplay/components/FileExtensionCell.test.jsx
index ca367b9..57f64d2 100644
--- a/src/containers/ResponseDisplay/components/FileExtensionCell.test.jsx
+++ b/src/containers/ResponseDisplay/components/FileExtensionCell.test.jsx
@@ -1,25 +1,42 @@
-import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-
+import { render } from '@testing-library/react';
import FileExtensionCell from './FileExtensionCell';
-describe('FileExtensionCell', () => {
- describe('component', () => {
- const props = {
- value: 'file_name.with_extension.pdf',
- };
- let el;
- beforeEach(() => {
- el = shallow();
- });
- test('snapshot', () => {
- expect(el.snapshot).toMatchSnapshot();
- });
+jest.unmock('@openedx/paragon');
+jest.unmock('react');
- describe('behavior', () => {
- test('content', () => {
- expect(el.instance.children[0].el).toEqual('PDF');
- });
- });
+describe('FileExtensionCell', () => {
+ const props = {
+ value: 'file_name.with_extension.pdf',
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('renders file extension in uppercase', () => {
+ const { getByText } = render();
+ expect(getByText('PDF')).toBeInTheDocument();
+ });
+
+ it('applies correct CSS class', () => {
+ const { container } = render();
+ const element = container.firstChild;
+ expect(element).toHaveClass('text-truncate');
+ });
+
+ it('extracts extension from file with multiple dots', () => {
+ const { getByText } = render();
+ expect(getByText('DOCX')).toBeInTheDocument();
+ });
+
+ it('handles file without extension', () => {
+ const { getByText } = render();
+ expect(getByText('FILENAME')).toBeInTheDocument();
+ });
+
+ it('handles empty file extension', () => {
+ const { container } = render();
+ const element = container.firstChild;
+ expect(element).toHaveTextContent('');
});
});
diff --git a/src/containers/ResponseDisplay/components/FileNameCell.test.jsx b/src/containers/ResponseDisplay/components/FileNameCell.test.jsx
index 7028fec..49ff689 100644
--- a/src/containers/ResponseDisplay/components/FileNameCell.test.jsx
+++ b/src/containers/ResponseDisplay/components/FileNameCell.test.jsx
@@ -1,25 +1,21 @@
import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
+import { render, screen } from '@testing-library/react';
import FileNameCell from './FileNameCell';
describe('FileNameCell', () => {
- describe('component', () => {
- const props = {
- value: 'some test text value',
- };
- let el;
- beforeEach(() => {
- el = shallow();
- });
- test('snapshot', () => {
- expect(el.snapshot).toMatchSnapshot();
- });
+ const props = {
+ value: 'some test text value',
+ };
- describe('behavior', () => {
- test('content', () => {
- expect(el.instance.children[0].el).toEqual(props.value);
- });
- });
+ it('renders the value text', () => {
+ render();
+ expect(screen.getByText('some test text value')).toBeInTheDocument();
+ });
+
+ it('applies text truncation class', () => {
+ const { container } = render();
+ const divElement = container.querySelector('div');
+ expect(divElement).toHaveClass('text-truncate');
});
});
diff --git a/src/containers/ResponseDisplay/components/__snapshots__/FileExtensionCell.test.jsx.snap b/src/containers/ResponseDisplay/components/__snapshots__/FileExtensionCell.test.jsx.snap
deleted file mode 100644
index 2a2d914..0000000
--- a/src/containers/ResponseDisplay/components/__snapshots__/FileExtensionCell.test.jsx.snap
+++ /dev/null
@@ -1,9 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`FileExtensionCell component snapshot 1`] = `
-
- PDF
-
-`;
diff --git a/src/containers/ResponseDisplay/components/__snapshots__/FileNameCell.test.jsx.snap b/src/containers/ResponseDisplay/components/__snapshots__/FileNameCell.test.jsx.snap
deleted file mode 100644
index 143afb6..0000000
--- a/src/containers/ResponseDisplay/components/__snapshots__/FileNameCell.test.jsx.snap
+++ /dev/null
@@ -1,9 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`FileNameCell component snapshot 1`] = `
-
- some test text value
-
-`;
diff --git a/src/containers/ResponseDisplay/index.test.jsx b/src/containers/ResponseDisplay/index.test.jsx
index 797124d..be56044 100644
--- a/src/containers/ResponseDisplay/index.test.jsx
+++ b/src/containers/ResponseDisplay/index.test.jsx
@@ -1,121 +1,127 @@
-import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-
-import createDOMPurify from 'dompurify';
-import parse from 'html-react-parser';
-
+import { render, screen } from '@testing-library/react';
import { fileUploadResponseOptions } from 'data/services/lms/constants';
import { selectors } from 'data/redux';
-
import { ResponseDisplay, mapStateToProps } from '.';
+jest.unmock('@openedx/paragon');
+jest.unmock('react');
+
jest.mock('data/redux', () => ({
selectors: {
grading: {
selected: {
- response: (state) => ({ response: state }),
+ response: jest.fn((state) => state.response || { text: [], files: [] }),
},
},
app: {
ora: {
- fileUploadResponseConfig: (state) => ({ config: state }),
+ fileUploadResponseConfig: jest.fn((state) => state.fileUploadResponseConfig || 'optional'),
},
},
},
}));
-jest.mock('./SubmissionFiles', () => 'SubmissionFiles');
+
+jest.mock('./SubmissionFiles', () => jest.fn(({ files }) => (
+ Files: {files.length}
+)));
+
+jest.mock('./PreviewDisplay', () => jest.fn(({ files }) => (
+ Preview: {files.length}
+)));
+
jest.mock('dompurify', () => () => ({
- sanitize: (text) => `sanitized (${text})`,
+ sanitize: (text) => text,
}));
-jest.mock('html-react-parser', () => (text) => `parsed html (${text})`);
+
+jest.mock('html-react-parser', () => (text) => text);
describe('ResponseDisplay', () => {
- describe('component', () => {
- const props = {
- response: {
- text: ['some text response here'],
- files: [
- {
- name: 'some file name.jpg',
- description: 'description for the file',
- downloadURL: '/valid-url-wink-wink',
- },
- {
- name: 'file number 2.jpg',
- description: 'description for this file',
- downloadURL: '/url-2',
- },
- ],
- },
- fileUploadResponseConfig: 'optional',
- };
- let el;
- beforeAll(() => {
- global.window = {};
- });
- beforeEach(() => {
- el = shallow();
- });
- describe('snapshot', () => {
- test('file upload enable with valid response', () => {
- expect(el.snapshot).toMatchSnapshot();
- });
+ const defaultProps = {
+ response: {
+ text: ['some text response here', 'another text response'],
+ files: [
+ {
+ name: 'some file name.jpg',
+ description: 'description for the file',
+ downloadURL: '/valid-url-wink-wink',
+ },
+ {
+ name: 'file number 2.jpg',
+ description: 'description for this file',
+ downloadURL: '/url-2',
+ },
+ ],
+ },
+ fileUploadResponseConfig: 'optional',
+ };
- test('file upload enable without response', () => {
- el = shallow();
- expect(el.snapshot).toMatchSnapshot();
- });
- test('file upload disable with valid response', () => {
- el = shallow();
- expect(el.snapshot).toMatchSnapshot();
- });
+ beforeAll(() => {
+ global.window = {};
+ });
- test('file upload disabled without response', () => {
- el = shallow();
- expect(el.snapshot).toMatchSnapshot();
- });
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('behavior', () => {
+ it('renders response display container', () => {
+ const { container } = render();
+ const responseDisplay = container.querySelector('.response-display');
+ expect(responseDisplay).toBeInTheDocument();
});
- describe('behavior', () => {
- test('get textContents', () => {
- const textContents = el.instance.findByTestId('response-display-text-content');
- expect(textContents.length).toEqual(
- props.response.text.length,
- );
- textContents.forEach((text, index) => {
- expect(text.el.children[0]).toEqual(
- parse(createDOMPurify(window).sanitize(props.response.text[index])),
- );
- });
- });
- test('get submittedFiles', () => {
- expect(el.instance.findByTestId('submission-files')[0].props.files).toEqual(props.response.files);
- });
- test('get allowFileUpload', () => {
- expect(el.instance.findByTestId('allow-file-upload').length > 0).toEqual(
- props.fileUploadResponseConfig !== fileUploadResponseOptions.none,
- );
- });
+ it('displays text content in cards', () => {
+ const { container } = render();
+ const textContents = container.querySelectorAll('.response-display-text-content');
+ expect(textContents).toHaveLength(defaultProps.response.text.length);
+ expect(textContents[0]).toHaveTextContent('some text response here');
+ expect(textContents[1]).toHaveTextContent('another text response');
+ });
+
+ it('displays submission files when file upload is allowed', () => {
+ render();
+ const submissionFiles = screen.getByTestId('submission-files');
+ expect(submissionFiles).toBeInTheDocument();
+ expect(submissionFiles).toHaveTextContent('Files: 2');
+ });
+
+ it('displays preview display when file upload is allowed', () => {
+ render();
+ const previewDisplay = screen.getByTestId('preview-display');
+ expect(previewDisplay).toBeInTheDocument();
+ expect(previewDisplay).toHaveTextContent('Preview: 2');
+ });
+
+ it('does not display file components when file upload is disabled', () => {
+ render();
+ expect(screen.queryByTestId('submission-files')).not.toBeInTheDocument();
+ expect(screen.queryByTestId('preview-display')).not.toBeInTheDocument();
+ });
+
+ it('renders empty content when no text response provided', () => {
+ const { container } = render();
+ const textContents = container.querySelectorAll('.response-display-text-content');
+ expect(textContents).toHaveLength(0);
});
});
+
describe('mapStateToProps', () => {
- let mapped;
const testState = {
- dummyText: ['text'],
- dummyFiles: ['files', 'file-2'],
+ response: {
+ text: ['test text'],
+ files: ['file1', 'file2'],
+ },
+ fileUploadResponseConfig: 'required',
};
- beforeEach(() => {
- mapped = mapStateToProps(testState);
+
+ it('maps response from grading.selected.response selector', () => {
+ const mapped = mapStateToProps(testState);
+ expect(mapped.response).toEqual(selectors.grading.selected.response(testState));
});
- test('response loads from grading.selected.response', () => {
- expect(mapped.response).toEqual(
- selectors.grading.selected.response(testState),
- );
- });
- test('response loads from grading.selected.response', () => {
- expect(mapped.fileUploadResponseConfig).toEqual(
- selectors.app.ora.fileUploadResponseConfig(testState),
- );
+
+ it('maps fileUploadResponseConfig from app.ora.fileUploadResponseConfig selector', () => {
+ const mapped = mapStateToProps(testState);
+ expect(mapped.fileUploadResponseConfig).toEqual(selectors.app.ora.fileUploadResponseConfig(testState));
});
});
});