@@ -1891,3 +1891,111 @@ class UserTests: RPCBaseTests {
1891
1891
}
1892
1892
}
1893
1893
}
1894
+
1895
+ #if os(iOS)
1896
+ import AuthenticationServices
1897
+
1898
+ @available ( iOS 15 . 0 , * )
1899
+ extension UserTests {
1900
+ func testStartPasskeyEnrollmentSuccess( ) async throws {
1901
+ setFakeGetAccountProvider ( )
1902
+ let expectation = expectation ( description: #function)
1903
+ signInWithEmailPasswordReturnFakeUser { user in
1904
+ do {
1905
+ // Mock backend response for StartPasskeyEnrollment
1906
+ self . rpcIssuer. respondBlock = {
1907
+ let request = try XCTUnwrap ( self . rpcIssuer? . request as? StartPasskeyEnrollmentRequest )
1908
+ XCTAssertEqual ( request. idToken, RPCBaseTests . kFakeAccessToken)
1909
+ return try self . rpcIssuer. respond (
1910
+ withJSON: [
1911
+ " credentialCreationOptions " : [
1912
+ " rp " : [ " id " : " example.com " ] ,
1913
+ " user " : [ " id " : " VXNlcklE " ] , // Base64 userID
1914
+ " challenge " : " Q2hhbGxlbmdl " , // Base64 challenge
1915
+ ] ,
1916
+ ]
1917
+ )
1918
+ }
1919
+ Task {
1920
+ let request = try await user. startPasskeyEnrollment ( withName: " MyPasskey " )
1921
+ XCTAssertEqual ( request. name, " MyPasskey " )
1922
+ XCTAssertNotNil ( request. challenge)
1923
+ XCTAssertNotNil ( request. userID)
1924
+ expectation. fulfill ( )
1925
+ }
1926
+ } catch {
1927
+ XCTFail ( " Unexpected error: \( error) " )
1928
+ }
1929
+ }
1930
+ await fulfillment ( of: [ expectation] , timeout: 5 )
1931
+ }
1932
+
1933
+ func testStartPasskeyEnrollmentWithNilNameSuccess( ) async throws {
1934
+ setFakeGetAccountProvider ( )
1935
+ let expectation = expectation ( description: #function)
1936
+ signInWithEmailPasswordReturnFakeUser { user in
1937
+ self . rpcIssuer. respondBlock = {
1938
+ try self . rpcIssuer. respond (
1939
+ withJSON: [
1940
+ " credentialCreationOptions " : [
1941
+ " rp " : [ " id " : " example.com " ] ,
1942
+ " user " : [ " id " : " VXNlcklE " ] ,
1943
+ " challenge " : " Q2hhbGxlbmdl " ,
1944
+ ] ,
1945
+ ]
1946
+ )
1947
+ }
1948
+ Task {
1949
+ let request = try await user. startPasskeyEnrollment ( withName: nil )
1950
+ XCTAssertEqual ( request. name, " Unnamed account (Apple) " )
1951
+ expectation. fulfill ( )
1952
+ }
1953
+ }
1954
+ await fulfillment ( of: [ expectation] , timeout: 5 )
1955
+ }
1956
+
1957
+ func testStartPasskeyEnrollmentWithEmptyNameSuccess( ) async throws {
1958
+ setFakeGetAccountProvider ( )
1959
+ let expectation = expectation ( description: #function)
1960
+ signInWithEmailPasswordReturnFakeUser { user in
1961
+ self . rpcIssuer. respondBlock = {
1962
+ try self . rpcIssuer. respond (
1963
+ withJSON: [
1964
+ " credentialCreationOptions " : [
1965
+ " rp " : [ " id " : " example.com " ] ,
1966
+ " user " : [ " id " : " VXNlcklE " ] ,
1967
+ " challenge " : " Q2hhbGxlbmdl " ,
1968
+ ] ,
1969
+ ]
1970
+ )
1971
+ }
1972
+ Task {
1973
+ let request = try await user. startPasskeyEnrollment ( withName: " " )
1974
+ XCTAssertEqual ( request. name, " Unnamed account (Apple) " )
1975
+ expectation. fulfill ( )
1976
+ }
1977
+ }
1978
+ await fulfillment ( of: [ expectation] , timeout: 5 )
1979
+ }
1980
+
1981
+ func testStartPasskeyEnrollmentFailure( ) async throws {
1982
+ setFakeGetAccountProvider ( )
1983
+ let expectation = expectation ( description: #function)
1984
+ signInWithEmailPasswordReturnFakeUser { user in
1985
+ self . rpcIssuer. respondBlock = {
1986
+ try self . rpcIssuer. respond ( serverErrorMessage: " OPERATION_NOT_ALLOWED " )
1987
+ }
1988
+ Task {
1989
+ do {
1990
+ _ = try await user. startPasskeyEnrollment ( withName: " FailCase " )
1991
+ XCTFail ( " Expected to throw error " )
1992
+ } catch let error as NSError {
1993
+ XCTAssertEqual ( error. code, AuthErrorCode . operationNotAllowed. rawValue)
1994
+ expectation. fulfill ( )
1995
+ }
1996
+ }
1997
+ }
1998
+ await fulfillment ( of: [ expectation] , timeout: 5 )
1999
+ }
2000
+ }
2001
+ #endif
0 commit comments