diff --git a/Libraries/Coordination/Test/Helpers/Coordinators/OtherCoordinator.swift b/Libraries/Coordination/Test/Helpers/Coordinators/OtherCoordinator.swift new file mode 100644 index 0000000..7cfcc4c --- /dev/null +++ b/Libraries/Coordination/Test/Helpers/Coordinators/OtherCoordinator.swift @@ -0,0 +1,36 @@ +// +// OtherCoordinator.swift +// ReviewsCoordinationTest +// +// Created by Javier Cicchelli on 21/03/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +import ReviewsCoordinationKit + +final class OtherCoordinator: Coordinator { + + // MARK: Constants + let router: Router + + // MARK: Properties + var children: [Coordinator] = [] + + // MARK: Initialisers + init(router: Router) { + self.router = router + } + + // MARK: Functions + func present( + animated: Bool, + onDismiss: (() -> Void)? + ) { + router.present( + OtherViewController(), + animated: animated, + onDismiss: onDismiss + ) + } + +} diff --git a/Libraries/Coordination/Test/Helpers/Coordinators/SomeCoordinator.swift b/Libraries/Coordination/Test/Helpers/Coordinators/SomeCoordinator.swift new file mode 100644 index 0000000..aafe216 --- /dev/null +++ b/Libraries/Coordination/Test/Helpers/Coordinators/SomeCoordinator.swift @@ -0,0 +1,36 @@ +// +// SomeCoordinator.swift +// ReviewsCoordinationTest +// +// Created by Javier Cicchelli on 21/03/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +import ReviewsCoordinationKit + +final class SomeCoordinator: Coordinator { + + // MARK: Constants + let router: Router + + // MARK: Properties + var children: [Coordinator] = [] + + // MARK: Initialisers + init(router: Router) { + self.router = router + } + + // MARK: Functions + func present( + animated: Bool, + onDismiss: (() -> Void)? + ) { + router.present( + SomeViewController(), + animated: animated, + onDismiss: onDismiss + ) + } + +} diff --git a/Libraries/Coordination/Test/Helpers/Routers/SpyRouter.swift b/Libraries/Coordination/Test/Helpers/Routers/SpyRouter.swift new file mode 100644 index 0000000..7342a7d --- /dev/null +++ b/Libraries/Coordination/Test/Helpers/Routers/SpyRouter.swift @@ -0,0 +1,46 @@ +// +// SpyRouter.swift +// ReviewsCoordinationTest +// +// Created by Javier Cicchelli on 21/03/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +import ReviewsCoordinationKit +import UIKit + +final class SpyRouter: Router { + + // MARK: Properties + var animated: Bool? + var onDismiss: OnDismissClosure? + var state: State = .initialised + var viewController: UIViewController? + + // MARK: Functions + func present( + _ viewController: UIViewController, + animated: Bool, + onDismiss: OnDismissClosure? + ) { + self.viewController = viewController + self.animated = animated + self.onDismiss = onDismiss + self.state = .presented + } + + func dismiss(animated: Bool) { + self.animated = animated + self.state = .dismissed + } + +} + +// MARK: - Enumerations +extension SpyRouter { + enum State { + case initialised + case presented + case dismissed + } +} diff --git a/Libraries/Coordination/Test/Helpers/TestViewControllers.swift b/Libraries/Coordination/Test/Helpers/TestViewControllers.swift new file mode 100644 index 0000000..1b9a1bb --- /dev/null +++ b/Libraries/Coordination/Test/Helpers/TestViewControllers.swift @@ -0,0 +1,12 @@ +// +// TestViewControllers.swift +// ReviewsCoordinationTests +// +// Created by Javier Cicchelli on 21/03/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +import UIKit + +final class SomeViewController: UIViewController {} +final class OtherViewController: UIViewController {} diff --git a/Libraries/Coordination/Test/Tests/Protocols/CoordinatorTests.swift b/Libraries/Coordination/Test/Tests/Protocols/CoordinatorTests.swift new file mode 100644 index 0000000..ea9af6a --- /dev/null +++ b/Libraries/Coordination/Test/Tests/Protocols/CoordinatorTests.swift @@ -0,0 +1,143 @@ +// +// CoordinatorTests.swift +// ReviewsCoordinationTest +// +// Created by Javier Cicchelli on 21/03/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +import ReviewsCoordinationKit +import UIKit +import XCTest + +final class CoordinatorTests: XCTestCase { + + // MARK: Properties + private var router: SpyRouter! + private var coordinator: Coordinator! + + // MARK: Tests + func testPresent_withoutOnDismissClosure() { + // Executing this test on the main thread is required as a `UIViewController` instance in being initialised here. + DispatchQueue.main.async { + // GIVEN + self.router = SpyRouter() + self.coordinator = SomeCoordinator(router: self.router) + + // WHEN + self.coordinator.present( + animated: false, + onDismiss: nil + ) + + // THEN + XCTAssertTrue(self.coordinator.children.isEmpty) + XCTAssertEqual(self.router.state, .presented) + XCTAssertTrue(self.router.viewController is SomeViewController) + XCTAssertFalse(self.router.animated ?? true) + XCTAssertNil(self.router.onDismiss) + } + } + + func testPresent_withOnDismissClosure() { + // Executing this test on the main thread is required as a `UIViewController` instance in being initialised here. + DispatchQueue.main.async { + // GIVEN + self.router = SpyRouter() + self.coordinator = OtherCoordinator(router: self.router) + + // WHEN + self.coordinator.present(animated: true) {} + + // THEN + XCTAssertTrue(self.coordinator.children.isEmpty) + XCTAssertEqual(self.router.state, .presented) + XCTAssertTrue(self.router.viewController is OtherViewController) + XCTAssertTrue(self.router.animated ?? false) + XCTAssertNotNil(self.router.onDismiss) + } + } + + func testPresentChild_withoutOnDismissClosure() { + // Executing this test on the main thread is required as a `UIViewController` instance in being initialised here. + DispatchQueue.main.async { + // GIVEN + self.router = SpyRouter() + self.coordinator = SomeCoordinator(router: self.router) + + let child = OtherCoordinator(router: self.router) + + // WHEN + self.coordinator.present( + child: child, + animated: false + ) + + // THEN + XCTAssertFalse(self.coordinator.children.isEmpty) + XCTAssertEqual(self.coordinator.children.count, 1) + XCTAssertEqual(self.router.state, .presented) + XCTAssertTrue(self.router.viewController is OtherViewController) + XCTAssertFalse(self.router.animated ?? true) + XCTAssertNil(self.router.onDismiss) + } + } + + func testPresentChild_withOnDismissClosure() { + // Executing this test on the main thread is required as a `UIViewController` instance in being initialised here. + DispatchQueue.main.async { + // GIVEN + self.router = SpyRouter() + self.coordinator = OtherCoordinator(router: self.router) + + let child = SomeCoordinator(router: self.router) + + // WHEN + self.coordinator.present( + child: child, + animated: true + ) {} + + // THEN + XCTAssertFalse(self.coordinator.children.isEmpty) + XCTAssertEqual(self.coordinator.children.count, 1) + XCTAssertEqual(self.router.state, .presented) + XCTAssertTrue(self.router.viewController is SomeViewController) + XCTAssertTrue(self.router.animated ?? false) + XCTAssertNotNil(self.router.onDismiss) + } + } + + func testDismiss_notAnimated() { + // GIVEN + router = SpyRouter() + coordinator = OtherCoordinator(router: router) + + // WHEN + coordinator.dismiss(animated: false) + + // THEN + XCTAssertTrue(coordinator.children.isEmpty) + XCTAssertEqual(router.state, .dismissed) + XCTAssertNil(router.viewController) + XCTAssertFalse(router.animated ?? true) + XCTAssertNil(router.onDismiss) + } + + func testDismiss_animated() { + // GIVEN + router = SpyRouter() + coordinator = OtherCoordinator(router: router) + + // WHEN + coordinator.dismiss(animated: true) + + // THEN + XCTAssertTrue(coordinator.children.isEmpty) + XCTAssertEqual(router.state, .dismissed) + XCTAssertNil(router.viewController) + XCTAssertTrue(router.animated ?? false) + XCTAssertNil(router.onDismiss) + } + +} diff --git a/Libraries/Package.swift b/Libraries/Package.swift index ba29fe8..e0327a1 100644 --- a/Libraries/Package.swift +++ b/Libraries/Package.swift @@ -24,7 +24,7 @@ let package = Package( .target( name: .Target.coordination.kit, dependencies: [ - .byName(name: .Target.coordination.kit), + .byName(name: .Target.foundation.kit), ], path: "Coordination/Kit" ),