Skip to content
This repository has been archived by the owner on Mar 24, 2022. It is now read-only.

Commit

Permalink
-tap should raise when the control has no width or height
Browse files Browse the repository at this point in the history
Encountered this on a project today. It felt very strange that PCK would allow
you to tap on controls that wouldn't be able to receive touch events in a real
setting. This sparked a discussion around "should we be using -clipsToBounds=Yes ?"
but decided that improving PCK to catch these errors earlier would be better.

For reference, the problem we needed to fix had to do with autolayout. We had forgot
to set some autolayout constraints correctly and ended up with a zero width, zero height
control that, while it looked okay, wasn't tappable.
  • Loading branch information
tjarratt committed Dec 14, 2015
1 parent c3f6489 commit a2e01b6
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGES.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* Adds ability to toggle UIViewController spec stubs
* Adds support for inspecting data loaded directly into UIWebViews
* Adds support for resetting messages sent to WatchKit interface elements.
* `-tap` will raise an exception if the control's width or height is zero.

## 0.3.0

Expand Down
2 changes: 2 additions & 0 deletions UIKit/Spec/Extensions/UIBarButtonItemSpec+Spec.mm
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
#endif

UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(0, 0, 1, 1);

[button addTarget:target
action:@selector(hello)
forControlEvents:event];
Expand Down
41 changes: 40 additions & 1 deletion UIKit/Spec/Extensions/UIControlSpec+Spec.mm
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@
beforeEach(^{
button.hidden = NO;
button.enabled = YES;
button.bounds = CGRectMake(0, 0, 100, 100);
});

context(@"when visible and enabled", ^{
context(@"when visible, enabled, and non-zero size", ^{
it(@"should send control actions", ^{
[button tap];
target should have_received(@selector(hello));
Expand Down Expand Up @@ -77,6 +78,44 @@
target should_not have_received(@selector(hello));
});
});

context(@"when its width is zero", ^{
beforeEach(^{
button.frame = CGRectMake(0, 0, 0, 100);
});

it(@"should cause a spec failure", ^{
^{
[button tap];
} should raise_exception.with_reason(@"Can't tap a control with no width or height. Your control may not be laid out correctly.");
});

it(@"should not send control actions", ^{
@try {
[button tap];
} @catch(NSException *e) { }
target should_not have_received(@selector(hello));
});
});

context(@"when its height is zero", ^{
beforeEach(^{
button.frame = CGRectMake(0, 0, 100, 0);
});

it(@"should cause a spec failure", ^{
^{
[button tap];
} should raise_exception.with_reason(@"Can't tap a control with no width or height. Your control may not be laid out correctly.");
});

it(@"should not send control actions", ^{
@try {
[button tap];
} @catch(NSException *e) { }
target should_not have_received(@selector(hello));
});
});
});
});

Expand Down
12 changes: 10 additions & 2 deletions UIKit/SpecHelper/Extensions/UIControl+Spec.m
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
#import "UIControl+Spec.h"

static NSString *exceptionName = @"Untappable";
static NSString *hiddenExceptionReason = @"Can't tap an invisible control";
static NSString *disabledExceptionReason = @"Can't tap a disabled control";
static NSString *zeroSizeExceptionReason = @"Can't tap a control with no width or height. Your control may not be laid out correctly.";

@implementation UIControl (Spec)

- (void)tap {
if (self.hidden) {
[[NSException exceptionWithName:@"Untappable" reason:@"Can't tap an invisible control" userInfo:nil] raise];
[[NSException exceptionWithName:exceptionName reason:hiddenExceptionReason userInfo:nil] raise];
}
if (!self.isEnabled) {
[[NSException exceptionWithName:@"Untappable" reason:@"Can't tap a disabled control" userInfo:nil] raise];
[[NSException exceptionWithName:exceptionName reason:disabledExceptionReason userInfo:nil] raise];
}
if (self.bounds.size.width == 0 || self.bounds.size.height == 0) {
[[NSException exceptionWithName:exceptionName reason:zeroSizeExceptionReason userInfo:nil] raise];
}
[self sendActionsForControlEvents:UIControlEventTouchUpInside];
}
Expand Down

0 comments on commit a2e01b6

Please sign in to comment.