Skip to content

Commit

Permalink
Merge pull request #105 from j-mutter/feature/keyboards
Browse files Browse the repository at this point in the history
Implements SLKeyboard protocol for custom keyboards
  • Loading branch information
wearhere committed Feb 11, 2014
2 parents 9d8105e + e7e3a66 commit 1b8a756
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 82 deletions.
10 changes: 10 additions & 0 deletions Integration Tests/Tests/SLKeyboardTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,14 @@ - (void)testTapKeyboardKey {
@"Did not type character as expected.");
}

- (void)testHideKeyboard_iPad {
SLAskApp(showKeyboard);
[self wait:[SLAskApp(keyboardInfo)[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];

[[SLKeyboard keyboard] hide];
[self wait:[SLAskApp(keyboardInfo)[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];

SLAssertTrueWithTimeout([[SLKeyboard keyboard] isValid] == NO, 2.0 , @"Keyboard should not be valid.");
}

@end

This file was deleted.

This file was deleted.

55 changes: 46 additions & 9 deletions Sources/Classes/UIAutomation/User Interface Elements/SLKeyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,30 @@
#import "SLButton.h"

/**
The SLKeyboard allows you to test whether your application's keyboard
is visible, and type strings.
To tap individual keys on the keyboard, use SLKeyboardKey.
The iOS 7 SDK exposes the UIInputView class which allows the creation of
custom keyboards and other input views.
https://developer.apple.com/library/iOS/documentation/UIKit/Reference/UIInputView_class/Reference/Reference.html
The SLKeyboard protocol declares a standard way to interact with these custom
keyboards, such as -typeString:, where classes implementing the protocol define
any logic required to enter a string via their accosiated custom UIInputView
*/
@interface SLKeyboard : SLStaticElement

@protocol SLKeyboard <NSObject>

/**
Returns an element representing the application's keyboard.
@return An element representing the application's keyboard.
*/
+ (SLKeyboard *)keyboard;
+ (instancetype)keyboard;

/**
Taps the keys of the specified keyboard as required
Taps the keys of the specified keyboard as required
to generate the specified string.
This string may contain characters that do not appear on the keyboard
in the keyboard's current state--the keyboard will change keyplanes
This string may contain characters that do not appear on the keyboard
in the keyboard's current state--the keyboard will change keyplanes
as necessary to make the corresponding keys visible.
@param string The string to be typed on the keyboard.
Expand All @@ -56,6 +60,39 @@
*/
- (void)typeString:(NSString *)string;

@optional
/**
Tap the keyboard's "Hide Keyboard" button to hide the keyboard without
executing any done/submit actions
*/
- (void)hide;

/**
Uses -[SLKeyboard typeString:] to tap the keys of the input string on the
receiver. Unlike -[SLKeyboard typeString:], this method will not throw an
exception if the input string contains characters that can be accessed on
the receiver only through a tap-hold gesture. Instead, this method will
send the setValue JavaScript message to the input element as a "fallback"
procedure.
@param string The string to be typed on the keyboard or set as the value for
element.
@param element The user interface element on which the setValue JavaScript
method will be called if the internal call to -[SLKeyboard typeString:]
throws an exception.
*/
- (void)typeString:(NSString *)string withSetValueFallbackUsingElement:(SLUIAElement *)element;

@end

/**
The SLKeyboard allows you to test whether your application's keyboard
is visible, and type strings.
To tap individual keys on the keyboard, use SLKeyboardKey.
*/
@interface SLKeyboard : SLStaticElement <SLKeyboard>

@end


Expand Down
14 changes: 14 additions & 0 deletions Sources/Classes/UIAutomation/User Interface Elements/SLKeyboard.m
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ - (void)typeString:(NSString *)string {
}
}

- (void)typeString:(NSString *)string withSetValueFallbackUsingElement:(SLUIAElement *)element {
@try {
[self typeString:string];
} @catch (id exception) {
[[SLLogger sharedLogger] logWarning:[NSString stringWithFormat:@"-[SLKeyboard typeString:] will fall back on UIAElement.setValue due to an exception in UIAKeyboard.typeString: %@", exception]];
[element waitUntilTappable:YES thenSendMessage:@"setValue('%@')", [string slStringByEscapingForJavaScriptLiteral]];
}
}

- (void)hide
{
[[SLKeyboardKey elementWithAccessibilityLabel:(@"Hide keyboard")] tap];
}

@end


Expand Down
25 changes: 25 additions & 0 deletions Sources/Classes/UIAutomation/User Interface Elements/SLTextField.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
//

#import "SLElement.h"
#import "SLKeyboard.h"

/**
`SLTextField` matches instances of `UITextField`.
Expand All @@ -39,6 +40,30 @@
*/
@property (nonatomic, copy) NSString *text;

/**
Type the text in the text field with a specific keyboard.
@param text A string to type into the text field
@param keyboard An SLElement that implements the SLKeyboard protocol
that will be used to type the given string
@exception SLUIAElementInvalidException Raised if the element is not valid
by the end of the [default timeout](+defaultTimeout).
@exception SLUIAElementNotTappableException Raised if the element is not
tappable when whatever amount of time remains of the default timeout after
the element becomes valid elapses.
*/
- (void)setText:(NSString *)text withKeyboard:(id<SLKeyboard>)keyboard;

/**
The default keyboard to be used by `setText:` and `setText:withKeyboard`.
Defaults to SLKeyboard
*/
@property (nonatomic) id<SLKeyboard> defaultKeyboard;

@end

/**
Expand Down
13 changes: 10 additions & 3 deletions Sources/Classes/UIAutomation/User Interface Elements/SLTextField.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

#import "SLTextField.h"
#import "SLUIAElement+Subclassing.h"
#import "SLKeyboard+Internal.h"

@implementation SLTextField

Expand All @@ -31,6 +30,11 @@ - (NSString *)text {
}

- (void)setText:(NSString *)text {
[self setText:text withKeyboard: _defaultKeyboard ?: [SLKeyboard keyboard]];
}

- (void)setText:(NSString *)text withKeyboard:(id<SLKeyboard>)keyboard
{
// Tap to show the keyboard (if the field doesn't already have keyboard focus,
// because in that case a real user would probably not tap again before typing)
if (![self hasKeyboardFocus]) {
Expand All @@ -39,8 +43,11 @@ - (void)setText:(NSString *)text {

// Clear any current text before typing the new text.
[self waitUntilTappable:YES thenSendMessage:@"setValue('')"];

[[SLKeyboard keyboard] typeString:text withSetValueFallbackUsingElement:self];
if ([keyboard respondsToSelector:@selector(typeString:withSetValueFallbackUsingElement:)]) {
[keyboard typeString:text withSetValueFallbackUsingElement:self];
} else {
[keyboard typeString:text];
}
}

- (BOOL)matchesObject:(NSObject *)object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
//

#import "SLElement.h"
#import "SLKeyboard.h"

/**
`SLTextView` matches instances of `UITextView`.
*/
@interface SLTextView : SLElement

/**
The text displayed by the text field.
The text displayed by the text view.
@exception SLUIAElementInvalidException Raised by both `-text` and `-setText:`
if the element is not valid by the end of the [default timeout](+defaultTimeout).
Expand All @@ -25,6 +26,30 @@
*/
@property (nonatomic, copy) NSString *text;

/**
Type the text in the text view with a specific keyboard.
@param text A string to type into the text view
@param keyboard An SLElement that implements the SLKeyboard protocol
that will be used to type the given string
@exception SLUIAElementInvalidException Raised if the element is not valid
by the end of the [default timeout](+defaultTimeout).
@exception SLUIAElementNotTappableException Raised if the element is not
tappable when whatever amount of time remains of the default timeout after
the element becomes valid elapses.
*/
- (void)setText:(NSString *)text withKeyboard:(id<SLKeyboard>)keyboard;

/**
The default keyboard to be used by `setText:` and `setText:withKeyboard`.
Defaults to SLKeyboard
*/
@property (nonatomic) id<SLKeyboard> defaultKeyboard;

@end


Expand Down
17 changes: 13 additions & 4 deletions Sources/Classes/UIAutomation/User Interface Elements/SLTextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@

#import "SLTextView.h"
#import "SLUIAElement+Subclassing.h"
#import "SLKeyboard+Internal.h"

@implementation SLTextView

- (NSString *)text {
return [self value];
}

- (void)setText:(NSString *)text {
- (void)setText:(NSString *)text
{
[self setText:text withKeyboard:_defaultKeyboard ?: [SLKeyboard keyboard]];
}

- (void)setText:(NSString *)text withKeyboard:(id<SLKeyboard>)keyboard
{
// Tap to show the keyboard (if the field doesn't already have keyboard focus,
// because in that case a real user would probably not tap again before typing)
if (![self hasKeyboardFocus]) {
Expand All @@ -25,8 +30,12 @@ - (void)setText:(NSString *)text {

// Clear any current text before typing the new text.
[self waitUntilTappable:YES thenSendMessage:@"setValue('')"];

[[SLKeyboard keyboard] typeString:text withSetValueFallbackUsingElement:self];

if ([keyboard respondsToSelector:@selector(typeString:withSetValueFallbackUsingElement:)]) {
[keyboard typeString:text withSetValueFallbackUsingElement:self];
} else {
[keyboard typeString:text];
}
}

- (BOOL)matchesObject:(NSObject *)object {
Expand Down
8 changes: 0 additions & 8 deletions Subliminal.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
0640035B178FDE7800479173 /* SLElementTouchAndHoldTestViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 06400359178FDE7800479173 /* SLElementTouchAndHoldTestViewController.xib */; };
064B6F55173B13E9004AB1BF /* SLElementVisibilityTestCoveredByClearRegion.xib in Resources */ = {isa = PBXBuildFile; fileRef = 064B6F54173B13E9004AB1BF /* SLElementVisibilityTestCoveredByClearRegion.xib */; };
064B6FC7173DCE9A004AB1BF /* SLElementVisibilityWithSubviews.xib in Resources */ = {isa = PBXBuildFile; fileRef = 064B6FC6173DCE9A004AB1BF /* SLElementVisibilityWithSubviews.xib */; };
0657C0E2181528B8007E72DF /* SLKeyboard+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 0657C0E0181528B6007E72DF /* SLKeyboard+Internal.h */; };
0657C0E3181528B8007E72DF /* SLKeyboard+Internal.m in Sources */ = {isa = PBXBuildFile; fileRef = 0657C0E1181528B7007E72DF /* SLKeyboard+Internal.m */; };
068D3E4D16DE9008004E7E28 /* SLTableViewChildElementMatchingTestViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 068D3E4C16DE9008004E7E28 /* SLTableViewChildElementMatchingTestViewController.xib */; };
06953E3F178FDA7100B3D1B7 /* SLElementTouchAndHoldTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 06953E3E178FDA7100B3D1B7 /* SLElementTouchAndHoldTest.m */; };
0696BA5816E013D600DD70CF /* SLElementDraggingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0696BA5516E013D600DD70CF /* SLElementDraggingTest.m */; };
Expand Down Expand Up @@ -246,8 +244,6 @@
06400359178FDE7800479173 /* SLElementTouchAndHoldTestViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SLElementTouchAndHoldTestViewController.xib; sourceTree = "<group>"; };
064B6F54173B13E9004AB1BF /* SLElementVisibilityTestCoveredByClearRegion.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SLElementVisibilityTestCoveredByClearRegion.xib; sourceTree = "<group>"; };
064B6FC6173DCE9A004AB1BF /* SLElementVisibilityWithSubviews.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SLElementVisibilityWithSubviews.xib; sourceTree = "<group>"; };
0657C0E0181528B6007E72DF /* SLKeyboard+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SLKeyboard+Internal.h"; sourceTree = "<group>"; };
0657C0E1181528B7007E72DF /* SLKeyboard+Internal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SLKeyboard+Internal.m"; sourceTree = "<group>"; };
068D3E4C16DE9008004E7E28 /* SLTableViewChildElementMatchingTestViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SLTableViewChildElementMatchingTestViewController.xib; sourceTree = "<group>"; };
06953E3E178FDA7100B3D1B7 /* SLElementTouchAndHoldTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLElementTouchAndHoldTest.m; sourceTree = "<group>"; };
0696BA5516E013D600DD70CF /* SLElementDraggingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLElementDraggingTest.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -715,8 +711,6 @@
2CE9AA4B17E3A747007EF0B5 /* SLSwitch.m */,
F0C07A511704011300C93F93 /* SLKeyboard.h */,
F0C07A521704011300C93F93 /* SLKeyboard.m */,
0657C0E0181528B6007E72DF /* SLKeyboard+Internal.h */,
0657C0E1181528B7007E72DF /* SLKeyboard+Internal.m */,
F00800CC174C1C64001927AC /* SLPopover.h */,
F00800CD174C1C64001927AC /* SLPopover.m */,
F0C07A491704002100C93F93 /* SLTextField.h */,
Expand Down Expand Up @@ -952,7 +946,6 @@
F04346A7175AD10200D91F7F /* NSObject+SLVisibility.h in Headers */,
F0A3F63417A715AE007529C3 /* SLTextView.h in Headers */,
DB501DC917B9669A001658CB /* SLStatusBar.h in Headers */,
0657C0E2181528B8007E72DF /* SLKeyboard+Internal.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1194,7 +1187,6 @@
F04346A8175AD10200D91F7F /* NSObject+SLVisibility.m in Sources */,
F0A3F63517A715AE007529C3 /* SLTextView.m in Sources */,
DB501DCA17B9669A001658CB /* SLStatusBar.m in Sources */,
0657C0E3181528B8007E72DF /* SLKeyboard+Internal.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down

0 comments on commit 1b8a756

Please sign in to comment.