From bdc7061836a27c605144e1df3f39c9916db97d4a Mon Sep 17 00:00:00 2001 From: Ayush Goyal Date: Fri, 27 Sep 2024 08:08:40 +0530 Subject: [PATCH] Merge branch liveness/alpha in to dca-v2 to include back camera (#5846) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update publish workflow * disable e2e tests in workflow * Squashed commit of the following: commit 984fa990abae25040a763cd65126d7f8afb5bc12 Author: thaddmt <68032955+thaddmt@users.noreply.github.com> Date: Thu Sep 26 11:10:45 2024 -0700 chore(liveness): allow selecting all cameras, allow camera selection … (#5833) * chore(liveness): allow selecting all cameras, allow camera selection on mobile * only show on mobile with facemovement challenge only * relax e2e tests on alpha * make more reaadable * fix * update names * refactor, add tests * Update packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/LivenessCameraModule.tsx Co-authored-by: Caleb Pollman * refactor --------- Co-authored-by: Caleb Pollman --- .../liveness/disable-start-screen.feature | 3 - .../ui/components/liveness/no-light.feature | 4 -- .../LivenessCheck/CameraSelector.tsx | 43 ++++++++++++++ .../LivenessCheck/LivenessCameraModule.tsx | 57 ++++++------------- .../__tests__/CameraSelector.test.tsx | 21 +++++++ .../__tests__/LivenessCameraModule.test.tsx | 7 ++- .../FaceLivenessDetector/utils/helpers.ts | 1 - 7 files changed, 86 insertions(+), 50 deletions(-) create mode 100644 packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/CameraSelector.tsx create mode 100644 packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/__tests__/CameraSelector.test.tsx diff --git a/packages/e2e/features/ui/components/liveness/disable-start-screen.feature b/packages/e2e/features/ui/components/liveness/disable-start-screen.feature index f9501b76611..c94a3699131 100644 --- a/packages/e2e/features/ui/components/liveness/disable-start-screen.feature +++ b/packages/e2e/features/ui/components/liveness/disable-start-screen.feature @@ -24,6 +24,3 @@ Feature: Disable Start Screen Then I click the "FaceMovementAndLightChallenge" selectfield and select the "FaceMovementChallenge" option Then I see "FaceMovementChallenge" Then I see "liveness-detector" element - Then I see the "Face didn't fit inside oval in time limit." timeout error - Then I click the "Try again" button - Then I see "Loading" diff --git a/packages/e2e/features/ui/components/liveness/no-light.feature b/packages/e2e/features/ui/components/liveness/no-light.feature index 0e2be1e9ff9..0c96c2aab63 100644 --- a/packages/e2e/features/ui/components/liveness/no-light.feature +++ b/packages/e2e/features/ui/components/liveness/no-light.feature @@ -23,7 +23,3 @@ Feature: Liveness Detector Then I see "connecting" Then I click the "Start video check" button Then I see "liveness-detector" element - Then I see "Move closer" - Then I see the "Face didn't fit inside oval in time limit." timeout error - Then I click the "Try again" button - Then I see the "Start video check" button diff --git a/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/CameraSelector.tsx b/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/CameraSelector.tsx new file mode 100644 index 00000000000..f68032db7d5 --- /dev/null +++ b/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/CameraSelector.tsx @@ -0,0 +1,43 @@ +import { Flex, Label, SelectField, View } from '@aws-amplify/ui-react'; +import React from 'react'; +import { LivenessClassNames } from '../types/classNames'; + +interface CameraSelectorProps { + deviceId?: string; + onSelect: (e: React.ChangeEvent) => void; + devices: MediaDeviceInfo[]; +} + +export const CameraSelector = (props: CameraSelectorProps): JSX.Element => { + const { + onSelect: onCameraChange, + devices: selectableDevices, + deviceId: selectedDeviceId, + } = props; + return ( + + + + + {selectableDevices.map((device) => ( + + ))} + + + + ); +}; diff --git a/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/LivenessCameraModule.tsx b/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/LivenessCameraModule.tsx index 78c81de1958..81b3dbc9cd7 100644 --- a/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/LivenessCameraModule.tsx +++ b/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/LivenessCameraModule.tsx @@ -1,15 +1,7 @@ import React, { useState, useRef } from 'react'; import { classNames } from '@aws-amplify/ui'; -import { - Button, - Flex, - Label, - Loader, - SelectField, - Text, - View, -} from '@aws-amplify/ui-react'; +import { Button, Flex, Loader, Text, View } from '@aws-amplify/ui-react'; import { useColorMode } from '@aws-amplify/ui-react/internal'; import { FaceMatchState, clearOvalCanvas, drawStaticOval } from '../service'; import { @@ -40,6 +32,7 @@ import { DefaultRecordingIcon, } from '../shared/DefaultStartScreenComponents'; import { FACE_MOVEMENT_CHALLENGE } from '../service/utils/constants'; +import { CameraSelector } from './CameraSelector'; export const selectChallengeType = createLivenessSelector( (state) => state.context.parsedSessionInformation?.Challenge?.Name @@ -160,6 +153,13 @@ export const LivenessCameraModule = ( videoWidth && videoHeight ? videoWidth / videoHeight : 0 ); + // Only mobile device camera selection for no light challenge + const hasMultipleDevices = !!selectableDevices?.length; + const allowDeviceSelection = + isStartView && + hasMultipleDevices && + (!isMobileScreen || isFaceMovementChallenge); + React.useEffect(() => { if (canvasRef?.current && videoRef?.current && videoStream && isStartView) { drawStaticOval(canvasRef.current, videoRef.current, videoStream); @@ -417,38 +417,13 @@ export const LivenessCameraModule = ( - {isStartView && - !isMobileScreen && - selectableDevices && - selectableDevices.length > 1 && ( - - - - - {selectableDevices?.map((device) => ( - - ))} - - - - )} + {allowDeviceSelection ? ( + + ) : null} diff --git a/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/__tests__/CameraSelector.test.tsx b/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/__tests__/CameraSelector.test.tsx new file mode 100644 index 00000000000..3b84a890c99 --- /dev/null +++ b/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/__tests__/CameraSelector.test.tsx @@ -0,0 +1,21 @@ +import { render } from '@testing-library/react'; +import { CameraSelector } from '../CameraSelector'; +import React from 'react'; + +const mockMediaDevice: MediaDeviceInfo = { + deviceId: 'foobar', + groupId: 'foobar', + kind: 'videoinput', + label: 'foobar', + toJSON: jest.fn(), +}; + +describe('CameraSelector', () => { + it('should render', () => { + const result = render( + {}} devices={[mockMediaDevice]} /> + ); + + expect(result.container).toBeDefined(); + }); +}); diff --git a/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/__tests__/LivenessCameraModule.test.tsx b/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/__tests__/LivenessCameraModule.test.tsx index cd06cff9d51..9a16bc00b6a 100644 --- a/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/__tests__/LivenessCameraModule.test.tsx +++ b/packages/react-liveness/src/components/FaceLivenessDetector/LivenessCheck/__tests__/LivenessCameraModule.test.tsx @@ -483,7 +483,9 @@ describe('LivenessCameraModule', () => { it('should render hair check screen when isStart = true', () => { isStart = true; mockStateMatchesAndSelectors(); - mockUseLivenessSelector.mockReturnValue(25).mockReturnValue(['device-id']); + mockUseLivenessSelector + .mockReturnValue(25) + .mockReturnValue(['device-id', 'device-id-2', 'device-id-3']); renderWithLivenessProvider( { videoEl.dispatchEvent(new Event('canplay')); expect(screen.getByTestId('popover-icon')).toBeInTheDocument(); + expect( + screen.getByTestId('amplify-liveness-camera-select') + ).toBeInTheDocument(); }); it('selectors should work', () => { diff --git a/packages/react-liveness/src/components/FaceLivenessDetector/utils/helpers.ts b/packages/react-liveness/src/components/FaceLivenessDetector/utils/helpers.ts index 815bc10608f..9fffdb0d07c 100644 --- a/packages/react-liveness/src/components/FaceLivenessDetector/utils/helpers.ts +++ b/packages/react-liveness/src/components/FaceLivenessDetector/utils/helpers.ts @@ -8,5 +8,4 @@ export const STATIC_VIDEO_CONSTRAINTS: MediaTrackConstraints = { ideal: 480, }, frameRate: { min: 15, ideal: 30, max: 30 }, - facingMode: 'user', };