From 8f424d8d2c0e4a78b00ebfb3e43e8ab07276f584 Mon Sep 17 00:00:00 2001 From: Zach Margolis Date: Wed, 19 Jul 2023 12:43:48 -0700 Subject: [PATCH 1/8] Refactor Acuant document detection to use more enum features [skip changelog] --- .../components/acuant-camera.tsx | 6 ++--- .../components/acuant-capture.tsx | 25 ++++++------------- .../components/documents-step-spec.jsx | 3 ++- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/app/javascript/packages/document-capture/components/acuant-camera.tsx b/app/javascript/packages/document-capture/components/acuant-camera.tsx index b6707d54eaa..81bde3bbbd3 100644 --- a/app/javascript/packages/document-capture/components/acuant-camera.tsx +++ b/app/javascript/packages/document-capture/components/acuant-camera.tsx @@ -94,9 +94,9 @@ interface AcuantCameraUIOptions { } export enum AcuantDocumentType { - NONE = 0, - ID = 1, - PASSPORT = 2, + none = 0, + id = 1, + passport = 2, } export type AcuantCaptureFailureError = diff --git a/app/javascript/packages/document-capture/components/acuant-capture.tsx b/app/javascript/packages/document-capture/components/acuant-capture.tsx index acbe5ccd9e5..72c2cbbfec0 100644 --- a/app/javascript/packages/document-capture/components/acuant-capture.tsx +++ b/app/javascript/packages/document-capture/components/acuant-capture.tsx @@ -16,20 +16,16 @@ import type { ReactNode, MouseEvent, Ref } from 'react'; import AnalyticsContext from '../context/analytics'; import AcuantContext from '../context/acuant'; import FailedCaptureAttemptsContext from '../context/failed-capture-attempts'; -import AcuantCamera from './acuant-camera'; +import AcuantCamera, { AcuantDocumentType } from './acuant-camera'; import AcuantCaptureCanvas from './acuant-capture-canvas'; import FileInput from './file-input'; import DeviceContext from '../context/device'; import UploadContext from '../context/upload'; import useCounter from '../hooks/use-counter'; import useCookie from '../hooks/use-cookie'; -import type { - AcuantSuccessResponse, - AcuantDocumentType, - AcuantCaptureFailureError, -} from './acuant-camera'; +import type { AcuantSuccessResponse, AcuantCaptureFailureError } from './acuant-camera'; -type AcuantDocumentTypeLabel = 'id' | 'passport' | 'none'; +type AcuantDocumentTypeLabel = keyof typeof AcuantDocumentType; type AcuantImageAssessment = 'success' | 'glare' | 'blurry' | 'unsupported'; type ImageSource = 'acuant' | 'upload'; @@ -136,16 +132,11 @@ export const isAcuantCameraAccessFailure = (error: AcuantCaptureFailureError): e * */ function getDocumentTypeLabel(documentType: AcuantDocumentType): AcuantDocumentTypeLabel | string { - switch (documentType) { - case 0: - return 'none'; - case 1: - return 'id'; - case 2: - return 'passport'; - default: - return `An error in document type returned: ${documentType}`; + const label = AcuantDocumentType[documentType]; + if (label === undefined) { + return `An error in document type returned: ${documentType}`; } + return label; } export function getNormalizedAcuantCaptureFailureMessage( @@ -438,7 +429,7 @@ function AcuantCapture( const { image, cardtype, dpi, moire, glare, sharpness } = nextCapture; const isAssessedAsGlare = glare < glareThreshold; const isAssessedAsBlurry = sharpness < sharpnessThreshold; - const isAssessedAsUnsupported = cardtype !== 1; + const isAssessedAsUnsupported = cardtype !== AcuantDocumentType.id; const { width, height, data } = image; let assessment: AcuantImageAssessment; diff --git a/spec/javascript/packages/document-capture/components/documents-step-spec.jsx b/spec/javascript/packages/document-capture/components/documents-step-spec.jsx index 0a289f0386a..4e8b609d0fc 100644 --- a/spec/javascript/packages/document-capture/components/documents-step-spec.jsx +++ b/spec/javascript/packages/document-capture/components/documents-step-spec.jsx @@ -9,6 +9,7 @@ import { UploadContextProvider, } from '@18f/identity-document-capture'; import DocumentsStep from '@18f/identity-document-capture/components/documents-step'; +import { AcuantDocumentType } from '@18f/identity-document-capture/components/acuant-camera'; import { render, useAcuant } from '../../../support/document-capture'; import { getFixtureFile } from '../../../support/file'; @@ -66,7 +67,7 @@ describe('document-capture/components/documents-step', () => { ); initialize(); - const result = { sharpness: 100, image: { data: '' }, cardtype: 1 }; + const result = { sharpness: 100, image: { data: '' }, cardtype: AcuantDocumentType.id }; window.AcuantCameraUI.start.callsFake(({ onCropped }) => onCropped({ ...result, glare: 10 })); await userEvent.click(getByLabelText('doc_auth.headings.document_capture_front')); From 553a21927347ab8bd28dc507e244667e4d7f33d8 Mon Sep 17 00:00:00 2001 From: Zach Margolis Date: Wed, 19 Jul 2023 16:01:09 -0700 Subject: [PATCH 2/8] Update one more test --- .../document-capture/components/document-capture-spec.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/javascript/packages/document-capture/components/document-capture-spec.jsx b/spec/javascript/packages/document-capture/components/document-capture-spec.jsx index c685a5dc62c..eeb13cc5265 100644 --- a/spec/javascript/packages/document-capture/components/document-capture-spec.jsx +++ b/spec/javascript/packages/document-capture/components/document-capture-spec.jsx @@ -18,6 +18,7 @@ import { expect } from 'chai'; import { useSandbox } from '@18f/identity-test-helpers'; import { render, useAcuant, useDocumentCaptureForm } from '../../../support/document-capture'; import { getFixtureFile } from '../../../support/file'; +import { AcuantDocumentType } from '@18f/identity-document-capture/components/acuant-camera'; describe('document-capture/components/document-capture', () => { const onSubmit = useDocumentCaptureForm(); @@ -91,7 +92,7 @@ describe('document-capture/components/document-capture', () => { image: { data: validUpload, }, - cardtype: 1, + cardtype: AcuantDocumentType.id, }); }); From 1273a4e76226083b8cb1ef4d04de35939bf17f9e Mon Sep 17 00:00:00 2001 From: Zach Margolis Date: Thu, 20 Jul 2023 05:57:55 -0700 Subject: [PATCH 3/8] Use ?? to simplify label function Co-authored-by: Andrew Duthie --- .../document-capture/components/acuant-capture.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/javascript/packages/document-capture/components/acuant-capture.tsx b/app/javascript/packages/document-capture/components/acuant-capture.tsx index 72c2cbbfec0..115d9f14904 100644 --- a/app/javascript/packages/document-capture/components/acuant-capture.tsx +++ b/app/javascript/packages/document-capture/components/acuant-capture.tsx @@ -131,13 +131,8 @@ export const isAcuantCameraAccessFailure = (error: AcuantCaptureFailureError): e * Returns a human-readable document label corresponding to the given document type constant. * */ -function getDocumentTypeLabel(documentType: AcuantDocumentType): AcuantDocumentTypeLabel | string { - const label = AcuantDocumentType[documentType]; - if (label === undefined) { - return `An error in document type returned: ${documentType}`; - } - return label; -} +const getDocumentTypeLabel = (documentType: AcuantDocumentType): AcuantDocumentTypeLabel | string => + AcuantDocumentType[documentType] ?? `An error in document type returned: ${documentType}`; export function getNormalizedAcuantCaptureFailureMessage( error: AcuantCaptureFailureError, From 48dcfa3019e2d7b773b8cae5ce0834adc5a30d30 Mon Sep 17 00:00:00 2001 From: Zach Margolis Date: Thu, 20 Jul 2023 06:04:08 -0700 Subject: [PATCH 4/8] Drop in enum values in a few more places --- .../components/acuant-capture-spec.jsx | 10 +++++++--- .../components/document-capture-spec.jsx | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx b/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx index 320abd0c920..5b8b9d33115 100644 --- a/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx +++ b/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx @@ -7,7 +7,11 @@ import AcuantCapture, { getNormalizedAcuantCaptureFailureMessage, getDecodedBase64ByteSize, } from '@18f/identity-document-capture/components/acuant-capture'; -import { AcuantContextProvider, AnalyticsContext } from '@18f/identity-document-capture'; +import { + AcuantContextProvider, + AnalyticsContext, + AcuantDocumentType, +} from '@18f/identity-document-capture'; import DeviceContext from '@18f/identity-document-capture/context/device'; import { I18nContext } from '@18f/identity-react-i18n'; import { I18n } from '@18f/identity-i18n'; @@ -20,7 +24,7 @@ const ACUANT_CAPTURE_SUCCESS_RESULT = { width: 1748, height: 1104, }, - cardtype: 1, + cardtype: AcuantDocumentType.id, dpi: 519, moire: 99, moireraw: 99, @@ -566,7 +570,7 @@ describe('document-capture/components/acuant-capture', () => { await Promise.resolve(); callbacks.onCropped({ ...ACUANT_CAPTURE_SUCCESS_RESULT, - cardtype: 2, + cardtype: AcuantDocumentType.passport, }); }), }); diff --git a/spec/javascript/packages/document-capture/components/document-capture-spec.jsx b/spec/javascript/packages/document-capture/components/document-capture-spec.jsx index eeb13cc5265..c50f07082bf 100644 --- a/spec/javascript/packages/document-capture/components/document-capture-spec.jsx +++ b/spec/javascript/packages/document-capture/components/document-capture-spec.jsx @@ -16,9 +16,9 @@ import DocumentCapture from '@18f/identity-document-capture/components/document- import { FlowContext } from '@18f/identity-verify-flow'; import { expect } from 'chai'; import { useSandbox } from '@18f/identity-test-helpers'; +import { AcuantDocumentType } from '@18f/identity-document-capture/components/acuant-camera'; import { render, useAcuant, useDocumentCaptureForm } from '../../../support/document-capture'; import { getFixtureFile } from '../../../support/file'; -import { AcuantDocumentType } from '@18f/identity-document-capture/components/acuant-camera'; describe('document-capture/components/document-capture', () => { const onSubmit = useDocumentCaptureForm(); From c7aa3fa81cdf01fdeaf164fa0b7e8292a48069cf Mon Sep 17 00:00:00 2001 From: Zach Margolis Date: Thu, 20 Jul 2023 06:11:54 -0700 Subject: [PATCH 5/8] Make enum uppercase, use String.toLowerCase() --- .../document-capture/components/acuant-camera.tsx | 6 +++--- .../document-capture/components/acuant-capture.tsx | 5 +++-- .../components/acuant-capture-spec.jsx | 11 ++++------- .../components/document-capture-spec.jsx | 2 +- .../components/documents-step-spec.jsx | 2 +- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/app/javascript/packages/document-capture/components/acuant-camera.tsx b/app/javascript/packages/document-capture/components/acuant-camera.tsx index 81bde3bbbd3..b6707d54eaa 100644 --- a/app/javascript/packages/document-capture/components/acuant-camera.tsx +++ b/app/javascript/packages/document-capture/components/acuant-camera.tsx @@ -94,9 +94,9 @@ interface AcuantCameraUIOptions { } export enum AcuantDocumentType { - none = 0, - id = 1, - passport = 2, + NONE = 0, + ID = 1, + PASSPORT = 2, } export type AcuantCaptureFailureError = diff --git a/app/javascript/packages/document-capture/components/acuant-capture.tsx b/app/javascript/packages/document-capture/components/acuant-capture.tsx index 115d9f14904..ced3217e1b5 100644 --- a/app/javascript/packages/document-capture/components/acuant-capture.tsx +++ b/app/javascript/packages/document-capture/components/acuant-capture.tsx @@ -132,7 +132,7 @@ export const isAcuantCameraAccessFailure = (error: AcuantCaptureFailureError): e * */ const getDocumentTypeLabel = (documentType: AcuantDocumentType): AcuantDocumentTypeLabel | string => - AcuantDocumentType[documentType] ?? `An error in document type returned: ${documentType}`; + AcuantDocumentType[documentType]?.toLowerCase() ?? `An error in document type returned: ${documentType}`; export function getNormalizedAcuantCaptureFailureMessage( error: AcuantCaptureFailureError, @@ -424,7 +424,7 @@ function AcuantCapture( const { image, cardtype, dpi, moire, glare, sharpness } = nextCapture; const isAssessedAsGlare = glare < glareThreshold; const isAssessedAsBlurry = sharpness < sharpnessThreshold; - const isAssessedAsUnsupported = cardtype !== AcuantDocumentType.id; + const isAssessedAsUnsupported = cardtype !== AcuantDocumentType.ID; const { width, height, data } = image; let assessment: AcuantImageAssessment; @@ -579,3 +579,4 @@ function AcuantCapture( } export default forwardRef(AcuantCapture); +export { AcuantDocumentType }; diff --git a/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx b/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx index 5b8b9d33115..b0b38f5c322 100644 --- a/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx +++ b/spec/javascript/packages/document-capture/components/acuant-capture-spec.jsx @@ -6,12 +6,9 @@ import AcuantCapture, { isAcuantCameraAccessFailure, getNormalizedAcuantCaptureFailureMessage, getDecodedBase64ByteSize, -} from '@18f/identity-document-capture/components/acuant-capture'; -import { - AcuantContextProvider, - AnalyticsContext, AcuantDocumentType, -} from '@18f/identity-document-capture'; +} from '@18f/identity-document-capture/components/acuant-capture'; +import { AcuantContextProvider, AnalyticsContext } from '@18f/identity-document-capture'; import DeviceContext from '@18f/identity-document-capture/context/device'; import { I18nContext } from '@18f/identity-react-i18n'; import { I18n } from '@18f/identity-i18n'; @@ -24,7 +21,7 @@ const ACUANT_CAPTURE_SUCCESS_RESULT = { width: 1748, height: 1104, }, - cardtype: AcuantDocumentType.id, + cardtype: AcuantDocumentType.ID, dpi: 519, moire: 99, moireraw: 99, @@ -570,7 +567,7 @@ describe('document-capture/components/acuant-capture', () => { await Promise.resolve(); callbacks.onCropped({ ...ACUANT_CAPTURE_SUCCESS_RESULT, - cardtype: AcuantDocumentType.passport, + cardtype: AcuantDocumentType.PASSPORT, }); }), }); diff --git a/spec/javascript/packages/document-capture/components/document-capture-spec.jsx b/spec/javascript/packages/document-capture/components/document-capture-spec.jsx index c50f07082bf..9641ccbc91d 100644 --- a/spec/javascript/packages/document-capture/components/document-capture-spec.jsx +++ b/spec/javascript/packages/document-capture/components/document-capture-spec.jsx @@ -92,7 +92,7 @@ describe('document-capture/components/document-capture', () => { image: { data: validUpload, }, - cardtype: AcuantDocumentType.id, + cardtype: AcuantDocumentType.ID, }); }); diff --git a/spec/javascript/packages/document-capture/components/documents-step-spec.jsx b/spec/javascript/packages/document-capture/components/documents-step-spec.jsx index 4e8b609d0fc..548fd4b325a 100644 --- a/spec/javascript/packages/document-capture/components/documents-step-spec.jsx +++ b/spec/javascript/packages/document-capture/components/documents-step-spec.jsx @@ -67,7 +67,7 @@ describe('document-capture/components/documents-step', () => { ); initialize(); - const result = { sharpness: 100, image: { data: '' }, cardtype: AcuantDocumentType.id }; + const result = { sharpness: 100, image: { data: '' }, cardtype: AcuantDocumentType.ID }; window.AcuantCameraUI.start.callsFake(({ onCropped }) => onCropped({ ...result, glare: 10 })); await userEvent.click(getByLabelText('doc_auth.headings.document_capture_front')); From 516b3c63f5031e23527ea714f2387c8a0cad3a9b Mon Sep 17 00:00:00 2001 From: Zach Margolis Date: Thu, 20 Jul 2023 09:05:51 -0700 Subject: [PATCH 6/8] lint fix --- .../packages/document-capture/components/acuant-camera.tsx | 3 +++ .../packages/document-capture/components/acuant-capture.tsx | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/javascript/packages/document-capture/components/acuant-camera.tsx b/app/javascript/packages/document-capture/components/acuant-camera.tsx index b6707d54eaa..2ec70c0bfc4 100644 --- a/app/javascript/packages/document-capture/components/acuant-camera.tsx +++ b/app/javascript/packages/document-capture/components/acuant-camera.tsx @@ -93,6 +93,9 @@ interface AcuantCameraUIOptions { text: AcuantCameraUIText; } +/** + * We call String.toLowerCase() on these when sending analytics events to the server + */ export enum AcuantDocumentType { NONE = 0, ID = 1, diff --git a/app/javascript/packages/document-capture/components/acuant-capture.tsx b/app/javascript/packages/document-capture/components/acuant-capture.tsx index ced3217e1b5..4b07f5f2dfb 100644 --- a/app/javascript/packages/document-capture/components/acuant-capture.tsx +++ b/app/javascript/packages/document-capture/components/acuant-capture.tsx @@ -132,7 +132,8 @@ export const isAcuantCameraAccessFailure = (error: AcuantCaptureFailureError): e * */ const getDocumentTypeLabel = (documentType: AcuantDocumentType): AcuantDocumentTypeLabel | string => - AcuantDocumentType[documentType]?.toLowerCase() ?? `An error in document type returned: ${documentType}`; + AcuantDocumentType[documentType]?.toLowerCase() ?? + `An error in document type returned: ${documentType}`; export function getNormalizedAcuantCaptureFailureMessage( error: AcuantCaptureFailureError, From 082292392980e3135ad4bad29515b515a01070da Mon Sep 17 00:00:00 2001 From: Zach Margolis Date: Thu, 20 Jul 2023 09:09:22 -0700 Subject: [PATCH 7/8] Remove AcuantDocumentTypeLabel because now the strings are lowercase --- .../packages/document-capture/components/acuant-capture.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/javascript/packages/document-capture/components/acuant-capture.tsx b/app/javascript/packages/document-capture/components/acuant-capture.tsx index 4b07f5f2dfb..615e0d310de 100644 --- a/app/javascript/packages/document-capture/components/acuant-capture.tsx +++ b/app/javascript/packages/document-capture/components/acuant-capture.tsx @@ -25,7 +25,6 @@ import useCounter from '../hooks/use-counter'; import useCookie from '../hooks/use-cookie'; import type { AcuantSuccessResponse, AcuantCaptureFailureError } from './acuant-camera'; -type AcuantDocumentTypeLabel = keyof typeof AcuantDocumentType; type AcuantImageAssessment = 'success' | 'glare' | 'blurry' | 'unsupported'; type ImageSource = 'acuant' | 'upload'; @@ -57,7 +56,7 @@ interface ImageAnalyticsPayload { } interface AcuantImageAnalyticsPayload extends ImageAnalyticsPayload { - documentType: AcuantDocumentTypeLabel | string; + documentType: string; dpi: number; moire: number; glare: number; @@ -131,7 +130,7 @@ export const isAcuantCameraAccessFailure = (error: AcuantCaptureFailureError): e * Returns a human-readable document label corresponding to the given document type constant. * */ -const getDocumentTypeLabel = (documentType: AcuantDocumentType): AcuantDocumentTypeLabel | string => +const getDocumentTypeLabel = (documentType: AcuantDocumentType): string => AcuantDocumentType[documentType]?.toLowerCase() ?? `An error in document type returned: ${documentType}`; From d0f757cb07a79966dafbead1ae457a6be74879ff Mon Sep 17 00:00:00 2001 From: Zach Margolis Date: Thu, 20 Jul 2023 09:11:13 -0700 Subject: [PATCH 8/8] update comment --- .../packages/document-capture/components/acuant-capture.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/packages/document-capture/components/acuant-capture.tsx b/app/javascript/packages/document-capture/components/acuant-capture.tsx index 615e0d310de..94259387c4e 100644 --- a/app/javascript/packages/document-capture/components/acuant-capture.tsx +++ b/app/javascript/packages/document-capture/components/acuant-capture.tsx @@ -127,8 +127,8 @@ export const isAcuantCameraAccessFailure = (error: AcuantCaptureFailureError): e error instanceof Error; /** - * Returns a human-readable document label corresponding to the given document type constant. - * + * Returns a human-readable document label corresponding to the given document type constant, + * such as "id" "passport" or "none" */ const getDocumentTypeLabel = (documentType: AcuantDocumentType): string => AcuantDocumentType[documentType]?.toLowerCase() ??