diff --git a/src/components/ConfirmModal.test.jsx b/src/components/ConfirmModal.test.jsx
index 1ccce7b..b85118a 100644
--- a/src/components/ConfirmModal.test.jsx
+++ b/src/components/ConfirmModal.test.jsx
@@ -1,4 +1,5 @@
-import { render, screen, fireEvent } from '@testing-library/react';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
import { ConfirmModal } from './ConfirmModal';
jest.unmock('@openedx/paragon');
@@ -29,15 +30,17 @@ describe('ConfirmModal', () => {
expect(getByText(props.content)).toBeInTheDocument();
});
- it('should call onCancel when cancel button is clicked', () => {
+ it('should call onCancel when cancel button is clicked', async () => {
render();
- fireEvent.click(screen.getByText(props.cancelText));
+ const user = userEvent.setup();
+ await user.click(screen.getByText(props.cancelText));
expect(props.onCancel).toHaveBeenCalledTimes(1);
});
- it('should call onConfirm when confirm button is clicked', () => {
+ it('should call onConfirm when confirm button is clicked', async () => {
render();
- fireEvent.click(screen.getByText(props.confirmText));
+ const user = userEvent.setup();
+ await user.click(screen.getByText(props.confirmText));
expect(props.onConfirm).toHaveBeenCalledTimes(1);
});
});
diff --git a/src/components/FilePreview/FileInfo.test.jsx b/src/components/FilePreview/FileInfo.test.jsx
index 1fa500f..c0f7d36 100644
--- a/src/components/FilePreview/FileInfo.test.jsx
+++ b/src/components/FilePreview/FileInfo.test.jsx
@@ -1,4 +1,5 @@
-import { render, screen, fireEvent } from '@testing-library/react';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
import FileInfo from './FileInfo';
@@ -20,10 +21,10 @@ describe('FileInfo component', () => {
expect(screen.getByText('FormattedMessage')).toBeInTheDocument();
});
- it('calls onClick when button is clicked', () => {
+ it('calls onClick when button is clicked', async () => {
render({children});
-
- fireEvent.click(screen.getByText('FormattedMessage'));
+ const user = userEvent.setup();
+ await user.click(screen.getByText('FormattedMessage'));
expect(props.onClick).toHaveBeenCalledTimes(1);
});
});
diff --git a/src/containers/CriterionContainer/CriterionFeedback.test.jsx b/src/containers/CriterionContainer/CriterionFeedback.test.jsx
index ac4ab11..7deae08 100644
--- a/src/containers/CriterionContainer/CriterionFeedback.test.jsx
+++ b/src/containers/CriterionContainer/CriterionFeedback.test.jsx
@@ -1,5 +1,6 @@
import React from 'react';
-import { render, fireEvent } from '@testing-library/react';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
import { actions, selectors } from 'data/redux';
import {
@@ -49,26 +50,26 @@ describe('Criterion Feedback', () => {
describe('component', () => {
describe('render', () => {
it('shows a non-disabled input when grading', () => {
- const { getByTestId } = render();
- const input = getByTestId('criterion-feedback-input');
+ render();
+ const input = screen.getByTestId('criterion-feedback-input');
expect(input).toBeInTheDocument();
expect(input).not.toBeDisabled();
expect(input).toHaveValue(props.value);
});
it('shows a disabled input when not grading', () => {
- const { getByTestId } = render(
+ render(
,
);
- const input = getByTestId('criterion-feedback-input');
+ const input = screen.getByTestId('criterion-feedback-input');
expect(input).toBeInTheDocument();
expect(input).toBeDisabled();
expect(input).toHaveValue(props.value);
});
it('displays an error message when feedback is invalid', () => {
- const { getByTestId } = render();
- expect(getByTestId('criterion-feedback-error-msg')).toBeInTheDocument();
+ render();
+ expect(screen.getByTestId('criterion-feedback-error-msg')).toBeInTheDocument();
});
it('does not render anything when config is set to disabled', () => {
@@ -80,12 +81,13 @@ describe('Criterion Feedback', () => {
});
describe('behavior', () => {
- it('calls setValue when input value changes', () => {
- const { getByTestId } = render();
- const input = getByTestId('criterion-feedback-input');
- fireEvent.change(input, { target: { value: 'some value' } });
+ it('calls setValue when input value changes', async () => {
+ render();
+ const user = userEvent.setup();
+ const input = screen.getByTestId('criterion-feedback-input');
+ await user.clear(input);
expect(props.setValue).toHaveBeenCalledWith({
- value: 'some value',
+ value: '',
orderNum: props.orderNum,
});
});
diff --git a/src/containers/ReviewActions/components/StartGradingButton/__snapshots__/index.test.jsx.snap b/src/containers/ReviewActions/components/StartGradingButton/__snapshots__/index.test.jsx.snap
deleted file mode 100644
index 9f58d4f..0000000
--- a/src/containers/ReviewActions/components/StartGradingButton/__snapshots__/index.test.jsx.snap
+++ /dev/null
@@ -1,18 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`StartGradingButton component component snapshots hide: renders empty component if hook.hide is true 1`] = `null`;
-
-exports[`StartGradingButton component component snapshots smoke test: forwards props to components from hooks 1`] = `
-
-
-
-
-
-`;
diff --git a/src/containers/ReviewActions/components/StartGradingButton/index.test.jsx b/src/containers/ReviewActions/components/StartGradingButton/index.test.jsx
index 096e678..2c806e6 100644
--- a/src/containers/ReviewActions/components/StartGradingButton/index.test.jsx
+++ b/src/containers/ReviewActions/components/StartGradingButton/index.test.jsx
@@ -1,49 +1,131 @@
-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 { useDispatch } from 'react-redux';
-
import * as hooks from './hooks';
import { StartGradingButton } from '.';
+import messages from '../messages';
-jest.mock('../OverrideGradeConfirmModal', () => 'OverrideGradeConfirmModal');
-jest.mock('../StopGradingConfirmModal', () => 'StopGradingConfirmModal');
+jest.unmock('@openedx/paragon');
+jest.unmock('react');
+jest.unmock('@edx/frontend-platform/i18n');
+
+jest.mock('react-redux', () => ({
+ useDispatch: jest.fn(),
+}));
jest.mock('./hooks', () => ({
buttonHooks: jest.fn(),
}));
-let el;
-describe('StartGradingButton component', () => {
- describe('component', () => {
- const dispatch = useDispatch();
- const buttonHooks = {
- hide: false,
- buttonArgs: { props: 'hooks.buttonArgs' },
- overrideGradeArgs: { props: 'hooks.overrideGradeArgs' },
- stopGradingArgs: { props: 'hooks.stopGradingArgs' },
- };
- describe('behavior', () => {
- it('initializes buttonHooks with dispatch and intl fields', () => {
- hooks.buttonHooks.mockReturnValueOnce(buttonHooks);
- el = shallow();
- const expected = { dispatch, intl: { formatMessage: expect.any(Function), formatDate: expect.any(Function) } };
- expect(hooks.buttonHooks).toHaveBeenCalledWith(expected);
- });
+describe('StartGradingButton', () => {
+ const mockDispatch = jest.fn();
+
+ const renderWithIntl = (component) => render(
+
+ {component}
+ ,
+ );
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ useDispatch.mockReturnValue(mockDispatch);
+ });
+
+ it('does not render when hide is true', () => {
+ hooks.buttonHooks.mockReturnValue({
+ hide: true,
+ buttonArgs: {},
+ overrideGradeArgs: {},
+ stopGradingArgs: {},
});
- describe('snapshots', () => {
- test('hide: renders empty component if hook.hide is true', () => {
- hooks.buttonHooks.mockReturnValueOnce({ ...buttonHooks, hide: true });
- el = shallow();
- expect(el.snapshot).toMatchSnapshot();
- expect(el.isEmptyRender()).toEqual(true);
- });
- test('smoke test: forwards props to components from hooks', () => {
- hooks.buttonHooks.mockReturnValueOnce(buttonHooks);
- el = shallow();
- expect(el.snapshot).toMatchSnapshot();
- expect(el.isEmptyRender()).toEqual(false);
- });
+ const { container } = renderWithIntl();
+ expect(container.firstChild).toBeNull();
+ });
+
+ it('renders primary button when visible', () => {
+ hooks.buttonHooks.mockReturnValue({
+ hide: false,
+ buttonArgs: { children: 'Start Grading' },
+ overrideGradeArgs: {
+ isOpen: false,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
+ stopGradingArgs: {
+ isOpen: false,
+ isOverride: false,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
+ });
+ renderWithIntl();
+ const button = screen.getByRole('button', { name: 'Start Grading' });
+ expect(button).toBeInTheDocument();
+ expect(button).toHaveClass('btn-primary');
+ });
+
+ it('renders override grade modal components', () => {
+ hooks.buttonHooks.mockReturnValue({
+ hide: false,
+ buttonArgs: { children: 'Start Grading' },
+ overrideGradeArgs: {
+ isOpen: true,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
+ stopGradingArgs: {
+ isOpen: false,
+ isOverride: false,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
+ });
+ renderWithIntl();
+ const overrideModalTitle = screen.getByText(messages.overrideConfirmTitle.defaultMessage);
+ expect(overrideModalTitle).toBeInTheDocument();
+ });
+
+ it('renders stop grading modal components', () => {
+ hooks.buttonHooks.mockReturnValue({
+ hide: false,
+ buttonArgs: { children: 'Start Grading' },
+ overrideGradeArgs: {
+ isOpen: false,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
+ stopGradingArgs: {
+ isOpen: true,
+ isOverride: false,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
+ });
+ renderWithIntl();
+ const stopGradingModalTitle = screen.getByText(messages.confirmStopGradingTitle.defaultMessage);
+ expect(stopGradingModalTitle).toBeInTheDocument();
+ });
+
+ it('calls buttonHooks with dispatch and intl', () => {
+ hooks.buttonHooks.mockReturnValue({
+ hide: false,
+ buttonArgs: { children: 'Start Grading' },
+ overrideGradeArgs: {
+ isOpen: false,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
+ stopGradingArgs: {
+ isOpen: false,
+ isOverride: false,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
+ });
+ renderWithIntl();
+ expect(hooks.buttonHooks).toHaveBeenCalledWith({
+ dispatch: mockDispatch,
+ intl: expect.any(Object),
});
});
});
diff --git a/src/containers/ReviewModal/ReviewContent.test.jsx b/src/containers/ReviewModal/ReviewContent.test.jsx
index 5aa32d9..5edda55 100644
--- a/src/containers/ReviewModal/ReviewContent.test.jsx
+++ b/src/containers/ReviewModal/ReviewContent.test.jsx
@@ -1,60 +1,89 @@
-import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-
-import { selectors } from 'data/redux';
-import { RequestKeys } from 'data/constants/requests';
+import { render, screen } from '@testing-library/react';
+import { IntlProvider } from '@edx/frontend-platform/i18n';
import {
ReviewContent,
- mapStateToProps,
} from './ReviewContent';
+jest.unmock('@openedx/paragon');
+jest.unmock('react');
+jest.unmock('@edx/frontend-platform/i18n');
+
+// Since we are only testing the ReviewContent component,
+// we can mock the child components to avoid unnecessary complexity on mocking the redux store.
+jest.mock('containers/ReviewModal/ReviewErrors/FetchErrors', () => {
+ const FetchErrors = () =>
FetchErrors
;
+ return FetchErrors;
+});
+jest.mock('containers/ReviewModal/ReviewErrors/SubmitErrors', () => {
+ const SubmitErrors = () => SubmitErrors
;
+ return SubmitErrors;
+});
+jest.mock('containers/ReviewModal/ReviewErrors/LockErrors', () => {
+ const LockErrors = () => LockErrors
;
+ return LockErrors;
+});
+jest.mock('containers/ReviewModal/ReviewErrors/DownloadErrors', () => {
+ const DownloadErrors = () => DownloadErrors
;
+ return DownloadErrors;
+});
+
+jest.mock('containers/ResponseDisplay', () => {
+ const ResponseDisplay = () => ResponseDisplay
;
+ return ResponseDisplay;
+});
+
+jest.mock('containers/Rubric', () => {
+ const Rubric = () => Rubric
;
+ return Rubric;
+});
+
jest.mock('data/redux', () => ({
selectors: {
app: {
- showRubric: (...args) => ({ showRubric: args }),
+ showRubric: jest.fn(() => true),
},
requests: {
- isCompleted: (...args) => ({ isCompleted: args }),
- isFailed: (...args) => ({ isFailed: args }),
+ isCompleted: jest.fn(() => false),
+ isFailed: jest.fn(() => false),
},
},
}));
-jest.mock('containers/ResponseDisplay', () => 'ResponseDisplay');
-jest.mock('containers/Rubric', () => 'Rubric');
-jest.mock('./ReviewErrors', () => 'ReviewErrors');
describe('ReviewContent component', () => {
- describe('component', () => {
- describe('render tests', () => {
- test('snapshot: not loaded, no error', () => {
- expect(shallow().isEmptyRender()).toEqual(true);
- });
- test('snapshot: show rubric', () => {
- expect(shallow().snapshot).toMatchSnapshot();
- });
- test('snapshot: hide rubric', () => {
- expect(shallow().snapshot).toMatchSnapshot();
- });
- test('snapshot: failed, showRubric (errors only)', () => {
- expect(shallow().snapshot).toMatchSnapshot();
- });
- });
+ const renderWithIntl = (component) => render(
+
+ {component}
+ ,
+ );
+
+ beforeEach(() => {
+ jest.clearAllMocks();
});
- describe('mapStateToProps', () => {
- let mapped;
- const testState = { some: 'test-state' };
- beforeEach(() => {
- mapped = mapStateToProps(testState);
+
+ describe('behavior', () => {
+ it('renders nothing when not loaded and no error', () => {
+ const { container } = renderWithIntl();
+ expect(container.querySelector('.content-block')).not.toBeInTheDocument();
});
- const requestKey = RequestKeys.fetchSubmission;
- test('showRubric loads from app.showRubric', () => {
- expect(mapped.showRubric).toEqual(selectors.app.showRubric(testState));
+
+ it('renders review errors when failed', () => {
+ renderWithIntl();
+ expect(screen.getByText('FetchErrors')).toBeInTheDocument();
+ expect(screen.getByText('SubmitErrors')).toBeInTheDocument();
+ expect(screen.getByText('LockErrors')).toBeInTheDocument();
+ expect(screen.getByText('DownloadErrors')).toBeInTheDocument();
});
- test('isFailed loads from requests.isFailed(fetchSubmission)', () => {
- expect(mapped.isFailed).toEqual(selectors.requests.isFailed(testState, { requestKey }));
+
+ it('renders response display when loaded', () => {
+ renderWithIntl();
+ expect(screen.getByText('ResponseDisplay')).toBeInTheDocument();
});
- test('isLoaded loads from requests.isCompleted(fetchSubmission)', () => {
- expect(mapped.isLoaded).toEqual(selectors.requests.isCompleted(testState, { requestKey }));
+
+ it('renders with rubric when showRubric is true and loaded', () => {
+ const { container, getByText } = renderWithIntl();
+ expect(container.querySelector('.content-block')).toBeInTheDocument();
+ expect(container.querySelector('.flex-nowrap')).toBeInTheDocument();
+ expect(getByText('Rubric')).toBeInTheDocument();
});
});
});
diff --git a/src/containers/ReviewModal/ReviewErrors/DownloadErrors.test.jsx b/src/containers/ReviewModal/ReviewErrors/DownloadErrors.test.jsx
index bc7a39e..e5d7260 100644
--- a/src/containers/ReviewModal/ReviewErrors/DownloadErrors.test.jsx
+++ b/src/containers/ReviewModal/ReviewErrors/DownloadErrors.test.jsx
@@ -1,22 +1,19 @@
-import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { IntlProvider } from '@edx/frontend-platform/i18n';
import { selectors, actions, thunkActions } from 'data/redux';
import { RequestKeys } from 'data/constants/requests';
+import { DownloadErrors, mapStateToProps, mapDispatchToProps } from './DownloadErrors';
-import {
- DownloadErrors,
- mapStateToProps,
- mapDispatchToProps,
-} from './DownloadErrors';
-
-let el;
+jest.unmock('@openedx/paragon');
+jest.unmock('react');
+jest.unmock('@edx/frontend-platform/i18n');
jest.mock('data/redux', () => ({
selectors: {
requests: {
- isFailed: (...args) => ({ isFailed: args }),
- error: (...args) => ({ error: args }),
+ isFailed: jest.fn((state) => state.isFailed || false),
+ error: jest.fn((state) => state.error || { files: [] }),
},
},
actions: {
@@ -26,62 +23,101 @@ jest.mock('data/redux', () => ({
download: { downloadFiles: jest.fn() },
},
}));
-jest.mock('./ReviewError', () => 'ReviewError');
+
+const renderWithIntl = (component) => render(
+
+ {component}
+ ,
+);
describe('DownloadErrors component', () => {
- const props = {
+ const defaultProps = {
isFailed: false,
- error: {
- files: [],
- },
+ error: { files: [] },
+ clearState: jest.fn(),
+ downloadFiles: jest.fn(),
};
- describe('component', () => {
- beforeEach(() => {
- props.clearState = jest.fn();
- props.downloadFiles = jest.fn().mockName('this.props.downloadFiles');
- el = shallow();
- });
- describe('snapshots', () => {
- test('failed: show error', () => {
- el = shallow();
- expect(el.snapshot).toMatchSnapshot();
- expect(el.isEmptyRender()).toEqual(false);
- });
- test('not failed: hide error', () => {
- expect(el.snapshot).toMatchSnapshot();
- expect(el.isEmptyRender()).toEqual(true);
- });
- });
- describe('behavior', () => {
- describe('clearState', () => {
- it('calls props.clearState with requestKey: downloadFiles', () => {
- el = shallow();
- el.instance.props.actions.cancel.onClick();
- expect(props.clearState).toHaveBeenCalledWith({ requestKey: RequestKeys.downloadFiles });
- });
- });
- });
+
+ beforeEach(() => {
+ jest.clearAllMocks();
});
+
+ it('should not render when isFailed is false', () => {
+ const { container } = renderWithIntl();
+ expect(container.firstChild).toBeNull();
+ });
+
+ it('should render error message when isFailed is true', () => {
+ const props = {
+ ...defaultProps,
+ isFailed: true,
+ error: { files: ['file-1-failed.error', 'file-2.failed'] },
+ };
+ const { getByText } = renderWithIntl();
+ expect(getByText("Couldn't download files")).toBeInTheDocument();
+ });
+
+ it('should display list of failed files', () => {
+ const props = {
+ ...defaultProps,
+ isFailed: true,
+ error: { files: ['file-1-failed.error', 'file-2.failed'] },
+ };
+ const { getByText } = renderWithIntl();
+ expect(getByText('file-1-failed.error')).toBeInTheDocument();
+ expect(getByText('file-2.failed')).toBeInTheDocument();
+ });
+
+ it('should call clearState when dismiss button is clicked', async () => {
+ const props = {
+ ...defaultProps,
+ isFailed: true,
+ error: { files: ['test-file.error'] },
+ };
+ renderWithIntl();
+ const user = userEvent.setup();
+ await user.click(screen.getByText('Dismiss'));
+ expect(props.clearState).toHaveBeenCalledWith({ requestKey: RequestKeys.downloadFiles });
+ });
+
+ it('should call downloadFiles when retry button is clicked', async () => {
+ const props = {
+ ...defaultProps,
+ isFailed: true,
+ error: { files: ['test-file.error'] },
+ };
+ renderWithIntl();
+ const user = userEvent.setup();
+ await user.click(screen.getByText('Retry download'));
+ expect(props.downloadFiles).toHaveBeenCalled();
+ });
+
describe('mapStateToProps', () => {
- let mapped;
- const testState = { some: 'test-state' };
- beforeEach(() => {
- mapped = mapStateToProps(testState);
+ it('should map isFailed from requests selector', () => {
+ const testState = { some: 'test-state' };
+ const mapped = mapStateToProps(testState);
+ expect(selectors.requests.isFailed).toHaveBeenCalledWith(testState, { requestKey: RequestKeys.downloadFiles });
+ expect(mapped.isFailed).toEqual(
+ selectors.requests.isFailed(testState, { requestKey: RequestKeys.downloadFiles }),
+ );
});
- test('isFailed loads from requests.isFailed(downloadFiles)', () => {
- const requestKey = RequestKeys.downloadFiles;
- expect(mapped.isFailed).toEqual(selectors.requests.isFailed(testState, { requestKey }));
- });
- test('error loads from requests.error(downloadFiles)', () => {
- const requestKey = RequestKeys.downloadFiles;
- expect(mapped.error).toEqual(selectors.requests.error(testState, { requestKey }));
+
+ it('should map error from requests selector', () => {
+ const testState = { some: 'test-state' };
+ const mapped = mapStateToProps(testState);
+ expect(selectors.requests.error).toHaveBeenCalledWith(testState, { requestKey: RequestKeys.downloadFiles });
+ expect(mapped.error).toEqual(
+ selectors.requests.error(testState, { requestKey: RequestKeys.downloadFiles }),
+ );
});
});
+
describe('mapDispatchToProps', () => {
- it('loads clearState from actions.requests.clearRequest', () => {
+ it('should map clearState to actions.requests.clearRequest', () => {
expect(mapDispatchToProps.clearState).toEqual(actions.requests.clearRequest);
});
- it('loads downloadFiles from thunkActions.download.downloadFiles', () => {
+
+ it('should map downloadFiles to thunkActions.download.downloadFiles', () => {
expect(mapDispatchToProps.downloadFiles).toEqual(thunkActions.download.downloadFiles);
});
});
diff --git a/src/containers/ReviewModal/ReviewErrors/__snapshots__/DownloadErrors.test.jsx.snap b/src/containers/ReviewModal/ReviewErrors/__snapshots__/DownloadErrors.test.jsx.snap
deleted file mode 100644
index a5b4c4e..0000000
--- a/src/containers/ReviewModal/ReviewErrors/__snapshots__/DownloadErrors.test.jsx.snap
+++ /dev/null
@@ -1,59 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`DownloadErrors component component snapshots failed: show error 1`] = `
-
-
-
-
-
- -
- file-1-failed.error
-
- -
- file-2.failed
-
-
-
-`;
-
-exports[`DownloadErrors component component snapshots not failed: hide error 1`] = `null`;
diff --git a/src/containers/ReviewModal/__snapshots__/ReviewContent.test.jsx.snap b/src/containers/ReviewModal/__snapshots__/ReviewContent.test.jsx.snap
deleted file mode 100644
index 4a57d2b..0000000
--- a/src/containers/ReviewModal/__snapshots__/ReviewContent.test.jsx.snap
+++ /dev/null
@@ -1,56 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`ReviewContent component component render tests snapshot: failed, showRubric (errors only) 1`] = `
-
-`;
-
-exports[`ReviewContent component component render tests snapshot: hide rubric 1`] = `
-
-`;
-
-exports[`ReviewContent component component render tests snapshot: show rubric 1`] = `
-
-`;
diff --git a/src/containers/ReviewModal/__snapshots__/index.test.jsx.snap b/src/containers/ReviewModal/__snapshots__/index.test.jsx.snap
deleted file mode 100644
index 2fd5eba..0000000
--- a/src/containers/ReviewModal/__snapshots__/index.test.jsx.snap
+++ /dev/null
@@ -1,72 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`ReviewModal component component snapshots closed 1`] = `
-
-
-
-
- }
- className="review-modal"
- isOpen={false}
- modalBodyClassName="review-modal-body"
- onClose={[MockFunction hooks.onClose]}
- title="test-ora-name"
->
-
-
-`;
-
-exports[`ReviewModal component component snapshots loading 1`] = `
-
-
-
-
- }
- className="review-modal"
- isOpen={true}
- modalBodyClassName="review-modal-body"
- onClose={[MockFunction hooks.onClose]}
- title="test-ora-name"
->
-
-
-
-
-`;
-
-exports[`ReviewModal component component snapshots success 1`] = `
-
-
-
-
- }
- className="review-modal"
- isOpen={true}
- modalBodyClassName="review-modal-body"
- onClose={[MockFunction hooks.onClose]}
- title="test-ora-name"
->
-
-
-
-`;
diff --git a/src/containers/ReviewModal/components/CloseReviewConfirmModal.test.jsx b/src/containers/ReviewModal/components/CloseReviewConfirmModal.test.jsx
index e1016eb..2667060 100644
--- a/src/containers/ReviewModal/components/CloseReviewConfirmModal.test.jsx
+++ b/src/containers/ReviewModal/components/CloseReviewConfirmModal.test.jsx
@@ -1,22 +1,51 @@
-import { shallow } from '@edx/react-unit-test-utils';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { IntlProvider } from '@edx/frontend-platform/i18n';
+import CloseReviewConfirmModal from './CloseReviewConfirmModal';
-import { CloseReviewConfirmModal } from './CloseReviewConfirmModal';
+jest.unmock('@openedx/paragon');
+jest.unmock('react');
+jest.unmock('@edx/frontend-platform/i18n');
-jest.mock('components/ConfirmModal', () => 'ConfirmModal');
+const renderWithIntl = (component) => render(
+
+ {component}
+ ,
+);
describe('CloseReviewConfirmModal', () => {
const props = {
isOpen: false,
- onCancel: jest.fn().mockName('this.props.onCancel'),
- onConfirm: jest.fn().mockName('this.props.onConfirm'),
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
};
- describe('snapshot', () => {
- test('closed', () => {
- expect(shallow().snapshot).toMatchSnapshot();
- });
- test('open', () => {
- expect(shallow().snapshot).toMatchSnapshot();
- });
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should not render content when modal is closed', () => {
+ const { queryByText } = renderWithIntl();
+ expect(queryByText('This cannot be undone')).toBeNull();
+ });
+
+ it('should display content when modal is open', () => {
+ const { getByText } = renderWithIntl();
+ expect(getByText('Are you sure you want to close this modal?')).toBeInTheDocument();
+ expect(getByText(/This cannot be undone.*This will discard unsaved work/)).toBeInTheDocument();
+ });
+
+ it('should call onCancel when cancel button is clicked', async () => {
+ renderWithIntl();
+ const user = userEvent.setup();
+ await user.click(screen.getByText('Go back'));
+ expect(props.onCancel).toHaveBeenCalledTimes(1);
+ });
+
+ it('should call onConfirm when confirm button is clicked', async () => {
+ renderWithIntl();
+ const user = userEvent.setup();
+ await user.click(screen.getByText('Close Modal'));
+ expect(props.onConfirm).toHaveBeenCalledTimes(1);
});
});
diff --git a/src/containers/ReviewModal/components/__snapshots__/CloseReviewConfirmModal.test.jsx.snap b/src/containers/ReviewModal/components/__snapshots__/CloseReviewConfirmModal.test.jsx.snap
deleted file mode 100644
index a035857..0000000
--- a/src/containers/ReviewModal/components/__snapshots__/CloseReviewConfirmModal.test.jsx.snap
+++ /dev/null
@@ -1,25 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`CloseReviewConfirmModal snapshot closed 1`] = `
-
-`;
-
-exports[`CloseReviewConfirmModal snapshot open 1`] = `
-
-`;
diff --git a/src/containers/ReviewModal/index.test.jsx b/src/containers/ReviewModal/index.test.jsx
index 78dcdd6..bb34d06 100644
--- a/src/containers/ReviewModal/index.test.jsx
+++ b/src/containers/ReviewModal/index.test.jsx
@@ -1,60 +1,133 @@
-import React from 'react';
import { useDispatch } from 'react-redux';
-import { shallow } from '@edx/react-unit-test-utils';
-
-import { formatMessage } from 'testUtils';
+import { render, screen } from '@testing-library/react';
+import { IntlProvider } from '@edx/frontend-platform/i18n';
import * as hooks from './hooks';
import { ReviewModal } from '.';
+import messages from './messages';
-jest.useFakeTimers('modern');
+jest.unmock('@openedx/paragon');
+jest.unmock('react');
+jest.unmock('@edx/frontend-platform/i18n');
-jest.mock('components/LoadingMessage', () => 'LoadingMessage');
-jest.mock('containers/DemoWarning', () => 'DemoWarning');
-jest.mock('containers/ReviewActions', () => 'ReviewActions');
-jest.mock('./ReviewContent', () => 'ReviewContent');
-jest.mock('./components/CloseReviewConfirmModal', () => 'CloseReviewConfirmModal');
+jest.mock('react-redux', () => ({
+ useDispatch: jest.fn(),
+ connect: jest.fn(() => (Component) => Component),
+}));
jest.mock('./hooks', () => ({
rendererHooks: jest.fn(),
}));
-describe('ReviewModal component', () => {
- const dispatch = useDispatch();
- const hookProps = {
- isLoading: false,
- title: 'test-ora-name',
- onClose: jest.fn().mockName('hooks.onClose'),
- isOpen: false,
- closeConfirmModalProps: {
- prop: 'hooks.closeConfirmModalProps',
- },
- };
+jest.mock('containers/ReviewModal/ReviewContent', () => {
+ const ReviewContent = () => ReviewContent
;
+ return ReviewContent;
+});
- const render = (newVals) => {
- hooks.rendererHooks.mockReturnValueOnce({ ...hookProps, ...newVals });
- return shallow();
- };
- describe('component', () => {
- describe('snapshots', () => {
- test('closed', () => {
- expect(render().snapshot).toMatchSnapshot();
- });
- test('loading', () => {
- expect(render({ isOpen: true, isLoading: true }).snapshot).toMatchSnapshot();
- });
- test('success', () => {
- expect(render({ isOpen: true }).snapshot).toMatchSnapshot();
- });
+jest.mock('containers/ReviewActions', () => {
+ const ReviewActions = () => ReviewActions
;
+ return ReviewActions;
+});
+
+jest.mock('containers/DemoWarning', () => {
+ const DemoWarning = () => DemoWarning
;
+ return DemoWarning;
+});
+
+jest.mock('containers/ReviewModal/components/CloseReviewConfirmModal', () => {
+ const CloseReviewConfirmModal = () => CloseReviewConfirmModal
;
+ return CloseReviewConfirmModal;
+});
+
+describe('ReviewModal', () => {
+ const mockDispatch = jest.fn();
+ beforeEach(() => {
+ jest.clearAllMocks();
+ useDispatch.mockReturnValue(mockDispatch);
+ });
+
+ it('calls rendererHooks with dispatch and intl', () => {
+ hooks.rendererHooks.mockReturnValue({
+ isLoading: false,
+ title: 'test-ora-name',
+ onClose: jest.fn(),
+ isOpen: false,
+ closeConfirmModalProps: {
+ isOpen: false,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
+ });
+
+ render();
+
+ expect(hooks.rendererHooks).toHaveBeenCalledWith({
+ dispatch: mockDispatch,
+ intl: expect.any(Object),
});
});
- describe('behavior', () => {
- it('initializes renderer hook with dispatch and intl props', () => {
- render();
- expect(hooks.rendererHooks).toHaveBeenCalledWith({
- dispatch,
- intl: { formatMessage, formatDate: expect.any(Function) },
- });
+
+ it('calls useDispatch hook', () => {
+ hooks.rendererHooks.mockReturnValue({
+ isLoading: false,
+ title: 'test-ora-name',
+ onClose: jest.fn(),
+ isOpen: false,
+ closeConfirmModalProps: {
+ isOpen: false,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
});
+
+ render();
+ screen.debug();
+ expect(useDispatch).toHaveBeenCalled();
+ });
+
+ it('renders correctly when open', () => {
+ hooks.rendererHooks.mockReturnValue({
+ isLoading: false,
+ title: 'test-ora-name',
+ onClose: jest.fn(),
+ isOpen: true,
+ closeConfirmModalProps: {
+ isOpen: false,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
+ });
+
+ render();
+ const reviewActions = screen.getByText('ReviewActions');
+ expect(reviewActions).toBeInTheDocument();
+
+ const demoWarning = screen.getByText('DemoWarning');
+ expect(demoWarning).toBeInTheDocument();
+
+ const reviewContent = screen.getByText('ReviewContent');
+ expect(reviewContent).toBeInTheDocument();
+
+ const closeReviewConfirmModal = screen.getByText('CloseReviewConfirmModal');
+ expect(closeReviewConfirmModal).toBeInTheDocument();
+ });
+
+ it('renders correctly loading message', () => {
+ hooks.rendererHooks.mockReturnValue({
+ isLoading: true,
+ title: 'test-ora-name',
+ onClose: jest.fn(),
+ isOpen: true,
+ closeConfirmModalProps: {
+ isOpen: false,
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ },
+ });
+
+ render();
+ screen.debug();
+ const loadingMessage = screen.getByText(messages.loadingResponse.defaultMessage);
+ expect(loadingMessage).toBeInTheDocument();
});
});