@smileid/usesmileid 12.0.0 → 12.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.d.ts +11 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.d.ts.map +1 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.js +17 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.js.map +1 -0
- package/dist/core/exception/capture_validation_exceptions.d.ts +1 -0
- package/dist/core/exception/capture_validation_exceptions.d.ts.map +1 -1
- package/dist/core/exception/capture_validation_exceptions.js +1 -0
- package/dist/core/exception/capture_validation_exceptions.js.map +1 -1
- package/dist/core/exception/index.d.ts +1 -0
- package/dist/core/exception/index.d.ts.map +1 -1
- package/dist/core/exception/index.js +1 -0
- package/dist/core/exception/index.js.map +1 -1
- package/dist/core/exception/use_smile_id_error_code.d.ts +1 -0
- package/dist/core/exception/use_smile_id_error_code.d.ts.map +1 -1
- package/dist/core/exception/use_smile_id_error_code.js +1 -0
- package/dist/core/exception/use_smile_id_error_code.js.map +1 -1
- package/dist/core/models/config.d.ts +19 -0
- package/dist/core/models/config.d.ts.map +1 -1
- package/dist/core/models/document_type.d.ts +1 -1
- package/dist/core/models/document_type.d.ts.map +1 -1
- package/dist/core/models/document_type.js +2 -2
- package/dist/core/models/document_type.js.map +1 -1
- package/dist/core/models/global_privacy_control.d.ts +36 -0
- package/dist/core/models/global_privacy_control.d.ts.map +1 -0
- package/dist/core/models/global_privacy_control.js +39 -0
- package/dist/core/models/global_privacy_control.js.map +1 -0
- package/dist/core/models/network_config.d.ts +2 -2
- package/dist/core/models/network_config.js +2 -2
- package/dist/data/api/interceptors/smile_auth_interceptor.d.ts.map +1 -1
- package/dist/data/api/interceptors/smile_auth_interceptor.js +3 -17
- package/dist/data/api/interceptors/smile_auth_interceptor.js.map +1 -1
- package/dist/data/api/smile_id_api.d.ts +1 -1
- package/dist/data/api/smile_id_api.d.ts.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.d.ts +4 -4
- package/dist/data/dsl/builder/retry_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.js +6 -6
- package/dist/data/dsl/builder/retry_config_builder.js.map +1 -1
- package/dist/data/smile_id_urls.d.ts +1 -1
- package/dist/data/smile_id_urls.js +1 -1
- package/dist/data/smile_id_urls.js.map +1 -1
- package/dist/data/util/retry_util.d.ts +1 -1
- package/dist/data/util/retry_util.d.ts.map +1 -1
- package/dist/data/util/retry_util.js +5 -0
- package/dist/data/util/retry_util.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/metadata/builder_configuration.d.ts +5 -0
- package/dist/metadata/builder_configuration.d.ts.map +1 -1
- package/dist/metadata/builder_configuration.js +1 -0
- package/dist/metadata/builder_configuration.js.map +1 -1
- package/dist/metadata/metadata_configuration_mappers.d.ts +2 -3
- package/dist/metadata/metadata_configuration_mappers.d.ts.map +1 -1
- package/dist/metadata/metadata_configuration_mappers.js +13 -6
- package/dist/metadata/metadata_configuration_mappers.js.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.d.ts.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.js +14 -5
- package/dist/metadata/use_smile_id_metadata_factory.js.map +1 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts +5 -2
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js +8 -3
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js.map +1 -1
- package/dist/presentation/components/use_smile_id_instructions_hero.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_instructions_hero.js +8 -3
- package/dist/presentation/components/use_smile_id_instructions_hero.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts +16 -0
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.js +18 -0
- package/dist/presentation/flow/dsl/builder/config_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts +3 -6
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.js +3 -6
- package/dist/presentation/flow/dsl/builder/screens_builder.js.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.d.ts +5 -1
- package/dist/presentation/flow/flow_navigation_manager.d.ts.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.js +7 -1
- package/dist/presentation/flow/flow_navigation_manager.js.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.d.ts.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.js +1 -1
- package/dist/presentation/flow/model/instructions_defaults.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_capture_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_capture_screen.js +13 -3
- package/dist/presentation/flow/screen/orchestrated_capture_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.js +3 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_preview_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_preview_screen.js +0 -8
- package/dist/presentation/flow/screen/orchestrated_preview_screen.js.map +1 -1
- package/dist/presentation/flow/use_smile_id_flow.d.ts.map +1 -1
- package/dist/presentation/flow/use_smile_id_flow.js +10 -4
- package/dist/presentation/flow/use_smile_id_flow.js.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.js +42 -20
- package/dist/presentation/flow/validation/flow_validator.js.map +1 -1
- package/dist/presentation/screen/helpers/capture_ui_state.d.ts +6 -6
- package/dist/presentation/screen/helpers/capture_ui_state.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/capture_ui_state.js +19 -19
- package/dist/presentation/screen/helpers/capture_ui_state.js.map +1 -1
- package/dist/presentation/screen/helpers/ess_turn_haptics.d.ts +2 -2
- package/dist/presentation/screen/helpers/ess_turn_haptics.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/ess_turn_haptics.js +6 -6
- package/dist/presentation/screen/helpers/ess_turn_haptics.js.map +1 -1
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.d.ts +5 -5
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js +11 -11
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js.map +1 -1
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.d.ts +13 -3
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.js +48 -6
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts +4 -2
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.js +36 -15
- package/dist/presentation/screen/use_smile_id_capture_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_consent_screen.d.ts +7 -0
- package/dist/presentation/screen/use_smile_id_consent_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_consent_screen.js +6 -5
- package/dist/presentation/screen/use_smile_id_consent_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_back_instructions.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_back_instructions.js +5 -13
- package/dist/presentation/screen/use_smile_id_document_back_instructions.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts +1 -21
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.js +3 -14
- package/dist/presentation/screen/use_smile_id_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.js +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.js.map +1 -1
- package/dist/presentation/utils/locale_utils.d.ts +10 -4
- package/dist/presentation/utils/locale_utils.d.ts.map +1 -1
- package/dist/presentation/utils/locale_utils.js +13 -5
- package/dist/presentation/utils/locale_utils.js.map +1 -1
- package/dist/testing/fake_face_analyzer.d.ts +43 -0
- package/dist/testing/fake_face_analyzer.d.ts.map +1 -0
- package/dist/testing/fake_face_analyzer.js +52 -0
- package/dist/testing/fake_face_analyzer.js.map +1 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +7 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/scenario_expectations.d.ts +28 -0
- package/dist/testing/scenario_expectations.d.ts.map +1 -0
- package/dist/testing/scenario_expectations.js +65 -0
- package/dist/testing/scenario_expectations.js.map +1 -0
- package/dist/testing/scenario_loader.d.ts +11 -0
- package/dist/testing/scenario_loader.d.ts.map +1 -0
- package/dist/testing/scenario_loader.js +64 -0
- package/dist/testing/scenario_loader.js.map +1 -0
- package/dist/testing/scripted_scan_results.d.ts +17 -0
- package/dist/testing/scripted_scan_results.d.ts.map +1 -0
- package/dist/testing/scripted_scan_results.js +52 -0
- package/dist/testing/scripted_scan_results.js.map +1 -0
- package/package.json +11 -4
- package/src/__tests__/dsl.test.ts +51 -1
- package/src/__tests__/setup_react_native.ts +17 -2
- package/src/__tests__/snapshots/__snapshots__/screens_structural.test.tsx.snap +5261 -0
- package/src/__tests__/snapshots/screens_structural.test.tsx +230 -0
- package/src/camera/__tests__/use_smile_id_camera_system.test.ts +103 -0
- package/src/core/exception/__tests__/builder_validation_exceptions.test.ts +67 -0
- package/src/core/exception/agent_mode_with_enhanced_liveness_exception.ts +20 -0
- package/src/core/exception/capture_validation_exceptions.ts +1 -0
- package/src/core/exception/index.ts +1 -0
- package/src/core/exception/use_smile_id_error_code.ts +1 -0
- package/src/core/models/__tests__/document_type.test.ts +2 -2
- package/src/core/models/__tests__/flow_models.test.ts +26 -0
- package/src/core/models/config.ts +22 -0
- package/src/core/models/document_type.ts +2 -2
- package/src/core/models/global_privacy_control.ts +45 -0
- package/src/core/models/network_config.ts +2 -2
- package/src/data/api/__tests__/smile_id_api.test.ts +1 -1
- package/src/data/api/interceptors/__tests__/gzip_interceptor.test.ts +83 -0
- package/src/data/api/interceptors/smile_auth_interceptor.ts +3 -18
- package/src/data/compression/__tests__/payload_compressor_real_jpeg.test.ts +6 -2
- package/src/data/dsl/builder/__tests__/config_builders.test.ts +62 -0
- package/src/data/dsl/builder/retry_config_builder.ts +6 -6
- package/src/data/factory/__tests__/retry_gzip_mac_composition.test.ts +163 -0
- package/src/data/factory/__tests__/signed_job_submission_headers.test.ts +1 -1
- package/src/data/repository/__tests__/network_retries.test.ts +1 -1
- package/src/data/repository/__tests__/use_smile_id_repository.test.ts +1 -1
- package/src/data/security/__tests__/request_canonicalizer.test.ts +132 -0
- package/src/data/smile_id_urls.ts +1 -1
- package/src/data/util/__tests__/retry_util.test.ts +25 -0
- package/src/data/util/retry_util.ts +9 -1
- package/src/index.ts +6 -4
- package/src/metadata/__tests__/metadata_configuration_mappers.test.ts +39 -0
- package/src/metadata/__tests__/metadata_configuration_objects.test.ts +2 -1
- package/src/metadata/__tests__/metadata_device_context.test.ts +3 -3
- package/src/metadata/__tests__/metadata_device_os_android.test.ts +18 -0
- package/src/metadata/__tests__/metadata_golden_fixture.json +1 -1
- package/src/metadata/__tests__/metadata_payload_golden.test.ts +4 -4
- package/src/metadata/__tests__/use_smile_id_metadata.test.ts +1 -1
- package/src/metadata/builder_configuration.ts +6 -0
- package/src/metadata/metadata_configuration_mappers.ts +21 -7
- package/src/metadata/use_smile_id_metadata_factory.ts +17 -6
- package/src/presentation/assets/si_document_green_book_hero_animation.json +1 -4668
- package/src/presentation/assets/si_document_hero_animation.json +1 -4799
- package/src/presentation/assets/si_document_hero_back_animation.json +1 -2039
- package/src/presentation/assets/si_document_passport_hero_animation.json +1 -14491
- package/src/presentation/assets/si_ess_all_directions_hero_animation.json +1 -0
- package/src/presentation/assets/si_ess_animation_all_directions.json +1 -6589
- package/src/presentation/assets/si_selfie_hero_animation.json +1 -1439
- package/src/presentation/assets/si_smile_to_capture_animation.json +1 -1439
- package/src/presentation/components/__tests__/use_smile_id_enhanced_smart_selfie_clip.test.tsx +9 -4
- package/src/presentation/components/__tests__/use_smile_id_instructions_hero.test.tsx +44 -0
- package/src/presentation/components/use_smile_id_enhanced_smart_selfie_clip.tsx +9 -3
- package/src/presentation/components/use_smile_id_instructions_hero.tsx +10 -0
- package/src/presentation/flow/__tests__/document_flow_navigation.test.ts +3 -3
- package/src/presentation/flow/__tests__/flow_navigation_manager.test.ts +49 -0
- package/src/presentation/flow/dsl/builder/__tests__/config_builder.test.ts +25 -0
- package/src/presentation/flow/dsl/builder/config_builder.ts +21 -0
- package/src/presentation/flow/dsl/builder/screens_builder.ts +3 -6
- package/src/presentation/flow/flow_navigation_manager.ts +6 -1
- package/src/presentation/flow/model/instructions_defaults.ts +1 -1
- package/src/presentation/flow/screen/orchestrated_capture_screen.tsx +18 -3
- package/src/presentation/flow/screen/orchestrated_consent_screen.tsx +5 -0
- package/src/presentation/flow/screen/orchestrated_preview_screen.tsx +0 -12
- package/src/presentation/flow/use_smile_id_flow.tsx +11 -4
- package/src/presentation/flow/validation/__tests__/flow_validator.test.ts +61 -1
- package/src/presentation/flow/validation/flow_validator.ts +55 -26
- package/src/presentation/screen/__tests__/capture_ui_state.test.ts +66 -47
- package/src/presentation/screen/__tests__/ess_turn_haptics.test.ts +15 -11
- package/src/presentation/screen/__tests__/scan_state_to_overlay_state.test.ts +47 -27
- package/src/presentation/screen/__tests__/use_smile_id_capture_screen.test.tsx +176 -14
- package/src/presentation/screen/__tests__/use_smile_id_document_back_instructions.test.tsx +1 -1
- package/src/presentation/screen/__tests__/use_smile_id_preview_screen.test.tsx +10 -40
- package/src/presentation/screen/helpers/__tests__/use_capture_orientation_lock.test.tsx +212 -0
- package/src/presentation/screen/helpers/capture_ui_state.ts +27 -27
- package/src/presentation/screen/helpers/ess_turn_haptics.ts +9 -9
- package/src/presentation/screen/helpers/scan_state_to_overlay_state.ts +13 -13
- package/src/presentation/screen/helpers/use_capture_orientation_lock.ts +69 -7
- package/src/presentation/screen/use_smile_id_capture_screen.tsx +47 -19
- package/src/presentation/screen/use_smile_id_consent_screen.tsx +16 -5
- package/src/presentation/screen/use_smile_id_document_back_instructions.tsx +14 -23
- package/src/presentation/screen/use_smile_id_document_preview_screen.tsx +1 -1
- package/src/presentation/screen/use_smile_id_preview_screen.tsx +13 -45
- package/src/presentation/screen/use_smile_id_processing_screen.tsx +1 -1
- package/src/presentation/utils/__tests__/locale_utils.test.ts +46 -5
- package/src/presentation/utils/locale_utils.ts +13 -4
- package/src/testing/__tests__/fake_face_analyzer.test.ts +42 -0
- package/src/testing/__tests__/scenario_expectations.test.ts +110 -0
- package/src/testing/__tests__/scenario_loader.test.ts +64 -0
- package/src/testing/fake_face_analyzer.ts +82 -0
- package/src/testing/index.ts +15 -0
- package/src/testing/scenario_expectations.ts +87 -0
- package/src/testing/scenario_loader.ts +83 -0
- package/src/testing/scripted_scan_results.ts +66 -0
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.d.ts +0 -15
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.d.ts.map +0 -1
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.js +0 -19
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.js.map +0 -1
- package/src/presentation/components/use_smile_id_face_silhouette_overlay.tsx +0 -27
|
@@ -11,19 +11,37 @@ import * as Brightness from "expo-brightness";
|
|
|
11
11
|
import { StatusBar } from "react-native";
|
|
12
12
|
import { UseSmileIDCaptureScreen } from "../use_smile_id_capture_screen";
|
|
13
13
|
import { CaptureType } from "../../../core/models/ml_config";
|
|
14
|
+
import { DocumentCaptureMode } from "../../../core/models/document_capture_mode";
|
|
15
|
+
import { mockedTakePhoto } from "../../../__tests__/setup_react_native";
|
|
14
16
|
import { enStrings } from "../../../l10n/strings_en";
|
|
15
17
|
import {
|
|
16
|
-
|
|
18
|
+
UseSmileIDScanStateType,
|
|
17
19
|
CaptureReadyEventKind,
|
|
18
20
|
} from "@smileid/usesmileid_bridge";
|
|
19
21
|
import type {
|
|
20
|
-
|
|
22
|
+
UseSmileIDScanState,
|
|
21
23
|
CaptureReadyEvent,
|
|
22
24
|
FaceScanResult,
|
|
23
25
|
} from "@smileid/usesmileid_bridge";
|
|
26
|
+
import { scriptedFaceScanResults } from "../../../testing/scripted_scan_results";
|
|
27
|
+
import { parseScriptedScenario } from "../../../testing/scenario_loader";
|
|
24
28
|
import { isSessionBoundary } from "../helpers/capture_ui_state";
|
|
25
29
|
import { UseSmileIDFeedbackDebouncer } from "../helpers/feedback_debouncer";
|
|
26
30
|
import { UseSmileIDMotion } from "../../theme/use_smile_id_motion";
|
|
31
|
+
import { readFileSync } from "node:fs";
|
|
32
|
+
import { dirname, join } from "node:path";
|
|
33
|
+
|
|
34
|
+
// The shared scenario set lives at the repo root (e2e/scenarios/), outside this
|
|
35
|
+
// package's tsc rootDir (./src), so the test reads selfie-happy-path.json at run
|
|
36
|
+
// time. These minimal ambient decls keep the read typed without pulling
|
|
37
|
+
// @types/node in (which would collide with react-native's global timer types).
|
|
38
|
+
declare module "node:fs" {
|
|
39
|
+
export function readFileSync(path: string, encoding: "utf8"): string;
|
|
40
|
+
}
|
|
41
|
+
declare module "node:path" {
|
|
42
|
+
export function dirname(path: string): string;
|
|
43
|
+
export function join(...parts: string[]): string;
|
|
44
|
+
}
|
|
27
45
|
|
|
28
46
|
// Capture the screen's per-frame `onResult` so tests can drive synthetic
|
|
29
47
|
// sequences — the vision-camera worklet can't run in vitest, and `onResult`
|
|
@@ -195,6 +213,18 @@ describe("UseSmileIDCaptureScreen", () => {
|
|
|
195
213
|
expect(mockedUseCameraDevice).toHaveBeenCalledWith("back");
|
|
196
214
|
});
|
|
197
215
|
|
|
216
|
+
it("uses the back lens for an agent-mode selfie capture", () => {
|
|
217
|
+
const { root } = render(
|
|
218
|
+
<UseSmileIDCaptureScreen
|
|
219
|
+
analyzer={fakeAnalyzer}
|
|
220
|
+
captureType={CaptureType.selfie}
|
|
221
|
+
allowAgentMode
|
|
222
|
+
/>,
|
|
223
|
+
);
|
|
224
|
+
expect(findByTestID(root, "si_capture_camera_preview")).not.toBeNull();
|
|
225
|
+
expect(mockedUseCameraDevice).toHaveBeenCalledWith("back");
|
|
226
|
+
});
|
|
227
|
+
|
|
198
228
|
it("shows a placeholder (not the camera) when permission is undetermined", () => {
|
|
199
229
|
const requestPermission = vi.fn(async () => true);
|
|
200
230
|
mockedUseCameraPermission.mockReturnValue({
|
|
@@ -278,9 +308,9 @@ describe("UseSmileIDCaptureScreen", () => {
|
|
|
278
308
|
// NOTE: the legacy `overlayState` / `captureProgress` prop-driven tests
|
|
279
309
|
// were removed in Phase 3 of the per-frame migration. The capture
|
|
280
310
|
// screen now owns its overlay state internally (derived from the
|
|
281
|
-
// analyzer's per-frame
|
|
311
|
+
// analyzer's per-frame UseSmileIDScanState), so there's no external prop to
|
|
282
312
|
// pin against. Phase 4 follow-up re-authors these as analyzer-driven
|
|
283
|
-
// tests that feed synthetic
|
|
313
|
+
// tests that feed synthetic UseSmileIDScanState transitions through a mock
|
|
284
314
|
// analyzer + frame stream.
|
|
285
315
|
|
|
286
316
|
it("forwards the back tap to onBack when the back button is supplied", () => {
|
|
@@ -331,7 +361,7 @@ describe("UseSmileIDCaptureScreen", () => {
|
|
|
331
361
|
});
|
|
332
362
|
|
|
333
363
|
// Removed in Phase 3 — feedback text is now driven by the analyzer's
|
|
334
|
-
//
|
|
364
|
+
// UseSmileIDScanState rather than a partner-supplied overlayState prop. Phase 4
|
|
335
365
|
// re-authors this against a mock analyzer that yields a synthetic
|
|
336
366
|
// "found + feedback=si_capture_low_light" result through the
|
|
337
367
|
// frame stream.
|
|
@@ -507,22 +537,22 @@ describe("UseSmileIDCaptureScreen", () => {
|
|
|
507
537
|
// Stale events → unsatisfied reset (drops them) → fresh events → finished.
|
|
508
538
|
emit({
|
|
509
539
|
output,
|
|
510
|
-
state: { type:
|
|
540
|
+
state: { type: UseSmileIDScanStateType.Found },
|
|
511
541
|
capturedEvents: [staleSelfie, staleLiveness],
|
|
512
542
|
});
|
|
513
543
|
emit({
|
|
514
544
|
output,
|
|
515
|
-
state: { type:
|
|
545
|
+
state: { type: UseSmileIDScanStateType.Unsatisfied },
|
|
516
546
|
capturedEvents: [],
|
|
517
547
|
});
|
|
518
548
|
emit({
|
|
519
549
|
output,
|
|
520
|
-
state: { type:
|
|
550
|
+
state: { type: UseSmileIDScanStateType.Found },
|
|
521
551
|
capturedEvents: [freshSelfie, freshLiveness],
|
|
522
552
|
});
|
|
523
553
|
emit({
|
|
524
554
|
output,
|
|
525
|
-
state: { type:
|
|
555
|
+
state: { type: UseSmileIDScanStateType.Finished },
|
|
526
556
|
capturedEvents: [],
|
|
527
557
|
});
|
|
528
558
|
|
|
@@ -541,6 +571,58 @@ describe("UseSmileIDCaptureScreen", () => {
|
|
|
541
571
|
expect.objectContaining({ retries: 1 }),
|
|
542
572
|
);
|
|
543
573
|
});
|
|
574
|
+
|
|
575
|
+
it("replays the shared selfie scenario to a full capture completion", async () => {
|
|
576
|
+
// Drives the capture gap headlessly through the frame stream's onResult
|
|
577
|
+
// seam: the shared scenario replayed to `finished` must reach
|
|
578
|
+
// onCaptureComplete with the scripted selfie + liveness events.
|
|
579
|
+
const onCaptureComplete = vi.fn();
|
|
580
|
+
const analyzer = makeFakeAnalyzer();
|
|
581
|
+
capturedOnResult = null;
|
|
582
|
+
render(
|
|
583
|
+
<UseSmileIDCaptureScreen
|
|
584
|
+
analyzer={analyzer}
|
|
585
|
+
captureType={CaptureType.selfie}
|
|
586
|
+
onCaptureComplete={onCaptureComplete}
|
|
587
|
+
/>,
|
|
588
|
+
);
|
|
589
|
+
expect(capturedOnResult).not.toBeNull();
|
|
590
|
+
|
|
591
|
+
// Consume the real shared scenario (not a hand-written copy) so a drift in
|
|
592
|
+
// the canonical script is caught here rather than silently diverging.
|
|
593
|
+
const scenarioDir = dirname(import.meta.url.replace(/^file:\/\//, ""));
|
|
594
|
+
const scenario = parseScriptedScenario(
|
|
595
|
+
JSON.parse(
|
|
596
|
+
readFileSync(
|
|
597
|
+
join(
|
|
598
|
+
scenarioDir,
|
|
599
|
+
"../../../../../e2e/scenarios/selfie-happy-path.json",
|
|
600
|
+
),
|
|
601
|
+
"utf8",
|
|
602
|
+
),
|
|
603
|
+
),
|
|
604
|
+
);
|
|
605
|
+
for (const result of scriptedFaceScanResults(scenario, {
|
|
606
|
+
livenessCount: 2,
|
|
607
|
+
})) {
|
|
608
|
+
act(() => {
|
|
609
|
+
capturedOnResult!(result);
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
await act(async () => {
|
|
613
|
+
await Promise.resolve();
|
|
614
|
+
await Promise.resolve();
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
expect(onCaptureComplete).toHaveBeenCalledTimes(1);
|
|
618
|
+
const events = onCaptureComplete.mock.calls[0][0] as CaptureReadyEvent[];
|
|
619
|
+
expect(
|
|
620
|
+
events.filter((e) => e.kind === CaptureReadyEventKind.Selfie),
|
|
621
|
+
).toHaveLength(1);
|
|
622
|
+
expect(
|
|
623
|
+
events.filter((e) => e.kind === CaptureReadyEventKind.Liveness),
|
|
624
|
+
).toHaveLength(2);
|
|
625
|
+
});
|
|
544
626
|
});
|
|
545
627
|
|
|
546
628
|
/**
|
|
@@ -566,9 +648,9 @@ describe("session-boundary epoch reset — debouncer regression", () => {
|
|
|
566
648
|
isImmediate: () => false,
|
|
567
649
|
});
|
|
568
650
|
|
|
569
|
-
let previousScanState:
|
|
651
|
+
let previousScanState: UseSmileIDScanState | null = null;
|
|
570
652
|
const processTransition = (
|
|
571
|
-
nextScanState:
|
|
653
|
+
nextScanState: UseSmileIDScanState,
|
|
572
654
|
nextFeedbackKey: string,
|
|
573
655
|
) => {
|
|
574
656
|
const boundary =
|
|
@@ -585,7 +667,7 @@ describe("session-boundary epoch reset — debouncer regression", () => {
|
|
|
585
667
|
|
|
586
668
|
// found — smile key settles after the debounce window.
|
|
587
669
|
processTransition(
|
|
588
|
-
{ type:
|
|
670
|
+
{ type: UseSmileIDScanStateType.Found, feedback: "si_capture_smile" },
|
|
589
671
|
"si_capture_smile",
|
|
590
672
|
);
|
|
591
673
|
vi.advanceTimersByTime(UseSmileIDMotion.feedbackDebounce);
|
|
@@ -593,7 +675,7 @@ describe("session-boundary epoch reset — debouncer regression", () => {
|
|
|
593
675
|
|
|
594
676
|
// Entering unsatisfied is not a boundary — no reset.
|
|
595
677
|
processTransition(
|
|
596
|
-
{ type:
|
|
678
|
+
{ type: UseSmileIDScanStateType.Unsatisfied },
|
|
597
679
|
"si_selfie_capture_unsatisfied",
|
|
598
680
|
);
|
|
599
681
|
vi.advanceTimersByTime(UseSmileIDMotion.feedbackDebounce);
|
|
@@ -605,7 +687,7 @@ describe("session-boundary epoch reset — debouncer regression", () => {
|
|
|
605
687
|
// Leaving unsatisfied is a boundary — without the reset the repeated
|
|
606
688
|
// smile key would be suppressed as a duplicate.
|
|
607
689
|
processTransition(
|
|
608
|
-
{ type:
|
|
690
|
+
{ type: UseSmileIDScanStateType.Found, feedback: "si_capture_smile" },
|
|
609
691
|
"si_capture_smile",
|
|
610
692
|
);
|
|
611
693
|
// seed() emits synchronously; no timer advance needed.
|
|
@@ -615,4 +697,84 @@ describe("session-boundary epoch reset — debouncer regression", () => {
|
|
|
615
697
|
"si_capture_smile",
|
|
616
698
|
]);
|
|
617
699
|
});
|
|
700
|
+
|
|
701
|
+
// Document capture has no Start button, so a scan timeout has to leave the
|
|
702
|
+
// user a way forward — the sibling SDKs surface the manual shutter as the
|
|
703
|
+
// recovery affordance (their shared scan state sets `showCaptureButton` on
|
|
704
|
+
// the timeout state). Without these, a timed-out flow is a dead end: only
|
|
705
|
+
// Back and ✕ remain.
|
|
706
|
+
describe("document capture timeout recovery", () => {
|
|
707
|
+
function renderDocumentScreen(props: {
|
|
708
|
+
readonly captureMode: ReturnType<typeof DocumentCaptureMode.AutoCapture>;
|
|
709
|
+
readonly allowGalleryUpload?: boolean;
|
|
710
|
+
}) {
|
|
711
|
+
const tree = render(
|
|
712
|
+
<UseSmileIDCaptureScreen
|
|
713
|
+
analyzer={fakeAnalyzer}
|
|
714
|
+
captureType={CaptureType.document}
|
|
715
|
+
captureMode={props.captureMode}
|
|
716
|
+
allowGalleryUpload={props.allowGalleryUpload ?? true}
|
|
717
|
+
/>,
|
|
718
|
+
);
|
|
719
|
+
// The overlay and its controls only mount once the canvas is measured;
|
|
720
|
+
// `onLayout` never fires under the test renderer, so drive it (landscape,
|
|
721
|
+
// as a document capture screen is).
|
|
722
|
+
act(() => {
|
|
723
|
+
findByTestID(tree.root, "si_capture_screen")!.props.onLayout({
|
|
724
|
+
nativeEvent: { layout: { width: 800, height: 400 } },
|
|
725
|
+
});
|
|
726
|
+
});
|
|
727
|
+
return tree;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function emitTimeout() {
|
|
731
|
+
expect(capturedOnResult).not.toBeNull();
|
|
732
|
+
act(() => {
|
|
733
|
+
capturedOnResult!({
|
|
734
|
+
output: { faces: [], brightness: 0 },
|
|
735
|
+
state: { type: UseSmileIDScanStateType.Timeout },
|
|
736
|
+
capturedEvents: [],
|
|
737
|
+
});
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
it("offers the manual shutter after a timeout, in every capture mode", () => {
|
|
742
|
+
const { root } = renderDocumentScreen({
|
|
743
|
+
captureMode: DocumentCaptureMode.AutoCapture,
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
emitTimeout();
|
|
747
|
+
|
|
748
|
+
expect(findByTestID(root, "si_document_manual_shutter")).not.toBeNull();
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
it("keeps the gallery button available after a timeout", () => {
|
|
752
|
+
const { root } = renderDocumentScreen({
|
|
753
|
+
captureMode: DocumentCaptureMode.AutoCaptureWithManualFallback({
|
|
754
|
+
activateManualAfterMs: 3000,
|
|
755
|
+
}),
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
emitTimeout();
|
|
759
|
+
|
|
760
|
+
expect(findByTestID(root, "si_document_gallery_upload")).not.toBeNull();
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
it("leaves the manual shutter usable after a timeout", () => {
|
|
764
|
+
const { root } = renderDocumentScreen({
|
|
765
|
+
captureMode: DocumentCaptureMode.ManualCapture,
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
emitTimeout();
|
|
769
|
+
|
|
770
|
+
const shutter = findByTestID(root, "si_document_manual_shutter");
|
|
771
|
+
expect(shutter).not.toBeNull();
|
|
772
|
+
// The timeout must not latch the one-shot delivery gate, or the button
|
|
773
|
+
// renders but does nothing.
|
|
774
|
+
act(() => {
|
|
775
|
+
shutter!.props.onPress();
|
|
776
|
+
});
|
|
777
|
+
expect(mockedTakePhoto).toHaveBeenCalledTimes(1);
|
|
778
|
+
});
|
|
779
|
+
});
|
|
618
780
|
});
|
|
@@ -104,7 +104,7 @@ describe("UseSmileIDDocumentBackInstructions", () => {
|
|
|
104
104
|
const skip = findByTestID(root, "si_document_skip_back_button");
|
|
105
105
|
expect(skip).not.toBeNull();
|
|
106
106
|
act(() => {
|
|
107
|
-
(skip!.props.
|
|
107
|
+
(skip!.props.onClick as () => void)();
|
|
108
108
|
});
|
|
109
109
|
expect(onSkip).toHaveBeenCalledTimes(1);
|
|
110
110
|
});
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
act,
|
|
6
6
|
type ReactTestInstance,
|
|
7
7
|
} from "react-test-renderer";
|
|
8
|
-
import { I18nManager,
|
|
8
|
+
import { I18nManager, StyleSheet, Text } from "react-native";
|
|
9
9
|
import { UseSmileIDPreviewScreen } from "../use_smile_id_preview_screen";
|
|
10
10
|
import { defaultLightTheme } from "../../theme/theme";
|
|
11
11
|
|
|
@@ -14,7 +14,7 @@ import { defaultLightTheme } from "../../theme/theme";
|
|
|
14
14
|
* - Image at the oval rect (not full-bleed)
|
|
15
15
|
* - Title + confirmation buttons + optional attribution in card
|
|
16
16
|
* - Accept / Retake gating from `resolvePreviewState`
|
|
17
|
-
* -
|
|
17
|
+
* - The confirm/retake pair is fixed (not customisable)
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
function render(element: React.ReactElement) {
|
|
@@ -164,46 +164,16 @@ describe("UseSmileIDPreviewScreen", () => {
|
|
|
164
164
|
}
|
|
165
165
|
});
|
|
166
166
|
|
|
167
|
-
it("
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
// affordances.
|
|
172
|
-
const onAccept = vi.fn();
|
|
173
|
-
const onReject = vi.fn();
|
|
167
|
+
it("always renders the fixed confirmation-button pair (not customisable)", () => {
|
|
168
|
+
// Preview buttons are intentionally not customisable: the screen always
|
|
169
|
+
// renders the fixed confirm/retake pair. Re-adding a slot API is a product
|
|
170
|
+
// decision, not a bug fix.
|
|
174
171
|
const { root } = render(
|
|
175
|
-
<UseSmileIDPreviewScreen
|
|
176
|
-
capturedSelfiePath={PATH}
|
|
177
|
-
onAccept={onAccept}
|
|
178
|
-
onReject={onReject}
|
|
179
|
-
continueButton={({ onClick }) => (
|
|
180
|
-
<Pressable testID="si_custom_continue" onPress={onClick}>
|
|
181
|
-
<Text>Confirm</Text>
|
|
182
|
-
</Pressable>
|
|
183
|
-
)}
|
|
184
|
-
cancelButton={({ onClick }) => (
|
|
185
|
-
<Pressable testID="si_custom_cancel" onPress={onClick}>
|
|
186
|
-
<Text>Retake</Text>
|
|
187
|
-
</Pressable>
|
|
188
|
-
)}
|
|
189
|
-
/>,
|
|
172
|
+
<UseSmileIDPreviewScreen capturedSelfiePath={PATH} />,
|
|
190
173
|
);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
// Default row must be gone — guards against a future refactor
|
|
195
|
-
// that double-renders the row alongside the slots.
|
|
196
|
-
expect(findByTestID(root, "si_preview_confirmation_buttons")).toBeNull();
|
|
197
|
-
|
|
198
|
-
act(() => {
|
|
199
|
-
(findByTestID(root, "si_custom_continue")!.props.onPress as () => void)();
|
|
200
|
-
});
|
|
201
|
-
expect(onAccept).toHaveBeenCalledTimes(1);
|
|
202
|
-
|
|
203
|
-
act(() => {
|
|
204
|
-
(findByTestID(root, "si_custom_cancel")!.props.onPress as () => void)();
|
|
205
|
-
});
|
|
206
|
-
expect(onReject).toHaveBeenCalledTimes(1);
|
|
174
|
+
expect(
|
|
175
|
+
findByTestID(root, "si_preview_confirmation_buttons"),
|
|
176
|
+
).not.toBeNull();
|
|
207
177
|
});
|
|
208
178
|
|
|
209
179
|
it("renders the card title in the theme primary color", () => {
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
|
+
import { create as createRenderer, act } from "react-test-renderer";
|
|
3
|
+
import * as ScreenOrientation from "expo-screen-orientation";
|
|
4
|
+
import { UseSmileIDCrashReporting } from "@smileid/usesmileid_bridge";
|
|
5
|
+
import type { DocumentOrientation } from "../../../../core/models/document_type";
|
|
6
|
+
import {
|
|
7
|
+
useCaptureOrientationLock,
|
|
8
|
+
resetUnsupportedLockWarningsForTesting,
|
|
9
|
+
} from "../use_capture_orientation_lock";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Lifecycle tests for `useCaptureOrientationLock`:
|
|
13
|
+
* - mount asserts the screen's own orientation
|
|
14
|
+
* - unmount applies the configured exit lock (portrait-up by default)
|
|
15
|
+
* - a host build that cannot honour the lock is warned about (dev builds,
|
|
16
|
+
* once per target) and reported (every build)
|
|
17
|
+
*
|
|
18
|
+
* The `expo-screen-orientation` mock lives in `setup_react_native.ts`.
|
|
19
|
+
* `__DEV__` is bundler-injected and deliberately NOT defined suite-wide —
|
|
20
|
+
* each test sets exactly the build shape it pins.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const mockedLockAsync = vi.mocked(ScreenOrientation.lockAsync);
|
|
24
|
+
const mockedSupportsLock = vi.mocked(
|
|
25
|
+
ScreenOrientation.supportsOrientationLockAsync,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const globalWithDev = globalThis as { __DEV__?: boolean };
|
|
29
|
+
|
|
30
|
+
function LockHost(props: {
|
|
31
|
+
readonly orientation: DocumentOrientation;
|
|
32
|
+
readonly exitLock?: ScreenOrientation.OrientationLock;
|
|
33
|
+
}) {
|
|
34
|
+
useCaptureOrientationLock(props.orientation, {
|
|
35
|
+
...(props.exitLock !== undefined ? { exitLock: props.exitLock } : {}),
|
|
36
|
+
});
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function flushPromises(): Promise<void> {
|
|
41
|
+
// A macrotask tick drains every pending microtask chain first, so this stays
|
|
42
|
+
// correct if the hook gains or loses `await`s.
|
|
43
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 0));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function mountHost(
|
|
47
|
+
props: Parameters<typeof LockHost>[0],
|
|
48
|
+
): Promise<ReturnType<typeof createRenderer>> {
|
|
49
|
+
let tree!: ReturnType<typeof createRenderer>;
|
|
50
|
+
act(() => {
|
|
51
|
+
tree = createRenderer(<LockHost {...props} />);
|
|
52
|
+
});
|
|
53
|
+
await act(async () => {
|
|
54
|
+
await flushPromises();
|
|
55
|
+
});
|
|
56
|
+
return tree;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
describe("useCaptureOrientationLock", () => {
|
|
60
|
+
let savedDev: boolean | undefined;
|
|
61
|
+
|
|
62
|
+
beforeEach(() => {
|
|
63
|
+
savedDev = globalWithDev.__DEV__;
|
|
64
|
+
delete globalWithDev.__DEV__;
|
|
65
|
+
resetUnsupportedLockWarningsForTesting();
|
|
66
|
+
mockedLockAsync.mockReset();
|
|
67
|
+
mockedLockAsync.mockResolvedValue(undefined);
|
|
68
|
+
mockedSupportsLock.mockReset();
|
|
69
|
+
mockedSupportsLock.mockResolvedValue(true);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
afterEach(() => {
|
|
73
|
+
if (savedDev === undefined) {
|
|
74
|
+
delete globalWithDev.__DEV__;
|
|
75
|
+
} else {
|
|
76
|
+
globalWithDev.__DEV__ = savedDev;
|
|
77
|
+
}
|
|
78
|
+
vi.restoreAllMocks();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("locks landscape on mount for a landscape document", async () => {
|
|
82
|
+
const tree = await mountHost({ orientation: "Landscape" });
|
|
83
|
+
|
|
84
|
+
expect(mockedLockAsync).toHaveBeenCalledTimes(1);
|
|
85
|
+
expect(mockedLockAsync).toHaveBeenCalledWith(
|
|
86
|
+
ScreenOrientation.OrientationLock.LANDSCAPE,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
await act(async () => {
|
|
90
|
+
tree.unmount();
|
|
91
|
+
await flushPromises();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("restores portrait-up on unmount when no exit lock is configured", async () => {
|
|
96
|
+
const tree = await mountHost({ orientation: "Landscape" });
|
|
97
|
+
mockedLockAsync.mockClear();
|
|
98
|
+
|
|
99
|
+
await act(async () => {
|
|
100
|
+
tree.unmount();
|
|
101
|
+
await flushPromises();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(mockedLockAsync).toHaveBeenCalledTimes(1);
|
|
105
|
+
expect(mockedLockAsync).toHaveBeenCalledWith(
|
|
106
|
+
ScreenOrientation.OrientationLock.PORTRAIT_UP,
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("applies the configured exit lock on unmount instead of portrait-up", async () => {
|
|
111
|
+
const tree = await mountHost({
|
|
112
|
+
orientation: "Landscape",
|
|
113
|
+
exitLock: ScreenOrientation.OrientationLock.DEFAULT,
|
|
114
|
+
});
|
|
115
|
+
mockedLockAsync.mockClear();
|
|
116
|
+
|
|
117
|
+
await act(async () => {
|
|
118
|
+
tree.unmount();
|
|
119
|
+
await flushPromises();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(mockedLockAsync).toHaveBeenCalledTimes(1);
|
|
123
|
+
expect(mockedLockAsync).toHaveBeenCalledWith(
|
|
124
|
+
ScreenOrientation.OrientationLock.DEFAULT,
|
|
125
|
+
);
|
|
126
|
+
expect(mockedLockAsync).not.toHaveBeenCalledWith(
|
|
127
|
+
ScreenOrientation.OrientationLock.PORTRAIT_UP,
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("warns and reports once when the host build cannot honour the lock", async () => {
|
|
132
|
+
// Pins the reporting contract for any build where the platform declares
|
|
133
|
+
// the lock unsupported (lockAsync would resolve without rotating).
|
|
134
|
+
globalWithDev.__DEV__ = true;
|
|
135
|
+
mockedSupportsLock.mockResolvedValue(false);
|
|
136
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
137
|
+
const captureException = vi
|
|
138
|
+
.spyOn(UseSmileIDCrashReporting, "captureException")
|
|
139
|
+
.mockImplementation(() => {});
|
|
140
|
+
|
|
141
|
+
const tree = await mountHost({ orientation: "Landscape" });
|
|
142
|
+
|
|
143
|
+
expect(captureException).toHaveBeenCalledTimes(1);
|
|
144
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
145
|
+
expect(warn.mock.calls[0]?.[0]).toContain("orientation");
|
|
146
|
+
|
|
147
|
+
await act(async () => {
|
|
148
|
+
tree.unmount();
|
|
149
|
+
await flushPromises();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("reports without warning when __DEV__ is absent (production build)", async () => {
|
|
154
|
+
mockedSupportsLock.mockResolvedValue(false);
|
|
155
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
156
|
+
const captureException = vi
|
|
157
|
+
.spyOn(UseSmileIDCrashReporting, "captureException")
|
|
158
|
+
.mockImplementation(() => {});
|
|
159
|
+
|
|
160
|
+
const tree = await mountHost({ orientation: "Landscape" });
|
|
161
|
+
|
|
162
|
+
expect(captureException).toHaveBeenCalledTimes(1);
|
|
163
|
+
expect(warn).not.toHaveBeenCalled();
|
|
164
|
+
|
|
165
|
+
await act(async () => {
|
|
166
|
+
tree.unmount();
|
|
167
|
+
await flushPromises();
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("warns once across capture-screen remounts for the same target", async () => {
|
|
172
|
+
globalWithDev.__DEV__ = true;
|
|
173
|
+
mockedSupportsLock.mockResolvedValue(false);
|
|
174
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
175
|
+
const captureException = vi
|
|
176
|
+
.spyOn(UseSmileIDCrashReporting, "captureException")
|
|
177
|
+
.mockImplementation(() => {});
|
|
178
|
+
|
|
179
|
+
const first = await mountHost({ orientation: "Landscape" });
|
|
180
|
+
await act(async () => {
|
|
181
|
+
first.unmount();
|
|
182
|
+
await flushPromises();
|
|
183
|
+
});
|
|
184
|
+
const second = await mountHost({ orientation: "Landscape" });
|
|
185
|
+
|
|
186
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
187
|
+
expect(captureException).toHaveBeenCalledTimes(2);
|
|
188
|
+
|
|
189
|
+
await act(async () => {
|
|
190
|
+
second.unmount();
|
|
191
|
+
await flushPromises();
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("stays silent when the host build permits the lock", async () => {
|
|
196
|
+
globalWithDev.__DEV__ = true;
|
|
197
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
198
|
+
const captureException = vi
|
|
199
|
+
.spyOn(UseSmileIDCrashReporting, "captureException")
|
|
200
|
+
.mockImplementation(() => {});
|
|
201
|
+
|
|
202
|
+
const tree = await mountHost({ orientation: "Portrait" });
|
|
203
|
+
|
|
204
|
+
expect(captureException).not.toHaveBeenCalled();
|
|
205
|
+
expect(warn).not.toHaveBeenCalled();
|
|
206
|
+
|
|
207
|
+
await act(async () => {
|
|
208
|
+
tree.unmount();
|
|
209
|
+
await flushPromises();
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
});
|