Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions Example/TSAlertController.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; };
607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; };
607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
607FACEC1AFB9204008FA782 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* Tests.swift */; };
607FACEC1AFB9204008FA782 /* TSAlertControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* TSAlertControllerTests.swift */; };
B9CB7BB683CE0BF2C0A6D730 /* Pods_TSAlertController_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01E2986C7734B41FD672F351 /* Pods_TSAlertController_Tests.framework */; };
C7692F1E2D5CB521009AB67F /* Wanderlust.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C7692F1D2D5CB521009AB67F /* Wanderlust.ttf */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -44,14 +44,25 @@
607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
607FACE51AFB9204008FA782 /* TSAlertController_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TSAlertController_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
607FACEB1AFB9204008FA782 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = "<group>"; };
607FACEB1AFB9204008FA782 /* TSAlertControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAlertControllerTests.swift; sourceTree = "<group>"; };
7C048B6697456CBE0C3CE64E /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
C7692F1D2D5CB521009AB67F /* Wanderlust.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Wanderlust.ttf; sourceTree = "<group>"; };
F0B7234F0869C770636141FB /* Pods-TSAlertController_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TSAlertController_Tests.debug.xcconfig"; path = "Target Support Files/Pods-TSAlertController_Tests/Pods-TSAlertController_Tests.debug.xcconfig"; sourceTree = "<group>"; };
F20D66B1383ED02E54413689 /* Pods-TSAlertController_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TSAlertController_Example.release.xcconfig"; path = "Target Support Files/Pods-TSAlertController_Example/Pods-TSAlertController_Example.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
C755164E2D6C6C2E003A34D7 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
MockViewController.swift,
);
target = 607FACCF1AFB9204008FA782 /* TSAlertController_Example */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
C755164A2D6C6C23003A34D7 /* Mock */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (C755164E2D6C6C2E003A34D7 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Mock; sourceTree = "<group>"; };
C7C7C55D2D5AD7E00099D5CB /* CustomView */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = CustomView; sourceTree = "<group>"; };
/* End PBXFileSystemSynchronizedRootGroup section */

Expand Down Expand Up @@ -130,7 +141,8 @@
607FACE81AFB9204008FA782 /* Tests */ = {
isa = PBXGroup;
children = (
607FACEB1AFB9204008FA782 /* Tests.swift */,
C755164A2D6C6C23003A34D7 /* Mock */,
607FACEB1AFB9204008FA782 /* TSAlertControllerTests.swift */,
607FACE91AFB9204008FA782 /* Supporting Files */,
);
path = Tests;
Expand Down Expand Up @@ -230,6 +242,9 @@
dependencies = (
607FACE71AFB9204008FA782 /* PBXTargetDependency */,
);
fileSystemSynchronizedGroups = (
C755164A2D6C6C23003A34D7 /* Mock */,
);
name = TSAlertController_Tests;
productName = Tests;
productReference = 607FACE51AFB9204008FA782 /* TSAlertController_Tests.xctest */;
Expand Down Expand Up @@ -378,7 +393,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
607FACEC1AFB9204008FA782 /* Tests.swift in Sources */,
607FACEC1AFB9204008FA782 /* TSAlertControllerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
24 changes: 24 additions & 0 deletions Example/Tests/Mock/MockViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// MockViewController.swift
// TSAlertController
//
// Created by 김건우 on 2/24/25.
// Copyright © 2025 CocoaPods. All rights reserved.
//

import UIKit

final class MockViewController: UIViewController {
var presentViewControllerTarget: UIViewController?

override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
//
viewControllerToPresent.loadViewIfNeeded()
//
viewControllerToPresent.beginAppearanceTransition(true, animated: flag)
viewControllerToPresent.endAppearanceTransition()

//
presentViewControllerTarget = viewControllerToPresent
}
}
221 changes: 221 additions & 0 deletions Example/Tests/TSAlertControllerTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import XCTest
@testable import TSAlertController

final class TSAlertControllerTests: XCTestCase {

func testTSAlertController_WhenInitialized_ShouldSetTitleMessageAndPreferredStyle() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
message: "Descriptive text that provides more details about the reason for the alert.",
preferredStyle: .alert
)
let mockViewController = MockViewController()

// when
mockViewController.present(alertController, animated: true)

// then
XCTAssertEqual(alertController.title, "The title of the alert")
XCTAssertEqual(alertController.message, "Descriptive text that provides more details about the reason for the alert.")
XCTAssertEqual(alertController.preferredStyle, .alert)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

func testTSAlertController_WhenIntializedWithTextFields_ShouldSetTextFields() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
preferredStyle: .alert
)
let mockViewController = MockViewController()

alertController.addTextField()
alertController.addTextField()

// when
mockViewController.present(alertController, animated: true)

// then
XCTAssertEqual(alertController.textFields?.count, 2)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

func testTSAlertController_WhenInitializedWithTwoButtonsAndAutomaticAxis_ShouldSetCorrectActionsOrderAndCount() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
preferredStyle: .alert
)
let mockViewController = MockViewController()

let ok = TSAlertAction(title: "OK", style: .default)
let cancel = TSAlertAction(title: "Cancel", style: .cancel)
alertController.addAction(ok)
alertController.addAction(cancel)

// when
mockViewController.present(alertController, animated: true)

// then
let actions = alertController.actions
XCTAssertEqual(actions.count, 2)
XCTAssertEqual(actions[0], cancel) // In LTR, the Cancel button is positioned at the far right.
XCTAssertEqual(alertController.viewConfiguration.buttonGroupAxis, .horizontal)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

func testTSAlertController_WhenIntializedWithFourButtonsAndAutomaticAxis_ShouldSetCorrectActionsOrderAndCount() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
preferredStyle: .alert
)
let mockViewController = MockViewController()

let home = TSAlertAction(title: "Go to Home", style: .default)
let profile = TSAlertAction(title: "Go to Profile", style: .default)
let settings = TSAlertAction(title: "Go to Settings", style: .default)
let cancel = TSAlertAction(title: "Cancel", style: .cancel)
alertController.addAction(home)
alertController.addAction(profile)
alertController.addAction(cancel)
alertController.addAction(settings)

// when
mockViewController.present(alertController, animated: true)

// then
let actions = alertController.actions
XCTAssertEqual(actions.count, 4)
XCTAssertEqual(actions[3], cancel) // If the button axis is vertical, the Cancel button is positioned at the very bottom.
XCTAssertEqual(actions, [home, profile, settings, cancel])
XCTAssertEqual(alertController.viewConfiguration.buttonGroupAxis, .vertical)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

func testTSAlertController_WhenInitalizedWithFourButtonsAndAutomaticAxis_ShouldSetCorrectActionsOrderAndCount() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
preferredStyle: .alert
)
let mockViewController = MockViewController()

alertController.addAction(.init(title: "Cancel", style: .cancel))
}


func testTSAlertController_WhenIntlaizedWithAlertStyle_ShouldSetDefaultConfiguration() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
preferredStyle: .alert
)
let mockViewController = MockViewController()

// when
mockViewController.present(alertController, animated: true)

// then
let config = alertController.configuration
XCTAssertEqual(config.enteringTransition, .fadeInAndScaleDown)
XCTAssertEqual(config.exitingTransition, .fadeOut)
XCTAssertEqual(config.headerAnimation, .none)
XCTAssertEqual(config.buttonGroupAnimation, .none)
XCTAssertEqual(config.prefersGrabberVisible, false)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

func testTSAlertController_WhenIntializedWithAlertStyle_SouldSetEnforceCorrectConfiguration() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
preferredStyle: .alert
)
let mockViewController = MockViewController()

// when
alertController.configuration.prefersGrabberVisible = true
mockViewController.present(alertController, animated: true)

// then
let config = alertController.configuration
XCTAssertEqual(config.prefersGrabberVisible, false)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

func testTSAlertController_WhenIntializedWithFloatingSheetStyle_ShouldSetDefaultConfiguration() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
preferredStyle: .floatingSheet
)
let mockViewController = MockViewController()

// when
mockViewController.present(alertController, animated: true)

// then
let config = alertController.configuration
XCTAssertEqual(config.enteringTransition, .slideUp)
XCTAssertEqual(config.exitingTransition, .slideDown)
XCTAssertEqual(config.headerAnimation, .none)
XCTAssertEqual(config.buttonGroupAnimation, .none)
XCTAssertEqual(config.prefersGrabberVisible, true)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

func testTSAlertController_WhenIntilizedWithFloatinSheetStyle_ShouldSetEnforceCorrectConfiguration() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
preferredStyle: .floatingSheet
)
let mockViewController = MockViewController()

// when
mockViewController.present(alertController, animated: true)

// then
XCTAssertTrue(true)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

func testTSAlertController_WhenIntializedWithAlertStyle_ShouldSetDefaultViewConfiguration() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
preferredStyle: .alert
)
let mockViewController = MockViewController()

// when
mockViewController.present(alertController, animated: true)

// then
let viewConfig = alertController.viewConfiguration
XCTAssertEqual(viewConfig.size.width, .proportional(minimumRatio: 0.75, maximumRatio: 0.75))
XCTAssertEqual(viewConfig.spacing.keyboardSpacing, 100)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

func testTSAlertController_WhenInitializedWithFloatingSheetStyle_ShouldSetDefaultViewConfiguration() {
// given
let alertController = TSAlertController(
title: "The title of the alert",
preferredStyle: .floatingSheet
)
let mockViewController = MockViewController()

// when
mockViewController.present(alertController, animated: true)

// then
let viewConfig = alertController.viewConfiguration
XCTAssertEqual(viewConfig.size.width, .proportional(minimumRatio: 0.95, maximumRatio: 0.95))
XCTAssertEqual(viewConfig.spacing.keyboardSpacing, 20)
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
}

}
28 changes: 0 additions & 28 deletions Example/Tests/Tests.swift

This file was deleted.

16 changes: 16 additions & 0 deletions Sources/TSAlert/TSAlertController+AnimationType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,19 @@ public extension TSAlertController {
}
}
}


// MARK: - Equatable

extension TSAlertController.AnimationType: Equatable {
public static func == (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case (.fadeIn, .fadeIn), (.slideUp, .slideUp):
return true
case let (.custom(lhsTransform, lhsAlpha), .custom(rhsTransform, rhsAlpha)):
return lhsTransform == rhsTransform && lhsAlpha == rhsAlpha
default:
return false
}
}
}
28 changes: 28 additions & 0 deletions Sources/TSAlert/TSAlertController+TransitionType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,31 @@ public extension TSAlertController {
}
}
}


// MARK: - Equatable

extension TSAlertController.EnteringTransitionType: Equatable {
public static func == (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case (.fadeInAndScaleDown, .fadeInAndScaleDown), (.slideUp, .slideUp):
return true
case let (.custom(lhsTransition), .custom(rhsTransition)):
return ObjectIdentifier(lhsTransition) == ObjectIdentifier(rhsTransition)
default:
return false
}
}
}
extension TSAlertController.ExitingTransitionType: Equatable {
public static func == (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case (.fadeOut, .fadeOut), (.slideDown, .slideDown):
return true
case let (.custom(lhsTransition), .custom(rhsTransition)):
return ObjectIdentifier(lhsTransition) == ObjectIdentifier(rhsTransition)
default:
return false
}
}
}
Loading