Skip to content

Commit

Permalink
Improve view initialization (#42)
Browse files Browse the repository at this point in the history
Currently, when you initialize an event generator from a UIView, it adds that view directly to a UIWindow. This can be a destructive change because the view might already be a subview of another view (possibly even already added to a window) and it will get removed.

This change detects if the view already has a window and uses that directly. If not, it will get the top level superview by transversing the view hierarchy and use that instead. Because we set the mainView to the view that was passed in the initializer, everything else remains the same and it should not be a breaking change.
  • Loading branch information
gabriellanata authored Feb 25, 2022
1 parent 1736a39 commit f61b74c
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 8 deletions.
2 changes: 1 addition & 1 deletion HammerTests.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = "HammerTests"
spec.version = "0.13.3"
spec.version = "0.14.0"
spec.summary = "iOS touch and keyboard syntheis library for unit tests."
spec.description = "Hammer is a touch and keyboard synthesis library for emulating user interaction events. It enables new ways of triggering UI actions in unit tests, replicating a real world environment as much as possible."
spec.homepage = "https://github.com/lyft/Hammer"
Expand Down
14 changes: 10 additions & 4 deletions Sources/Hammer/EventGenerator/EventGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,12 @@ public final class EventGenerator {

/// Initialize an event generator for a specified UIViewController.
///
/// Event Generator will temporarily create a wrapper UIWindow to send touches.
/// If the view controller's view does not have a window, this will temporarily create a wrapper
/// UIWindow to send touches.
///
/// - parameter viewController: The viewController to receive events.
public convenience init(viewController: UIViewController) throws {
let window = UIWindow(wrapping: viewController)
let window = viewController.view.window ?? UIWindow(wrapping: viewController)

if #available(iOS 13.0, *) {
window.backgroundColor = .systemBackground
Expand All @@ -81,12 +82,17 @@ public final class EventGenerator {

/// Initialize an event generator for a specified UIView.
///
/// Event Generator will temporarily create a wrapper UIWindow to send touches.
/// If the view does not have a window, this will temporarily create a wrapper UIWindow to send touches.
///
/// - parameter view: The view to receive events.
/// - parameter alignment: The wrapping alignment to use.
public convenience init(view: UIView, alignment: WrappingAlignment = .center) throws {
try self.init(viewController: UIViewController(wrapping: view, alignment: alignment))
if let window = view.window {
try self.init(window: window)
} else {
try self.init(viewController: UIViewController(wrapping: view.topLevelView, alignment: alignment))
}

self.mainView = view
}

Expand Down
6 changes: 3 additions & 3 deletions Sources/Hammer/Utilties/HammerError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ extension HammerError: CustomStringConvertible {
case .viewIsNotInHierarchy(let view):
return "View is not in hierarchy: \(view.shortDescription)"
case .viewIsNotVisible(let view):
return "View is not in visible: \(view.shortDescription)"
return "View is not visible: \(view.shortDescription)"
case .viewIsNotHittable(let view):
return "View is not in hittable: \(view.shortDescription)"
return "View is not hittable: \(view.shortDescription)"
case .pointIsNotHittable(let point):
return "Point is not in hittable: \(point)"
return "Point is not hittable: \(point)"
case .unableToFindView(let identifier):
return "Unable to find view: \"\(identifier)\""
case .invalidViewType(let identifier, let type, let expected):
Expand Down
7 changes: 7 additions & 0 deletions Sources/Hammer/Utilties/UIKit+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,10 @@ extension UIViewController {
}
}
}

extension UIView {
/// Returns the view at the top level of the view hierarchy. Could be a UIWindow.
var topLevelView: UIView {
return self.superview?.topLevelView ?? self
}
}

0 comments on commit f61b74c

Please sign in to comment.