Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -490,44 +490,50 @@ function AcuantCapture(
setIsCapturingEnvironment(false);
}

function onAcuantImageCaptureFailure(error: AcuantCaptureFailureError, code: string | undefined) {
const { SEQUENCE_BREAK_CODE } = window.AcuantJavascriptWebSdk;
if (isAcuantCameraAccessFailure(error)) {
if (fullScreenRef.current?.focusTrap) {
suspendFocusTrapForAnticipatedFocus(fullScreenRef.current.focusTrap);
}

// Internally, Acuant sets a cookie to bail on guided capture if initialization had
// previously failed for any reason, including declined permission. Since the cookie
// never expires, and since we want to re-prompt even if the user had previously
// declined, unset the cookie value when failure occurs for permissions.
setAcuantFailureCookie(null);

onCameraAccessDeclined();
} else if (code === SEQUENCE_BREAK_CODE) {
setOwnErrorMessage(
`${t('doc_auth.errors.upload_error')} ${t('errors.messages.try_again')
.split(' ')
.join(NBSP_UNICODE)}`,
);

refreshAcuantFailureCookie();
} else if (error === undefined) {
// Show a more generic error message when there's a cropping error.
// Errors with a value of `undefined` are cropping errors.
setOwnErrorMessage(t('errors.general'));
} else {
setOwnErrorMessage(t('doc_auth.errors.camera.failed'));
}

setIsCapturingEnvironment(false);
trackEvent('IdV: Image capture failed', {
field: name,
error: getNormalizedAcuantCaptureFailureMessage(error, code),
});
}

return (
<div className={[className, 'document-capture-acuant-capture'].filter(Boolean).join(' ')}>
{isCapturingEnvironment && (
<AcuantCamera
onCropStart={() => setHasStartedCropping(true)}
onImageCaptureSuccess={onAcuantImageCaptureSuccess}
onImageCaptureFailure={(error, code) => {
const { SEQUENCE_BREAK_CODE } = window.AcuantJavascriptWebSdk;
if (isAcuantCameraAccessFailure(error)) {
if (fullScreenRef.current?.focusTrap) {
suspendFocusTrapForAnticipatedFocus(fullScreenRef.current.focusTrap);
}

// Internally, Acuant sets a cookie to bail on guided capture if initialization had
// previously failed for any reason, including declined permission. Since the cookie
// never expires, and since we want to re-prompt even if the user had previously
// declined, unset the cookie value when failure occurs for permissions.
setAcuantFailureCookie(null);

onCameraAccessDeclined();
} else if (code === SEQUENCE_BREAK_CODE) {
setOwnErrorMessage(
`${t('doc_auth.errors.upload_error')} ${t('errors.messages.try_again')
.split(' ')
.join(NBSP_UNICODE)}`,
);

refreshAcuantFailureCookie();
} else {
setOwnErrorMessage(t('doc_auth.errors.camera.failed'));
}

setIsCapturingEnvironment(false);
trackEvent('IdV: Image capture failed', {
field: name,
error: getNormalizedAcuantCaptureFailureMessage(error, code),
});
}}
onImageCaptureFailure={onAcuantImageCaptureFailure}
>
{!hasStartedCropping && (
<FullScreen
Expand Down
Comment thread
charleyf marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import sinon from 'sinon';
import { fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { waitFor, createEvent } from '@testing-library/dom';
import AcuantCapture, {
isAcuantCameraAccessFailure,
getNormalizedAcuantCaptureFailureMessage,
getDecodedBase64ByteSize,
AcuantDocumentType,
getDecodedBase64ByteSize,
getNormalizedAcuantCaptureFailureMessage,
isAcuantCameraAccessFailure,
} from '@18f/identity-document-capture/components/acuant-capture';
import { AcuantContextProvider, AnalyticsContext } from '@18f/identity-document-capture';
import { createEvent, waitFor } from '@testing-library/dom';

import DeviceContext from '@18f/identity-document-capture/context/device';
import { I18nContext } from '@18f/identity-react-i18n';
import { I18n } from '@18f/identity-i18n';
import { render, useAcuant } from '../../../support/document-capture';
import { I18nContext } from '@18f/identity-react-i18n';
import { fireEvent } from '@testing-library/react';
import sinon from 'sinon';
import userEvent from '@testing-library/user-event';
import { getFixtureFile } from '../../../support/file';
import { render, useAcuant } from '../../../support/document-capture';

const ACUANT_CAPTURE_SUCCESS_RESULT = {
image: {
Expand Down Expand Up @@ -288,6 +289,37 @@ describe('document-capture/components/acuant-capture', () => {
expect(document.activeElement).to.equal(button);
});

it('shows a generic error if camera starts but cropping error occurs', async () => {
Comment thread
charleyf marked this conversation as resolved.
const trackEvent = sinon.spy();
const { container, getByLabelText, findByText } = render(
<AnalyticsContext.Provider value={{ trackEvent }}>
<DeviceContext.Provider value={{ isMobile: true }}>
<AcuantContextProvider sdkSrc="about:blank" cameraSrc="about:blank">
<AcuantCapture label="Image" name="test" />
</AcuantContextProvider>
</DeviceContext.Provider>
</AnalyticsContext.Provider>,
);

initialize({
// Call `onCropped` with a response of 'undefined'
start: sinon.stub().callsArgWithAsync(1, undefined),
});

const button = getByLabelText('Image');
await userEvent.click(button);
// "Oops, something went wrong. Please try again."
await findByText('errors.general');

expect(window.AcuantCameraUI.end).to.have.been.calledOnce();
expect(container.querySelector('.full-screen')).to.be.null();
expect(trackEvent).to.have.been.calledWith('IdV: Image capture failed', {
field: 'test',
error: 'Cropping failure',
});
expect(document.activeElement).to.equal(button);
});

it('shows error if capture fails: latest version of Acuant SDK', async () => {
const trackEvent = sinon.spy();
const { container, getByLabelText, findByText } = render(
Expand Down