// // Copyright Amazon.com Inc. or its affiliates. // All Rights Reserved. // // SPDX-License-Identifier: Apache-2.0 // import Foundation import XCTest @testable import Amplify @testable import AWSCognitoAuthPlugin import AWSCognitoIdentityProvider import ClientRuntime class UserBehaviorResendCodeTests: BasePluginTest { /// Test a successful resendConfirmationCode call with .done as next step /// /// - Given: an auth plugin with mocked service. Mocked service calls should mock a successul response /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get a successful result with .email as the attribute's destination /// func testSuccessfulResendConfirmationCode() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in GetUserAttributeVerificationCodeOutputResponse( codeDeliveryDetails: .init( attributeName: "attributeName", deliveryMedium: .email, destination: "destination")) }) let attribute = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) guard case .email = attribute.destination else { XCTFail("Result should be .email for attributeKey") return } } /// Test a resendConfirmationCode call with invalid result /// /// - Given: an auth plugin with mocked service. Mocked service calls should mock a invalid response /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get an .unknown error /// func testResendConfirmationCodeWithInvalidResult() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in GetUserAttributeVerificationCodeOutputResponse() }) do { _ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) XCTFail("Should return an error if the result from service is invalid") } catch { guard case AuthError.unknown = error else { XCTFail("Should produce an unknown error") return } } } /// Test a resendConfirmationCode call with CodeMismatchException response from service /// /// - Given: an auth plugin with mocked service. Mocked service should mock a /// CodeMismatchException response /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get a .service error with .codeMismatch as underlyingError /// func testResendConfirmationCodeWithCodeMismatchException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in throw SdkError.service( GetUserAttributeVerificationCodeOutputError.codeDeliveryFailureException( .init()), .init(body: .empty, statusCode: .accepted)) }) do { _ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) XCTFail("Should return an error if the result from service is invalid") } catch { guard case AuthError.service(_, _, let underlyingError) = error else { XCTFail("Should produce service error instead of \(error)") return } guard case .codeDelivery = (underlyingError as? AWSCognitoAuthError) else { XCTFail("Underlying error should be codeMismatch \(error)") return } } } /// Test a resendConfirmationCode call with InternalErrorException response from service /// /// - Given: an auth plugin with mocked service. Mocked service should mock a InternalErrorException response /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get an .unknown error /// func testResendConfirmationCodeWithInternalErrorException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in throw GetUserAttributeVerificationCodeOutputError.internalErrorException(.init()) }) do { _ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) XCTFail("Should return an error if the result from service is invalid") } catch { guard case AuthError.unknown = error else { XCTFail("Should produce an unknown error instead of \(error)") return } } } /// Test a resendConfirmationCode call with InvalidParameterException response from service /// /// - Given: an auth plugin with mocked service. Mocked service should mock a /// InvalidParameterException response /// /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get a .service error with .invalidParameter as underlyingError /// func testResendConfirmationCodeWithInvalidParameterException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in throw GetUserAttributeVerificationCodeOutputError.invalidParameterException(.init()) }) do { _ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) XCTFail("Should return an error if the result from service is invalid") } catch { guard case AuthError.service(_, _, let underlyingError) = error else { XCTFail("Should produce service error instead of \(error)") return } guard case .invalidParameter = (underlyingError as? AWSCognitoAuthError) else { XCTFail("Underlying error should be invalidParameter \(error)") return } } } /// Test a resendConfirmationCode call with LimitExceededException response from service /// /// - Given: an auth plugin with mocked service. Mocked service should mock a /// LimitExceededException response /// /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get a .service error with .limitExceeded as underlyingError /// func testResendConfirmationCodeWithLimitExceededException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in throw GetUserAttributeVerificationCodeOutputError.limitExceededException(.init()) }) do { _ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) XCTFail("Should return an error if the result from service is invalid") } catch { guard case AuthError.service(_, _, let underlyingError) = error else { XCTFail("Should produce service error instead of \(error)") return } guard case .limitExceeded = (underlyingError as? AWSCognitoAuthError) else { XCTFail("Underlying error should be limitExceeded \(error)") return } } } /// Test a resendConfirmationCode call with NotAuthorizedException response from service /// /// - Given: an auth plugin with mocked service. Mocked service should mock a /// NotAuthorizedException response /// /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get a .notAuthorized error /// func testResendConfirmationCodeWithNotAuthorizedException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in throw GetUserAttributeVerificationCodeOutputError.notAuthorizedException(.init()) }) do { _ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) XCTFail("Should return an error if the result from service is invalid") } catch { guard case AuthError.notAuthorized = error else { XCTFail("Should produce notAuthorized error instead of \(error)") return } } } /// Test a resendConfirmationCode call with PasswordResetRequiredException response from service /// /// - Given: an auth plugin with mocked service. Mocked service should mock a /// PasswordResetRequiredException response /// /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get a .service error with .passwordResetRequired as underlyingError /// func testResendConfirmationCodeWithPasswordResetRequiredException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in throw GetUserAttributeVerificationCodeOutputError.passwordResetRequiredException(.init()) }) do { _ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) XCTFail("Should return an error if the result from service is invalid") } catch { guard case AuthError.service(_, _, let underlyingError) = error else { XCTFail("Should produce service error instead of \(error)") return } guard case .passwordResetRequired = (underlyingError as? AWSCognitoAuthError) else { XCTFail("Underlying error should be passwordResetRequired \(error)") return } } } /// Test a resendConfirmationCode call with ResourceNotFoundException response from service /// /// - Given: an auth plugin with mocked service. Mocked service should mock a /// ResourceNotFoundException response /// /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get a .service error with .resourceNotFound as underlyingError /// func testResendConfirmationCodeWithResourceNotFoundException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in throw GetUserAttributeVerificationCodeOutputError.resourceNotFoundException(.init()) }) do { _ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) XCTFail("Should return an error if the result from service is invalid") } catch { guard case AuthError.service(_, _, let underlyingError) = error else { XCTFail("Should produce service error instead of \(error)") return } guard case .resourceNotFound = (underlyingError as? AWSCognitoAuthError) else { XCTFail("Underlying error should be resourceNotFound \(error)") return } } } /// Test a resendConfirmationCode call with TooManyRequestsException response from service /// /// - Given: an auth plugin with mocked service. Mocked service should mock a /// TooManyRequestsException response /// /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get a .service error with .requestLimitExceeded as underlyingError /// func testResendConfirmationCodeWithTooManyRequestsException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in throw GetUserAttributeVerificationCodeOutputError.tooManyRequestsException(.init()) }) do { _ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) XCTFail("Should return an error if the result from service is invalid") } catch { guard case AuthError.service(_, _, let underlyingError) = error else { XCTFail("Should produce service error instead of \(error)") return } guard case .requestLimitExceeded = (underlyingError as? AWSCognitoAuthError) else { XCTFail("Underlying error should be requestLimitExceeded \(error)") return } } } /// Test a resendConfirmationCode call with UserNotFound response from service /// /// - Given: an auth plugin with mocked service. Mocked service should mock a /// UserNotConfirmedException response /// /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get a .service error with .userNotConfirmed as underlyingError /// func testResendConfirmationCodeWithUserNotConfirmedException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in throw GetUserAttributeVerificationCodeOutputError.userNotConfirmedException(.init()) }) do { _ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) XCTFail("Should return an error if the result from service is invalid") } catch { guard case AuthError.service(_, _, let underlyingError) = error else { XCTFail("Should produce service error instead of \(error)") return } guard case .userNotConfirmed = (underlyingError as? AWSCognitoAuthError) else { XCTFail("Underlying error should be userNotConfirmed \(error)") return } } } /// Test a resendConfirmationCode call with UserNotFound response from service /// /// - Given: an auth plugin with mocked service. Mocked service should mock a /// UserNotFoundException response /// /// - When: /// - I invoke resendConfirmationCode /// - Then: /// - I should get a .service error with .userNotFound as underlyingError /// func testResendConfirmationCodeWithUserNotFoundException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutputResponse: { _ in throw GetUserAttributeVerificationCodeOutputError.userNotFoundException(.init()) }) do { _ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email) XCTFail("Should return an error if the result from service is invalid") } catch { guard case AuthError.service(_, _, let underlyingError) = error else { XCTFail("Should produce service error instead of \(error)") return } guard case .userNotFound = (underlyingError as? AWSCognitoAuthError) else { XCTFail("Underlying error should be userNotFound \(error)") return } } } }