Add more descriptive errors for IDV submission
This commit is contained in:
@@ -576,6 +576,21 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Submit',
|
||||
description: 'Button to confirm all information is correct and submit.',
|
||||
},
|
||||
'id.verification.submission.alert.error.face': {
|
||||
id: 'id.verification.submission.alert.error.face',
|
||||
defaultMessage: 'A photo of your face is required. Please retake your portrait photo.',
|
||||
description: 'Error message displayed when the user\'s portrait photo is missing.',
|
||||
},
|
||||
'id.verification.submission.alert.error.id': {
|
||||
id: 'id.verification.submission.alert.error.id',
|
||||
defaultMessage: 'A photo of your ID card is required. Please retake your ID photo.',
|
||||
description: 'Error message displayed when the user\'s ID photo is missing.',
|
||||
},
|
||||
'id.verification.submission.alert.error.name': {
|
||||
id: 'id.verification.submission.alert.error.name',
|
||||
defaultMessage: 'A valid account name is required. Please update your account name to match the name on your ID.',
|
||||
description: 'Error message displayed when the user\'s account name is missing.',
|
||||
},
|
||||
'id.verification.review.error': {
|
||||
id: 'id.verification.review.error',
|
||||
defaultMessage: 'edX Support Page',
|
||||
|
||||
@@ -84,6 +84,9 @@ export async function submitIdVerification(verificationData) {
|
||||
await getAuthenticatedHttpClient().post(url, urlEncodedPostData, requestConfig);
|
||||
return { success: true, message: null };
|
||||
} catch (e) {
|
||||
return { success: false, message: String(e) }; // TODO: is String(e) right?
|
||||
return {
|
||||
success: false,
|
||||
status: e.customAttributes.httpErrorStatus,
|
||||
message: String(e) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ function SummaryPanel(props) {
|
||||
} = useContext(IdVerificationContext);
|
||||
const nameToBeUsed = idPhotoName || nameOnAccount || '';
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [submissionError, setSubmissionError] = useState(false);
|
||||
const [submissionError, setSubmissionError] = useState(null);
|
||||
|
||||
function SubmitButton() {
|
||||
async function handleClick() {
|
||||
@@ -43,7 +43,7 @@ function SummaryPanel(props) {
|
||||
} else {
|
||||
stopUserMedia();
|
||||
setIsSubmitting(false);
|
||||
setSubmissionError(true);
|
||||
setSubmissionError(result);
|
||||
}
|
||||
}
|
||||
return (
|
||||
@@ -59,6 +59,29 @@ function SummaryPanel(props) {
|
||||
);
|
||||
}
|
||||
|
||||
function getError() {
|
||||
if (submissionError.status === 400) {
|
||||
if (submissionError.message.includes('face_image')) {
|
||||
return props.intl.formatMessage(messages['id.verification.submission.alert.error.face']);
|
||||
} else if (submissionError.message.includes('Photo ID image')) {
|
||||
return props.intl.formatMessage(messages['id.verification.submission.alert.error.id']);
|
||||
} else if (submissionError.message.includes('Name')) {
|
||||
return props.intl.formatMessage(messages['id.verification.submission.alert.error.name']);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="idv.submission.alert.error"
|
||||
defaultMessage={`
|
||||
We encountered a technical error while trying to submit ID verification.
|
||||
This might be a temporary issue, so please try again in a few minutes.
|
||||
If the problem persists, please go to {support_link} for help.
|
||||
`}
|
||||
values={{ support_link: <Alert.Link href="https://support.edx.org/hc/en-us">{props.intl.formatMessage(messages['id.verification.review.error'])}</Alert.Link> }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BasePanel
|
||||
name={panelSlug}
|
||||
@@ -69,18 +92,9 @@ function SummaryPanel(props) {
|
||||
variant="danger"
|
||||
data-testid="submission-error"
|
||||
dismissible
|
||||
onClose={() => setSubmissionError(false)}
|
||||
onClose={() => setSubmissionError(null)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="idv.submission.alert.error"
|
||||
defaultMessage={`
|
||||
We encountered a technical error while trying to submit ID verification.
|
||||
This might be a temporary issue, so please try again in a few minutes.
|
||||
If the problem persists,
|
||||
please go to {support_link} for help.
|
||||
`}
|
||||
values={{ support_link: <Alert.Link href="https://support.edx.org/hc/en-us">{props.intl.formatMessage(messages['id.verification.review.error'])}</Alert.Link> }}
|
||||
/>
|
||||
{getError()}
|
||||
</Alert>}
|
||||
<p>
|
||||
{props.intl.formatMessage(messages['id.verification.review.description'])}
|
||||
|
||||
@@ -33,7 +33,7 @@ describe('SummaryPanel', () => {
|
||||
stopUserMedia: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
const getPanel = async () => {
|
||||
await act(async () => render((
|
||||
<Router history={history}>
|
||||
<IntlProvider locale="en">
|
||||
@@ -43,13 +43,14 @@ describe('SummaryPanel', () => {
|
||||
</IntlProvider>
|
||||
</Router>
|
||||
)));
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('routes back to TakePortraitPhotoPanel', async () => {
|
||||
await getPanel();
|
||||
const button = await screen.findByTestId('portrait-retake');
|
||||
fireEvent.click(button);
|
||||
expect(history.location.pathname).toEqual('/take-portrait-photo');
|
||||
@@ -57,6 +58,7 @@ describe('SummaryPanel', () => {
|
||||
});
|
||||
|
||||
it('routes back to TakeIdPhotoPanel', async () => {
|
||||
await getPanel();
|
||||
const button = await screen.findByTestId('id-retake');
|
||||
fireEvent.click(button);
|
||||
expect(history.location.pathname).toEqual('/take-id-photo');
|
||||
@@ -64,6 +66,7 @@ describe('SummaryPanel', () => {
|
||||
});
|
||||
|
||||
it('allows user to upload ID photo', async () => {
|
||||
await getPanel();
|
||||
const collapsible = await screen.getAllByRole('button', { 'aria-expanded': false })[0];
|
||||
fireEvent.click(collapsible);
|
||||
const uploadButton = await screen.getByTestId('fileUpload');
|
||||
@@ -71,6 +74,7 @@ describe('SummaryPanel', () => {
|
||||
});
|
||||
|
||||
it('submits', async () => {
|
||||
await getPanel();
|
||||
const button = await screen.findByTestId('submit-button');
|
||||
fireEvent.click(button);
|
||||
expect(dataService.submitIdVerification).toHaveBeenCalled();
|
||||
@@ -78,21 +82,53 @@ describe('SummaryPanel', () => {
|
||||
});
|
||||
|
||||
it('shows error when cannot submit', async () => {
|
||||
await cleanup();
|
||||
dataService.submitIdVerification = jest.fn().mockReturnValue({ success: false });
|
||||
await act(async () => render((
|
||||
<Router history={history}>
|
||||
<IntlProvider locale="en">
|
||||
<IdVerificationContext.Provider value={contextValue}>
|
||||
<IntlSummaryPanel {...defaultProps} />
|
||||
</IdVerificationContext.Provider>
|
||||
</IntlProvider>
|
||||
</Router>
|
||||
)));
|
||||
await getPanel();
|
||||
const button = await screen.findByTestId('submit-button');
|
||||
await act(async () => fireEvent.click(button));
|
||||
expect(dataService.submitIdVerification).toHaveBeenCalled();
|
||||
const error = await screen.getByTestId('submission-error');
|
||||
expect(error).toBeDefined();
|
||||
});
|
||||
|
||||
it('displays correct error for missing portrait photo', async () => {
|
||||
dataService.submitIdVerification = jest.fn().mockReturnValue({
|
||||
success: false,
|
||||
status: 400,
|
||||
message: 'Missing required parameter face_image',
|
||||
});
|
||||
await getPanel();
|
||||
const button = await screen.findByTestId('submit-button');
|
||||
await act(async () => fireEvent.click(button));
|
||||
const error = await screen.getByTestId('submission-error');
|
||||
expect(error).toHaveTextContent('A photo of your face is required. Please retake your portrait photo.');
|
||||
});
|
||||
|
||||
it('displays correct error for missing id photo', async () => {
|
||||
dataService.submitIdVerification = jest.fn().mockReturnValue({
|
||||
success: false,
|
||||
status: 400,
|
||||
message: 'Photo ID image is required if the user does not have an initial verification attempt.',
|
||||
});
|
||||
await getPanel();
|
||||
const button = await screen.findByTestId('submit-button');
|
||||
await act(async () => fireEvent.click(button));
|
||||
const error = await screen.getByTestId('submission-error');
|
||||
expect(error).toHaveTextContent('A photo of your ID card is required. Please retake your ID photo.');
|
||||
});
|
||||
|
||||
it('displays correct error for missing account name', async () => {
|
||||
dataService.submitIdVerification = jest.fn().mockReturnValue({
|
||||
success: false,
|
||||
status: 400,
|
||||
message: 'Name must be at least 1 character long.',
|
||||
});
|
||||
await getPanel();
|
||||
const button = await screen.findByTestId('submit-button');
|
||||
await act(async () => fireEvent.click(button));
|
||||
const error = await screen.getByTestId('submission-error');
|
||||
expect(error).toHaveTextContent(
|
||||
'A valid account name is required. Please update your account name to match the name on your ID.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user