diff --git a/README.md b/README.md index 6aadc11b..f2c3ca75 100755 --- a/README.md +++ b/README.md @@ -41,11 +41,23 @@ For Objective-C projects, set the **Embedded Content Contains Swift Code** flag You can integrate Uber Rides into your project manually without using a dependency manager. -Drag the `UberRides` project into your own and add the resource as an **Embedded Binary**, as well as a **Target Dependency** and **Linked Framework** (under Build Phases) in order to build on the simulator and on a device. +Drag the `UberRides.xcodeproj` project into your project as a subproject -

- Manually Install Framework -

+In your project's Build Target, click on the **General** tab and then under **Embedded Binaries** click the `+` button. Choose the `UberRides.framework` in your project. + +Now click on the `UberRides.xcodeproj` sub project and open the **General** tab. Under **Linked Frameworks and Libraries** delete the `Pods.framework` entry + +Now click on **Build Phase** (still in the UberRides subproject) and delete the **Check Pods Manifest.lock** & **Copy Pods Resources** script phases + +Now we need to get our dependencies. Clone the ObjectMapper dependency [found here](https://github.com/Hearst-DD/ObjectMapper) (we use version 1.1.5) + +Once you have that, also drag the `ObjectMapper.xcodeproj` into your project + +Click back onto the UberRides subproject, go to the **General** tab and click the `+` button under **Linked Frameworks and Libraries** + +Choose the ObjectMapper iOS framework + +Now build your project and everything should be good to go ### Configuring iOS 9.0 @@ -78,7 +90,7 @@ Add the following code snippet, replacing the placeholders with your app’s inf Additionally, the SDK provides a static Configuration class to further customize your settings. Inside of `application:didFinishLaunchingWithOptions:` in your `AppDelegate` is a good place to do this: -``` +```swift // Don’t forget to import UberRides // Swift func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { @@ -91,7 +103,7 @@ func application(application: UIApplication, didFinishLaunchingWithOptions launc } ``` -``` +```objective-c // Objective-C - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // China based apps should specify the region @@ -112,7 +124,7 @@ Getting the user to authorize location services can be done with Apple’s CoreL The Uber Rides SDK provides a simple way to add the Ride Request Widget in only a few lines of code via the `RideRequestButton`. You simply need to provide a `RideRequesting` object and an optional `RideParameters` object. -``` +```swift // Swift // Pass in a UIViewController to modally present the Ride Request Widget over let behavior = RideRequestViewRequestingBehavior(presentingViewController: self) @@ -123,7 +135,7 @@ let button = RideRequestButton(rideParameters: parameters, requestingBehavior: b self.view.addSubview(button) ``` -``` +```objective-c // Objective-C // Pass in a UIViewController to modally present the Ride Request Widget over id behavior = [[UBSDKRideRequestViewRequestingBehavior alloc] initWithPresentingViewController: self]; @@ -140,7 +152,7 @@ That’s it! When a user taps the button, a **RideRequestViewController** will b Basic error handling is provided by default, but can be overwritten by specifying a **RideRequestViewControllerDelegate**. -``` +```swift // Swift extension your_class : RideRequestViewControllerDelegate { func rideRequestViewController(rideRequestViewController: RideRequestViewController, didReceiveError error: NSError) { @@ -151,6 +163,10 @@ extension your_class : RideRequestViewControllerDelegate { // No AccessToken saved case .AccessTokenExpired: // AccessToken expired / invalid + case .NetworkError: + // A network connectivity error + case .NotSupported: + // The attempted operation is not supported on the current device case .Unknown: // Other error } @@ -165,7 +181,7 @@ behavior.modalRideRequestViewController.rideRequestViewController.delegate = del let button = RideRequestButton(rideParameters: parameters, requestingBehavior: behavior) ``` -``` +```objective-c // Objective-C // Need to implement the UBSDKRideRequestViewControllerDelegate @interface your_class () @@ -184,6 +200,9 @@ let button = RideRequestButton(rideParameters: parameters, requestingBehavior: b case RideRequestViewErrorTypeAccessTokenMissing: // AccessToken expired / invalid break; + case RideRequestViewErrorTypeNetworkError: + // A network connectivity error + break; case RideRequestViewErrorTypeUnknown: // Other error break; @@ -205,7 +224,7 @@ UBSDKRideRequestButton *button = [[UBSDKRideRequestButton alloc] initWithRidePar Import the library into your project, and add a Ride Request Button to your view like you would any other UIView: -``` +```swift // Swift import UberRides @@ -213,7 +232,7 @@ let button = RideRequestButton() view.addSubview(button) ``` -``` +```objective-c // Objective-C @import UberRides; @@ -227,7 +246,7 @@ This will create a request button with default behavior, with the pickup pin set The SDK provides an simple object for defining your ride requests. The `RideParameters` object lets you specify pickup location, dropoff location, product ID, and more. Creating `RideParameters` is easy using the `RideParametersBuilder` object. -``` +```swift // Swift let builder = RideParametersBuilder() let pickupLocation = CLLocation(latitude: 37.787654, longitude: -122.402760) @@ -237,7 +256,7 @@ builder.setPickupLocation(pickupLocation).setDropoffLocation(dropoffLocation) let rideParameters = builder.build() ``` -``` +```objective-c // Objective-C UBSDKRideParametersBuilder *builder = [[UBSDKRideParametersBuilder alloc] init]; CLLocation *pickupLocation = [[CLLocation alloc] initWithLatitude:37.787654 longitude:-122.402760]; @@ -249,7 +268,7 @@ UBSDKRideParameters *rideParameters = [builder build]; You can also have the SDK determine the user’s current location (you must handle getting location permission beforehand, however) -``` +```swift // Swift // If no pickup location is specified, the default is to use current location let parameters = RideParametersBuilder().build() @@ -259,7 +278,7 @@ builder.setPickupToCurrentLocation() let parameters = builder.build() // Both 'parameters' variables are equivalent ``` -``` +```objective-c // Objective-C // If no pickup location is specified, the default is to use current location UBSDKRideParameters *parameters = [[[UBSDKRideParametersBuilder alloc] init] build]; @@ -275,13 +294,13 @@ We suggest passing additional parameters to make the Uber experience even more s The default color has a black background with white text. You can update the button to have a white background with black text by setting the color style -``` +```swift // Swift let button = RideRequestButton() // Black Background, White Text button.colorStyle = .White // White Background, Black Text ``` -``` +```objective-c // Objective-C UBSDKRideRequestButton *button = [[UBSDKRideRequestButton alloc] init]; // Black Background, White Text [button setColorStyle:RequestButtonColorStyleWhite]; // White Background, Black Text @@ -293,7 +312,7 @@ If you want to provide a more custom experience in your app, there are a few cla ### Implicit Grant Authorization Before you can request any rides, you need to get an `AccessToken`. The Uber Rides SDK provides the `LoginManager` class for this task. Simply instantiate an instance use its login method to present the login screen to the user. -``` +```swift // Swift let loginManager = LoginManager() loginManager.login(requestedScopes:[.RideWidgets], presentingViewController: self, completion: { accessToken, error in @@ -302,7 +321,7 @@ loginManager.login(requestedScopes:[.RideWidgets], presentingViewController: sel }) ``` -``` +```objective-c // Objective-C UBSDKLoginManager *loginManager = [[UBSDKLoginManager alloc] init]; [loginManager loginWithRequestedScopes:@[ UBSDKRidesScope.RideWidgets ] presentingViewController: self completion: ^(UBSDKAccessToken * _Nullable accessToken, NSError * _Nullable error) { @@ -318,7 +337,7 @@ The SDK presents a web view controller where the user logs into their Uber accou ### Custom Authorization / TokenManager If your app allows users to authorize via your own customized logic, you will need to create an `AccessToken` manually and save it in the keychain using the `TokenManager`. -``` +```swift // Swift let accessTokenString = "access_token_string" let token = AccessToken(tokenString: accessTokenString) @@ -329,7 +348,7 @@ if TokenManager.saveToken(token) { } ``` -``` +```objective-c // Objective-C NSString *accessTokenString = @"access_token_string"; UBSDKAccessToken *token = [[UBSDKAccessToken alloc] initWithTokenString: accessTokenString]; @@ -342,13 +361,13 @@ if ([UBSDKTokenManager saveToken: token]) { The `TokenManager` can also be used to fetch and delete `AccessToken`s -``` +```swift // Swift TokenManger.fetchToken() TokenManager.deleteToken() ``` -``` +```objective-c // Objective-C [UBSDKTokenManager fetchToken]; [UBSDKTokenManager deleteToken]; @@ -357,7 +376,7 @@ TokenManager.deleteToken() ### RideRequestView The `RideRequestView` is like any other view you’d add to your app. Create a new instance using a `RideParameters` object and add it to your app wherever you like. -``` +```swift // Swift // Example of setting up the RideRequestView let location = CLLocation(latitude: 37.787654, longitude: -122.402760) @@ -366,7 +385,7 @@ let rideRequestView = RideRequestView(rideParameters: parameters, frame: self.vi self.view.addSubview(rideRequestView) ``` -``` +```objective-c // Objective-C // Example of setting up the UBSDKRideRequestView CLLocation *location = [[CLLocation alloc] initWithLatitude: 37.787654 longitude: -122.402760]; @@ -380,7 +399,7 @@ That’s it! When you’re ready to show the control, call the load() function. You can also optionally specify a `RideRequestViewDelegate` to handle errors loading the widget. -``` +```swift // Swift extension your_class : RideRequestViewDelegate { func rideRequestView(rideRequestView: RideRequestView, didReceiveError error: NSError) { @@ -391,13 +410,17 @@ extension your_class : RideRequestViewDelegate { // No AccessToken saved case .AccessTokenExpired: // AccessToken expired / invalid + case .NetworkError: + // A network connectivity error + case .NotSupported: + // The attempted operation is not supported on the current device case .Unknown: // Other error } } } ``` -``` +```objective-c // Objective-C // Delegate methods - (void)rideRequestView:(UBSDKRideRequestView *)rideRequestView didReceiveError:(NSError *)error { @@ -411,6 +434,9 @@ extension your_class : RideRequestViewDelegate { case RideRequestViewErrorTypeAccessTokenMissing: // AccessToken expired / invalid break; + case RideRequestViewErrorTypeNetworkError: + // A network connectivity error + break; case RideRequestViewErrorTypeUnknown: // Other error break; @@ -423,14 +449,14 @@ extension your_class : RideRequestViewDelegate { ### RideRequestViewController A `RideRequestViewController` is simply a `UIViewController` that contains a fullscreen `RideRequestView`. It also handles logging in non-authenticated users for you. Create a new instance with your desired `RideParameters` and `LoginManager` (used to log in, if necessary). -``` +```swift // Swift // Setting up a RideRequestViewController let parameters = RideParametersBuilder().build() let loginManager = LoginManager() let rideRequestViewController = RideRequestViewController(rideParameters: parameters, loginManager: loginManager) ``` -``` +```objective-c // Objective-C // Setting up a RideRequestViewController UBSDKRideParameters *parameters = [[[UBSDKRideParametersBuilder alloc] init] build]; @@ -440,7 +466,7 @@ UBSDKRideRequestViewController *rideRequestViewController = [[UBSDKRideRequestVi You can also optionally specify a RideRequestViewControllerDelegate to handle potential errors passed from the wrapped RideRequestView -``` +```swift // Swift extension your_class : RideRequestViewControllerDelegate { func rideRequestViewController(rideRequestViewController: RideRequestViewController, didReceiveError error: NSError) { @@ -451,13 +477,17 @@ extension your_class : RideRequestViewControllerDelegate { // No AccessToken saved case .AccessTokenExpired: // AccessToken expired / invalid + case .NetworkError: + // A network connectivity error + case .NotSupported: + // The attempted operation is not supported on the current device case .Unknown: // Other error } } } ``` -``` +```objective-c // Objective-C // Implement the delegate methods - (void)rideRequestViewController:(UBSDKRideRequestViewController *)rideRequestViewController didReceiveError:(NSError *)error { @@ -471,6 +501,9 @@ extension your_class : RideRequestViewControllerDelegate { case RideRequestViewErrorTypeAccessTokenMissing: // AccessToken expired / invalid break; + case RideRequestViewErrorTypeNetworkError: + // A network connectivity error + break; case RideRequestViewErrorTypeUnknown: // Other error break; diff --git a/UberRides.podspec b/UberRides.podspec index 0a605df5..dbd24ba6 100644 --- a/UberRides.podspec +++ b/UberRides.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "UberRides" - s.version = "0.4.0" + s.version = "0.4.1" s.summary = "The Official Uber Rides iOS SDK." s.description = <<-DESC This Swift library allows you to integrate Uber into your iOS app. It is designed to make it quick and easy to add a 'Request a Ride' button in your application, seamlessly connecting your users with Uber. diff --git a/source/UberRides/Info.plist b/source/UberRides/Info.plist index c9410942..2bb1ea9d 100644 --- a/source/UberRides/Info.plist +++ b/source/UberRides/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.4.0 + 0.4.1 CFBundleSignature ???? CFBundleVersion diff --git a/source/UberRides/Resources/en.lproj/Localizable.strings b/source/UberRides/Resources/en.lproj/Localizable.strings index f373311f..17e0a1d3 100644 --- a/source/UberRides/Resources/en.lproj/Localizable.strings +++ b/source/UberRides/Resources/en.lproj/Localizable.strings @@ -17,4 +17,5 @@ "Login is temporarily unavailable." = "Login is temporarily unavailable."; "User cancelled the login process." = "User cancelled the login process."; "Try Again" = "Try Again"; -"Cancel" = "Cancel"; \ No newline at end of file +"Cancel" = "Cancel"; +"The operation you are attempting is not supported on the current device." = "The operation you are attempting is not supported on the current device."; \ No newline at end of file diff --git a/source/UberRides/Resources/hi-In.lproj/Localizable.strings b/source/UberRides/Resources/hi-In.lproj/Localizable.strings index a0e33eb9..3b9306e9 100644 --- a/source/UberRides/Resources/hi-In.lproj/Localizable.strings +++ b/source/UberRides/Resources/hi-In.lproj/Localizable.strings @@ -17,4 +17,5 @@ "Login is temporarily unavailable." = "Login is temporarily unavailable."; "User cancelled the login process." = "User cancelled the login process."; "Try Again" = "पुन: प्रयास करें"; -"Cancel" = "रद्द"; \ No newline at end of file +"Cancel" = "रद्द"; +"The operation you are attempting is not supported on the current device." = "The operation you are attempting is not supported on the current device."; \ No newline at end of file diff --git a/source/UberRides/Resources/zh-Hans.lproj/Localizable.strings b/source/UberRides/Resources/zh-Hans.lproj/Localizable.strings index 678fc6d9..0469e186 100644 --- a/source/UberRides/Resources/zh-Hans.lproj/Localizable.strings +++ b/source/UberRides/Resources/zh-Hans.lproj/Localizable.strings @@ -17,4 +17,5 @@ "Login is temporarily unavailable." = "Login is temporarily unavailable."; "User cancelled the login process." = "User cancelled the login process."; "Try Again" = "重试"; -"Cancel" = "取消"; \ No newline at end of file +"Cancel" = "取消"; +"The operation you are attempting is not supported on the current device." = "The operation you are attempting is not supported on the current device."; \ No newline at end of file diff --git a/source/UberRides/Resources/zh-Hant.lproj/Localizable.strings b/source/UberRides/Resources/zh-Hant.lproj/Localizable.strings index dbefb694..668cf54d 100644 --- a/source/UberRides/Resources/zh-Hant.lproj/Localizable.strings +++ b/source/UberRides/Resources/zh-Hant.lproj/Localizable.strings @@ -17,4 +17,5 @@ "Login is temporarily unavailable." = "暫時無法登入。"; "User cancelled the login process." = "使用者取消了登入程序。"; "Try Again" = "再試"; -"Cancel" = "取消"; \ No newline at end of file +"Cancel" = "取消"; +"The operation you are attempting is not supported on the current device." = "The operation you are attempting is not supported on the current device."; \ No newline at end of file diff --git a/source/UberRides/RideRequestView.swift b/source/UberRides/RideRequestView.swift index a8a5cad3..cf949019 100644 --- a/source/UberRides/RideRequestView.swift +++ b/source/UberRides/RideRequestView.swift @@ -221,6 +221,12 @@ extension RideRequestView: WKNavigationDelegate { delegate?.rideRequestView(self, didReceiveError: error) decisionHandler(.Cancel) return + } else if url.scheme == "tel" || url.scheme == "sms" { + if (!UIApplication.sharedApplication().openURL(url)) { + delegate?.rideRequestView(self, didReceiveError: RideRequestViewErrorFactory.errorForType(.NotSupported)) + } + decisionHandler(.Cancel) + return } } diff --git a/source/UberRides/RideRequestViewController.swift b/source/UberRides/RideRequestViewController.swift index c86f84ca..3f42eaab 100644 --- a/source/UberRides/RideRequestViewController.swift +++ b/source/UberRides/RideRequestViewController.swift @@ -189,6 +189,13 @@ import MapKit self.presentViewController(alertController, animated: true, completion: nil) } + func displayNotSupportedErrorAlert() { + let alertController = UIAlertController(title: nil, message: LocalizationUtil.localizedString(forKey: "The operation you are attempting is not supported on the current device.", comment: "The operation you are attempting is not supported on the current device."), preferredStyle: .Alert) + let okayAction = UIAlertAction(title: LocalizationUtil.localizedString(forKey: "OK", comment: "OK"), style: .Default, handler: nil) + alertController.addAction(okayAction) + self.presentViewController(alertController, animated: true, completion: nil) + } + //MARK: Private private func setupRideRequestView() { @@ -242,6 +249,9 @@ extension RideRequestViewController : RideRequestViewDelegate { case .NetworkError: self.displayNetworkErrorAlert() break + case .NotSupported: + self.displayNotSupportedErrorAlert() + break case .AccessTokenMissing: fallthrough case .AccessTokenExpired: diff --git a/source/UberRides/RideRequestViewErrorFactory.swift b/source/UberRides/RideRequestViewErrorFactory.swift index a925ab04..d5528a9d 100644 --- a/source/UberRides/RideRequestViewErrorFactory.swift +++ b/source/UberRides/RideRequestViewErrorFactory.swift @@ -55,6 +55,8 @@ class RideRequestViewErrorFactory { switch rawValue { case "network_error": return .NetworkError + case "not_supported": + return .NotSupported case "no_access_token": return .AccessTokenMissing case "unauthorized": diff --git a/source/UberRides/RideRequestViewErrorType.swift b/source/UberRides/RideRequestViewErrorType.swift index bb053d7d..50bd9989 100644 --- a/source/UberRides/RideRequestViewErrorType.swift +++ b/source/UberRides/RideRequestViewErrorType.swift @@ -28,12 +28,14 @@ Possible errors that can occur in the RideRequestView. - AccessTokenMissing: There is no access token to make the request with - AccessTokenExpired: Access token has expired. - NetworkError: A network error occured +- NotSupported: The functionality attempted is not supported on the current device - Unknown: Unknown error occured. */ @objc public enum RideRequestViewErrorType: Int { case AccessTokenExpired case AccessTokenMissing case NetworkError + case NotSupported case Unknown func toString() -> String { @@ -44,6 +46,8 @@ Possible errors that can occur in the RideRequestView. return "no_access_token" case .NetworkError: return "network_error" + case .NotSupported: + return "not_supported" case .Unknown: return "unknown" } diff --git a/source/UberRidesTests/RideRequestViewControllerTests.swift b/source/UberRidesTests/RideRequestViewControllerTests.swift index f3ffdc30..de30576d 100644 --- a/source/UberRidesTests/RideRequestViewControllerTests.swift +++ b/source/UberRidesTests/RideRequestViewControllerTests.swift @@ -403,4 +403,45 @@ class RideRequestViewControllerTests: XCTestCase { }) } + func testPresentNotSupportedErrorAlert_whenNotSupportedError() { + let expectation = expectationWithDescription("Test presentNotSupportedAlert() call") + + let notSupportedClosure: () -> () = { + expectation.fulfill() + } + let testIdentifier = "testAccessTokenIdentifier" + TokenManager.deleteToken(testIdentifier) + + let loginManager = LoginManager(accessTokenIdentifier: testIdentifier) + + let rideRequestViewControllerMock = RideRequestViewControllerMock(rideParameters: RideParametersBuilder().build(), loginManager: loginManager, notSupportedClosure: notSupportedClosure) + + rideRequestViewControllerMock.rideRequestView(rideRequestViewControllerMock.rideRequestView, didReceiveError: RideRequestViewErrorFactory.errorForType(.NotSupported)) + + waitForExpectationsWithTimeout(timeout, handler: { error in + XCTAssertNil(error) + }) + } + + func testPresentNotSupportedErrorAlert_presentsAlertView() { + let expectation = expectationWithDescription("Test presentNotSupportedAlert() call") + + let presentViewControllerClosure: ((UIViewController, Bool, (() -> Void)?) -> ()) = { (viewController, flag, completion) in + expectation.fulfill() + XCTAssertTrue(viewController.dynamicType == UIAlertController.self) + } + + let testIdentifier = "testAccessTokenIdentifier" + TokenManager.deleteToken(testIdentifier) + + let loginManager = LoginManager(accessTokenIdentifier: testIdentifier) + + let rideRequestViewControllerMock = RideRequestViewControllerMock(rideParameters: RideParametersBuilder().build(), loginManager: loginManager, presentViewControllerClosure: presentViewControllerClosure) + + rideRequestViewControllerMock.rideRequestView(rideRequestViewControllerMock.rideRequestView, didReceiveError: RideRequestViewErrorFactory.errorForType(.NotSupported)) + + waitForExpectationsWithTimeout(timeout, handler: { error in + XCTAssertNil(error) + }) + } } diff --git a/source/UberRidesTests/RideRequestViewErrorFactoryTests.swift b/source/UberRidesTests/RideRequestViewErrorFactoryTests.swift index 6ffc1b89..02a0d475 100644 --- a/source/UberRidesTests/RideRequestViewErrorFactoryTests.swift +++ b/source/UberRidesTests/RideRequestViewErrorFactoryTests.swift @@ -27,6 +27,8 @@ class RideRequestViewErrorFactoryTests: XCTestCase { let expectedErrorToStringMapping = [ RideRequestViewErrorType.AccessTokenExpired : RideRequestViewErrorType.AccessTokenExpired.toString(), RideRequestViewErrorType.AccessTokenMissing : RideRequestViewErrorType.AccessTokenMissing.toString(), + RideRequestViewErrorType.NetworkError : RideRequestViewErrorType.NetworkError.toString(), + RideRequestViewErrorType.NotSupported : RideRequestViewErrorType.NotSupported.toString(), RideRequestViewErrorType.Unknown : RideRequestViewErrorType.Unknown.toString() ] diff --git a/source/UberRidesTests/RideRequestViewTests.swift b/source/UberRidesTests/RideRequestViewTests.swift index ded0789a..58a34557 100644 --- a/source/UberRidesTests/RideRequestViewTests.swift +++ b/source/UberRidesTests/RideRequestViewTests.swift @@ -183,6 +183,75 @@ class RideRequestViewTests: XCTestCase { XCTAssertNil(error) }) } + + func testNotSupportedDelegateCalled_whenSMS() { + expectation = expectationWithDescription("Delegate called") + let cancelRequestExpectation = expectationWithDescription("Request was cancelled") + + let rideRequestView = RideRequestView(rideParameters: RideParametersBuilder().build(), accessToken:nil, frame:CGRectZero) + rideRequestView.delegate = self + let smsURLString = "sms:5555555555" + guard let smsURL = NSURL(string: smsURLString) else { + XCTAssert(false) + return + } + let smsURLRequest = NSURLRequest(URL: smsURL) + let navigationActionMock = WKNavigationActionMock(urlRequest: smsURLRequest) + + if let delegate = rideRequestView.webView.navigationDelegate { + delegate.webView!(rideRequestView.webView, decidePolicyForNavigationAction: navigationActionMock, decisionHandler: { (policy: WKNavigationActionPolicy) -> Void in + XCTAssertEqual(policy, WKNavigationActionPolicy.Cancel) + cancelRequestExpectation.fulfill() + }) + + waitForExpectationsWithTimeout(timeout, handler: { error in + XCTAssertNotNil(self.error) + XCTAssertEqual(self.error?.code, RideRequestViewErrorType.NotSupported.rawValue) + }) + } else { + XCTAssert(false) + } + } + + func testNotSupportedDelegateCalled_whenTel() { + expectation = expectationWithDescription("Delegate called") + let cancelRequestExpectation = expectationWithDescription("Request was cancelled") + + let rideRequestView = RideRequestView(rideParameters: RideParametersBuilder().build(), accessToken:nil, frame:CGRectZero) + rideRequestView.delegate = self + let telURLString = "tel:5555555555" + guard let telURL = NSURL(string: telURLString) else { + XCTAssert(false) + return + } + let telURLRequest = NSURLRequest(URL: telURL) + let navigationActionMock = WKNavigationActionMock(urlRequest: telURLRequest) + + if let delegate = rideRequestView.webView.navigationDelegate { + delegate.webView!(rideRequestView.webView, decidePolicyForNavigationAction: navigationActionMock, decisionHandler: { (policy: WKNavigationActionPolicy) -> Void in + XCTAssertEqual(policy, WKNavigationActionPolicy.Cancel) + cancelRequestExpectation.fulfill() + }) + + waitForExpectationsWithTimeout(timeout, handler: { error in + XCTAssertNotNil(self.error) + XCTAssertEqual(self.error?.code, RideRequestViewErrorType.NotSupported.rawValue) + }) + } else { + XCTAssert(false) + } + } +} + +private class WKNavigationActionMock : WKNavigationAction { + override var request: NSURLRequest { + return backingRequest + } + var backingRequest = NSURLRequest() + init(urlRequest: NSURLRequest) { + backingRequest = urlRequest + super.init() + } } extension RideRequestViewTests: RideRequestViewDelegate { diff --git a/source/UberRidesTests/RidesMocks.swift b/source/UberRidesTests/RidesMocks.swift index c15bf8cd..0d79a04c 100644 --- a/source/UberRidesTests/RidesMocks.swift +++ b/source/UberRidesTests/RidesMocks.swift @@ -50,10 +50,13 @@ class RideRequestViewMock : RideRequestView { class RideRequestViewControllerMock : RideRequestViewController { var loadClosure: (() -> ())? var networkClosure: (() -> ())? + var notSupportedClosure: (() -> ())? var presentViewControllerClosure: ((UIViewController, Bool, (() -> Void)?) -> ())? - init(rideParameters: RideParameters, loginManager: LoginManager, loadClosure: (() -> ())?, networkClosure: (() -> ())?, presentViewControllerClosure: ((UIViewController, Bool, (() -> Void)?) -> ())?) { + + init(rideParameters: RideParameters, loginManager: LoginManager, loadClosure: (() -> ())? = nil, networkClosure: (() -> ())? = nil, presentViewControllerClosure: ((UIViewController, Bool, (() -> Void)?) -> ())? = nil, notSupportedClosure: (() -> ())? = nil) { self.loadClosure = loadClosure self.networkClosure = networkClosure + self.notSupportedClosure = notSupportedClosure self.presentViewControllerClosure = presentViewControllerClosure super.init(rideParameters: rideParameters, loginManager: loginManager) } @@ -78,6 +81,14 @@ class RideRequestViewControllerMock : RideRequestViewController { } } + override func displayNotSupportedErrorAlert() { + if let notSupportedClosure = notSupportedClosure { + notSupportedClosure() + } else { + super.displayNotSupportedErrorAlert() + } + } + override func presentViewController(viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) { if let presentViewControllerClosure = presentViewControllerClosure { presentViewControllerClosure(viewControllerToPresent, flag, completion)