chore: unenroll confirm modal tests
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`UnenrollConfirmModal component snapshot: modalStates.confirm 1`] = `
|
||||
<ModalDialog
|
||||
hasCloseButton={false}
|
||||
isOpen={true}
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
title=""
|
||||
>
|
||||
<div
|
||||
className="bg-white p-3 rounded shadow"
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "start",
|
||||
}
|
||||
}
|
||||
>
|
||||
<ConfirmPane
|
||||
handleClose={[MockFunction hooks.close]}
|
||||
handleConfirm={[MockFunction hooks.confirm]}
|
||||
/>
|
||||
</div>
|
||||
</ModalDialog>
|
||||
`;
|
||||
|
||||
exports[`UnenrollConfirmModal component snapshot: modalStates.finished, reason given 1`] = `
|
||||
<ModalDialog
|
||||
hasCloseButton={false}
|
||||
isOpen={true}
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
title=""
|
||||
>
|
||||
<div
|
||||
className="bg-white p-3 rounded shadow"
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "start",
|
||||
}
|
||||
}
|
||||
>
|
||||
<FinishedPane
|
||||
gaveReason={true}
|
||||
handleClose={[MockFunction hooks.closeAndRefresh]}
|
||||
/>
|
||||
</div>
|
||||
</ModalDialog>
|
||||
`;
|
||||
|
||||
exports[`UnenrollConfirmModal component snapshot: modalStates.finished, reason skipped 1`] = `
|
||||
<ModalDialog
|
||||
hasCloseButton={false}
|
||||
isOpen={true}
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
title=""
|
||||
>
|
||||
<div
|
||||
className="bg-white p-3 rounded shadow"
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "start",
|
||||
}
|
||||
}
|
||||
>
|
||||
<FinishedPane
|
||||
gaveReason={true}
|
||||
handleClose={[MockFunction hooks.closeAndRefresh]}
|
||||
/>
|
||||
</div>
|
||||
</ModalDialog>
|
||||
`;
|
||||
|
||||
exports[`UnenrollConfirmModal component snapshot: modalStates.reason 1`] = `
|
||||
<ModalDialog
|
||||
hasCloseButton={false}
|
||||
isOpen={true}
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
title=""
|
||||
>
|
||||
<div
|
||||
className="bg-white p-3 rounded shadow"
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "start",
|
||||
}
|
||||
}
|
||||
>
|
||||
<ReasonPane
|
||||
reason={
|
||||
Object {
|
||||
"isSkipped": false,
|
||||
"reasonProps": "other",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</ModalDialog>
|
||||
`;
|
||||
@@ -7,7 +7,7 @@ import * as module from './hooks';
|
||||
|
||||
export const state = StrictDict({
|
||||
confirmed: (val) => React.useState(val),
|
||||
customReason: (val) => React.useState(val),
|
||||
customOption: (val) => React.useState(val),
|
||||
isSkipped: (val) => React.useState(val),
|
||||
selectedReason: (val) => React.useState(val),
|
||||
submittedReason: (val) => React.useState(val),
|
||||
@@ -19,11 +19,15 @@ export const modalStates = StrictDict({
|
||||
finished: 'finished',
|
||||
});
|
||||
|
||||
export const valueCallback = (cb, prereqs = []) => (
|
||||
React.useCallback(e => cb(e.target.value), prereqs)
|
||||
);
|
||||
|
||||
export const unenrollReasons = () => {
|
||||
const [selectedReason, setSelectedReason] = module.state.selectedReason(null);
|
||||
const [submittedReason, setSubmittedReason] = module.state.submittedReason(null);
|
||||
const [isSkipped, setIsSkipped] = module.state.isSkipped(false);
|
||||
const [customOption, setCustomOption] = module.state.customReason('');
|
||||
const [customOption, setCustomOption] = module.state.customOption('');
|
||||
|
||||
return {
|
||||
clear: React.useCallback(() => {
|
||||
@@ -32,15 +36,21 @@ export const unenrollReasons = () => {
|
||||
setCustomOption('');
|
||||
setIsSkipped(false);
|
||||
}, []),
|
||||
|
||||
value: submittedReason,
|
||||
|
||||
customOption: {
|
||||
value: customOption,
|
||||
onChange: React.useCallback((e) => setCustomOption(e.target.value), []),
|
||||
onChange: module.valueCallback(setCustomOption),
|
||||
},
|
||||
isSkipped,
|
||||
isSubmitted: submittedReason !== null || isSkipped,
|
||||
|
||||
selected: selectedReason,
|
||||
selectOption: React.useCallback((e) => setSelectedReason(e.target.value), []),
|
||||
selectOption: module.valueCallback(setSelectedReason),
|
||||
|
||||
isSkipped,
|
||||
skip: React.useCallback(() => setIsSkipped(true), [isSkipped]),
|
||||
|
||||
isSubmitted: submittedReason !== null || isSkipped,
|
||||
submit: React.useCallback(() => {
|
||||
if (selectedReason === 'custom') {
|
||||
setSubmittedReason(customOption);
|
||||
@@ -48,7 +58,6 @@ export const unenrollReasons = () => {
|
||||
setSubmittedReason(selectedReason);
|
||||
}
|
||||
}, [customOption, selectedReason]),
|
||||
value: submittedReason,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -57,7 +66,7 @@ export const modalHooks = ({ closeModal, dispatch }) => {
|
||||
|
||||
const confirm = React.useCallback(() => setIsConfirmed(true), []);
|
||||
|
||||
const reason = unenrollReasons();
|
||||
const reason = module.unenrollReasons();
|
||||
const close = () => {
|
||||
closeModal();
|
||||
setIsConfirmed(false);
|
||||
@@ -66,7 +75,7 @@ export const modalHooks = ({ closeModal, dispatch }) => {
|
||||
|
||||
let modalState;
|
||||
if (isConfirmed) {
|
||||
modalState = reason.isSubmitted ? modalStates.finished : modalState.reason;
|
||||
modalState = reason.isSubmitted ? modalStates.finished : modalStates.reason;
|
||||
} else {
|
||||
modalState = modalStates.confirm;
|
||||
}
|
||||
@@ -74,14 +83,14 @@ export const modalHooks = ({ closeModal, dispatch }) => {
|
||||
const closeAndRefresh = React.useCallback(() => {
|
||||
dispatch(thunkActions.app.refreshList());
|
||||
close();
|
||||
}, []);
|
||||
}, [reason, isConfirmed]);
|
||||
|
||||
return {
|
||||
isConfirmed,
|
||||
confirm,
|
||||
reason,
|
||||
close: React.useCallback(close, [reason, isConfirmed]),
|
||||
closeAndRefresh,
|
||||
close,
|
||||
modalState,
|
||||
};
|
||||
};
|
||||
|
||||
206
src/containers/UnenrollConfirmModal/hooks.test.js
Normal file
206
src/containers/UnenrollConfirmModal/hooks.test.js
Normal file
@@ -0,0 +1,206 @@
|
||||
import React from 'react';
|
||||
|
||||
import { MockUseState, testCardValues } from 'testUtils';
|
||||
import * as hooks from './hooks';
|
||||
import { thunkActions } from 'data/redux';
|
||||
|
||||
jest.mock('data/redux/thunkActions/app', () => ({
|
||||
refreshList: jest.fn((args) => ({ refreshList: args })),
|
||||
}));
|
||||
|
||||
const state = new MockUseState(hooks);
|
||||
const testValue = 'test-value';
|
||||
let out;
|
||||
let hook;
|
||||
|
||||
describe('UnenrollConfirmModal hooks', () => {
|
||||
describe('state fields', () => {
|
||||
state.testGetter(state.keys.confirmed);
|
||||
state.testGetter(state.keys.customOption);
|
||||
state.testGetter(state.keys.isSkipped);
|
||||
state.testGetter(state.keys.selectedReason);
|
||||
state.testGetter(state.keys.submittedReason);
|
||||
});
|
||||
describe('valueCallback', () => {
|
||||
describe('returned react callback', () => {
|
||||
test('calls passed method with event value and prereqs', () => {
|
||||
const cb = jest.fn();
|
||||
const prereqs = ['test', 'values'];
|
||||
const returned = hooks.valueCallback(cb, prereqs).useCallback;
|
||||
expect(returned.prereqs).toEqual(prereqs);
|
||||
returned.cb({ target: { value: testValue } });
|
||||
expect(cb).toHaveBeenCalledWith(testValue);
|
||||
});
|
||||
test('calls passed method with event value and no prereqs if not passed', () => {
|
||||
const cb = jest.fn();
|
||||
const returned = hooks.valueCallback(cb).useCallback;
|
||||
expect(returned.prereqs).toEqual([]);
|
||||
returned.cb({ target: { value: testValue } });
|
||||
expect(cb).toHaveBeenCalledWith(testValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('unenrollReasons', () => {
|
||||
const mockValueCB = (cb) => ({ callback: cb });
|
||||
beforeEach(() => {
|
||||
hook = hooks.unenrollReasons;
|
||||
state.mock();
|
||||
hooks.valueCallback = jest.fn(mockValueCB);
|
||||
out = hook();
|
||||
});
|
||||
afterEach(() => {
|
||||
state.restore();
|
||||
hooks.valueCallback.mockClear();
|
||||
});
|
||||
describe('clear method', () => {
|
||||
it('resets selected and submitted reasons, custom option and isSkipped', () => {
|
||||
const { cb, prereqs } = out.clear.useCallback;
|
||||
expect(prereqs).toEqual([]);
|
||||
cb();
|
||||
expect(state.setState.selectedReason).toHaveBeenCalledWith(null);
|
||||
expect(state.setState.submittedReason).toHaveBeenCalledWith(null);
|
||||
expect(state.setState.customOption).toHaveBeenCalledWith('');
|
||||
expect(state.setState.isSkipped).toHaveBeenCalledWith(false);
|
||||
});
|
||||
});
|
||||
test('value returns submitted reason', () => {
|
||||
state.mockVal(state.keys.submittedReason, testValue);
|
||||
expect(hook().value).toEqual(testValue);
|
||||
});
|
||||
test('customOption.value returns custom option', () => {
|
||||
state.mockVal(state.keys.customOption, testValue);
|
||||
expect(hook().customOption.value).toEqual(testValue);
|
||||
});
|
||||
test('customOption.onChange returns valueCallback for setCustomOption', () => {
|
||||
expect(out.customOption.onChange).toEqual(mockValueCB(state.setState.customOption));
|
||||
});
|
||||
test('selected returns selectedReason', () => {
|
||||
state.mockVal(state.keys.selectedReason, testValue);
|
||||
expect(hook().selected).toEqual(testValue);
|
||||
});
|
||||
test('selectedOption returns valueCallback for setSelectedReason', () => {
|
||||
expect(out.selectOption).toEqual(mockValueCB(state.setState.selectedReason));
|
||||
});
|
||||
test('isSkipped returns state value', () => {
|
||||
state.mockVal(state.keys.isSkipped, testValue);
|
||||
expect(hook().isSkipped).toEqual(testValue);
|
||||
});
|
||||
test('skip returns callback based on isSkipped that sets isSkipped to true', () => {
|
||||
const { cb, prereqs } = out.skip.useCallback;
|
||||
expect(prereqs).toEqual([state.stateVals.isSkipped]);
|
||||
cb();
|
||||
expect(state.setState.isSkipped).toHaveBeenCalledWith(true);
|
||||
});
|
||||
describe('isSubmitted', () => {
|
||||
it('returns false if submittedReason is null and not isSkipped', () => {
|
||||
expect(out.isSubmitted).toEqual(false);
|
||||
});
|
||||
it('returns true if submittedReason is not null', () => {
|
||||
state.mockVal(state.keys.submittedReason, testValue);
|
||||
expect(hook().isSubmitted).toEqual(true);
|
||||
});
|
||||
it('returns true if isSkipped', () => {
|
||||
state.mockVal(state.keys.isSkipped, true);
|
||||
expect(hook().isSubmitted).toEqual(true);
|
||||
});
|
||||
});
|
||||
describe('submit', () => {
|
||||
it('sets customOption as submittedReason if selectedReason is custom', () => {
|
||||
state.mockVal(state.keys.selectedReason, 'custom');
|
||||
state.mockVal(state.keys.customOption, testValue);
|
||||
hook().submit.useCallback.cb();
|
||||
expect(state.setState.submittedReason).toHaveBeenCalledWith(testValue);
|
||||
});
|
||||
it('sets selectedReason as submittedReason if selectedReason is not custom', () => {
|
||||
state.mockVal(state.keys.selectedReason, testValue);
|
||||
state.mockVal(state.keys.customOption, 'customValue');
|
||||
hook().submit.useCallback.cb();
|
||||
expect(state.setState.submittedReason).toHaveBeenCalledWith(testValue);
|
||||
});
|
||||
it('depends on customOption and selectedReason', () => {
|
||||
const customValue = 'custom-value';
|
||||
state.mockVal(state.keys.selectedReason, testValue);
|
||||
state.mockVal(state.keys.customOption, customValue);
|
||||
const { prereqs } = hook().submit.useCallback;
|
||||
expect(prereqs).toContain(testValue);
|
||||
expect(prereqs).toContain(customValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('modalHooks', () => {
|
||||
const closeModal = jest.fn();
|
||||
const dispatch = jest.fn();
|
||||
let mockReason;
|
||||
beforeEach(() => {
|
||||
hook = hooks.modalHooks;
|
||||
mockReason = {
|
||||
isSubmitted: false,
|
||||
clear: jest.fn(),
|
||||
};
|
||||
state.mock();
|
||||
state.mockVal(state.keys.confirmed, testValue);
|
||||
hooks.unenrollReasons = jest.fn(() => mockReason);
|
||||
out = hook({ closeModal, dispatch });
|
||||
});
|
||||
afterEach(() => {
|
||||
state.restore();
|
||||
hooks.unenrollReasons.mockReset();
|
||||
});
|
||||
test('isConfirmed is forwarded from state', () => {
|
||||
expect(out.isConfirmed).toEqual(testValue);
|
||||
});
|
||||
test('confirm is no-prereqs callback that sets isConfirmed to true', () => {
|
||||
const { cb, prereqs } = out.confirm.useCallback;
|
||||
expect(prereqs).toEqual([]);
|
||||
cb();
|
||||
expect(state.setState.confirmed).toHaveBeenCalledWith(true);
|
||||
});
|
||||
test('reason returns unenrollReasons output', () => {
|
||||
expect(out.reason).toEqual(mockReason);
|
||||
});
|
||||
describe('close', () => {
|
||||
test('callback based on reason and isConfirmed', () => {
|
||||
expect(out.close.useCallback.prereqs).toEqual([mockReason, testValue]);
|
||||
});
|
||||
it('calls closeModal, sets isConfirmed to false, and calls reason.clear', () => {
|
||||
out.close.useCallback.cb();
|
||||
expect(closeModal).toHaveBeenCalled();
|
||||
expect(state.setState.confirmed).toHaveBeenCalledWith(false);
|
||||
expect(mockReason.clear).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
describe('closeAndRefresh', () => {
|
||||
test('callback based on reason and isConfirmed', () => {
|
||||
expect(out.closeAndRefresh.useCallback.prereqs).toEqual([mockReason, testValue]);
|
||||
});
|
||||
it('calls closeModal, sets isConfirmed to false, and calls reason.clear', () => {
|
||||
out.closeAndRefresh.useCallback.cb();
|
||||
expect(closeModal).toHaveBeenCalled();
|
||||
expect(state.setState.confirmed).toHaveBeenCalledWith(false);
|
||||
expect(mockReason.clear).toHaveBeenCalled();
|
||||
});
|
||||
it('dispatches refreshList thunkAction', () => {
|
||||
out.closeAndRefresh.useCallback.cb();
|
||||
expect(dispatch).toHaveBeenCalledWith(thunkActions.app.refreshList());
|
||||
});
|
||||
});
|
||||
describe('modalState', () => {
|
||||
it('returns modalStates.finished if confirmed and submitted', () => {
|
||||
state.mockVal(state.keys.confirmed, true);
|
||||
hooks.unenrollReasons = jest.fn(() => ({ ...mockReason, isSubmitted: true }));
|
||||
out = hook({ closeModal, dispatch });
|
||||
expect(out.modalState).toEqual(hooks.modalStates.finished);
|
||||
});
|
||||
it('returns modalStates.reason if confirmed and not submitted', () => {
|
||||
state.mockVal(state.keys.confirmed, true);
|
||||
out = hook({ closeModal, dispatch });
|
||||
expect(out.modalState).toEqual(hooks.modalStates.reason);
|
||||
});
|
||||
it('returns modalStates.confirm if not confirmed', () => {
|
||||
state.mockVal(state.keys.confirmed, false);
|
||||
out = hook({ closeModal, dispatch });
|
||||
expect(out.modalState).toEqual(hooks.modalStates.confirm);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -12,7 +12,7 @@ import ConfirmPane from './components/ConfirmPane';
|
||||
import ReasonPane from './components/ReasonPane';
|
||||
import FinishedPane from './components/FinishedPane';
|
||||
|
||||
import hooks, { modalStates } from './hooks';
|
||||
import { modalHooks, modalStates } from './hooks';
|
||||
|
||||
export const UnenrollConfirmModal = ({
|
||||
closeModal,
|
||||
@@ -25,7 +25,7 @@ export const UnenrollConfirmModal = ({
|
||||
closeAndRefresh,
|
||||
close,
|
||||
modalState,
|
||||
} = hooks({ dispatch, closeModal });
|
||||
} = modalHooks({ dispatch, closeModal });
|
||||
return (
|
||||
<ModalDialog
|
||||
isOpen={show}
|
||||
|
||||
58
src/containers/UnenrollConfirmModal/index.test.jsx
Normal file
58
src/containers/UnenrollConfirmModal/index.test.jsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { UnenrollConfirmModal } from '.';
|
||||
|
||||
import * as hooks from './hooks';
|
||||
|
||||
jest.mock('./components/ConfirmPane', () => 'ConfirmPane');
|
||||
jest.mock('./components/ReasonPane', () => 'ReasonPane');
|
||||
jest.mock('./components/FinishedPane', () => 'FinishedPane');
|
||||
|
||||
jest.mock('./hooks', () => ({
|
||||
__esModule: true,
|
||||
modalStates: jest.requireActual('./hooks').modalStates,
|
||||
modalHooks: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('UnenrollConfirmModal component', () => {
|
||||
const dispatch = useDispatch();
|
||||
const hookProps = {
|
||||
confirm: jest.fn().mockName('hooks.confirm'),
|
||||
reason: {
|
||||
isSkipped: false,
|
||||
reasonProps: 'other',
|
||||
},
|
||||
close: jest.fn().mockName('hooks.close'),
|
||||
closeAndRefresh: jest.fn().mockName('hooks.closeAndRefresh'),
|
||||
modalState: hooks.modalStates.confirm,
|
||||
};
|
||||
const closeModal = jest.fn().mockName('props.closeModal');
|
||||
const show = true;
|
||||
test('hooks called with dispatch and closeModal props', () => {
|
||||
hooks.modalHooks.mockReturnValueOnce(hookProps);
|
||||
shallow(<UnenrollConfirmModal {...{ closeModal, show }} />);
|
||||
expect(hooks.modalHooks).toHaveBeenCalledWith({ dispatch, closeModal });
|
||||
});
|
||||
test('snapshot: modalStates.confirm', () => {
|
||||
hooks.modalHooks.mockReturnValueOnce(hookProps);
|
||||
expect(shallow(<UnenrollConfirmModal {...{ closeModal, show }} />)).toMatchSnapshot();
|
||||
});
|
||||
test('snapshot: modalStates.finished, reason given', () => {
|
||||
hooks.modalHooks.mockReturnValueOnce({ ...hookProps, modalState: hooks.modalStates.finished });
|
||||
expect(shallow(<UnenrollConfirmModal {...{ closeModal, show }} />)).toMatchSnapshot();
|
||||
});
|
||||
test('snapshot: modalStates.finished, reason skipped', () => {
|
||||
hooks.modalHooks.mockReturnValueOnce({
|
||||
...hookProps,
|
||||
modalState: hooks.modalStates.finished,
|
||||
isSkipped: true,
|
||||
});
|
||||
expect(shallow(<UnenrollConfirmModal {...{ closeModal, show }} />)).toMatchSnapshot();
|
||||
});
|
||||
test('snapshot: modalStates.reason', () => {
|
||||
hooks.modalHooks.mockReturnValueOnce({ ...hookProps, modalState: hooks.modalStates.reason });
|
||||
expect(shallow(<UnenrollConfirmModal {...{ closeModal, show }} />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -77,6 +77,7 @@ jest.mock('@edx/paragon', () => jest.requireActual('testUtils').mockNestedCompon
|
||||
Hyperlink: 'Hyperlink',
|
||||
Icon: 'Icon',
|
||||
IconButton: 'IconButton',
|
||||
ModalDialog: 'ModalDialog',
|
||||
MultiSelectDropdownFilter: 'MultiSelectDropdownFilter',
|
||||
OverlayTrigger: 'OverlayTrigger',
|
||||
Popover: {
|
||||
|
||||
Reference in New Issue
Block a user