Skip to content

Commit 4d3a6a8

Browse files
authored
chore: add UI integration test (#33)
* add integration test app * make face liveness session extendable * add UI integration test * remove unused code * fix build issue * test: fix failed test
1 parent 4e0fc17 commit 4d3a6a8

34 files changed

+2087
-18
lines changed

Diff for: .gitignore

+16-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,26 @@ HostApp/dist/
1313
HostApp/node_modules/
1414
HostApp/generated-src/
1515
HostApp/aws-exports.js
16-
HostApp/.gitignore
1716
HostApp/awsconfiguration.json
1817
HostApp/amplifyconfiguration.json
1918
HostApp/amplifyconfiguration.dart
2019
HostApp/amplify-build-config.json
2120
HostApp/amplify-gradle-config.json
2221
HostApp/amplifytools.xcconfig
2322
HostApp/.secret-*
24-
HostApp/**.sample
23+
HostApp/**.sample
24+
Tests/IntegrationTestApp/amplify/
25+
Tests/IntegrationTestApp/build/
26+
Tests/IntegrationTestApp/dist/
27+
Tests/IntegrationTestApp/node_modules/
28+
Tests/IntegrationTestApp/generated-src/
29+
Tests/IntegrationTestApp/aws-exports.js
30+
Tests/IntegrationTestApp/awsconfiguration.json
31+
Tests/IntegrationTestApp/amplifyconfiguration.json
32+
Tests/IntegrationTestApp/amplifyconfiguration.dart
33+
Tests/IntegrationTestApp/amplify-build-config.json
34+
Tests/IntegrationTestApp/amplify-gradle-config.json
35+
Tests/IntegrationTestApp/amplifytools.xcconfig
36+
Tests/IntegrationTestApp/.secret-*
37+
Tests/IntegrationTestApp/**.sample
38+
Tests/IntegrationTestApp/*.xcodeproj

Diff for: Sources/FaceLiveness/AV/LivenessCaptureSession.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@
88
import UIKit
99
import AVFoundation
1010

11-
final class LivenessCaptureSession {
11+
class LivenessCaptureSession {
1212
let captureDevice: LivenessCaptureDevice
1313
private let captureQueue = DispatchQueue(label: "com.amazonaws.faceliveness.cameracapturequeue")
14-
private let outputDelegate: OutputSampleBufferCapturer
15-
private var captureSession: AVCaptureSession?
14+
let outputDelegate: OutputSampleBufferCapturer
15+
var captureSession: AVCaptureSession?
1616

1717
init(captureDevice: LivenessCaptureDevice, outputDelegate: OutputSampleBufferCapturer) {
1818
self.captureDevice = captureDevice
1919
self.outputDelegate = outputDelegate
2020
}
2121

22-
func startSession(frame: CGRect) throws -> AVCaptureVideoPreviewLayer {
22+
func startSession(frame: CGRect) throws -> CALayer {
2323
guard let camera = captureDevice.avCaptureDevice
2424
else { throw LivenessCaptureSessionError.cameraUnavailable }
2525

Diff for: Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionView.swift

+41-1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,46 @@ public struct FaceLivenessDetectorView: View {
8383
)
8484
)
8585
}
86+
87+
init(
88+
sessionID: String,
89+
credentialsProvider: AWSCredentialsProvider? = nil,
90+
region: String,
91+
disableStartView: Bool = false,
92+
isPresented: Binding<Bool>,
93+
onCompletion: @escaping (Result<Void, FaceLivenessDetectionError>) -> Void,
94+
captureSession: LivenessCaptureSession
95+
) {
96+
self.disableStartView = disableStartView
97+
self._isPresented = isPresented
98+
self.onCompletion = onCompletion
99+
100+
self.sessionTask = Task {
101+
let session = try await AWSPredictionsPlugin.startFaceLivenessSession(
102+
withID: sessionID,
103+
credentialsProvider: credentialsProvider,
104+
region: region,
105+
options: .init(),
106+
completion: map(detectionCompletion: onCompletion)
107+
)
108+
return session
109+
}
110+
111+
let faceInOvalStateMatching = FaceInOvalMatching(
112+
instructor: Instructor()
113+
)
114+
115+
self._viewModel = StateObject(
116+
wrappedValue: .init(
117+
faceDetector: captureSession.outputDelegate.faceDetector,
118+
faceInOvalMatching: faceInOvalStateMatching,
119+
captureSession: captureSession,
120+
videoChunker: captureSession.outputDelegate.videoChunker,
121+
closeButtonAction: { onCompletion(.failure(.userCancelled)) },
122+
sessionID: sessionID
123+
)
124+
)
125+
}
86126

87127
public var body: some View {
88128
switch displayState {
@@ -204,7 +244,7 @@ enum InstructionState {
204244
case display(text: String)
205245
}
206246

207-
fileprivate func map(detectionCompletion: @escaping (Result<Void, FaceLivenessDetectionError>) -> Void) -> ((Result<Void, FaceLivenessSessionError>) -> Void) {
247+
private func map(detectionCompletion: @escaping (Result<Void, FaceLivenessDetectionError>) -> Void) -> ((Result<Void, FaceLivenessSessionError>) -> Void) {
208248
{ result in
209249
switch result {
210250
case .success:

Diff for: Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionViewModel.swift

+1-3
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,9 @@ class FaceLivenessDetectionViewModel: ObservableObject {
117117
captureSession.stopRunning()
118118
}
119119

120-
func startCamera(withinFrame frame: CGRect) -> AVCaptureVideoPreviewLayer? {
120+
func startCamera(withinFrame frame: CGRect) -> CALayer? {
121121
do {
122122
let avLayer = try captureSession.startSession(frame: frame)
123-
avLayer.frame = frame
124-
layerRectConverted = avLayer.layerRectConverted(fromMetadataOutputRect:)
125123
DispatchQueue.main.async {
126124
self.livenessState.checkIsFacePrepared()
127125
}

Diff for: Sources/FaceLiveness/Views/Liveness/LivenessViewController.swift

+1-8
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Amplify
1313

1414
final class _LivenessViewController: UIViewController {
1515
let viewModel: FaceLivenessDetectionViewModel
16-
var previewLayer: AVCaptureVideoPreviewLayer!
16+
var previewLayer: CALayer!
1717

1818
let faceShapeLayer = CAShapeLayer()
1919
var ovalExists = false
@@ -86,13 +86,6 @@ final class _LivenessViewController: UIViewController {
8686
}
8787
}
8888

89-
90-
91-
func convert(rect: CGRect) -> CGRect {
92-
let box = previewLayer.layerRectConverted(fromMetadataOutputRect: rect)
93-
return box
94-
}
95-
9689
var runningFreshness = false
9790
var hasSentClientInformationEvent = false
9891
var challengeID = UUID().uuidString

0 commit comments

Comments
 (0)