mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-11 22:55:59 +05:45
476 lines
21 KiB
Swift
476 lines
21 KiB
Swift
// Copyright 2023 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License")
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import Foundation
|
|
import XCTest
|
|
|
|
@testable import FirebaseAuth
|
|
import FirebaseCore
|
|
|
|
#if os(iOS)
|
|
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
|
|
class OAuthProviderTests: RPCBaseTests {
|
|
static let kFakeAuthorizedDomain = "test.firebaseapp.com"
|
|
static let kFakeAuthorizedWebDomain = "test.web.app"
|
|
private let kFakeAccessToken = "fakeAccessToken"
|
|
private let kFakeIDToken = "fakeIDToken"
|
|
private let kFakeProviderID = "fakeProviderID"
|
|
static let kFakeAPIKey = "asdfghjkl"
|
|
static let kFakeEmulatorHost = "emulatorhost"
|
|
static let kFakeEmulatorPort = 12345
|
|
static let kFakeClientID = "123456.apps.googleusercontent.com"
|
|
static let kFakeOAuthResponseURL = "fakeOAuthResponseURL"
|
|
static let kFakeFirebaseAppID = "1:123456789:ios:123abc456def"
|
|
static let kFakeEncodedFirebaseAppID = "app-1-123456789-ios-123abc456def"
|
|
static let kFakeTenantID = "tenantID"
|
|
static let kFakeReverseClientID = "com.googleusercontent.apps.123456"
|
|
|
|
// Switches for testing different OAuth test flows
|
|
// TODO: Consider using an enum for these instead.
|
|
static var testTenantID = false
|
|
static var testCancel = false
|
|
static var testErrorString = false
|
|
static var testInternalError = false
|
|
static var testInvalidClientID = false
|
|
static var testUnknownError = false
|
|
static var testAppID = false
|
|
static var testEmulator = false
|
|
static var testAppCheck = false
|
|
|
|
static var auth: Auth?
|
|
|
|
/** @fn testObtainingOAuthCredentialNoIDToken
|
|
@brief Tests the correct creation of an OAuthCredential without an IDToken.
|
|
*/
|
|
func testObtainingOAuthCredentialNoIDToken() throws {
|
|
initApp(#function)
|
|
let credential = OAuthProvider.credential(providerID: .apple,
|
|
accessToken: kFakeAccessToken)
|
|
XCTAssertEqual(credential.accessToken, kFakeAccessToken)
|
|
XCTAssertEqual(credential.provider, AuthProviderID.apple.rawValue)
|
|
XCTAssertNil(credential.idToken)
|
|
}
|
|
|
|
/** @fn testObtainingOAuthCredentialWithFullName
|
|
@brief Tests the correct creation of an OAuthCredential with a fullName.
|
|
*/
|
|
func testObtainingOAuthCredentialWithFullName() throws {
|
|
let kFakeGivenName = "Paul"
|
|
let kFakeFamilyName = "B"
|
|
var fullName = PersonNameComponents()
|
|
fullName.givenName = kFakeGivenName
|
|
fullName.familyName = kFakeFamilyName
|
|
initApp(#function)
|
|
let credential = OAuthProvider.appleCredential(withIDToken: kFakeIDToken, rawNonce: nil,
|
|
fullName: fullName)
|
|
XCTAssertEqual(credential.fullName, fullName)
|
|
XCTAssertEqual(credential.provider, "apple.com")
|
|
XCTAssertEqual(credential.idToken, kFakeIDToken)
|
|
XCTAssertNil(credential.accessToken)
|
|
}
|
|
|
|
/** @fn testObtainingOAuthCredentialWithIDToken
|
|
@brief Tests the correct creation of an OAuthCredential with an IDToken
|
|
*/
|
|
func testObtainingOAuthCredentialWithIDToken() throws {
|
|
initApp(#function)
|
|
let credential = OAuthProvider.credential(providerID: .email,
|
|
idToken: kFakeIDToken,
|
|
accessToken: kFakeAccessToken)
|
|
XCTAssertEqual(credential.accessToken, kFakeAccessToken)
|
|
XCTAssertEqual(credential.provider, AuthProviderID.email.rawValue)
|
|
XCTAssertEqual(credential.idToken, kFakeIDToken)
|
|
}
|
|
|
|
/** @fn testObtainingOAuthProvider
|
|
@brief Tests the correct creation of an FIROAuthProvider instance.
|
|
*/
|
|
func testObtainingOAuthProvider() throws {
|
|
initApp(#function)
|
|
let provider = OAuthProvider(providerID: kFakeProviderID, auth: OAuthProviderTests.auth!)
|
|
XCTAssertEqual(provider.providerID, kFakeProviderID)
|
|
}
|
|
|
|
/** @fn testGetCredentialWithUIDelegateWithClientID
|
|
@brief Tests a successful invocation of @c getCredentialWithUIDelegate
|
|
*/
|
|
func testGetCredentialWithUIDelegateWithClientID() throws {
|
|
initApp(#function)
|
|
try testOAuthFlow(description: #function)
|
|
}
|
|
|
|
/** @fn testGetCredentialWithUIDelegateWithTenantID
|
|
@brief Tests a successful invocation of @c getCredentialWithUIDelegate:completion:
|
|
*/
|
|
func testGetCredentialWithUIDelegateWithTenantID() throws {
|
|
initApp(#function)
|
|
|
|
// Update tenantID on workqueue to enable _protectedDataDidBecomeAvailableObserver to finish
|
|
// init.
|
|
kAuthGlobalWorkQueue.sync {
|
|
OAuthProviderTests.auth?.tenantID = OAuthProviderTests.kFakeTenantID
|
|
}
|
|
OAuthProviderTests.testTenantID = true
|
|
try testOAuthFlow(description: #function)
|
|
OAuthProviderTests.auth?.tenantID = nil
|
|
OAuthProviderTests.testTenantID = false
|
|
}
|
|
|
|
/** @fn testGetCredentialWithUIDelegateUserCancellationWithClientID
|
|
@brief Tests an unsuccessful invocation of @c testGetCredentialWithUIDelegateUserCancellationWithClientID due to user
|
|
cancelation.
|
|
*/
|
|
func testGetCredentialWithUIDelegateUserCancellationWithClientID() throws {
|
|
initApp(#function)
|
|
OAuthProviderTests.testCancel = true
|
|
try testOAuthFlow(description: #function)
|
|
OAuthProviderTests.testCancel = false
|
|
}
|
|
|
|
/** @fn testGetCredentialWithUIDelegateNetworkRequestFailedWithClientID
|
|
@brief Tests an unsuccessful invocation of @c getCredentialWithUIDelegate due to a
|
|
failed network request within the web context.
|
|
*/
|
|
func testGetCredentialWithUIDelegateNetworkRequestFailedWithClientID() throws {
|
|
initApp(#function)
|
|
OAuthProviderTests.testErrorString = true
|
|
try testOAuthFlow(description: #function)
|
|
OAuthProviderTests.testErrorString = false
|
|
}
|
|
|
|
/** @fn testGetCredentialWithUIDelegateInternalErrorWithClientID
|
|
@brief Tests an unsuccessful invocation of @c getCredentialWithUIDelegate due to an
|
|
internal error within the web context.
|
|
*/
|
|
func testGetCredentialWithUIDelegateInternalErrorWithClientID() throws {
|
|
initApp(#function)
|
|
OAuthProviderTests.testInternalError = true
|
|
try testOAuthFlow(description: #function)
|
|
OAuthProviderTests.testInternalError = false
|
|
}
|
|
|
|
/** @fn testGetCredentialWithUIDelegateInvalidClientID
|
|
@brief Tests an unsuccessful invocation of @c getCredentialWithUIDelegate due to an
|
|
use of an invalid client ID.
|
|
*/
|
|
func testGetCredentialWithUIDelegateInvalidClientID() throws {
|
|
initApp(#function)
|
|
OAuthProviderTests.testInvalidClientID = true
|
|
try testOAuthFlow(description: #function)
|
|
OAuthProviderTests.testInvalidClientID = false
|
|
}
|
|
|
|
/** @fn testGetCredentialWithUIDelegateUnknownErrorWithClientID
|
|
@brief Tests an unsuccessful invocation of @c getCredentialWithUIDelegate due to an
|
|
unknown error.
|
|
*/
|
|
func testGetCredentialWithUIDelegateUnknownErrorWithClientID() throws {
|
|
initApp(#function)
|
|
OAuthProviderTests.testUnknownError = true
|
|
try testOAuthFlow(description: #function)
|
|
OAuthProviderTests.testUnknownError = false
|
|
}
|
|
|
|
/** @fn testGetCredentialWithUIDelegateWithFirebaseAppID
|
|
@brief Tests a successful invocation of @c getCredentialWithUIDelegate
|
|
*/
|
|
func testGetCredentialWithUIDelegateWithFirebaseAppID() throws {
|
|
initApp(#function, useAppID: true, omitClientID: true,
|
|
scheme: OAuthProviderTests.kFakeEncodedFirebaseAppID)
|
|
OAuthProviderTests.testAppID = true
|
|
try testOAuthFlow(description: #function)
|
|
OAuthProviderTests.testAppID = false
|
|
}
|
|
|
|
/** @fn testGetCredentialWithUIDelegateWithFirebaseAppIDWhileClientIdPresent
|
|
@brief Tests a successful invocation of @c getCredentialWithUIDelegate when the
|
|
client ID is present in the plist file, but the encoded app ID is the registered custom URL
|
|
scheme.
|
|
*/
|
|
func testGetCredentialWithUIDelegateWithFirebaseAppIDWhileClientIdPresent() throws {
|
|
initApp(#function, useAppID: true, scheme: OAuthProviderTests.kFakeEncodedFirebaseAppID)
|
|
OAuthProviderTests.testAppID = true
|
|
try testOAuthFlow(description: #function)
|
|
OAuthProviderTests.testAppID = false
|
|
}
|
|
|
|
/** @fn testGetCredentialWithUIDelegateUseEmulator
|
|
@brief Tests a successful invocation of @c getCredentialWithUIDelegate when using the emulator.
|
|
*/
|
|
func testGetCredentialWithUIDelegateUseEmulator() throws {
|
|
initApp(#function, useAppID: true)
|
|
OAuthProviderTests.auth?.requestConfiguration.emulatorHostAndPort =
|
|
"\(OAuthProviderTests.kFakeEmulatorHost):\(OAuthProviderTests.kFakeEmulatorPort)"
|
|
OAuthProviderTests.testEmulator = true
|
|
try testOAuthFlow(description: #function)
|
|
OAuthProviderTests.testEmulator = false
|
|
}
|
|
|
|
/** @fn testGetCredentialWithUIDelegateWithAppCheckToken
|
|
@brief Tests a successful invocation of @c getCredentialWithUIDelegate
|
|
*/
|
|
func testGetCredentialWithUIDelegateWithAppCheckToken() throws {
|
|
let fakeAppCheck = FakeAppCheck()
|
|
initApp(#function, useAppID: true)
|
|
OAuthProviderTests.auth?.requestConfiguration.appCheck = fakeAppCheck
|
|
OAuthProviderTests.testAppCheck = true
|
|
try testOAuthFlow(description: #function)
|
|
OAuthProviderTests.testAppCheck = false
|
|
}
|
|
|
|
/** @fn testOAuthCredentialCoding
|
|
@brief Tests successful archiving and unarchiving of @c GoogleAuthCredential.
|
|
*/
|
|
func testOAuthCredentialCoding() throws {
|
|
let kAccessToken = "accessToken"
|
|
let kIDToken = "idToken"
|
|
let kRawNonce = "nonce"
|
|
let kSecret = "sEcret"
|
|
let kFullName = PersonNameComponents()
|
|
let kPendingToken = "pendingToken"
|
|
|
|
let credential = OAuthCredential(withProviderID: "dummyProvider",
|
|
idToken: kIDToken,
|
|
rawNonce: kRawNonce,
|
|
accessToken: kAccessToken,
|
|
secret: kSecret,
|
|
fullName: kFullName,
|
|
pendingToken: kPendingToken)
|
|
|
|
XCTAssertTrue(OAuthCredential.supportsSecureCoding)
|
|
let data = try NSKeyedArchiver.archivedData(
|
|
withRootObject: credential,
|
|
requiringSecureCoding: true
|
|
)
|
|
let unarchivedCredential = try XCTUnwrap(NSKeyedUnarchiver.unarchivedObject(
|
|
ofClasses: [OAuthCredential.self, NSPersonNameComponents.self], from: data
|
|
) as? OAuthCredential)
|
|
XCTAssertEqual(unarchivedCredential.idToken, kIDToken)
|
|
XCTAssertEqual(unarchivedCredential.rawNonce, kRawNonce)
|
|
XCTAssertEqual(unarchivedCredential.accessToken, kAccessToken)
|
|
XCTAssertEqual(unarchivedCredential.secret, kSecret)
|
|
XCTAssertEqual(unarchivedCredential.fullName, kFullName)
|
|
XCTAssertEqual(unarchivedCredential.pendingToken, kPendingToken)
|
|
XCTAssertEqual(unarchivedCredential.provider, OAuthProvider.id)
|
|
}
|
|
|
|
private func initApp(_ functionName: String, useAppID: Bool = false, omitClientID: Bool = false,
|
|
scheme: String = OAuthProviderTests.kFakeReverseClientID) {
|
|
let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
|
|
gcmSenderID: "00000000000000000-00000000000-000000000")
|
|
options.apiKey = OAuthProviderTests.kFakeAPIKey
|
|
options.projectID = "myProjectID"
|
|
if useAppID {
|
|
options.googleAppID = OAuthProviderTests.kFakeFirebaseAppID
|
|
}
|
|
if !omitClientID {
|
|
options.clientID = OAuthProviderTests.kFakeClientID
|
|
}
|
|
|
|
let strippedName = functionName.replacingOccurrences(of: "(", with: "")
|
|
.replacingOccurrences(of: ")", with: "")
|
|
FirebaseApp.configure(name: strippedName, options: options)
|
|
OAuthProviderTests.auth = Auth.auth(app: FirebaseApp.app(name: strippedName)!)
|
|
OAuthProviderTests.auth?.mainBundleUrlTypes =
|
|
[["CFBundleURLSchemes": [scheme]]]
|
|
}
|
|
|
|
private func testOAuthFlow(description: String,
|
|
with fakeAppCheck: FakeAppCheck? = nil) throws {
|
|
let expectation = self.expectation(description: description)
|
|
let provider = OAuthProvider(providerID: kFakeProviderID, auth: OAuthProviderTests.auth!)
|
|
|
|
// Use fake authURLPresenter so we can test the parameters that get sent to it.
|
|
OAuthProviderTests.auth?.authURLPresenter = FakePresenter()
|
|
|
|
// 1. Setup fakes and parameters for getCredential.
|
|
if !OAuthProviderTests.testEmulator {
|
|
let projectConfigExpectation = self.expectation(description: "projectConfiguration")
|
|
rpcIssuer?.projectConfigRequester = { request in
|
|
// 3. Validate the created Request instance.
|
|
XCTAssertEqual(request.apiKey, OAuthProviderTests.kFakeAPIKey)
|
|
XCTAssertEqual(request.endpoint, "getProjectConfig")
|
|
// 4. Fulfill the expectation.
|
|
projectConfigExpectation.fulfill()
|
|
kAuthGlobalWorkQueue.async {
|
|
do {
|
|
// 5. Send the response from the fake backend.
|
|
try self.rpcIssuer?
|
|
.respond(withJSON: ["authorizedDomains": [
|
|
OAuthProviderTests.kFakeAuthorizedWebDomain,
|
|
OAuthProviderTests.kFakeAuthorizedDomain]])
|
|
} catch {
|
|
XCTFail("Failure sending response: \(error)")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class FakePresenter: NSObject, AuthWebViewControllerDelegate {
|
|
func webViewController(_ webViewController: AuthWebViewController,
|
|
canHandle URL: URL) -> Bool {
|
|
XCTFail("Do not call")
|
|
return false
|
|
}
|
|
|
|
func webViewControllerDidCancel(_ webViewController: AuthWebViewController) {
|
|
XCTFail("Do not call")
|
|
}
|
|
|
|
func webViewController(_ webViewController: AuthWebViewController,
|
|
didFailWithError error: Error) {
|
|
XCTFail("Do not call")
|
|
}
|
|
|
|
func present(_ presentURL: URL, uiDelegate UIDelegate: AuthUIDelegate?,
|
|
callbackMatcher: @escaping (URL?) -> Bool,
|
|
completion: @escaping (URL?, Error?) -> Void) {
|
|
// 6. Verify flow triggers present in the FakePresenter class with the right parameters.
|
|
if OAuthProviderTests.testEmulator {
|
|
XCTAssertEqual(presentURL.scheme, "http")
|
|
XCTAssertEqual(presentURL.host, OAuthProviderTests.kFakeEmulatorHost)
|
|
XCTAssertEqual(presentURL.port, OAuthProviderTests.kFakeEmulatorPort)
|
|
XCTAssertEqual(presentURL.path, "/emulator/auth/handler")
|
|
} else {
|
|
XCTAssertEqual(presentURL.scheme, "https")
|
|
XCTAssertEqual(presentURL.host, OAuthProviderTests.kFakeAuthorizedDomain)
|
|
XCTAssertEqual(presentURL.path, "/__/auth/handler")
|
|
}
|
|
let params = AuthWebUtils.dictionary(withHttpArgumentsString: presentURL.query)
|
|
XCTAssertEqual(params["ibi"], Bundle.main.bundleIdentifier)
|
|
if OAuthProviderTests.testAppID {
|
|
XCTAssertEqual(params["appId"], OAuthProviderTests.kFakeFirebaseAppID)
|
|
} else {
|
|
XCTAssertEqual(params["clientId"], OAuthProviderTests.kFakeClientID)
|
|
}
|
|
XCTAssertEqual(params["apiKey"], OAuthProviderTests.kFakeAPIKey)
|
|
XCTAssertEqual(params["authType"], "signInWithRedirect")
|
|
XCTAssertNotNil(params["v"])
|
|
if OAuthProviderTests.testTenantID {
|
|
XCTAssertEqual(params["tid"], OAuthProviderTests.kFakeTenantID)
|
|
} else {
|
|
XCTAssertNil(params["tid"])
|
|
}
|
|
let appCheckToken = presentURL.fragment
|
|
let verifyAppCheckToken = OAuthProviderTests.testAppCheck ? "fac=fakeAppCheckToken" : nil
|
|
XCTAssertEqual(appCheckToken, verifyAppCheckToken)
|
|
|
|
// 7. Test callbackMatcher
|
|
let kFakeRedirectStart = OAuthProviderTests
|
|
.testAppID ? "app-1-123456789-ios-123abc456def" :
|
|
OAuthProviderTests.kFakeReverseClientID
|
|
let kFakeRedirectURLBase = kFakeRedirectStart + "://firebaseauth/" +
|
|
"link?deep_link_id=https%3A%2F%2Fexample.firebaseapp.com%2F__%2Fauth%2Fcallback%3F"
|
|
var kFakeRedirectURLRest = "authType%3DsignInWithRedirect%26link%3D"
|
|
|
|
if OAuthProviderTests.testInternalError {
|
|
kFakeRedirectURLRest = "firebaseError%3D%257B%2522code%2522%253" +
|
|
"A%2522auth%252Finternal-error%2522%252C%2522message%2522%253A%2522Internal%2520" +
|
|
"error%2520.%2522%257D%26authType%3DsignInWithRedirect"
|
|
} else if OAuthProviderTests.testInvalidClientID {
|
|
kFakeRedirectURLRest = "firebaseError%3D%257B%2522code%2522%253A%2522auth" +
|
|
"%252Finvalid-oauth-client-id%2522%252C%2522message%2522%253A%2522The%2520OAuth%2520client%" +
|
|
"2520ID%2520provided%2520is%2520either%2520invalid%2520or%2520does%2520not%2520match%2520the%" +
|
|
"2520specified%2520API%2520key.%2522%257D%26authType%3DsignInWithRedirect"
|
|
} else if OAuthProviderTests.testErrorString {
|
|
kFakeRedirectURLRest = "firebaseError%3D%257B%2522code%2" +
|
|
"522%253A%2522auth%252Fnetwork-request-failed%2522%252C%2522message%2522%253A%2522The%" +
|
|
"2520network%2520request%2520failed%2520.%2522%257D%26authType%3DsignInWithRedirect"
|
|
} else if OAuthProviderTests.testUnknownError {
|
|
kFakeRedirectURLRest = "firebaseError%3D%257B%2522code%2522%253A%2522auth%2" +
|
|
"52Funknown-error-id%2522%252C%2522message%2522%253A%2522The%2520OAuth%2520client%2520ID%" +
|
|
"2520provided%2520is%2520either%2520invalid%2520or%2520does%2520not%2520match%2520the%2520" +
|
|
"specified%2520API%2520key.%2522%257D%26authType%3DsignInWithRedirect"
|
|
}
|
|
var redirectURL = "\(kFakeRedirectURLBase)\(kFakeRedirectURLRest)"
|
|
// Add fake OAuthResponse to callback.
|
|
if !OAuthProviderTests.testErrorString, !OAuthProviderTests.testInternalError,
|
|
!OAuthProviderTests.testInvalidClientID, !OAuthProviderTests.testUnknownError {
|
|
redirectURL += OAuthProviderTests.kFakeOAuthResponseURL
|
|
}
|
|
|
|
// Verify that the URL is rejected by the callback matcher without the event ID.
|
|
XCTAssertFalse(callbackMatcher(URL(string: "\(redirectURL)")))
|
|
|
|
// Verify that the URL is accepted by the callback matcher with the matching event ID.
|
|
let redirectWithEventID =
|
|
"\(redirectURL)%26eventId%3D\(params["eventId"] ?? "missingEventID")"
|
|
let originalComponents = URLComponents(string: redirectWithEventID)!
|
|
XCTAssertTrue(callbackMatcher(originalComponents.url))
|
|
|
|
var components = originalComponents
|
|
components.query = "https"
|
|
XCTAssertFalse(callbackMatcher(components.url))
|
|
|
|
components = originalComponents
|
|
components.host = "badhost"
|
|
XCTAssertFalse(callbackMatcher(components.url))
|
|
|
|
components = originalComponents
|
|
components.path = "badpath"
|
|
XCTAssertFalse(callbackMatcher(components.url))
|
|
|
|
components = originalComponents
|
|
components.query = "badquery"
|
|
XCTAssertFalse(callbackMatcher(components.url))
|
|
|
|
// 8. Do the callback to the original call.
|
|
kAuthGlobalWorkQueue.async {
|
|
if OAuthProviderTests.testCancel {
|
|
completion(nil, AuthErrorUtils.webContextCancelledError(message: nil))
|
|
} else {
|
|
completion(originalComponents.url, nil)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. Request the credential.
|
|
provider.getCredentialWith(nil) { credential, error in
|
|
|
|
// 9. After the response triggers the callback, verify the values in the callback credential
|
|
XCTAssertTrue(Thread.isMainThread)
|
|
if OAuthProviderTests.testCancel {
|
|
XCTAssertNil(credential)
|
|
XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.webContextCancelled.rawValue)
|
|
} else if OAuthProviderTests.testErrorString {
|
|
XCTAssertNil(credential)
|
|
XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.webNetworkRequestFailed.rawValue)
|
|
} else if OAuthProviderTests.testInternalError {
|
|
XCTAssertNil(credential)
|
|
XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.webInternalError.rawValue)
|
|
} else if OAuthProviderTests.testInvalidClientID {
|
|
XCTAssertNil(credential)
|
|
XCTAssertEqual((error as? NSError)?.code, AuthErrorCode.invalidClientID.rawValue)
|
|
} else if OAuthProviderTests.testUnknownError {
|
|
XCTAssertNil(credential)
|
|
XCTAssertEqual(
|
|
(error as? NSError)?.code,
|
|
AuthErrorCode.webSignInUserInteractionFailure.rawValue
|
|
)
|
|
} else {
|
|
XCTAssertNil(error)
|
|
let oAuthCredential = credential as? OAuthCredential
|
|
XCTAssertEqual(
|
|
oAuthCredential?.OAuthResponseURLString,
|
|
OAuthProviderTests.kFakeOAuthResponseURL
|
|
)
|
|
}
|
|
expectation.fulfill()
|
|
}
|
|
waitForExpectations(timeout: 5)
|
|
}
|
|
}
|
|
#endif
|