Improve test coverage of MessageDialog in ShareKit

Reviewed By: shuxinzhang

Differential Revision: D35806609

fbshipit-source-id: d205dba25e18b47bca22ea4f5d142f64f018a170
This commit is contained in:
Sam Odom
2022-04-21 15:30:32 -07:00
committed by Facebook GitHub Bot
parent 677ba3ff30
commit 0ab188aafe
4 changed files with 187 additions and 12 deletions

View File

@@ -241,7 +241,7 @@ public class MessageDialog: NSObject, SharingDialog { // swiftlint:disable:this
return shouldUseNativeDialog && internalUtility.isMessengerAppInstalled
}
private func handleCompletion(dialogResults: [String: Any], response: BridgeAPIResponse) {
func handleCompletion(dialogResults: [String: Any], response: BridgeAPIResponse) {
let completionGesture = dialogResults[ShareBridgeAPI.CompletionGesture.key] as? String
let isCancelGesture = (completionGesture == ShareBridgeAPI.CompletionGesture.cancelValue)
if isCancelGesture || response.isCancelled {

View File

@@ -0,0 +1,18 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
import FBSDKCoreKit
final class TestBridgeAPIResponse: BridgeAPIResponse {
var stubbedResponseParameters: [String: Any]?
override var responseParameters: [String: Any]? {
stubbedResponseParameters ?? super.responseParameters
}
}

View File

@@ -12,13 +12,6 @@ import XCTest
final class MessageDialogTests: XCTestCase {
enum Assumptions {
static let contentValidation = """
Known valid content should pass validation without issue. \
If this test fails then the criteria for the fixture may no longer be valid
"""
}
// swiftlint:disable implicitly_unwrapped_optional
var dialog: MessageDialog!
var shareDialogConfiguration: TestShareDialogConfiguration!
@@ -161,6 +154,22 @@ final class MessageDialogTests: XCTestCase {
)
}
func testCreatingWithFactoryMethod() {
let content = ShareModelTestUtility.linkContent
dialog = MessageDialog.dialog(content: content, delegate: delegate)
XCTAssertIdentical(dialog.shareContent, content, .factoryCreation)
XCTAssertIdentical(dialog.delegate, delegate, .factoryCreation)
}
func testCreatingAndShowingWithFactoryMethod() {
let content = ShareModelTestUtility.linkContent
dialog = MessageDialog.show(content: content, delegate: delegate)
XCTAssertIdentical(dialog.shareContent, content, .factoryCreation)
XCTAssertIdentical(dialog.delegate, delegate, .factoryCreation)
}
func testCanShow() {
shareDialogConfiguration.stubbedShouldUseNativeDialog = true
internalUtility.isMessengerAppInstalled = true
@@ -192,13 +201,13 @@ final class MessageDialogTests: XCTestCase {
dialog = MessageDialog()
dialog.shareContent = ShareModelTestUtility.linkContent
XCTAssertNoThrow(try dialog.validate(), Assumptions.contentValidation)
XCTAssertNoThrow(try dialog.validate(), .contentValidation)
dialog.shareContent = ShareModelTestUtility.photoContentWithImages
XCTAssertNoThrow(try dialog.validate(), Assumptions.contentValidation)
XCTAssertNoThrow(try dialog.validate(), .contentValidation)
dialog.shareContent = ShareModelTestUtility.videoContentWithoutPreviewPhoto
XCTAssertNoThrow(try dialog.validate(), Assumptions.contentValidation)
XCTAssertNoThrow(try dialog.validate(), .contentValidation)
dialog.shareContent = ShareModelTestUtility.cameraEffectContent
XCTAssertNil(
@@ -256,6 +265,142 @@ final class MessageDialogTests: XCTestCase {
XCTAssertEqual(error.message, "Message dialog does not support ShareCameraEffectContent.", .failureIsHandled)
XCTAssertNil(error.underlyingError, .failureIsHandled)
}
func testShowingDialog() throws {
shareDialogConfiguration.stubbedShouldUseNativeDialog = true
shareDialogConfiguration.stubbedShouldUseSafariViewController = true
internalUtility.isMessengerAppInstalled = true
let parameters = ["key": "value"]
TestShareUtility.stubbedBridgeParameters = parameters
let request = TestBridgeAPIRequest()
bridgeAPIRequestFactory.stubbedBridgeAPIRequest = request
let content = ShareModelTestUtility.linkContent
content.pageID = "foo"
dialog.shareContent = content
XCTAssertTrue(dialog.show(), .showingValidDialog)
// Getting bridge parameters
XCTAssertIdentical(shareUtility.capturedBridgeParametersShareContent, content, .showingValidDialog)
let options = try XCTUnwrap(shareUtility.capturedBridgeParametersBridgeOptions, .showingValidDialog)
XCTAssertTrue(options.isEmpty, .showingValidDialog)
XCTAssertEqual(
shareUtility.capturedBridgeParametersShouldFailOnDataError,
dialog.shouldFailOnDataError,
.showingValidDialog
)
// Creating bridge API request
XCTAssertEqual(bridgeAPIRequestFactory.capturedProtocolType, .native, .showingValidDialog)
XCTAssertEqual(bridgeAPIRequestFactory.capturedScheme, URLScheme.messengerApp.rawValue, .showingValidDialog)
XCTAssertEqual(bridgeAPIRequestFactory.capturedMethodName, ShareBridgeAPI.MethodName.share, .showingValidDialog)
XCTAssertEqual(bridgeAPIRequestFactory.capturedParameters as? [String: String], parameters, .showingValidDialog)
XCTAssertNil(bridgeAPIRequestFactory.capturedUserInfo, .showingValidDialog)
// Opening bridge API request
XCTAssertIdentical(bridgeAPIRequestOpener.capturedRequest, request, .showingValidDialog)
XCTAssertEqual(
bridgeAPIRequestOpener.capturedUseSafariViewController,
shareDialogConfiguration.stubbedShouldUseSafariViewController,
.showingValidDialog
)
XCTAssertNil(bridgeAPIRequestOpener.capturedFromViewController, .showingValidDialog)
// Logging
XCTAssertEqual(eventLogger.logInternalEventName, .shareDialogShow, .showingValidDialog)
let expectedParameters: [AppEvents.ParameterName: String] = [
.shareContentType: ShareAppEventsParameters.ContentTypeValue.status,
.shareContentUUID: content.shareUUID!, // swiftlint:disable:this force_unwrapping
.shareContentPageID: content.pageID!, // swiftlint:disable:this force_unwrapping
]
XCTAssertEqual(
eventLogger.logInternalEventParameters as? [AppEvents.ParameterName: String],
expectedParameters,
.showingValidDialog
)
XCTAssertTrue(eventLogger.logInternalEventIsImplicitlyLogged ?? false, .showingValidDialog)
XCTAssertEqual(eventLogger.logInternalEventAccessToken, TestAccessTokenWallet.current, .showingValidDialog)
// Completion
let response = TestBridgeAPIResponse(request: request, error: nil)
response.stubbedResponseParameters = parameters
bridgeAPIRequestOpener.capturedCompletionBlock?(response)
XCTAssertEqual(delegate?.sharerDidCompleteResults as? [String: String], parameters, .showingValidDialog)
XCTAssertIdentical(internalUtility.unregisterTransientObjectObject as AnyObject, dialog, .showingValidDialog)
}
func testHandlingNormalCancellation() {
let request = TestBridgeAPIRequest()
let response = TestBridgeAPIResponse(cancelledWith: request)
dialog.handleCompletion(dialogResults: [:], response: response)
XCTAssertEqual(eventLogger.logInternalEventName, .messengerShareDialogResult, .cancellationIsHandled)
XCTAssertEqual(
eventLogger.logInternalEventParameters as? [AppEvents.ParameterName: String],
[.outcome: ShareAppEventsParameters.DialogOutcomeValue.cancelled],
.cancellationIsHandled
)
XCTAssertTrue(eventLogger.logInternalEventIsImplicitlyLogged ?? false, .cancellationIsHandled)
XCTAssertIdentical(eventLogger.logInternalEventAccessToken, accessTokenWallet.current, .cancellationIsHandled)
XCTAssertIdentical(delegate.sharerDidCancelSharer as AnyObject, dialog, .cancellationIsHandled)
}
func testHandlingCancellationViaGesture() {
let request = TestBridgeAPIRequest()
let response = TestBridgeAPIResponse(request: request, error: nil)
let results = [ShareBridgeAPI.CompletionGesture.key: ShareBridgeAPI.CompletionGesture.cancelValue]
dialog.handleCompletion(dialogResults: results, response: response)
XCTAssertEqual(eventLogger.logInternalEventName, .messengerShareDialogResult, .cancellationIsHandled)
XCTAssertEqual(
eventLogger.logInternalEventParameters as? [AppEvents.ParameterName: String],
[.outcome: ShareAppEventsParameters.DialogOutcomeValue.cancelled],
.cancellationIsHandled
)
XCTAssertTrue(eventLogger.logInternalEventIsImplicitlyLogged ?? false, .cancellationIsHandled)
XCTAssertIdentical(eventLogger.logInternalEventAccessToken, accessTokenWallet.current, .cancellationIsHandled)
XCTAssertIdentical(delegate.sharerDidCancelSharer as AnyObject, dialog, .cancellationIsHandled)
}
func testHandlingFailure() {
let request = TestBridgeAPIRequest()
let error = SampleError()
let response = TestBridgeAPIResponse(request: request, error: error)
dialog.handleCompletion(dialogResults: [:], response: response)
XCTAssertEqual(eventLogger.logInternalEventName, .shareDialogResult, .failureIsHandled)
XCTAssertEqual(
eventLogger.logInternalEventParameters as? [AppEvents.ParameterName: String],
[
.outcome: ShareAppEventsParameters.DialogOutcomeValue.failed,
.errorMessage: String(describing: error),
],
.failureIsHandled
)
XCTAssertTrue(eventLogger.logInternalEventIsImplicitlyLogged ?? false, .failureIsHandled)
XCTAssertIdentical(eventLogger.logInternalEventAccessToken, accessTokenWallet.current, .failureIsHandled)
XCTAssertIdentical(delegate.sharerDidFailSharer as AnyObject, dialog, .failureIsHandled)
XCTAssertEqual(delegate.sharerDidFailError as? SampleError, error, .failureIsHandled)
}
func testHandlingSuccess() {
let request = TestBridgeAPIRequest()
let response = TestBridgeAPIResponse(request: request, error: nil)
let results = ["key": "value"]
dialog.handleCompletion(dialogResults: results, response: response)
XCTAssertEqual(eventLogger.logInternalEventName, .messengerShareDialogResult, .successIsHandled)
XCTAssertEqual(
eventLogger.logInternalEventParameters as? [AppEvents.ParameterName: String],
[.outcome: ShareAppEventsParameters.DialogOutcomeValue.completed],
.successIsHandled
)
XCTAssertTrue(eventLogger.logInternalEventIsImplicitlyLogged ?? false, .successIsHandled)
XCTAssertIdentical(eventLogger.logInternalEventAccessToken, accessTokenWallet.current, .successIsHandled)
XCTAssertIdentical(delegate.sharerDidCompleteSharer as AnyObject, dialog, .successIsHandled)
XCTAssertEqual(delegate.sharerDidCompleteResults as? [String: String], results, .successIsHandled)
}
}
// MARK: - Assumptions
@@ -269,5 +414,15 @@ fileprivate extension String {
"The MessageDialog type uses a custom \(type) dependency when provided"
}
static let factoryCreation = "A dialog can be created using a factory method"
static let contentValidation = """
Known valid content passes validation without issue. \
When this test fails then the criteria for the fixture may no longer be valid.
"""
static let cancellationIsHandled = "Cancellation is sent to a dialog's delegate and logged"
static let failureIsHandled = "Failure is sent to a dialog's delegate and logged"
static let successIsHandled = "Success is sent to a dialog's delegate and logged"
static let showingValidDialog = "A dialog shows valid content by creating a bridge API request an opening it"
}

View File

@@ -6,6 +6,8 @@
* LICENSE file in the root directory of this source tree.
*/
public struct SampleError: Error {
public struct SampleError: Error, Equatable {
private let uuid = UUID()
public init() {}
}