EmailLinkAuthTests.swift 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Copyright 2020 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import Foundation
  15. import Combine
  16. import XCTest
  17. import FirebaseAuth
  18. class EmailLinkAuthTests: XCTestCase {
  19. static let apiKey = Credentials.apiKey
  20. static let accessTokenTimeToLive: TimeInterval = 60 * 60
  21. static let refreshToken = "REFRESH_TOKEN"
  22. static let accessToken = "ACCESS_TOKEN"
  23. static let email = "johnnyappleseed@apple.com"
  24. static let password = "secret"
  25. static let localID = "LOCAL_ID"
  26. static let displayName = "Johnny Appleseed"
  27. static let passwordHash = "UkVEQUNURUQ="
  28. static let fakeEmailSignInlink =
  29. "https://test.app.goo.gl/?link=https://test.firebaseapp.com/__/auth/action?apiKey%3DtestAPIKey%26mode%3DsignIn%26oobCode%3Dtestoobcode%26continueUrl%3Dhttps://test.apps.com&ibi=com.test.com&ifl=https://test.firebaseapp.com/__/auth/action?apiKey%3DtestAPIKey%26mode%3DsignIn%26oobCode%3Dtestoobcode%26continueUrl%3Dhttps://test.apps.com"
  30. static let fakeOOBCode = "testoobcode"
  31. static let continueURL = "continueURL"
  32. class MockEmailLinkSignInResponse: FIREmailLinkSignInResponse {
  33. override var idToken: String { return EmailLinkAuthTests.accessToken }
  34. override var refreshToken: String { return EmailLinkAuthTests.refreshToken }
  35. override var approximateExpirationDate: Date {
  36. Date(timeIntervalSinceNow: EmailLinkAuthTests.accessTokenTimeToLive)
  37. }
  38. }
  39. class MockGetAccountInfoResponseUser: FIRGetAccountInfoResponseUser {
  40. override var localID: String { return EmailLinkAuthTests.localID }
  41. override var email: String { return EmailLinkAuthTests.email }
  42. override var displayName: String { return EmailLinkAuthTests.displayName }
  43. }
  44. class MockGetAccountInfoResponse: FIRGetAccountInfoResponse {
  45. override var users: [FIRGetAccountInfoResponseUser] {
  46. return [MockGetAccountInfoResponseUser(dictionary: [:])]
  47. }
  48. }
  49. class MockGetOOBConfirmationCodeResponse: FIRGetOOBConfirmationCodeResponse {
  50. override var oobCode: String { return EmailLinkAuthTests.fakeOOBCode }
  51. }
  52. class MockAuthBackend: AuthBackendImplementationMock {
  53. override func getAccountInfo(_ request: FIRGetAccountInfoRequest,
  54. callback: @escaping FIRGetAccountInfoResponseCallback) {
  55. XCTAssertEqual(request.apiKey, EmailLinkAuthTests.apiKey)
  56. XCTAssertEqual(request.accessToken, EmailLinkAuthTests.accessToken)
  57. let response = MockGetAccountInfoResponse()
  58. callback(response, nil)
  59. }
  60. override func emailLinkSignin(_ request: FIREmailLinkSignInRequest,
  61. callback: @escaping FIREmailLinkSigninResponseCallback) {
  62. XCTAssertEqual(request.apiKey, EmailLinkAuthTests.apiKey)
  63. XCTAssertEqual(request.email, EmailLinkAuthTests.email)
  64. XCTAssertEqual(request.oobCode, EmailLinkAuthTests.fakeOOBCode)
  65. callback(MockEmailLinkSignInResponse(), nil)
  66. }
  67. override func getOOBConfirmationCode(_ request: FIRGetOOBConfirmationCodeRequest,
  68. callback: @escaping FIRGetOOBConfirmationCodeResponseCallback) {
  69. XCTAssertEqual(request.apiKey, EmailLinkAuthTests.apiKey)
  70. XCTAssertEqual(request.email, EmailLinkAuthTests.email)
  71. XCTAssertEqual(request.continueURL, EmailLinkAuthTests.continueURL)
  72. XCTAssertTrue(request.handleCodeInApp)
  73. callback(MockGetOOBConfirmationCodeResponse(), nil)
  74. }
  75. }
  76. func app() -> FirebaseApp {
  77. FirebaseApp.appForAuthUnitTestsWithName(name: "app1")
  78. }
  79. func testSignInUserWithEmailAndLink() {
  80. // given
  81. FIRAuthBackend.setBackendImplementation(MockAuthBackend())
  82. let auth = Auth.auth(app: app())
  83. var cancellables = Set<AnyCancellable>()
  84. let userSignInExpectation = expectation(description: "User signed in")
  85. // when
  86. auth
  87. .signIn(withEmail: EmailLinkAuthTests.email, link: EmailLinkAuthTests.fakeEmailSignInlink)
  88. .sink { completion in
  89. switch completion {
  90. case .finished:
  91. print("Finished")
  92. case let .failure(error):
  93. XCTFail("💥 Something went wrong: \(error)")
  94. }
  95. } receiveValue: { authDataResult in
  96. XCTAssertNotNil(authDataResult.user)
  97. XCTAssertEqual(authDataResult.user.refreshToken, EmailLinkAuthTests.refreshToken)
  98. XCTAssertFalse(authDataResult.user.isAnonymous)
  99. XCTAssertEqual(authDataResult.user.email, EmailLinkAuthTests.email)
  100. userSignInExpectation.fulfill()
  101. }
  102. .store(in: &cancellables)
  103. // then
  104. wait(for: [userSignInExpectation], timeout: expectationTimeout)
  105. }
  106. func testSendSignInLinkToEmail() {
  107. // given
  108. FIRAuthBackend.setBackendImplementation(MockAuthBackend())
  109. let auth = Auth.auth(app: app())
  110. var cancellables = Set<AnyCancellable>()
  111. let sendSignInLinkExpectation = expectation(description: "Sign in link sent")
  112. let actionSettings = ActionCodeSettings()
  113. actionSettings.url = URL(string: EmailLinkAuthTests.continueURL)
  114. actionSettings.handleCodeInApp = true
  115. // when
  116. auth
  117. .sendSignInLink(toEmail: EmailLinkAuthTests.email, actionCodeSettings: actionSettings)
  118. .sink { completion in
  119. switch completion {
  120. case .finished:
  121. print("Finished")
  122. case let .failure(error):
  123. XCTFail("💥 Something went wrong: \(error)")
  124. }
  125. } receiveValue: {
  126. sendSignInLinkExpectation.fulfill()
  127. }
  128. .store(in: &cancellables)
  129. // then
  130. wait(for: [sendSignInLinkExpectation], timeout: expectationTimeout)
  131. }
  132. }