Create a gist now

Instantly share code, notes, and snippets.

Swift 2.2 curried functions for asserting IB outlets and actions are wired up correctly.
//
// SpecFunctions.swift
//
// Created by Ben Chatelain on 6/6/15.
// Copyright (c) 2015-2016 Ben Chatelain.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Quick
import Nimble
import UIKit
typealias ButtonTest = String -> AnyObject?
typealias CurriedOutletTest = (UIViewController) -> (String -> AnyObject?)
typealias CurriedButtonTest = (UIViewController) -> (AnyClass -> (String -> AnyObject?))
// MARK: - Outlets
func outlet(viewController: UIViewController)(_ outlet: String) -> AnyObject? {
guard let object = viewController.valueForKey(outlet)
else { fail("\(outlet) outlet was nil"); return nil }
return object
}
func outlet<T>(viewController: UIViewController)(type: T.Type)(_ expectedOutlet: String) -> T? {
guard let object = outlet(viewController)(expectedOutlet)
else { return nil }
debugPrint(object.dynamicType)
guard let objectOfType = object as? T
else { fail("\(object) outlet was not a \(type)"); return nil }
return objectOfType
}
// MARK: - Actions
func action<T>(viewController: UIViewController)(type: T.Type)
(_ expectedAction: String, from expectedOutlet: String) {
let optionalControl = outlet(viewController)(type: type)(expectedOutlet)
var target: AnyObject?
var action: String?
if let control = optionalControl {
switch control {
case let button as UIBarButtonItem:
target = button.target
action = button.action.description
case let control as UIControl:
target = control.allTargets().first!
var allActions: [String] = []
for event: UIControlEvents in [.TouchUpInside, .ValueChanged] {
allActions += control.actionsForTarget(target!, forControlEvent: event) ?? []
}
// Filter down to the expected action
action = allActions.filter({$0 == expectedAction}).first!
default:
fail("Unhandled control type: \(control.dynamicType)")
}
}
expect(target) === viewController
expect(action).toNot(beNil())
if let action = action {
expect(action) == expectedAction
}
}
import Quick
import Nimble
import UIKit
class ViewControllerSpec: QuickSpec {
override func spec() {
// Start with an empty object so property can be non-optional
// Also needs to be initialized before passing to curried helper functions.
var viewController = ViewController()
beforeEach {
viewController = StoryboardScene.Workspace.instantiateSettingsTable()
viewController.loadView()
expect(viewController.view).toNot(beNil())
}
var hasButtonOutlet = outlet(viewController)(type: UIBarButtonItem.self)
var receivesAction = action(viewController)(type: UIBarButtonItem.self)
describe("view controller") {
// MARK: - Outlets
it("has a leftDoneButton outlet") {
hasButtonOutlet("leftDoneButton")
}
it("has a rightDoneButton outlet") {
hasButtonOutlet("rightDoneButton")
}
// MARK: - Actions
it("receives a didTapDone action from leftDoneButton") {
receivesAction("didTapDone", from: "leftDoneButton")
}
it("receives a didTapDone action from rightDoneButton") {
receivesAction("didTapDone", from: "rightDoneButton")
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment