@smileid/usesmileid 12.0.0 → 12.0.2
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 +8 -0
- package/README.md +1 -1
- package/dist/camera/camera_defaults.d.ts +2 -0
- package/dist/camera/camera_defaults.d.ts.map +1 -1
- package/dist/camera/camera_defaults.js +2 -0
- package/dist/camera/camera_defaults.js.map +1 -1
- 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/flow_exceptions.d.ts +4 -2
- package/dist/core/exception/flow_exceptions.d.ts.map +1 -1
- package/dist/core/exception/flow_exceptions.js +3 -2
- package/dist/core/exception/flow_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/missing_job_type_exception.d.ts +1 -3
- package/dist/core/exception/missing_job_type_exception.d.ts.map +1 -1
- package/dist/core/exception/missing_job_type_exception.js +2 -4
- package/dist/core/exception/missing_job_type_exception.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 +5 -1
- package/dist/data/api/smile_id_api.d.ts.map +1 -1
- package/dist/data/api/smile_id_api.js +30 -27
- package/dist/data/api/smile_id_api.js.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/model/job_request.d.ts +28 -12
- package/dist/data/model/job_request.d.ts.map +1 -1
- package/dist/data/model/token_payload.d.ts +78 -0
- package/dist/data/model/token_payload.d.ts.map +1 -0
- package/dist/data/model/token_payload.js +132 -0
- package/dist/data/model/token_payload.js.map +1 -0
- package/dist/data/model/user_details_payload.d.ts +39 -0
- package/dist/data/model/user_details_payload.d.ts.map +1 -0
- package/dist/data/model/user_details_payload.js +53 -0
- package/dist/data/model/user_details_payload.js.map +1 -0
- 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/data/util/use_smile_id_token_decoder.d.ts +15 -3
- package/dist/data/util/use_smile_id_token_decoder.d.ts.map +1 -1
- package/dist/data/util/use_smile_id_token_decoder.js +20 -8
- package/dist/data/util/use_smile_id_token_decoder.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/l10n/strings_en.d.ts +4 -1
- package/dist/l10n/strings_en.d.ts.map +1 -1
- package/dist/l10n/strings_en.js +4 -1
- package/dist/l10n/strings_en.js.map +1 -1
- package/dist/l10n/use_smile_id_localizations.d.ts +10 -0
- package/dist/l10n/use_smile_id_localizations.d.ts.map +1 -1
- package/dist/l10n/use_smile_id_localizations.js +59 -3
- package/dist/l10n/use_smile_id_localizations.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_button.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_button.js +8 -2
- package/dist/presentation/components/use_smile_id_button.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 +6 -12
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.js +7 -12
- package/dist/presentation/flow/dsl/builder/screens_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js +23 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.d.ts +22 -3
- package/dist/presentation/flow/flow_navigation_manager.d.ts.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.js +84 -46
- 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/screen/orchestrated_processing_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_processing_screen.js +25 -5
- package/dist/presentation/flow/screen/orchestrated_processing_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 +45 -12
- package/dist/presentation/flow/use_smile_id_flow.js.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.d.ts +16 -2
- package/dist/presentation/flow/validation/flow_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.js +61 -47
- package/dist/presentation/flow/validation/flow_validator.js.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.d.ts +7 -0
- package/dist/presentation/flow/validation/job_type_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.js +52 -27
- package/dist/presentation/flow/validation/job_type_validator.js.map +1 -1
- package/dist/presentation/flow/validation/user_details_validator.d.ts +9 -0
- package/dist/presentation/flow/validation/user_details_validator.d.ts.map +1 -0
- package/dist/presentation/flow/validation/user_details_validator.js +40 -0
- package/dist/presentation/flow/validation/user_details_validator.js.map +1 -0
- package/dist/presentation/screen/helpers/capture_screen_helpers.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/capture_screen_helpers.js +1 -0
- package/dist/presentation/screen/helpers/capture_screen_helpers.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 +90 -23
- 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__/react_native_mock.tsx +22 -0
- package/src/__tests__/setup_react_native.ts +17 -2
- package/src/__tests__/snapshots/__snapshots__/screens_structural.test.tsx.snap +5267 -0
- package/src/__tests__/snapshots/screens_structural.test.tsx +230 -0
- package/src/camera/__tests__/camera_permissions.test.ts +72 -0
- package/src/camera/__tests__/camera_system_focus.test.ts +173 -0
- package/src/camera/__tests__/use_smile_id_camera_preview.test.tsx +461 -0
- package/src/camera/__tests__/use_smile_id_camera_system.test.ts +103 -0
- package/src/camera/__tests__/use_smile_id_frame_stream_hook.test.tsx +229 -0
- package/src/camera/camera_defaults.ts +3 -0
- package/src/core/exception/__tests__/builder_validation_exceptions.test.ts +81 -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/flow_exceptions.test.ts +10 -0
- package/src/core/exception/flow_exceptions.ts +3 -2
- package/src/core/exception/index.ts +1 -0
- package/src/core/exception/missing_job_type_exception.ts +2 -4
- 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 +275 -1
- package/src/data/api/interceptors/__tests__/credential_header_redaction.test.ts +144 -0
- 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/api/smile_id_api.ts +36 -49
- package/src/data/compression/__tests__/payload_compressor_real_jpeg.test.ts +6 -2
- package/src/data/dsl/__tests__/use_smile_id_network_builder.test.ts +157 -0
- 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/model/__tests__/token_payload.test.ts +224 -0
- package/src/data/model/__tests__/user_details_payload.test.ts +100 -0
- package/src/data/model/job_request.ts +27 -12
- package/src/data/model/token_payload.ts +182 -0
- package/src/data/model/user_details_payload.ts +84 -0
- package/src/data/repository/__tests__/network_retries.test.ts +1 -1
- package/src/data/repository/__tests__/repository_dispatch.test.ts +366 -0
- 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/security/__tests__/signing_crypto.test.ts +203 -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/__tests__/use_smile_id_token_decoder.test.ts +179 -0
- package/src/data/util/retry_util.ts +9 -1
- package/src/data/util/use_smile_id_token_decoder.ts +29 -8
- package/src/index.ts +6 -4
- package/src/l10n/__tests__/use_smile_id_localizations.test.ts +122 -5
- package/src/l10n/__tests__/use_smile_id_localizations_provider.test.tsx +112 -0
- package/src/l10n/__tests__/use_smile_id_localizations_surface.test.ts +231 -0
- package/src/l10n/strings_en.ts +5 -1
- package/src/l10n/use_smile_id_localizations.ts +80 -3
- package/src/metadata/__tests__/device_orientation_sampling.test.ts +165 -0
- package/src/metadata/__tests__/geolocation.test.ts +150 -0
- 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__/optional_native_modules.test.ts +234 -0
- package/src/metadata/__tests__/use_smile_id_metadata.test.ts +1 -1
- package/src/metadata/__tests__/use_smile_id_metadata_factory.test.ts +615 -0
- 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_content_card.test.tsx +112 -0
- package/src/presentation/components/__tests__/use_smile_id_enhanced_smart_selfie_clip.test.tsx +9 -4
- package/src/presentation/components/__tests__/use_smile_id_face_oval_image.test.tsx +190 -0
- package/src/presentation/components/__tests__/use_smile_id_instructions_hero.test.tsx +44 -0
- package/src/presentation/components/__tests__/use_smile_id_learn_more_content.test.tsx +159 -0
- package/src/presentation/components/__tests__/use_smile_id_processing_center_indicator.test.tsx +88 -0
- package/src/presentation/components/use_smile_id_button.tsx +7 -2
- 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 +372 -1
- package/src/presentation/flow/__tests__/use_smile_id_flow.test.tsx +651 -0
- package/src/presentation/flow/dsl/__tests__/use_smile_id_builder_component.test.tsx +120 -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 +7 -12
- package/src/presentation/flow/dsl/use_smile_id_flow_builder.ts +27 -1
- package/src/presentation/flow/flow_navigation_manager.ts +108 -93
- package/src/presentation/flow/graph/__tests__/screen_renderer.test.tsx +102 -0
- package/src/presentation/flow/model/instructions_defaults.ts +1 -1
- package/src/presentation/flow/screen/__tests__/orchestrated_capture_screen.test.tsx +836 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_consent_screen.test.tsx +165 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_instructions_screen.test.tsx +163 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_preview_screen.test.tsx +224 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_processing_screen.test.tsx +338 -0
- 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/screen/orchestrated_processing_screen.tsx +42 -5
- package/src/presentation/flow/use_smile_id_flow.tsx +63 -12
- package/src/presentation/flow/validation/__tests__/flow_validator.test.ts +219 -1
- package/src/presentation/flow/validation/__tests__/job_type_validator.test.ts +200 -0
- package/src/presentation/flow/validation/flow_validator.ts +85 -57
- package/src/presentation/flow/validation/job_type_validator.ts +73 -39
- package/src/presentation/flow/validation/user_details_validator.ts +53 -0
- 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__/feedback_copy_table.test.ts +145 -0
- 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 +524 -14
- package/src/presentation/screen/__tests__/use_smile_id_document_back_instructions.test.tsx +4 -2
- package/src/presentation/screen/__tests__/use_smile_id_permission_screen.test.tsx +68 -0
- 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_screen_helpers.ts +1 -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 +107 -28
- 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/theme/__tests__/use_use_smile_id_fonts.test.tsx +166 -0
- 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.
|
|
@@ -446,6 +476,18 @@ describe("UseSmileIDCaptureScreen", () => {
|
|
|
446
476
|
expect(mockedSetBrightness).toHaveBeenCalledWith(1);
|
|
447
477
|
});
|
|
448
478
|
|
|
479
|
+
it("asks for dark status-bar content, matching the white capture scrim", () => {
|
|
480
|
+
const { root } = render(
|
|
481
|
+
<UseSmileIDCaptureScreen
|
|
482
|
+
analyzer={fakeAnalyzer}
|
|
483
|
+
captureType={CaptureType.selfie}
|
|
484
|
+
/>,
|
|
485
|
+
);
|
|
486
|
+
expect(root.findAllByType(StatusBar)[0]!.props.barStyle).toBe(
|
|
487
|
+
"dark-content",
|
|
488
|
+
);
|
|
489
|
+
});
|
|
490
|
+
|
|
449
491
|
it("renders a translucent status bar so the preview is edge-to-edge", () => {
|
|
450
492
|
// Translucent status bar = full-bleed window = full-screen oval reference.
|
|
451
493
|
const { root } = render(
|
|
@@ -507,22 +549,22 @@ describe("UseSmileIDCaptureScreen", () => {
|
|
|
507
549
|
// Stale events → unsatisfied reset (drops them) → fresh events → finished.
|
|
508
550
|
emit({
|
|
509
551
|
output,
|
|
510
|
-
state: { type:
|
|
552
|
+
state: { type: UseSmileIDScanStateType.Found },
|
|
511
553
|
capturedEvents: [staleSelfie, staleLiveness],
|
|
512
554
|
});
|
|
513
555
|
emit({
|
|
514
556
|
output,
|
|
515
|
-
state: { type:
|
|
557
|
+
state: { type: UseSmileIDScanStateType.Unsatisfied },
|
|
516
558
|
capturedEvents: [],
|
|
517
559
|
});
|
|
518
560
|
emit({
|
|
519
561
|
output,
|
|
520
|
-
state: { type:
|
|
562
|
+
state: { type: UseSmileIDScanStateType.Found },
|
|
521
563
|
capturedEvents: [freshSelfie, freshLiveness],
|
|
522
564
|
});
|
|
523
565
|
emit({
|
|
524
566
|
output,
|
|
525
|
-
state: { type:
|
|
567
|
+
state: { type: UseSmileIDScanStateType.Finished },
|
|
526
568
|
capturedEvents: [],
|
|
527
569
|
});
|
|
528
570
|
|
|
@@ -541,6 +583,58 @@ describe("UseSmileIDCaptureScreen", () => {
|
|
|
541
583
|
expect.objectContaining({ retries: 1 }),
|
|
542
584
|
);
|
|
543
585
|
});
|
|
586
|
+
|
|
587
|
+
it("replays the shared selfie scenario to a full capture completion", async () => {
|
|
588
|
+
// Drives the capture gap headlessly through the frame stream's onResult
|
|
589
|
+
// seam: the shared scenario replayed to `finished` must reach
|
|
590
|
+
// onCaptureComplete with the scripted selfie + liveness events.
|
|
591
|
+
const onCaptureComplete = vi.fn();
|
|
592
|
+
const analyzer = makeFakeAnalyzer();
|
|
593
|
+
capturedOnResult = null;
|
|
594
|
+
render(
|
|
595
|
+
<UseSmileIDCaptureScreen
|
|
596
|
+
analyzer={analyzer}
|
|
597
|
+
captureType={CaptureType.selfie}
|
|
598
|
+
onCaptureComplete={onCaptureComplete}
|
|
599
|
+
/>,
|
|
600
|
+
);
|
|
601
|
+
expect(capturedOnResult).not.toBeNull();
|
|
602
|
+
|
|
603
|
+
// Consume the real shared scenario (not a hand-written copy) so a drift in
|
|
604
|
+
// the canonical script is caught here rather than silently diverging.
|
|
605
|
+
const scenarioDir = dirname(import.meta.url.replace(/^file:\/\//, ""));
|
|
606
|
+
const scenario = parseScriptedScenario(
|
|
607
|
+
JSON.parse(
|
|
608
|
+
readFileSync(
|
|
609
|
+
join(
|
|
610
|
+
scenarioDir,
|
|
611
|
+
"../../../../../e2e/scenarios/selfie-happy-path.json",
|
|
612
|
+
),
|
|
613
|
+
"utf8",
|
|
614
|
+
),
|
|
615
|
+
),
|
|
616
|
+
);
|
|
617
|
+
for (const result of scriptedFaceScanResults(scenario, {
|
|
618
|
+
livenessCount: 2,
|
|
619
|
+
})) {
|
|
620
|
+
act(() => {
|
|
621
|
+
capturedOnResult!(result);
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
await act(async () => {
|
|
625
|
+
await Promise.resolve();
|
|
626
|
+
await Promise.resolve();
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
expect(onCaptureComplete).toHaveBeenCalledTimes(1);
|
|
630
|
+
const events = onCaptureComplete.mock.calls[0][0] as CaptureReadyEvent[];
|
|
631
|
+
expect(
|
|
632
|
+
events.filter((e) => e.kind === CaptureReadyEventKind.Selfie),
|
|
633
|
+
).toHaveLength(1);
|
|
634
|
+
expect(
|
|
635
|
+
events.filter((e) => e.kind === CaptureReadyEventKind.Liveness),
|
|
636
|
+
).toHaveLength(2);
|
|
637
|
+
});
|
|
544
638
|
});
|
|
545
639
|
|
|
546
640
|
/**
|
|
@@ -566,9 +660,9 @@ describe("session-boundary epoch reset — debouncer regression", () => {
|
|
|
566
660
|
isImmediate: () => false,
|
|
567
661
|
});
|
|
568
662
|
|
|
569
|
-
let previousScanState:
|
|
663
|
+
let previousScanState: UseSmileIDScanState | null = null;
|
|
570
664
|
const processTransition = (
|
|
571
|
-
nextScanState:
|
|
665
|
+
nextScanState: UseSmileIDScanState,
|
|
572
666
|
nextFeedbackKey: string,
|
|
573
667
|
) => {
|
|
574
668
|
const boundary =
|
|
@@ -585,7 +679,7 @@ describe("session-boundary epoch reset — debouncer regression", () => {
|
|
|
585
679
|
|
|
586
680
|
// found — smile key settles after the debounce window.
|
|
587
681
|
processTransition(
|
|
588
|
-
{ type:
|
|
682
|
+
{ type: UseSmileIDScanStateType.Found, feedback: "si_capture_smile" },
|
|
589
683
|
"si_capture_smile",
|
|
590
684
|
);
|
|
591
685
|
vi.advanceTimersByTime(UseSmileIDMotion.feedbackDebounce);
|
|
@@ -593,7 +687,7 @@ describe("session-boundary epoch reset — debouncer regression", () => {
|
|
|
593
687
|
|
|
594
688
|
// Entering unsatisfied is not a boundary — no reset.
|
|
595
689
|
processTransition(
|
|
596
|
-
{ type:
|
|
690
|
+
{ type: UseSmileIDScanStateType.Unsatisfied },
|
|
597
691
|
"si_selfie_capture_unsatisfied",
|
|
598
692
|
);
|
|
599
693
|
vi.advanceTimersByTime(UseSmileIDMotion.feedbackDebounce);
|
|
@@ -605,7 +699,7 @@ describe("session-boundary epoch reset — debouncer regression", () => {
|
|
|
605
699
|
// Leaving unsatisfied is a boundary — without the reset the repeated
|
|
606
700
|
// smile key would be suppressed as a duplicate.
|
|
607
701
|
processTransition(
|
|
608
|
-
{ type:
|
|
702
|
+
{ type: UseSmileIDScanStateType.Found, feedback: "si_capture_smile" },
|
|
609
703
|
"si_capture_smile",
|
|
610
704
|
);
|
|
611
705
|
// seed() emits synchronously; no timer advance needed.
|
|
@@ -615,4 +709,420 @@ describe("session-boundary epoch reset — debouncer regression", () => {
|
|
|
615
709
|
"si_capture_smile",
|
|
616
710
|
]);
|
|
617
711
|
});
|
|
712
|
+
|
|
713
|
+
// Document capture has no Start button, so a scan timeout has to leave the
|
|
714
|
+
// user a way forward — the sibling SDKs surface the manual shutter as the
|
|
715
|
+
// recovery affordance (their shared scan state sets `showCaptureButton` on
|
|
716
|
+
// the timeout state). Without these, a timed-out flow is a dead end: only
|
|
717
|
+
// Back and ✕ remain.
|
|
718
|
+
describe("document capture timeout recovery", () => {
|
|
719
|
+
function renderDocumentScreen(props: {
|
|
720
|
+
readonly captureMode: ReturnType<typeof DocumentCaptureMode.AutoCapture>;
|
|
721
|
+
readonly allowGalleryUpload?: boolean;
|
|
722
|
+
}) {
|
|
723
|
+
const tree = render(
|
|
724
|
+
<UseSmileIDCaptureScreen
|
|
725
|
+
analyzer={fakeAnalyzer}
|
|
726
|
+
captureType={CaptureType.document}
|
|
727
|
+
captureMode={props.captureMode}
|
|
728
|
+
allowGalleryUpload={props.allowGalleryUpload ?? true}
|
|
729
|
+
/>,
|
|
730
|
+
);
|
|
731
|
+
// The overlay and its controls only mount once the canvas is measured;
|
|
732
|
+
// `onLayout` never fires under the test renderer, so drive it (landscape,
|
|
733
|
+
// as a document capture screen is).
|
|
734
|
+
act(() => {
|
|
735
|
+
findByTestID(tree.root, "si_capture_screen")!.props.onLayout({
|
|
736
|
+
nativeEvent: { layout: { width: 800, height: 400 } },
|
|
737
|
+
});
|
|
738
|
+
});
|
|
739
|
+
return tree;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function emitTimeout() {
|
|
743
|
+
expect(capturedOnResult).not.toBeNull();
|
|
744
|
+
act(() => {
|
|
745
|
+
capturedOnResult!({
|
|
746
|
+
output: { faces: [], brightness: 0 },
|
|
747
|
+
state: { type: UseSmileIDScanStateType.Timeout },
|
|
748
|
+
capturedEvents: [],
|
|
749
|
+
});
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
it("offers the manual shutter after a timeout, in every capture mode", () => {
|
|
754
|
+
const { root } = renderDocumentScreen({
|
|
755
|
+
captureMode: DocumentCaptureMode.AutoCapture,
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
emitTimeout();
|
|
759
|
+
|
|
760
|
+
expect(findByTestID(root, "si_document_manual_shutter")).not.toBeNull();
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
it("keeps the gallery button available after a timeout", () => {
|
|
764
|
+
const { root } = renderDocumentScreen({
|
|
765
|
+
captureMode: DocumentCaptureMode.AutoCaptureWithManualFallback({
|
|
766
|
+
activateManualAfterMs: 3000,
|
|
767
|
+
}),
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
emitTimeout();
|
|
771
|
+
|
|
772
|
+
expect(findByTestID(root, "si_document_gallery_upload")).not.toBeNull();
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
it("leaves the manual shutter usable after a timeout", () => {
|
|
776
|
+
const { root } = renderDocumentScreen({
|
|
777
|
+
captureMode: DocumentCaptureMode.ManualCapture,
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
emitTimeout();
|
|
781
|
+
|
|
782
|
+
const shutter = findByTestID(root, "si_document_manual_shutter");
|
|
783
|
+
expect(shutter).not.toBeNull();
|
|
784
|
+
// The timeout must not latch the one-shot delivery gate, or the button
|
|
785
|
+
// renders but does nothing.
|
|
786
|
+
act(() => {
|
|
787
|
+
shutter!.props.onPress();
|
|
788
|
+
});
|
|
789
|
+
expect(mockedTakePhoto).toHaveBeenCalledTimes(1);
|
|
790
|
+
});
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
describe("selfie capture timeout recovery", () => {
|
|
794
|
+
function renderSelfieScreen() {
|
|
795
|
+
return render(
|
|
796
|
+
<UseSmileIDCaptureScreen
|
|
797
|
+
analyzer={fakeAnalyzer}
|
|
798
|
+
captureType={CaptureType.selfie}
|
|
799
|
+
/>,
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
function startCapture(root: ReactTestInstance) {
|
|
804
|
+
act(() => {
|
|
805
|
+
findByTestID(root, "si_capture_start_button")!.props.onClick();
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
function emit(state: UseSmileIDScanState) {
|
|
810
|
+
expect(capturedOnResult).not.toBeNull();
|
|
811
|
+
act(() => {
|
|
812
|
+
capturedOnResult!({
|
|
813
|
+
output: { faces: [], brightness: 0 },
|
|
814
|
+
state,
|
|
815
|
+
capturedEvents: [],
|
|
816
|
+
});
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
it("offers Start again after a timeout", () => {
|
|
821
|
+
const { root } = renderSelfieScreen();
|
|
822
|
+
startCapture(root);
|
|
823
|
+
|
|
824
|
+
emit({ type: UseSmileIDScanStateType.Timeout });
|
|
825
|
+
|
|
826
|
+
const start = findByTestID(root, "si_capture_start_button");
|
|
827
|
+
expect(start).not.toBeNull();
|
|
828
|
+
expect(start!.props.enabled).toBe(true);
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
it("resets the native session when Start is tapped after a timeout", async () => {
|
|
832
|
+
const { root } = renderSelfieScreen();
|
|
833
|
+
startCapture(root);
|
|
834
|
+
emit({ type: UseSmileIDScanStateType.Timeout });
|
|
835
|
+
fakeAnalyzer.reset.mockClear();
|
|
836
|
+
|
|
837
|
+
startCapture(root);
|
|
838
|
+
await act(async () => {
|
|
839
|
+
await Promise.resolve();
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
// The native session is terminal after a timeout — without a reset the
|
|
843
|
+
// first retry frame re-reports Timeout and re-latches the error.
|
|
844
|
+
expect(fakeAnalyzer.reset).toHaveBeenCalledTimes(1);
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
it("restarts the session when Start is tapped after a timeout", () => {
|
|
848
|
+
const onStartCapture = vi.fn();
|
|
849
|
+
const { root } = render(
|
|
850
|
+
<UseSmileIDCaptureScreen
|
|
851
|
+
analyzer={fakeAnalyzer}
|
|
852
|
+
captureType={CaptureType.selfie}
|
|
853
|
+
onStartCapture={onStartCapture}
|
|
854
|
+
/>,
|
|
855
|
+
);
|
|
856
|
+
startCapture(root);
|
|
857
|
+
emit({ type: UseSmileIDScanStateType.Timeout });
|
|
858
|
+
|
|
859
|
+
startCapture(root);
|
|
860
|
+
|
|
861
|
+
expect(onStartCapture).toHaveBeenCalledTimes(2);
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
it("still delivers a capture that completes on the retry", async () => {
|
|
865
|
+
const onCaptureComplete = vi.fn();
|
|
866
|
+
const { root } = render(
|
|
867
|
+
<UseSmileIDCaptureScreen
|
|
868
|
+
analyzer={fakeAnalyzer}
|
|
869
|
+
captureType={CaptureType.selfie}
|
|
870
|
+
onCaptureComplete={onCaptureComplete}
|
|
871
|
+
/>,
|
|
872
|
+
);
|
|
873
|
+
startCapture(root);
|
|
874
|
+
emit({ type: UseSmileIDScanStateType.Timeout });
|
|
875
|
+
startCapture(root);
|
|
876
|
+
|
|
877
|
+
emit({ type: UseSmileIDScanStateType.Finished });
|
|
878
|
+
await act(async () => {
|
|
879
|
+
await Promise.resolve();
|
|
880
|
+
await Promise.resolve();
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
expect(onCaptureComplete).toHaveBeenCalledTimes(1);
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
it("drops a capture that lands after the timeout was already reported", async () => {
|
|
887
|
+
const onCaptureComplete = vi.fn();
|
|
888
|
+
const onCaptureTimeout = vi.fn();
|
|
889
|
+
const { root } = render(
|
|
890
|
+
<UseSmileIDCaptureScreen
|
|
891
|
+
analyzer={fakeAnalyzer}
|
|
892
|
+
captureType={CaptureType.selfie}
|
|
893
|
+
onCaptureComplete={onCaptureComplete}
|
|
894
|
+
onCaptureTimeout={onCaptureTimeout}
|
|
895
|
+
/>,
|
|
896
|
+
);
|
|
897
|
+
startCapture(root);
|
|
898
|
+
|
|
899
|
+
emit({ type: UseSmileIDScanStateType.Timeout });
|
|
900
|
+
emit({ type: UseSmileIDScanStateType.Finished });
|
|
901
|
+
await act(async () => {
|
|
902
|
+
await Promise.resolve();
|
|
903
|
+
await Promise.resolve();
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
expect(onCaptureTimeout).toHaveBeenCalledTimes(1);
|
|
907
|
+
expect(onCaptureComplete).not.toHaveBeenCalled();
|
|
908
|
+
});
|
|
909
|
+
|
|
910
|
+
it("does not pad the retry with frames banked before the timeout", async () => {
|
|
911
|
+
const onCaptureComplete = vi.fn();
|
|
912
|
+
const { root } = render(
|
|
913
|
+
<UseSmileIDCaptureScreen
|
|
914
|
+
analyzer={fakeAnalyzer}
|
|
915
|
+
captureType={CaptureType.selfie}
|
|
916
|
+
onCaptureComplete={onCaptureComplete}
|
|
917
|
+
/>,
|
|
918
|
+
);
|
|
919
|
+
startCapture(root);
|
|
920
|
+
act(() => {
|
|
921
|
+
capturedOnResult!({
|
|
922
|
+
output: { faces: [], brightness: 0 },
|
|
923
|
+
state: { type: UseSmileIDScanStateType.Found },
|
|
924
|
+
capturedEvents: [
|
|
925
|
+
{
|
|
926
|
+
kind: CaptureReadyEventKind.Liveness,
|
|
927
|
+
captureIndex: 0,
|
|
928
|
+
url: "file:///stale.jpg",
|
|
929
|
+
},
|
|
930
|
+
] as CaptureReadyEvent[],
|
|
931
|
+
});
|
|
932
|
+
});
|
|
933
|
+
emit({ type: UseSmileIDScanStateType.Timeout });
|
|
934
|
+
|
|
935
|
+
startCapture(root);
|
|
936
|
+
act(() => {
|
|
937
|
+
capturedOnResult!({
|
|
938
|
+
output: { faces: [], brightness: 0 },
|
|
939
|
+
state: { type: UseSmileIDScanStateType.Found },
|
|
940
|
+
capturedEvents: [
|
|
941
|
+
{
|
|
942
|
+
kind: CaptureReadyEventKind.Selfie,
|
|
943
|
+
captureIndex: 0,
|
|
944
|
+
url: "file:///fresh.jpg",
|
|
945
|
+
},
|
|
946
|
+
] as CaptureReadyEvent[],
|
|
947
|
+
});
|
|
948
|
+
});
|
|
949
|
+
emit({ type: UseSmileIDScanStateType.Finished });
|
|
950
|
+
await act(async () => {
|
|
951
|
+
await Promise.resolve();
|
|
952
|
+
await Promise.resolve();
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
expect(onCaptureComplete).toHaveBeenCalledTimes(1);
|
|
956
|
+
const [delivered] = onCaptureComplete.mock.calls[0] as [
|
|
957
|
+
readonly CaptureReadyEvent[],
|
|
958
|
+
];
|
|
959
|
+
expect(delivered.map((event) => event.url)).toEqual([
|
|
960
|
+
"file:///fresh.jpg",
|
|
961
|
+
]);
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
it("reports the timeout to the partner exactly once", () => {
|
|
965
|
+
const onCaptureTimeout = vi.fn();
|
|
966
|
+
const { root } = render(
|
|
967
|
+
<UseSmileIDCaptureScreen
|
|
968
|
+
analyzer={fakeAnalyzer}
|
|
969
|
+
captureType={CaptureType.selfie}
|
|
970
|
+
onCaptureTimeout={onCaptureTimeout}
|
|
971
|
+
/>,
|
|
972
|
+
);
|
|
973
|
+
startCapture(root);
|
|
974
|
+
|
|
975
|
+
emit({ type: UseSmileIDScanStateType.Timeout });
|
|
976
|
+
emit({ type: UseSmileIDScanStateType.Timeout });
|
|
977
|
+
|
|
978
|
+
expect(onCaptureTimeout).toHaveBeenCalledTimes(1);
|
|
979
|
+
});
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
describe("no camera frames at all", () => {
|
|
983
|
+
beforeEach(() => {
|
|
984
|
+
vi.useFakeTimers();
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
afterEach(() => {
|
|
988
|
+
vi.useRealTimers();
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
function renderAndStart() {
|
|
992
|
+
const tree = render(
|
|
993
|
+
<UseSmileIDCaptureScreen
|
|
994
|
+
analyzer={fakeAnalyzer}
|
|
995
|
+
captureType={CaptureType.selfie}
|
|
996
|
+
/>,
|
|
997
|
+
);
|
|
998
|
+
act(() => {
|
|
999
|
+
findByTestID(tree.root, "si_capture_start_button")!.props.onClick();
|
|
1000
|
+
});
|
|
1001
|
+
return tree;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
function elapseFirstFrameWait() {
|
|
1005
|
+
act(() => {
|
|
1006
|
+
vi.advanceTimersByTime(10_000);
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
it("names the cause instead of sitting on the initial instruction", () => {
|
|
1011
|
+
const { root } = renderAndStart();
|
|
1012
|
+
|
|
1013
|
+
elapseFirstFrameWait();
|
|
1014
|
+
|
|
1015
|
+
expect(collectText(findByTestID(root, "si_capture_feedback_text")!)).toBe(
|
|
1016
|
+
enStrings.si_capture_camera_unavailable,
|
|
1017
|
+
);
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
it("leaves the user a way to retry", () => {
|
|
1021
|
+
const { root } = renderAndStart();
|
|
1022
|
+
|
|
1023
|
+
elapseFirstFrameWait();
|
|
1024
|
+
|
|
1025
|
+
const start = findByTestID(root, "si_capture_start_button");
|
|
1026
|
+
expect(start).not.toBeNull();
|
|
1027
|
+
expect(start!.props.enabled).toBe(true);
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
it("reports a terminal timeout so the flow is not left waiting", () => {
|
|
1031
|
+
const onCaptureTimeout = vi.fn();
|
|
1032
|
+
const tree = render(
|
|
1033
|
+
<UseSmileIDCaptureScreen
|
|
1034
|
+
analyzer={fakeAnalyzer}
|
|
1035
|
+
captureType={CaptureType.selfie}
|
|
1036
|
+
onCaptureTimeout={onCaptureTimeout}
|
|
1037
|
+
/>,
|
|
1038
|
+
);
|
|
1039
|
+
act(() => {
|
|
1040
|
+
findByTestID(tree.root, "si_capture_start_button")!.props.onClick();
|
|
1041
|
+
});
|
|
1042
|
+
|
|
1043
|
+
elapseFirstFrameWait();
|
|
1044
|
+
|
|
1045
|
+
expect(onCaptureTimeout).toHaveBeenCalledTimes(1);
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
it("drops the stall copy once a frame finally arrives", () => {
|
|
1049
|
+
const { root } = renderAndStart();
|
|
1050
|
+
elapseFirstFrameWait();
|
|
1051
|
+
expect(collectText(findByTestID(root, "si_capture_feedback_text")!)).toBe(
|
|
1052
|
+
enStrings.si_capture_camera_unavailable,
|
|
1053
|
+
);
|
|
1054
|
+
|
|
1055
|
+
act(() => {
|
|
1056
|
+
capturedOnResult!({
|
|
1057
|
+
output: { faces: [], brightness: 0 },
|
|
1058
|
+
state: { type: UseSmileIDScanStateType.Initial },
|
|
1059
|
+
capturedEvents: [],
|
|
1060
|
+
});
|
|
1061
|
+
});
|
|
1062
|
+
|
|
1063
|
+
expect(
|
|
1064
|
+
collectText(findByTestID(root, "si_capture_feedback_text")!),
|
|
1065
|
+
).not.toBe(enStrings.si_capture_camera_unavailable);
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
it("still fires when the partner passes an inline callback", () => {
|
|
1069
|
+
const onCaptureTimeout = vi.fn();
|
|
1070
|
+
const screen = (
|
|
1071
|
+
<UseSmileIDCaptureScreen
|
|
1072
|
+
analyzer={fakeAnalyzer}
|
|
1073
|
+
captureType={CaptureType.selfie}
|
|
1074
|
+
onCaptureTimeout={(state) => onCaptureTimeout(state)}
|
|
1075
|
+
/>
|
|
1076
|
+
);
|
|
1077
|
+
const tree = render(screen);
|
|
1078
|
+
act(() => {
|
|
1079
|
+
findByTestID(tree.root, "si_capture_start_button")!.props.onClick();
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
for (let step = 0; step < 4; step += 1) {
|
|
1083
|
+
act(() => {
|
|
1084
|
+
tree.update(
|
|
1085
|
+
<UseSmileIDCaptureScreen
|
|
1086
|
+
analyzer={fakeAnalyzer}
|
|
1087
|
+
captureType={CaptureType.selfie}
|
|
1088
|
+
onCaptureTimeout={(state) => onCaptureTimeout(state)}
|
|
1089
|
+
/>,
|
|
1090
|
+
);
|
|
1091
|
+
});
|
|
1092
|
+
act(() => {
|
|
1093
|
+
vi.advanceTimersByTime(3_000);
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
expect(onCaptureTimeout).toHaveBeenCalledTimes(1);
|
|
1098
|
+
});
|
|
1099
|
+
|
|
1100
|
+
it("stays quiet once a frame has been analyzed", () => {
|
|
1101
|
+
const onCaptureTimeout = vi.fn();
|
|
1102
|
+
const tree = render(
|
|
1103
|
+
<UseSmileIDCaptureScreen
|
|
1104
|
+
analyzer={fakeAnalyzer}
|
|
1105
|
+
captureType={CaptureType.selfie}
|
|
1106
|
+
onCaptureTimeout={onCaptureTimeout}
|
|
1107
|
+
/>,
|
|
1108
|
+
);
|
|
1109
|
+
act(() => {
|
|
1110
|
+
findByTestID(tree.root, "si_capture_start_button")!.props.onClick();
|
|
1111
|
+
});
|
|
1112
|
+
act(() => {
|
|
1113
|
+
capturedOnResult!({
|
|
1114
|
+
output: { faces: [], brightness: 0 },
|
|
1115
|
+
state: { type: UseSmileIDScanStateType.Initial },
|
|
1116
|
+
capturedEvents: [],
|
|
1117
|
+
});
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
elapseFirstFrameWait();
|
|
1121
|
+
|
|
1122
|
+
expect(onCaptureTimeout).not.toHaveBeenCalled();
|
|
1123
|
+
expect(
|
|
1124
|
+
collectText(findByTestID(tree.root, "si_capture_feedback_text")!),
|
|
1125
|
+
).not.toBe(enStrings.si_capture_camera_unavailable);
|
|
1126
|
+
});
|
|
1127
|
+
});
|
|
618
1128
|
});
|
|
@@ -62,7 +62,9 @@ describe("UseSmileIDDocumentBackInstructions", () => {
|
|
|
62
62
|
/>,
|
|
63
63
|
);
|
|
64
64
|
expect(findByTestID(root, "si_document_back_instructions")).not.toBeNull();
|
|
65
|
-
expect(
|
|
65
|
+
expect(
|
|
66
|
+
findTextNode(root, "Flip your \u2068Green Book\u2069"),
|
|
67
|
+
).not.toBeNull();
|
|
66
68
|
});
|
|
67
69
|
|
|
68
70
|
it("invokes onCaptureBack from the primary button", () => {
|
|
@@ -104,7 +106,7 @@ describe("UseSmileIDDocumentBackInstructions", () => {
|
|
|
104
106
|
const skip = findByTestID(root, "si_document_skip_back_button");
|
|
105
107
|
expect(skip).not.toBeNull();
|
|
106
108
|
act(() => {
|
|
107
|
-
(skip!.props.
|
|
109
|
+
(skip!.props.onClick as () => void)();
|
|
108
110
|
});
|
|
109
111
|
expect(onSkip).toHaveBeenCalledTimes(1);
|
|
110
112
|
});
|