@@ -29,6 +29,11 @@ class AuthTests: RPCBaseTests {
2929 static let kFakeRecaptchaVersion = " RecaptchaVersion "
3030 static let kRpId = " FAKE_RP_ID "
3131 static let kChallenge = " Y2hhbGxlbmdl "
32+ private let kCredentialID = " FAKE_CREDENTIAL_ID "
33+ private let kClientDataJSON = " FAKE_CLIENT_DATA "
34+ private let kAuthenticatorData = " FAKE_AUTHENTICATOR_DATA "
35+ private let kSignature = " FAKE_SIGNATURE "
36+ private let kUserId = " FAKE_USERID "
3237 var auth : Auth !
3338 static var testNum = 0
3439 var authDispatcherCallback : ( ( ) -> Void ) ?
@@ -2510,5 +2515,119 @@ class AuthTests: RPCBaseTests {
25102515 }
25112516 waitForExpectations ( timeout: 5 )
25122517 }
2518+
2519+ /// Helper mock to simulate platform credential fields
2520+ struct MockPlatformCredential {
2521+ let credentialID : Data
2522+ let clientDataJSON : Data
2523+ let authenticatorData : Data
2524+ let signature : Data
2525+ let userID : Data
2526+ }
2527+
2528+ private func buildFinalizeRequest( mock: MockPlatformCredential )
2529+ -> FinalizePasskeySignInRequest {
2530+ return FinalizePasskeySignInRequest (
2531+ credentialID: kCredentialID,
2532+ clientDataJSON: kClientDataJSON,
2533+ authenticatorData: kAuthenticatorData,
2534+ signature: kSignature,
2535+ userId: kUserId,
2536+ requestConfiguration: auth!. requestConfiguration
2537+ )
2538+ }
2539+
2540+ func testFinalizePasskeysigninSuccess( ) async throws {
2541+ setFakeGetAccountProvider ( )
2542+ let expectation = expectation ( description: #function)
2543+ rpcIssuer. respondBlock = {
2544+ let request = try XCTUnwrap ( self . rpcIssuer? . request as? FinalizePasskeySignInRequest )
2545+ XCTAssertEqual ( request. credentialID, self . kCredentialID)
2546+ XCTAssertNotNil ( request. credentialID)
2547+ XCTAssertEqual ( request. clientDataJSON, self . kClientDataJSON)
2548+ XCTAssertNotNil ( request. clientDataJSON)
2549+ XCTAssertEqual ( request. authenticatorData, self . kAuthenticatorData)
2550+ XCTAssertNotNil ( request. authenticatorData)
2551+ XCTAssertEqual ( request. signature, self . kSignature)
2552+ XCTAssertNotNil ( request. signature)
2553+ XCTAssertEqual ( request. userId, self . kUserId)
2554+ XCTAssertNotNil ( request. userId)
2555+ return try self . rpcIssuer. respond (
2556+ withJSON: [
2557+ " idToken " : RPCBaseTests . kFakeAccessToken,
2558+ " refreshToken " : self . kRefreshToken,
2559+ ]
2560+ )
2561+ }
2562+ let mock = MockPlatformCredential (
2563+ credentialID: Data ( kCredentialID. utf8) ,
2564+ clientDataJSON: Data ( kClientDataJSON. utf8) ,
2565+ authenticatorData: Data ( kAuthenticatorData. utf8) ,
2566+ signature: Data ( kSignature. utf8) ,
2567+ userID: Data ( kUserId. utf8)
2568+ )
2569+ Task {
2570+ let request = self . buildFinalizeRequest ( mock: mock)
2571+ _ = try await self . authBackend. call ( with: request)
2572+ expectation. fulfill ( )
2573+ }
2574+ XCTAssertNotNil ( AuthTests . kFakeAccessToken)
2575+ await fulfillment ( of: [ expectation] , timeout: 5 )
2576+ }
2577+
2578+ func testFinalizePasskeySignInFailure( ) async throws {
2579+ setFakeGetAccountProvider ( )
2580+ let expectation = expectation ( description: #function)
2581+ rpcIssuer. respondBlock = {
2582+ // Simulate backend error (e.g., OperationNotAllowed)
2583+ try self . rpcIssuer. respond ( serverErrorMessage: " OPERATION_NOT_ALLOWED " )
2584+ }
2585+ let mock = MockPlatformCredential (
2586+ credentialID: Data ( kCredentialID. utf8) ,
2587+ clientDataJSON: Data ( kClientDataJSON. utf8) ,
2588+ authenticatorData: Data ( kAuthenticatorData. utf8) ,
2589+ signature: Data ( kSignature. utf8) ,
2590+ userID: Data ( kUserId. utf8)
2591+ )
2592+ Task {
2593+ let request = self . buildFinalizeRequest ( mock: mock)
2594+ do {
2595+ _ = try await self . authBackend. call ( with: request)
2596+ XCTFail ( " Expected error but got success " )
2597+ } catch {
2598+ let nsError = error as NSError
2599+ XCTAssertEqual ( nsError. code, AuthErrorCode . operationNotAllowed. rawValue)
2600+ expectation. fulfill ( )
2601+ }
2602+ }
2603+ await fulfillment ( of: [ expectation] , timeout: 5 )
2604+ }
2605+
2606+ func testFinalizePasskeySignInFailureWithoutAssertion( ) async throws {
2607+ setFakeGetAccountProvider ( )
2608+ let expectation = expectation ( description: #function)
2609+ rpcIssuer. respondBlock = {
2610+ try self . rpcIssuer. respond ( serverErrorMessage: " INVALID_AUTHENTICATOR_RESPONSE " )
2611+ }
2612+ let mock = MockPlatformCredential (
2613+ credentialID: Data ( kCredentialID. utf8) ,
2614+ clientDataJSON: Data ( ) , // Empty or missing data
2615+ authenticatorData: Data ( kAuthenticatorData. utf8) ,
2616+ signature: Data ( ) , // Empty or missing data
2617+ userID: Data ( kUserId. utf8)
2618+ )
2619+ Task {
2620+ let request = self . buildFinalizeRequest ( mock: mock)
2621+ do {
2622+ _ = try await self . authBackend. call ( with: request)
2623+ XCTFail ( " Expected invalid_authenticator_response error " )
2624+ } catch {
2625+ let nsError = error as NSError
2626+ XCTAssertEqual ( nsError. code, AuthErrorCode . invalidAuthenticatorResponse. rawValue)
2627+ expectation. fulfill ( )
2628+ }
2629+ }
2630+ await fulfillment ( of: [ expectation] , timeout: 5 )
2631+ }
25132632 }
25142633#endif
0 commit comments