import XCTest @testable import Presentation final class SideMenuPresentTransitionTests: XCTestCase { var sut: SideMenuPresentTransition! private var dismissInteractor: MockSideMenuDismissalInteractor! private var menuAnimator: MockSideMenuAnimator! override func setUp() { dismissInteractor = MockSideMenuDismissalInteractor() menuAnimator = MockSideMenuAnimator() sut = SideMenuPresentTransition( dismissInteractor: dismissInteractor, menuAnimator: menuAnimator, viewAnimator: MockUIViewAnimator.self ) } override func tearDown() { sut = nil dismissInteractor = nil menuAnimator = nil } func test_transitionDuration() { XCTAssertEqual(sut.transitionDuration(using: nil), 0.25) } func test_animateWithoutFromViewController() { let context = MockViewControllerContextTransitioning() context.mockViewControllerForKey[.from] = nil sut.animateTransition(using: context) XCTAssert(context.didCompleteTransition == false) } func test_animateWithoutToViewController() { let context = MockViewControllerContextTransitioning() context.mockViewControllerForKey[.to] = nil sut.animateTransition(using: context) XCTAssert(context.didCompleteTransition == false) } func test_AnimateTransition() { let fromViewController = UIViewController() let toViewController = UIViewController() let context = MockViewControllerContextTransitioning() context.mockViewControllerForKey[.from] = fromViewController context.mockViewControllerForKey[.to] = toViewController sut.animateTransition(using: context) let viewsWithTag = context.containerView.subviews.filter { $0.tag == SideMenuPresentTransition.fromViewTag } XCTAssertEqual(viewsWithTag.count, 1) let fromView = viewsWithTag[0] XCTAssertNotNil(fromView) XCTAssertEqual(fromView.layer.shadowRadius, 32) XCTAssertEqual(fromView.layer.shadowOffset, .zero) XCTAssertEqual(fromView.layer.shadowOpacity, 1) XCTAssertTrue(sut.viewAnimator is MockUIViewAnimator.Type) XCTAssertEqual(menuAnimator.didAnimateToProgress, 1) XCTAssertEqual(menuAnimator.didAnimateInContainerView, context.containerView) context.mockCancelTransition = false XCTAssertEqual(context.didCompleteTransition, true) } } private final class MockSideMenuDismissalInteractor: NSObject, SideMenuDismissInteracting { var didSetupWithView: UIView? var interactionInProgress: Bool { fatalError() } var percentDrivenInteractiveTransition = UIPercentDrivenInteractiveTransition() func setup(view: UIView, action: @escaping () -> Void) { didSetupWithView = view action() } func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) { fatalError() } } private final class MockSideMenuAnimator: SideMenuAnimating { var didAnimateInContainerView: UIView? var didAnimateToProgress: CGFloat? func animate(in containerView: UIView, to progress: CGFloat) { didAnimateInContainerView = containerView didAnimateToProgress = progress } } private final class MockUIViewAnimator: Presentation.UIViewAnimating { static var didAnimateWithDuration: TimeInterval? static func animate(withDuration duration: TimeInterval, animations: @escaping () -> Void, completion: ((Bool) -> Void)?) { didAnimateWithDuration = duration animations() completion?(true) } } private final class MockViewControllerContextTransitioning: NSObject, UIViewControllerContextTransitioning { let mockContainerView = UIView() var mockCancelTransition: Bool = false var didCompleteTransition: Bool? var containerView: UIView { mockContainerView } var transitionWasCancelled: Bool { mockCancelTransition } func completeTransition(_ didComplete: Bool) { didCompleteTransition = didComplete } var mockViewControllerForKey = [UITransitionContextViewControllerKey: UIViewController]() func viewController(forKey key: UITransitionContextViewControllerKey) -> UIViewController? { mockViewControllerForKey[key] } var isAnimated: Bool { fatalError() } var isInteractive: Bool { fatalError() } var targetTransform: CGAffineTransform { fatalError() } var presentationStyle: UIModalPresentationStyle { fatalError() } func cancelInteractiveTransition() {fatalError() } func pauseInteractiveTransition() { fatalError() } func finishInteractiveTransition() { fatalError() } func finalFrame(for vc: UIViewController) -> CGRect { fatalError() } func initialFrame(for vc: UIViewController) -> CGRect { fatalError() } func view(forKey key: UITransitionContextViewKey) -> UIView? { fatalError() } func updateInteractiveTransition(_ percentComplete: CGFloat) { fatalError() } }