From 1cbeff45c39e4668a871f42023803ac63153e953 Mon Sep 17 00:00:00 2001 From: Alex Odawa Date: Wed, 21 Jan 2015 16:14:01 -0800 Subject: [PATCH 1/2] add a new test actor, KIFUIViewTestActor, which separates the APIs of finding from acting on an element --- Additions/NSPredicate+KIFAdditions.h | 18 + Additions/NSPredicate+KIFAdditions.m | 71 +++ Additions/NSString+KIFAdditions.h | 16 + Additions/NSString+KIFAdditions.m | 24 + .../UIAccessibilityElement-KIFAdditions.h | 6 + .../UIAccessibilityElement-KIFAdditions.m | 117 ++++- Classes/KIF.h | 3 + Classes/KIFTestActor.h | 2 - Classes/KIFUIObject.h | 18 + Classes/KIFUIObject.m | 28 ++ Classes/KIFUITestActor.h | 122 ++++- Classes/KIFUITestActor.m | 167 ++++--- Classes/KIFUIViewTestActor.h | 83 ++++ Classes/KIFUIViewTestActor.m | 435 ++++++++++++++++++ ...cessibilityIdentifierTests_ViewTestActor.m | 78 ++++ KIF Tests/CollectionViewTests_ViewTestActor.m | 63 +++ KIF Tests/CompositionTests_ViewTestActor.m | 68 +++ KIF Tests/ExistTests_ViewTestActor.m | 32 ++ KIF Tests/GestureTests_ViewTestActor.m | 111 +++++ KIF Tests/LandscapeTests_ViewTestActor.m | 40 ++ KIF Tests/LongPressTests_ViewTestActor.m | 45 ++ KIF Tests/ModalViewTests_ViewTestActor.m | 77 ++++ KIF Tests/MultiFingerTests_ViewTestActor.m | 85 ++++ KIF Tests/PickerTests_ViewTestActor.m | 114 +++++ KIF Tests/PullToRefreshTests_ViewTestActor.m | 41 ++ KIF Tests/ScrollViewTests_ViewTestActor.m | 40 ++ KIF Tests/SearchFieldTests_ViewTestActor.m | 37 ++ .../SpecificControlTests_ViewTestActor.m | 62 +++ KIF Tests/SystemAlertTests_ViewTestActor.m | 59 +++ KIF Tests/TableViewTests_ViewTestActor.m | 154 +++++++ KIF Tests/TappingTests_ViewTestActor.m | 84 ++++ KIF Tests/TypingTests_ViewTestActor.m | 99 ++++ .../WaitForAbscenceTests_ViewTestActor.m | 43 ++ .../WaitForAnimationTests_ViewTestActor.m | 35 ++ .../WaitForTappableViewTests_ViewTestActor.m | 43 ++ KIF Tests/WaitForViewTests_ViewTestActor.m | 33 ++ KIF Tests/WebViewTests_ViewTestActor.m | 47 ++ KIF.xcodeproj/project.pbxproj | 142 +++++- .../xcschemes/KIF Documentation.xcscheme | 10 +- .../xcshareddata/xcschemes/KIF.xcscheme | 2 +- .../xcschemes/KIFFramework.xcscheme | 10 +- 41 files changed, 2653 insertions(+), 111 deletions(-) create mode 100644 Additions/NSPredicate+KIFAdditions.h create mode 100644 Additions/NSPredicate+KIFAdditions.m create mode 100644 Additions/NSString+KIFAdditions.h create mode 100644 Additions/NSString+KIFAdditions.m create mode 100644 Classes/KIFUIObject.h create mode 100644 Classes/KIFUIObject.m create mode 100644 Classes/KIFUIViewTestActor.h create mode 100644 Classes/KIFUIViewTestActor.m create mode 100644 KIF Tests/AccessibilityIdentifierTests_ViewTestActor.m create mode 100644 KIF Tests/CollectionViewTests_ViewTestActor.m create mode 100644 KIF Tests/CompositionTests_ViewTestActor.m create mode 100644 KIF Tests/ExistTests_ViewTestActor.m create mode 100644 KIF Tests/GestureTests_ViewTestActor.m create mode 100644 KIF Tests/LandscapeTests_ViewTestActor.m create mode 100644 KIF Tests/LongPressTests_ViewTestActor.m create mode 100644 KIF Tests/ModalViewTests_ViewTestActor.m create mode 100644 KIF Tests/MultiFingerTests_ViewTestActor.m create mode 100644 KIF Tests/PickerTests_ViewTestActor.m create mode 100644 KIF Tests/PullToRefreshTests_ViewTestActor.m create mode 100644 KIF Tests/ScrollViewTests_ViewTestActor.m create mode 100644 KIF Tests/SearchFieldTests_ViewTestActor.m create mode 100644 KIF Tests/SpecificControlTests_ViewTestActor.m create mode 100644 KIF Tests/SystemAlertTests_ViewTestActor.m create mode 100644 KIF Tests/TableViewTests_ViewTestActor.m create mode 100644 KIF Tests/TappingTests_ViewTestActor.m create mode 100644 KIF Tests/TypingTests_ViewTestActor.m create mode 100644 KIF Tests/WaitForAbscenceTests_ViewTestActor.m create mode 100644 KIF Tests/WaitForAnimationTests_ViewTestActor.m create mode 100644 KIF Tests/WaitForTappableViewTests_ViewTestActor.m create mode 100644 KIF Tests/WaitForViewTests_ViewTestActor.m create mode 100644 KIF Tests/WebViewTests_ViewTestActor.m diff --git a/Additions/NSPredicate+KIFAdditions.h b/Additions/NSPredicate+KIFAdditions.h new file mode 100644 index 000000000..98f06f0b6 --- /dev/null +++ b/Additions/NSPredicate+KIFAdditions.h @@ -0,0 +1,18 @@ +// +// NSPredicate+KIFAdditions.h +// KIF +// +// Created by Alex Odawa on 2/3/15. +// +// + +#import + +@interface NSPredicate (KIFAdditions) + +@property NSString *kifPredicateDescription; + +- (NSArray *)flatten; +- (NSCompoundPredicate *)minusSubpredicatesFrom:(NSPredicate *)otherPredicate; + +@end diff --git a/Additions/NSPredicate+KIFAdditions.m b/Additions/NSPredicate+KIFAdditions.m new file mode 100644 index 000000000..9f89f3cde --- /dev/null +++ b/Additions/NSPredicate+KIFAdditions.m @@ -0,0 +1,71 @@ +// +// NSPredicate+KIFAdditions.m +// KIF +// +// Created by Alex Odawa on 2/3/15. +// +// + +#import +#import "NSPredicate+KIFAdditions.h" + +@implementation NSPredicate (KIFAdditions) + +- (NSArray *)flatten +{ + NSMutableArray *result = [[NSMutableArray alloc] init]; + + if ([self isKindOfClass:[NSCompoundPredicate class]]) { + for (NSPredicate *predicate in ((NSCompoundPredicate *)self).subpredicates) { + [result addObjectsFromArray:[predicate flatten]]; + } + } else { + [result addObject:self]; + } + + return result; +} + +- (NSCompoundPredicate *)minusSubpredicatesFrom:(NSPredicate *)otherPredicate; +{ + if (self == otherPredicate) { + return nil; + } + NSMutableSet *subpredicates = [NSMutableSet setWithArray:[self flatten]]; + NSMutableSet *otherSubpredicates = [NSMutableSet setWithArray:[otherPredicate flatten]]; + [subpredicates minusSet:otherSubpredicates]; + return [[NSCompoundPredicate alloc] initWithType:NSAndPredicateType + subpredicates:[subpredicates allObjects]]; +} + +- (void)setKifPredicateDescription:(NSString *)description; +{ + NSString *desc = description.copy; + objc_setAssociatedObject(self, @selector(kifPredicateDescription), desc, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (NSString *)kifPredicateDescription; +{ + id object = objc_getAssociatedObject(self, @selector(kifPredicateDescription)); + if (object) { + return object; + } + // Compound predicates containing subpredicates with the kifPredicateDescription set should still get our pretty formatting. + if ([self isKindOfClass:[NSCompoundPredicate class]]) { + NSArray *subpredicates = [self flatten]; + NSString *description = @""; + + for (NSPredicate *predicate in subpredicates) { + if (description.length > 0) { + description = [description stringByAppendingString:@", "]; + } + description = [description stringByAppendingString:predicate.kifPredicateDescription]; + } + + return description; + } + + return self.description; +} + +@end diff --git a/Additions/NSString+KIFAdditions.h b/Additions/NSString+KIFAdditions.h new file mode 100644 index 000000000..1cbacf624 --- /dev/null +++ b/Additions/NSString+KIFAdditions.h @@ -0,0 +1,16 @@ +// +// NSString+KIFAdditions.h +// KIF +// +// Created by Alex Odawa on 1/28/16. +// +// + +#import + +#pragma mark - NSString +@interface NSString (KIFAdditions) + +- (BOOL)KIF_isEqualToStringOrAttributedString:(id)aString; + +@end diff --git a/Additions/NSString+KIFAdditions.m b/Additions/NSString+KIFAdditions.m new file mode 100644 index 000000000..c20fc3e19 --- /dev/null +++ b/Additions/NSString+KIFAdditions.m @@ -0,0 +1,24 @@ +// +// NSString+KIFAdditions.m +// KIF +// +// Created by Alex Odawa on 1/28/16. +// +// + +#import "NSString+KIFAdditions.h" + +#pragma mark - NSString +@implementation NSString (KIFAdditions) + +- (BOOL)KIF_isEqualToStringOrAttributedString:(id)aString; +{ + // Somtimes Accessibility Elements will return an AXAttributedString. + // This compares the raw backing string against a vanilla NSString, ignoring any attributes. + if ([aString respondsToSelector:@selector(string)]) { + return [self isEqualToString:[(id)aString string]]; + } + return [self isEqualToString:aString]; +} + +@end diff --git a/Additions/UIAccessibilityElement-KIFAdditions.h b/Additions/UIAccessibilityElement-KIFAdditions.h index d8aee6c3a..552996a28 100644 --- a/Additions/UIAccessibilityElement-KIFAdditions.h +++ b/Additions/UIAccessibilityElement-KIFAdditions.h @@ -66,4 +66,10 @@ */ + (UIView *)viewContainingAccessibilityElement:(UIAccessibilityElement *)element tappable:(BOOL)mustBeTappable error:(NSError **)error; +/*! + @abstract Returns a human readable string of UIAccessiblityTrait names, derived from UIAccessibilityConstants.h. + @param traits The accessibility traits to list. +*/ ++ (NSString *)stringFromAccessibilityTraits:(UIAccessibilityTraits)traits; + @end diff --git a/Additions/UIAccessibilityElement-KIFAdditions.m b/Additions/UIAccessibilityElement-KIFAdditions.m index d0c877414..b073ec2d6 100644 --- a/Additions/UIAccessibilityElement-KIFAdditions.m +++ b/Additions/UIAccessibilityElement-KIFAdditions.m @@ -8,6 +8,7 @@ // which Square, Inc. licenses this file to you. #import "NSError-KIFAdditions.h" +#import "NSPredicate+KIFAdditions.h" #import "UIAccessibilityElement-KIFAdditions.h" #import "UIApplication-KIFAdditions.h" #import "UIScrollView-KIFAdditions.h" @@ -62,7 +63,7 @@ + (BOOL)accessibilityElement:(out UIAccessibilityElement **)foundElement view:(o if (!element) { if (error) { - *error = [NSError KIFErrorWithFormat:@"Could not find view matching: %@", predicate]; + *error = [self errorForFailingPredicate:predicate]; } return NO; } @@ -174,4 +175,118 @@ + (UIView *)viewContainingAccessibilityElement:(UIAccessibilityElement *)element return view; } ++ (NSError *)errorForFailingPredicate:(NSPredicate*)failingPredicate; +{ + NSPredicate *closestMatchingPredicate = [self findClosestMatchingPredicate:failingPredicate]; + if (closestMatchingPredicate) { + return [NSError KIFErrorWithFormat:@"Found element with %@ but not %@", \ + closestMatchingPredicate.kifPredicateDescription, \ + [failingPredicate minusSubpredicatesFrom:closestMatchingPredicate].kifPredicateDescription]; + } + return [NSError KIFErrorWithFormat:@"Could not find element with %@", failingPredicate.kifPredicateDescription]; +} + ++ (NSPredicate *)findClosestMatchingPredicate:(NSPredicate *)aPredicate; +{ + if (!aPredicate) { + return nil; + } + + UIAccessibilityElement *match = [[UIApplication sharedApplication] accessibilityElementMatchingBlock:^BOOL (UIAccessibilityElement *element) { + return [aPredicate evaluateWithObject:element]; + }]; + if (match) { + return aPredicate; + } + + // Breadth-First algorithm to match as many subpredicates as possible + NSMutableArray *queue = [NSMutableArray arrayWithObject:aPredicate]; + while (queue.count > 0) { + // Dequeuing + NSPredicate *predicate = [queue firstObject]; + [queue removeObject:predicate]; + + // Remove one subpredicate at a time an then check if an element would match this resulting predicate + for (NSPredicate *subpredicate in [predicate flatten]) { + NSPredicate *predicateMinusOneCondition = [predicate minusSubpredicatesFrom:subpredicate]; + if (predicateMinusOneCondition) { + UIAccessibilityElement *match = [[UIApplication sharedApplication] accessibilityElementMatchingBlock:^BOOL (UIAccessibilityElement *element) { + return [predicateMinusOneCondition evaluateWithObject:element]; + }]; + if (match) { + return predicateMinusOneCondition; + } + [queue addObject:predicateMinusOneCondition]; + } + } + } + return nil; +} + ++ (NSString *)stringFromAccessibilityTraits:(UIAccessibilityTraits)traits; +{ + if (traits == UIAccessibilityTraitNone) { + return @"UIAccessibilityTraitNone"; + } + + NSString *string = @""; + + NSArray *allTraits = @[ + @(UIAccessibilityTraitButton), + @(UIAccessibilityTraitLink), + @(UIAccessibilityTraitHeader), + @(UIAccessibilityTraitSearchField), + @(UIAccessibilityTraitImage), + @(UIAccessibilityTraitSelected), + @(UIAccessibilityTraitPlaysSound), + @(UIAccessibilityTraitKeyboardKey), + @(UIAccessibilityTraitStaticText), + @(UIAccessibilityTraitSummaryElement), + @(UIAccessibilityTraitNotEnabled), + @(UIAccessibilityTraitUpdatesFrequently), + @(UIAccessibilityTraitStartsMediaSession), + @(UIAccessibilityTraitAdjustable), + @(UIAccessibilityTraitAllowsDirectInteraction), + @(UIAccessibilityTraitCausesPageTurn) + ]; + + NSArray *traitNames = @[ + @"UIAccessibilityTraitButton", + @"UIAccessibilityTraitLink", + @"UIAccessibilityTraitHeader", + @"UIAccessibilityTraitSearchField", + @"UIAccessibilityTraitImage", + @"UIAccessibilityTraitSelected", + @"UIAccessibilityTraitPlaysSound", + @"UIAccessibilityTraitKeyboardKey", + @"UIAccessibilityTraitStaticText", + @"UIAccessibilityTraitSummaryElement", + @"UIAccessibilityTraitNotEnabled", + @"UIAccessibilityTraitUpdatesFrequently", + @"UIAccessibilityTraitStartsMediaSession", + @"UIAccessibilityTraitAdjustable", + @"UIAccessibilityTraitAllowsDirectInteraction", + @"UIAccessibilityTraitCausesPageTurn" + ]; + + + for (NSNumber *trait in allTraits) { + if ((traits & trait.longLongValue) == trait.longLongValue) { + NSString *name = [traitNames objectAtIndex:[allTraits indexOfObject:trait]]; + if (string.length > 0) { + string = [string stringByAppendingString:@", "]; + } + string = [string stringByAppendingString:name]; + traits &= ~trait.longLongValue; + } + } + if (traits != UIAccessibilityTraitNone) { + if (string.length > 0) { + string = [string stringByAppendingString:@", "]; + } + string = [string stringByAppendingFormat:@"UNKNOWN ACCESSIBILITY TRAIT: %llu", traits]; + } + return string; +} + @end diff --git a/Classes/KIF.h b/Classes/KIF.h index a8c00a37b..bccb241d0 100644 --- a/Classes/KIF.h +++ b/Classes/KIF.h @@ -13,4 +13,7 @@ #import "KIFUITestActor.h" #import "KIFUITestActor-ConditionalTests.h" +#import "KIFUIViewTestActor.h" +#import "KIFUIObject.h" + #import "XCTestCase-KIFAdditions.h" diff --git a/Classes/KIFTestActor.h b/Classes/KIFTestActor.h index 50c6263a0..0665fa844 100644 --- a/Classes/KIFTestActor.h +++ b/Classes/KIFTestActor.h @@ -51,7 +51,6 @@ return KIFTestStepResultWait; \ } \ }) - /*! @enum KIFTestStepResult @abstract Result codes from a test step. @@ -98,7 +97,6 @@ typedef void (^KIFTestCompletionBlock)(KIFTestStepResult result, NSError *error) - (void)runBlock:(KIFTestExecutionBlock)executionBlock timeout:(NSTimeInterval)timeout; - (void)runBlock:(KIFTestExecutionBlock)executionBlock; - /*! @discussion Attempts to run the test block similar to -runBlock:complete:timeout: but does not halt the test on completion, instead returning NO on failure and providing an error description to the optional error parameter. */ diff --git a/Classes/KIFUIObject.h b/Classes/KIFUIObject.h new file mode 100644 index 000000000..2e64cb519 --- /dev/null +++ b/Classes/KIFUIObject.h @@ -0,0 +1,18 @@ +// +// KIFUIObject.h +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + +#import + +@interface KIFUIObject : NSObject + +@property (nonatomic, weak, readonly) UIView *view; +@property (nonatomic, weak, readonly) UIAccessibilityElement *element; + +- (instancetype)initWithElement:(UIAccessibilityElement *)element view:(UIView *)view; + +@end diff --git a/Classes/KIFUIObject.m b/Classes/KIFUIObject.m new file mode 100644 index 000000000..e4ec226f4 --- /dev/null +++ b/Classes/KIFUIObject.m @@ -0,0 +1,28 @@ +// +// KIFUIObject.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + +#import "KIFUIObject.h" + + +@implementation KIFUIObject + +- (instancetype)initWithElement:(UIAccessibilityElement *)element view:(UIView *)view; +{ + self = [super init]; + if (self) { + _element = element; + _view = view; + } + return self; +} + +- (NSString *)description; +{ + return [NSString stringWithFormat:@"<%@;\n| element=%@;\n| | view=%@>", [super description], self.element, self.view]; +} +@end diff --git a/Classes/KIFUITestActor.h b/Classes/KIFUITestActor.h index 9dc3f58f5..5627689e9 100644 --- a/Classes/KIFUITestActor.h +++ b/Classes/KIFUITestActor.h @@ -71,11 +71,10 @@ typedef NS_ENUM(NSUInteger, KIFPullToRefreshTiming) { static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirection direction) { - switch (direction) - { - // As discovered on the Frank mailing lists, it won't register as a - // swipe if you move purely horizontally or vertically, so need a - // slight orthogonal offset too. + switch (direction) { + // As discovered on the Frank mailing lists, it won't register as a + // swipe if you move purely horizontally or vertically, so need a + // slight orthogonal offset too. case KIFSwipeDirectionRight: return CGPointMake(UIScreen.mainScreen.majorSwipeDisplacement, kKIFMinorSwipeDisplacement); case KIFSwipeDirectionLeft: @@ -256,13 +255,21 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)tapAccessibilityElement:(UIAccessibilityElement *)element inView:(UIView *)view; +/*! + @abstract Taps a stepper to either increment or decrement the stepper. Presumed that - (minus) to decrement is on the left. + @discussion This will locate the left or right half of the stepper and perform a calculated click. + @param label The accessibility identifier of the view to interact with. + @param stepperDirection The direction in which to change the value of the stepper (KIFStepperDirectionIncrement | KIFStepperDirectionDecrement) + */ +-(void)tapStepperWithAccessibilityLabel:(NSString *)accessibilityLabel increment:(KIFStepperDirection)stepperDirection; + /*! @abstract Taps the increment|decrement button of a UIStepper view in the view heirarchy. @discussion Unlike the -tapViewWithAccessibilityLabel: family of methods, this method allows you to tap an arbitrary element. Combined with -waitForAccessibilityElement:view:withLabel:value:traits:tappable: or +[UIAccessibilityElement accessibilityElement:view:withLabel:value:traits:tappable:error:] this provides an opportunity for more complex logic. @param element The accessibility element to tap. @param view The view containing the accessibility element. */ -- (void)tapStepperWithAccessibilityElement:(UIAccessibilityElement *)element increment: (KIFStepperDirection) stepperDirection inView:(UIView *)view; +- (void)tapStepperWithAccessibilityElement:(UIAccessibilityElement *)element increment:(KIFStepperDirection)stepperDirection inView:(UIView *)view; /*! @abstract Taps the screen at a particular point. @@ -332,6 +339,16 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec - (void)enterTextIntoCurrentFirstResponder:(NSString *)text; - (void)enterTextIntoCurrentFirstResponder:(NSString *)text fallbackView:(UIView *)fallbackView; +/*! + @abstract Enters text into a particular view in the view hierarchy. + @discussion If the element isn't currently tappable, then the step will attempt to wait until it is. Once the view is present and tappable, a tap event is simulated in the center of the view or element, then text is entered into the view by simulating taps on the appropriate keyboard keys. + @param text The text to enter. + @param expectedResult What the text value should be after entry, including any formatting done by the field. If this is nil, the "text" parameter will be used. + @param element the element to type into. + @param view the view to type into. + */ +- (void)enterText:(NSString *)text intoElement:(UIAccessibilityElement *)element inView:(UIView *)view expectedResult:(NSString *)expectedResult; + /*! @abstract Enters text into a particular view in the view hierarchy. @discussion The view or accessibility element with the given label is searched for in the view hierarchy. If the element isn't found or isn't currently tappable, then the step will attempt to wait until it is. Once the view is present and tappable, a tap event is simulated in the center of the view or element, then text is entered into the view by simulating taps on the appropriate keyboard keys. @@ -353,7 +370,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec - (void)clearTextFromFirstResponder; - (void)clearTextFromViewWithAccessibilityLabel:(NSString *)label; - (void)clearTextFromViewWithAccessibilityLabel:(NSString *)label traits:(UIAccessibilityTraits)traits; -- (void)clearTextFromElement:(UIAccessibilityElement*)element inView:(UIView*)view; +- (void)clearTextFromElement:(UIAccessibilityElement *)element inView:(UIView *)view; - (void)clearTextFromAndThenEnterTextIntoCurrentFirstResponder:(NSString *)text; - (void)clearTextFromAndThenEnterText:(NSString *)text intoViewWithAccessibilityLabel:(NSString *)label; @@ -381,7 +398,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec @discussion With a date picker view already visible, this step will select the different rotating weel values in order of how the array parameter is passed in. After it is done it will hide the date picker. It works with all 4 UIDatePickerMode* modes. The input parameter of type NSArray has to match in what order the date picker is displaying the values/columns. So if the locale is changing the input parameter has to be adjusted. Example: Mode: UIDatePickerModeDate, Locale: en_US, Input param: NSArray *date = @[@"June", @"17", @"1965"];. Example: Mode: UIDatePickerModeDate, Locale: de_DE, Input param: NSArray *date = @[@"17.", @"Juni", @"1965". @param datePickerColumnValues Each element in the NSArray represents a rotating wheel in the date picker control. Elements from 0 - n are listed in the order of the rotating wheels, left to right. */ -- (void) selectDatePickerValue:(NSArray*)datePickerColumnValues; +- (void)selectDatePickerValue:(NSArray *)datePickerColumnValues; /*! @abstract Toggles a UISwitch into a specified position. @@ -391,6 +408,16 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)setOn:(BOOL)switchIsOn forSwitchWithAccessibilityLabel:(NSString *)label; +/*! + @abstract Toggles a UISwitch into a specified position. + @discussion If the Switch isn't currently tappable, then the step will attempt to wait until it is. Once the view is present, the step will return if it's already in the desired position. If the switch is tappable but not in the desired position, a tap event is simulated in the center of the view or element, toggling the switch into the desired position. + @param switchIsOn The desired position of the UISwitch. + @param switchView The switch to switch. + @param element The accessibility element for the switch. + + */ +- (void)setSwitch:(UISwitch *)switchView element:(UIAccessibilityElement *)element On:(BOOL)switchIsOn; + /*! @abstract Slides a UISlider to a specified value. @discussion The UISlider with the given label is searched for in the view hierarchy. If the element isn't found or isn't currently tappable, then the step will attempt to wait until it is. Once the view is present, the step will attempt to drag the slider to the new value. The step will fail if it finds a view with the given accessibility label that is not a UISlider or if value is outside of the possible values. Because this step simulates drag events, the value reached may not be the exact value requested and the app may ignore the touch events if the movement is less than the drag gesture recognizer's minimum distance. @@ -424,7 +451,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec @param tableViewLabel Accessibility label of the table view. @param indexPath Index path of the row to tap. */ -- (void)tapRowInTableViewWithAccessibilityLabel:(NSString*)tableViewLabel atIndexPath:(NSIndexPath *)indexPath KIF_DEPRECATED("Use tapRowAtIndexPath:inTableViewWithAccessibilityIdentifier:"); +- (void)tapRowInTableViewWithAccessibilityLabel:(NSString *)tableViewLabel atIndexPath:(NSIndexPath *)indexPath KIF_DEPRECATED("Use tapRowAtIndexPath:inTableViewWithAccessibilityIdentifier:"); /*! @abstract Taps the row at indexPath in a table view with the given identifier. @@ -437,6 +464,17 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)tapRowAtIndexPath:(NSIndexPath *)indexPath inTableViewWithAccessibilityIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(5_0); +/*! + @abstract Taps the row at indexPath in a given table view. + @discussion This step will tap the row at indexPath. + + For cases where you may need to work from the end of a table view rather than the beginning, negative sections count back from the end of the table view (-1 is the last section) and negative rows count back from the end of the section (-1 is the last row for that section). + + @param indexPath Index path of the row to tap. + @param tableView UITableView containing row to tap. + */ +- (void)tapRowAtIndexPath:(NSIndexPath *)indexPath inTableView:(UITableView *)tableView; + /*! @abstract Taps the item at indexPath in a collection view with the given identifier. @discussion This step will get the view with the specified accessibility identifier and tap the item at indexPath. @@ -449,12 +487,16 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec - (void)tapItemAtIndexPath:(NSIndexPath *)indexPath inCollectionViewWithAccessibilityIdentifier:(NSString *)identifier; /*! - @abstract Taps a stepper to either increment or decrement the stepper. Presumed that - (minus) to decrement is on the left. - @discussion This will locate the left or right half of the stepper and perform a calculated click. - @param accessibilityLabel The accessibility identifier of the view to interact with. - @param stepperDirection The direction in which to change the value of the stepper (KIFStepperDirectionIncrement | KIFStepperDirectionDecrement) + @abstract Taps the item at indexPath in a given collection view. + @discussion This step will get the view with the specified accessibility identifier and tap the item at indexPath. + + For cases where you may need to work from the end of a collection view rather than the beginning, negative sections count back from the end of the collection view (-1 is the last section) and negative items count back from the end of the section (-1 is the last item for that section). + + @param label The accessibility identifier of the view to interact with. + @param indexPath Index path of the item to tap. + @param collectionView the UICollectionView containing the item. */ --(void) tapStepperWithAccessibilityLabel: (NSString *)accessibilityLabel increment: (KIFStepperDirection) stepperDirection; +- (void)tapItemAtIndexPath:(NSIndexPath *)indexPath inCollectionView:(UICollectionView *)collectionView; #if TARGET_IPHONE_SIMULATOR /*! @@ -494,6 +536,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec /*! @abstract Swipes a particular view in the view heirarchy. @discussion Unlike the -swipeViewWithAccessibilityLabel: family of methods, this method allows you to swipe an arbitrary element. Combined with -waitForAccessibilityElement:view:withLabel:value:traits:tappable: or +[UIAccessibilityElement accessibilityElement:view:withLabel:value:traits:tappable:error:] this provides an opportunity for more complex logic. +@param element The accessibility element of the view to swipe. @param element The accessibility element to tap. @param viewToSwipe The view containing the accessibility element. */ @@ -542,6 +585,16 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (void)scrollViewWithAccessibilityIdentifier:(NSString *)identifier byFractionOfSizeHorizontal:(CGFloat)horizontalFraction vertical:(CGFloat)verticalFraction NS_AVAILABLE_IOS(5_0); +/*! + @abstract Scrolls a particular view in the view hierarchy by an amount indicated as a fraction of its size. + @discussion The view will scroll by the indicated fraction of its size, with the scroll centered on the center of the view. + @param element The accessibility element of the view to scroll. + @param viewToScroll the view to scroll. + @param horizontalFraction The horizontal displacement of the scroll action, as a fraction of the width of the view. + @param verticalFraction The vertical displacement of the scroll action, as a fraction of the height of the view. + */ +- (void)scrollAccessibilityElement:(UIAccessibilityElement *)element inView:(UIView *)viewToScroll byFractionOfSizeHorizontal:(CGFloat)horizontalFraction vertical:(CGFloat)verticalFraction; + /*! @abstract Waits until a view or accessibility element is the first responder. @discussion The first responder is found by searching the view hierarchy of the application's @@ -575,6 +628,31 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec */ - (UITableViewCell *)waitForCellAtIndexPath:(NSIndexPath *)indexPath inTableViewWithAccessibilityIdentifier:(NSString *)identifier; +/*! + @abstract Waits for the cell at indexPath in a given table view. + @discussion This step will get the cell at the indexPath. + + For cases where you may need to work from the end of a table view rather than the beginning, negative sections count back from the end of the table view (-1 is the last section) and negative rows count back from the end of the section (-1 is the last row for that section). + + @param indexPath Index path of the cell. + @param tableView UITableView containing the cell. + @result Table view cell at index path + */ +- (UITableViewCell *)waitForCellAtIndexPath:(NSIndexPath *)indexPath inTableView:(UITableView *)tableView; + +/*! + @abstract Waits for the cell at indexPath in a given collection view. + @discussion This step will get the cell at the indexPath. + + For cases where you may need to work from the end of a table view rather than the beginning, negative sections count back from the end of the table view (-1 is the last section) and negative rows count back from the end of the section (-1 is the last row for that section). + + @param indexPath Index path of the cell. + @param collectionView UICollectionView containing the cell. + @result Collection view cell at index path + */ +- (UICollectionViewCell *)waitForCellAtIndexPath:(NSIndexPath *)indexPath inCollectionView:(UICollectionView *)collectionView; + + /*! @abstract Waits for the cell at indexPath in a collection view with the given identifier. @discussion This step will get the view with the specified accessibility identifier and then get the cell at indexPath. @@ -600,14 +678,26 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec - (void)moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath inTableViewWithAccessibilityIdentifier:(NSString *)identifier; /*! - @abstract Swipes the row at indexPath in the given direction. + @abstract Moves the row at sourceIndexPath to destinationIndexPath in a given table view. + @discussion This step will move the row at sourceIndexPath to destinationIndexPath. + + For cases where you may need to work from the end of a table view rather than the beginning, negative sections count back from the end of the table view (-1 is the last section) and negative rows count back from the end of the section (-1 is the last row for that section). + @param sourceIndexPath Index path of the row to move. + @param destinationIndexPath Desired final index path of the row after moving. + @param tableView UITableView containing the cell. + */ +- (void)moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath inTableView:(UITableView *)tableView; + +/*! + @abstract Swipes the row at indexPath in the given direction. @param indexPath Index path of the row to swipe. @param tableView Table view to operate on. @param direction Direction of the swipe. - */ +*/ - (void)swipeRowAtIndexPath:(NSIndexPath *)indexPath inTableView:(UITableView *)tableView inDirection:(KIFSwipeDirection)direction; + /*! @abstract Backgrounds app using UIAutomation command, simulating pressing the Home button @param duration Amount of time for a background event before the app becomes active again diff --git a/Classes/KIFUITestActor.m b/Classes/KIFUITestActor.m index b4dbc759c..250813001 100644 --- a/Classes/KIFUITestActor.m +++ b/Classes/KIFUITestActor.m @@ -62,10 +62,11 @@ - (UIView *)waitForTappableViewWithAccessibilityLabel:(NSString *)label value:(N - (UIView *)waitForViewWithAccessibilityLabel:(NSString *)label value:(NSString *)value traits:(UIAccessibilityTraits)traits tappable:(BOOL)mustBeTappable { UIView *view = nil; - @autoreleasepool { + @autoreleasepool + { [self waitForAccessibilityElement:NULL view:&view withLabel:label value:value traits:traits tappable:mustBeTappable]; } - + return view; } @@ -81,7 +82,7 @@ - (void)waitForAccessibilityElement:(UIAccessibilityElement **)element view:(out if (![UIAccessibilityElement instancesRespondToSelector:@selector(accessibilityIdentifier)]) { [self failWithError:[NSError KIFErrorWithFormat:@"Running test on platform that does not support accessibilityIdentifier"] stopTest:YES]; } - + [self waitForAccessibilityElement:element view:view withElementMatchingPredicate:[NSPredicate predicateWithFormat:@"accessibilityIdentifier = %@", identifier] tappable:mustBeTappable]; } @@ -202,7 +203,8 @@ - (void)tapViewWithAccessibilityLabel:(NSString *)label traits:(UIAccessibilityT - (void)tapViewWithAccessibilityLabel:(NSString *)label value:(NSString *)value traits:(UIAccessibilityTraits)traits { - @autoreleasepool { + @autoreleasepool + { UIView *view = nil; UIAccessibilityElement *element = nil; [self waitForAccessibilityElement:&element view:&view withLabel:label value:value traits:traits tappable:YES]; @@ -288,7 +290,8 @@ - (void)longPressViewWithAccessibilityLabel:(NSString *)label value:(NSString *) - (void)longPressViewWithAccessibilityLabel:(NSString *)label value:(NSString *)value traits:(UIAccessibilityTraits)traits duration:(NSTimeInterval)duration; { - @autoreleasepool { + @autoreleasepool + { UIView *view = nil; UIAccessibilityElement *element = nil; [self waitForAccessibilityElement:&element view:&view withLabel:label value:value traits:traits tappable:YES]; @@ -313,7 +316,7 @@ - (void)longPressAccessibilityElement:(UIAccessibilityElement *)element inView:( return KIFTestStepResultSuccess; }]; - + // Wait for view to settle. [self waitForTimeInterval:0.5]; } @@ -367,12 +370,14 @@ - (void)enterTextIntoCurrentFirstResponder:(NSString *)text fallbackView:(UIView [text enumerateSubstringsInRange:NSMakeRange(0, text.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock: ^(NSString *characterString,NSRange substringRange,NSRange enclosingRange,BOOL * stop) + { if (![KIFTypist enterCharacter:characterString]) { // Attempt to cheat if we couldn't find the character UIView * fallback = fallbackView; if (!fallback) { UIResponder *firstResponder = [[[UIApplication sharedApplication] keyWindow] firstResponder]; + if ([firstResponder isKindOfClass:[UIView class]]) { fallback = (UIView *)firstResponder; } @@ -397,9 +402,14 @@ - (void)enterText:(NSString *)text intoViewWithAccessibilityLabel:(NSString *)la { UIView *view = nil; UIAccessibilityElement *element = nil; - + [self waitForAccessibilityElement:&element view:&view withLabel:label value:nil traits:traits tappable:YES]; + [self enterText:text intoElement:element inView:view expectedResult:expectedResult]; +} + +- (void)enterText:(NSString *)text intoElement:(UIAccessibilityElement *)element inView:(UIView *)view expectedResult:(NSString *)expectedResult; +{ // In iOS7, tapping a field that is already first responder moves the cursor to the front of the field if (view.window.firstResponder != view) { [self tapAccessibilityElement:element inView:view]; @@ -416,9 +426,9 @@ - (void)expectView:(UIView *)view toContainText:(NSString *)expectedResult if (![view respondsToSelector:@selector(text)]) { return; } - + UITextView *textView = (UITextView *)view; - + // Some slower machines take longer for typing to catch up, so wait for a bit before failing [self runBlock:^KIFTestStepResult(NSError **error) { // We trim \n and \r because they trigger the return key, so they won't show up in the final product on single-line inputs. @@ -451,18 +461,18 @@ - (void)clearTextFromViewWithAccessibilityLabel:(NSString *)label traits:(UIAcce { UIView *view = nil; UIAccessibilityElement *element = nil; - + [self waitForAccessibilityElement:&element view:&view withLabel:label value:nil traits:traits tappable:YES]; - [self clearTextFromElement:element inView:view]; + [self clearTextFromElement:element inView:view]; } -- (void)clearTextFromElement:(UIAccessibilityElement*)element inView:(UIView*)view +- (void)clearTextFromElement:(UIAccessibilityElement *)element inView:(UIView *)view { [self tapAccessibilityElement:element inView:view]; // Per issue #294, the tap occurs in the center of the text view. If the text is too long, this means not all text gets cleared. To address this for most cases, we can check if the selected view conforms to UITextInput and select the whole text range. if ([view conformsToProtocol:@protocol(UITextInput)]) { - id textInput = (id )view; + id textInput = (id)view; [textInput setSelectedTextRange:[textInput textRangeFromPosition:textInput.beginningOfDocument toPosition:textInput.endOfDocument]]; [self waitForTimeInterval:0.1]; @@ -497,47 +507,46 @@ - (void)clearTextFromAndThenEnterTextIntoCurrentFirstResponder:(NSString *)text [self enterTextIntoCurrentFirstResponder:text]; } -- (void) selectDatePickerValue:(NSArray*)datePickerColumnValues { +- (void)selectDatePickerValue:(NSArray *)datePickerColumnValues +{ [self selectPickerValue:datePickerColumnValues pickerType:KIFUIDatePicker]; } - (void)selectPickerViewRowWithTitle:(NSString *)title { - NSArray *dataToSelect = @[title]; + NSArray *dataToSelect = @[ title ]; [self selectPickerValue:dataToSelect pickerType:KIFUIPickerView]; } - (void)selectPickerViewRowWithTitle:(NSString *)title inComponent:(NSInteger)component { NSMutableArray *dataToSelect = [[NSMutableArray alloc] init]; - + // Assume it is datePicker and then test our hypothesis later! UIPickerView *pickerView = [[[[UIApplication sharedApplication] datePickerWindow] subviewsWithClassNameOrSuperClassNamePrefix:@"UIPickerView"] lastObject]; - + // Check which type of UIPickerVIew is visible on current window. KIFPickerType pickerType = 0; if ([pickerView respondsToSelector:@selector(setDate:animated:)]) { pickerType = KIFUIDatePicker; - } - else { + } else { pickerType = KIFUIPickerView; pickerView = [[[[UIApplication sharedApplication] pickerViewWindow] subviewsWithClassNameOrSuperClassNamePrefix:@"UIPickerView"] lastObject]; } - + // Add title at component index and add empty strings for other. // This support legacy function re-use. for (int i = 0; i < pickerView.numberOfComponents; i++) { if (component == i) { [dataToSelect addObject:title]; - } - else { + } else { NSInteger currentIndex = [pickerView selectedRowInComponent:i]; NSString *rowTitle = nil; if ([pickerView.delegate respondsToSelector:@selector(pickerView:titleForRow:forComponent:)]) { - rowTitle = [pickerView.delegate pickerView:pickerView titleForRow:currentIndex forComponent: i]; + rowTitle = [pickerView.delegate pickerView:pickerView titleForRow:currentIndex forComponent:i]; } else if ([pickerView.delegate respondsToSelector:@selector(pickerView:viewForRow:forComponent:reusingView:)]) { // This delegate inserts views directly, so try to figure out what the title is by looking for a label - UIView *rowView = [pickerView.delegate pickerView:pickerView viewForRow:currentIndex forComponent: i reusingView:nil]; + UIView *rowView = [pickerView.delegate pickerView:pickerView viewForRow:currentIndex forComponent:i reusingView:nil]; NSArray *labels = [rowView subviewsWithClassNameOrSuperClassNamePrefix:@"UILabel"]; UILabel *label = (labels.count > 0 ? labels[0] : nil); rowTitle = label.text; @@ -550,12 +559,12 @@ - (void)selectPickerViewRowWithTitle:(NSString *)title inComponent:(NSInteger)co } } } - + [self selectPickerValue:dataToSelect pickerType:pickerType]; } -- (void) selectPickerValue:(NSArray*)pickerColumnValues pickerType:(KIFPickerType)pickerType { - +- (void)selectPickerValue:(NSArray *)pickerColumnValues pickerType:(KIFPickerType)pickerType +{ [self runBlock:^KIFTestStepResult(NSError **error) { NSInteger columnCount = [pickerColumnValues count]; NSMutableArray* found_values = [NSMutableArray arrayWithCapacity:columnCount]; @@ -642,39 +651,42 @@ - (void) selectPickerValue:(NSArray*)pickerColumnValues pickerType:(KIFPickerTyp return KIFTestStepResultSuccess; }]; - } - (void)setOn:(BOOL)switchIsOn forSwitchWithAccessibilityLabel:(NSString *)label { UIView *view = nil; UIAccessibilityElement *element = nil; - + [self waitForAccessibilityElement:&element view:&view withLabel:label value:nil traits:UIAccessibilityTraitButton tappable:YES]; - + if (![view isKindOfClass:[UISwitch class]]) { [self failWithError:[NSError KIFErrorWithFormat:@"View with accessibility label \"%@\" is a %@, not a UISwitch", label, NSStringFromClass([view class])] stopTest:YES]; } - UISwitch *switchView = (UISwitch *)view; - + + [self setSwitch:switchView element:element On:switchIsOn]; +} + +- (void)setSwitch:(UISwitch *)switchView element:(UIAccessibilityElement *)element On:(BOOL)switchIsOn +{ // No need to switch it if it's already in the correct position if (switchView.isOn == switchIsOn) { return; } - - [self tapAccessibilityElement:element inView:view]; - + + [self tapAccessibilityElement:element inView:switchView]; + // If we succeeded, stop the test. if (switchView.isOn == switchIsOn) { return; } - - NSLog(@"Faking turning switch %@ with accessibility label %@", switchIsOn ? @"ON" : @"OFF", label); + + NSLog(@"Faking turning switch %@", switchIsOn ? @"ON" : @"OFF"); [switchView setOn:switchIsOn animated:YES]; [switchView sendActionsForControlEvents:UIControlEventValueChanged]; [self waitForTimeInterval:0.5]; - + // We gave it our best shot. Fail the test. if (switchView.isOn != switchIsOn) { [self failWithError:[NSError KIFErrorWithFormat:@"Failed to toggle switch to \"%@\"; instead, it was \"%@\"", switchIsOn ? @"ON" : @"OFF", switchView.on ? @"ON" : @"OFF"] stopTest:YES]; @@ -688,26 +700,26 @@ - (void)setValue:(float)value forSliderWithAccessibilityLabel:(NSString *)label UISlider *slider = nil; UIAccessibilityElement *element = nil; [self waitForAccessibilityElement:&element view:&slider withLabel:label value:nil traits:UIAccessibilityTraitNone tappable:YES]; - + if (![slider isKindOfClass:[UISlider class]]) { [self failWithError:[NSError KIFErrorWithFormat:@"View with accessibility label \"%@\" is a %@, not a UISlider", label, NSStringFromClass([slider class])] stopTest:YES]; } - [self setValue:value forSlider:slider]; + [self setValue:value forSlider:slider]; } - (void)setValue:(float)value forSlider:(UISlider *)slider { - if (value < slider.minimumValue) { - [self failWithError:[NSError KIFErrorWithFormat:@"Cannot slide past minimum value of %f", slider.minimumValue] stopTest:YES]; - } - - if (value > slider.maximumValue) { - [self failWithError:[NSError KIFErrorWithFormat:@"Cannot slide past maximum value of %f", slider.maximumValue] stopTest:YES]; - } + if (value < slider.minimumValue) { + [self failWithError:[NSError KIFErrorWithFormat:@"Cannot slide past minimum value of %f", slider.minimumValue] stopTest:YES]; + } - CGRect trackRect = [slider trackRectForBounds:slider.bounds]; - CGPoint currentPosition = CGPointCenteredInRect([slider thumbRectForBounds:slider.bounds trackRect:trackRect value:slider.value]); - CGPoint finalPosition = CGPointCenteredInRect([slider thumbRectForBounds:slider.bounds trackRect:trackRect value:value]); + if (value > slider.maximumValue) { + [self failWithError:[NSError KIFErrorWithFormat:@"Cannot slide past maximum value of %f", slider.maximumValue] stopTest:YES]; + } + + CGRect trackRect = [slider trackRectForBounds:slider.bounds]; + CGPoint currentPosition = CGPointCenteredInRect([slider thumbRectForBounds:slider.bounds trackRect:trackRect value:slider.value]); + CGPoint finalPosition = CGPointCenteredInRect([slider thumbRectForBounds:slider.bounds trackRect:trackRect value:value]); if (value == slider.minimumValue) { finalPosition.x = 0; @@ -715,7 +727,7 @@ - (void)setValue:(float)value forSlider:(UISlider *)slider finalPosition.x = slider.bounds.size.width; } - [slider dragFromPoint:currentPosition toPoint:finalPosition steps:10]; + [slider dragFromPoint:currentPosition toPoint:finalPosition steps:10]; } - (void)dismissPopover @@ -759,10 +771,10 @@ - (void)choosePhotoInAlbum:(NSString *)albumName atRow:(NSInteger)row column:(NS return KIFTestStepResultSuccess; }]; - + // Wait for media picker view controller to be pushed. [self waitForTimeInterval:1]; - + // Tap the desired photo in the grid // TODO: This currently only works for the first page of photos. It should scroll appropriately at some point. UIAccessibilityElement *headerElt = [[UIApplication sharedApplication] accessibilityElementMatchingBlock:^(UIAccessibilityElement *element) { @@ -786,7 +798,7 @@ - (void)tapRowAtIndexPath:(NSIndexPath *)indexPath inTableViewWithAccessibilityI [self tapRowAtIndexPath:indexPath inTableView:tableView]; } -- (void)tapRowInTableViewWithAccessibilityLabel:(NSString*)tableViewLabel atIndexPath:(NSIndexPath *)indexPath +- (void)tapRowInTableViewWithAccessibilityLabel:(NSString *)tableViewLabel atIndexPath:(NSIndexPath *)indexPath { UITableView *tableView = (UITableView *)[self waitForViewWithAccessibilityLabel:tableViewLabel]; [self tapRowAtIndexPath:indexPath inTableView:tableView]; @@ -797,7 +809,7 @@ - (void)tapRowAtIndexPath:(NSIndexPath *)indexPath inTableView:(UITableView *)ta UITableViewCell *cell = [self waitForCellAtIndexPath:indexPath inTableView:tableView]; CGRect cellFrame = [cell.contentView convertRect:cell.contentView.frame toView:tableView]; [tableView tapAtPoint:CGPointCenteredInRect(cellFrame)]; - + [self waitForAnimationsToFinish]; } @@ -836,10 +848,10 @@ - (void)tapItemAtIndexPath:(NSIndexPath *)indexPath inCollectionView:(UICollecti { UICollectionViewCell *cell; cell = [self waitForCellAtIndexPath:indexPath inCollectionView:collectionView]; - + CGRect cellFrame = [cell.contentView convertRect:cell.contentView.frame toView:collectionView]; [collectionView tapAtPoint:CGPointCenteredInRect(cellFrame)]; - + [self waitForAnimationsToFinish]; } @@ -936,17 +948,17 @@ - (void)scrollViewWithAccessibilityIdentifier:(NSString *)identifier byFractionO - (void)scrollAccessibilityElement:(UIAccessibilityElement *)element inView:(UIView *)viewToScroll byFractionOfSizeHorizontal:(CGFloat)horizontalFraction vertical:(CGFloat)verticalFraction { const NSUInteger kNumberOfPointsInScrollPath = 5; - + // Within this method, all geometry is done in the coordinate system of the view to scroll. - + CGRect elementFrame = [viewToScroll.windowOrIdentityWindow convertRect:element.accessibilityFrame toView:viewToScroll]; - + KIFDisplacement scrollDisplacement = CGPointMake(elementFrame.size.width * horizontalFraction, elementFrame.size.height * verticalFraction); - + CGPoint scrollStart = CGPointCenteredInRect(elementFrame); scrollStart.x -= scrollDisplacement.x / 2; scrollStart.y -= scrollDisplacement.y / 2; - + [viewToScroll dragFromPoint:scrollStart displacement:scrollDisplacement steps:kNumberOfPointsInScrollPath]; } @@ -1026,9 +1038,9 @@ - (UITableViewCell *)waitForCellAtIndexPath:(NSIndexPath *)indexPath inTableView return KIFTestStepResultSuccess; }]; - + [self waitForTimeInterval:0.1]; // Let things settle. - + return cell; } @@ -1045,15 +1057,15 @@ - (UICollectionViewCell *)waitForCellAtIndexPath:(NSIndexPath *)indexPath inColl if (![collectionView isKindOfClass:[UICollectionView class]]) { [self failWithError:[NSError KIFErrorWithFormat:@"View is not a collection view"] stopTest:YES]; } - + NSInteger section = indexPath.section; - NSInteger item = indexPath.item; - + NSInteger item = indexPath.item; + // If section < 0, search from the end of the table. if (section < 0) { section += collectionView.numberOfSections; } - + // If item < 0, search from the end of the section. if (item < 0) { item += [collectionView numberOfItemsInSection:section]; @@ -1088,7 +1100,7 @@ - (UICollectionViewCell *)waitForCellAtIndexPath:(NSIndexPath *)indexPath inColl } if (!cell) { - [self failWithError:[NSError KIFErrorWithFormat: @"Collection view cell at index path %@ not found", indexPath] stopTest:YES]; + [self failWithError:[NSError KIFErrorWithFormat:@"Collection view cell at index path %@ not found", indexPath] stopTest:YES]; } return cell; @@ -1100,14 +1112,14 @@ - (void)tapStatusBar KIFTestWaitCondition(![UIApplication sharedApplication].statusBarHidden, error, @"Expected status bar to be visible."); return KIFTestStepResultSuccess; }]; - + UIWindow *statusBarWindow = [[UIApplication sharedApplication] statusBarWindow]; NSArray *statusBars = [statusBarWindow subviewsWithClassNameOrSuperClassNamePrefix:@"UIStatusBar"]; - + if (statusBars.count == 0) { - [self failWithError:[NSError KIFErrorWithFormat: @"Could not find the status bar"] stopTest:YES]; + [self failWithError:[NSError KIFErrorWithFormat:@"Could not find the status bar"] stopTest:YES]; } - + [self tapAccessibilityElement:statusBars[0] inView:statusBars[0]]; } @@ -1115,9 +1127,13 @@ - (void)moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPa { UITableView *tableView; [self waitForAccessibilityElement:NULL view:&tableView withIdentifier:identifier tappable:NO]; - + [self moveRowAtIndexPath:sourceIndexPath toIndexPath:destinationIndexPath inTableView:tableView]; +} + +- (void)moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath inTableView:(UITableView *)tableView +{ UITableViewCell *cell = [self waitForCellAtIndexPath:sourceIndexPath inTableView:tableView]; - + NSError *error = nil; if (![tableView dragCell:cell toIndexPath:destinationIndexPath error:&error]) { [self failWithError:error stopTest:YES]; @@ -1178,4 +1194,3 @@ - (void)tapStepperWithAccessibilityElement:(UIAccessibilityElement *)element inc [self waitForAnimationsToFinish]; } @end - diff --git a/Classes/KIFUIViewTestActor.h b/Classes/KIFUIViewTestActor.h new file mode 100644 index 000000000..4ee6f3412 --- /dev/null +++ b/Classes/KIFUIViewTestActor.h @@ -0,0 +1,83 @@ +// +// KIFUIViewActor.h +// KIF +// +// Created by Alex Odawa on 1/21/15. +// +// + +#import + +#define viewTester KIFActorWithClass(KIFUIViewTestActor) + + +@interface KIFUIViewTestActor : KIFTestActor + +@property (nonatomic, strong, readonly) UIView *view; +@property (nonatomic, strong, readonly) UIAccessibilityElement *element; +@property (nonatomic, strong, readonly) NSPredicate *predicate; + +- (instancetype)usingPredicate:(NSPredicate *)predicate; +- (instancetype)usingLabel:(NSString *)accessibilityLabel; +- (instancetype)usingIdentifier:(NSString *)accessibilityIdentifier; +- (instancetype)usingTraits:(UIAccessibilityTraits)accessibilityTraits; +- (instancetype)usingValue:(NSString *)accessibilityValue; + +- (void)tap; +- (void)longPress; +- (void)longPressWithDuration:(NSTimeInterval)duration; + +- (void)tapScreenAtPoint:(CGPoint)screenPoint; +- (void)swipeInDirection:(KIFSwipeDirection)direction; + +- (UIView *)waitForView; +- (void)waitForAbsenceOfView; +- (void)waitToBecomeTappable; +- (void)waitToBecomeFirstResponder; + +- (BOOL)tryFindingView; +- (BOOL)tryFindingTappableView; + +- (void)enterText:(NSString *)text; +- (void)enterText:(NSString *)text expectedResult:(NSString *)expectedResult; +- (void)enterTextIntoCurrentFirstResponder:(NSString *)text; +- (void)enterTextIntoCurrentFirstResponder:(NSString *)text fallbackView:(UIView *)fallbackView; + +- (void)clearText; +- (void)clearTextFromFirstResponder; +- (void)clearAndEnterText:(NSString *)text; +- (void)clearAndEnterText:(NSString *)text expectedResult:(NSString *)expectedResult; + +- (void)waitForSoftwareKeyboard; +- (void)waitForAbsenceOfSoftwareKeyboard; +- (void)waitForKeyInputReady; + +- (void)setSliderValue:(float)value; +- (void)setSwitchOn:(BOOL)switchIsOn; + +- (void)tapRowInTableViewAtIndexPath:(NSIndexPath *)indexPath; +- (UITableViewCell *)waitForCellInTableViewAtIndexPath:(NSIndexPath *)indexPath; +- (void)moveRowInTableViewAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath; + +- (void)tapCollectionViewItemAtIndexPath:(NSIndexPath *)indexPath; +- (UICollectionViewCell *)waitForCellInCollectionViewAtIndexPath:(NSIndexPath *)indexPath; + +- (void)scrollByFractionOfSizeHorizontal:(CGFloat)horizontalFraction vertical:(CGFloat)verticalFraction; + +- (void)selectPickerViewRowWithTitle:(NSString *)title; +- (void)selectPickerViewRowWithTitle:(NSString *)title inComponent:(NSInteger)component; +- (void)selectDatePickerValue:(NSArray *)datePickerColumnValues; +- (void)choosePhotoInAlbum:(NSString *)albumName atRow:(NSInteger)row column:(NSInteger)column; + +- (void)tapStatusBar; +- (void)dismissPopover; + +- (void)pullToRefresh; +- (void)pullToRefreshWithDuration:(KIFPullToRefreshTiming)pullDownDuration; + +#if TARGET_IPHONE_SIMULATOR +- (BOOL)acknowledgeSystemAlert; +#endif + + +@end diff --git a/Classes/KIFUIViewTestActor.m b/Classes/KIFUIViewTestActor.m new file mode 100644 index 000000000..6bef4bfa4 --- /dev/null +++ b/Classes/KIFUIViewTestActor.m @@ -0,0 +1,435 @@ +// +// KIFUIViewActor.m +// KIF +// +// Created by Alex Odawa on 1/21/15. +// +// + +#import "KIFUIViewTestActor.h" +#import "UIWindow-KIFAdditions.h" +#import "NSPredicate+KIFAdditions.h" +#import "UIAccessibilityElement-KIFAdditions.h" +#import "NSString+KIFAdditions.h" + +@interface KIFUIViewTestActor () + +@property (nonatomic, strong, readonly) KIFUITestActor *actor; +@property (nonatomic, strong, readwrite) NSPredicate *predicate; + +@end + + +@implementation KIFUIViewTestActor + +#pragma mark - Initialization + +- (instancetype)usingPredicate:(NSPredicate *)predicate; +{ + + [self _appendPredicate:predicate]; + return self; +} + +- (instancetype)usingLabel:(NSString *)accessibilityLabel; +{ + int systemVersion = [UIDevice currentDevice].systemVersion.intValue; + NSPredicate *predicate; + if ([accessibilityLabel rangeOfString:@"\n"].location == NSNotFound || systemVersion == 6) { + predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + id label = [evaluatedObject accessibilityLabel]; + return [accessibilityLabel KIF_isEqualToStringOrAttributedString:label]; + }]; + } + else { + // On iOS 6 the accessibility label may contain line breaks, so when trying to find the + // element, these line breaks are necessary. But on iOS 7 the system replaces them with + // spaces. So the same test breaks on either iOS 6 or iOS 7. iOS 8 befuddles this again by + // limiting replacement to spaces in between strings. + // UNLESS the accessibility label is set programatically in which case the line breaks remain regardless of OS version. + // To work around this replace the line breaks using the preferred method and try matching both. + + __block NSString *alternate = nil; + if (systemVersion == 7) { + alternate = [accessibilityLabel stringByReplacingOccurrencesOfString:@"\n" withString:@" "]; + } else { + alternate = [accessibilityLabel stringByReplacingOccurrencesOfString:@"\\b\\n\\b" withString:@" " options:NSRegularExpressionSearch range:NSMakeRange(0, accessibilityLabel.length)]; + } + + predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + id label = [evaluatedObject accessibilityLabel]; + return ([accessibilityLabel KIF_isEqualToStringOrAttributedString:label] || [alternate KIF_isEqualToStringOrAttributedString:label]); + }]; + } + predicate.kifPredicateDescription = [NSString stringWithFormat:@"Accessibility label equal to \"%@\"", accessibilityLabel]; + return [self usingPredicate:predicate]; +} + + +- (instancetype)usingIdentifier:(NSString *)accessibilityIdentifier; +{ + NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + id identifier = [evaluatedObject accessibilityIdentifier]; + + return [accessibilityIdentifier KIF_isEqualToStringOrAttributedString:identifier]; + }]; + + predicate.kifPredicateDescription = [NSString stringWithFormat:@"Accessibility identifier equal to \"%@\"", accessibilityIdentifier]; + + return [self usingPredicate:predicate]; +} + +- (instancetype)usingTraits:(UIAccessibilityTraits)accessibilityTraits; +{ + NSPredicate *predicate =[NSPredicate predicateWithFormat:@"(accessibilityTraits & %@) == %@", @(accessibilityTraits), @(accessibilityTraits)]; + predicate.kifPredicateDescription = [NSString stringWithFormat:@"Accessibility traits including \"%@\"", [UIAccessibilityElement stringFromAccessibilityTraits:accessibilityTraits]]; + + return [self usingPredicate:predicate]; +} + +- (instancetype)usingValue:(NSString *)accessibilityValue; +{ + return [self usingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + NSString *value = [evaluatedObject accessibilityValue]; + if ([value isKindOfClass:[NSAttributedString class]]) { + value = [(NSAttributedString *)value string]; + } + return [value isEqualToString:accessibilityValue]; + }]]; +} + +#pragma mark - System Actions + +#if TARGET_IPHONE_SIMULATOR +- (BOOL)acknowledgeSystemAlert; +{ + return [self.actor acknowledgeSystemAlert]; +} +#endif + +- (void)tapStatusBar; +{ + [self.actor tapStatusBar]; +} + +- (void)dismissPopover; +{ + [self.actor dismissPopover]; +} + +#pragma mark - Waiting + +- (UIView *)waitForView; +{ + return [self _predicateSearchWithRequiresMatch:YES mustBeTappable:NO].view; +} + +- (void)waitForAbsenceOfView; +{ + [self runBlock:^KIFTestStepResult(NSError **error) { + // If the app is ignoring interaction events, then wait before doing our analysis + KIFTestWaitCondition(![[UIApplication sharedApplication] isIgnoringInteractionEvents], error, @"Application is ignoring interaction events."); + + // If the element can't be found, then we're done + KIFUIObject *found = [self _predicateSearchWithRequiresMatch:NO mustBeTappable:NO]; + if (!found) { + return KIFTestStepResultSuccess; + } + + // If we found an element, but it's not associated with a view, then something's wrong. Wait it out and try again. + KIFTestWaitCondition(found.view, error, @"Cannot find view containing accessibility element \"%@\"", found.element); + + // Hidden views count as absent + KIFTestWaitCondition([found.view isHidden] || [found.view superview] == nil, error, @"Accessibility element \"%@\" is visible and not hidden.", found); + + return KIFTestStepResultSuccess; + }]; +} + +- (void)waitToBecomeTappable; + +{ + [self _predicateSearchWithRequiresMatch:YES mustBeTappable:YES]; +} + +- (void)waitToBecomeFirstResponder; +{ + [self runBlock:^KIFTestStepResult(NSError **error) { + UIResponder *firstResponder = [[[UIApplication sharedApplication] keyWindow] firstResponder]; + + KIFTestWaitCondition([self.predicate evaluateWithObject:firstResponder], error, @"Expected first responder to match '%@', got '%@'", self.predicate, firstResponder); + return KIFTestStepResultSuccess; + }]; +} +#pragma mark Typist Waiting + +- (void)waitForSoftwareKeyboard; +{ + [self.actor waitForSoftwareKeyboard]; +} +- (void)waitForAbsenceOfSoftwareKeyboard; +{ + [self.actor waitForAbsenceOfSoftwareKeyboard]; +} +- (void)waitForKeyInputReady; +{ + [self.actor waitForKeyInputReady]; +} + +#pragma mark - Conditionals + +- (BOOL)tryFindingView; +{ + return ([self _predicateSearchWithRequiresMatch:NO mustBeTappable:NO] != nil); +} + +- (BOOL)tryFindingTappableView; +{ + return ([self _predicateSearchWithRequiresMatch:NO mustBeTappable:YES] != nil); +} + + +#pragma mark - Tap Actions + +- (void)tap; +{ + KIFUIObject *found = [self _predicateSearchWithRequiresMatch:YES mustBeTappable:YES]; + [self.actor tapAccessibilityElement:found.element inView:found.view]; +} + +- (void)longPress; +{ + [self longPressWithDuration:.5]; +} + +- (void)longPressWithDuration:(NSTimeInterval)duration; +{ + KIFUIObject *found = [self _predicateSearchWithRequiresMatch:YES mustBeTappable:YES]; + [self.actor longPressAccessibilityElement:found.element inView:found.view duration:duration]; +} + +#pragma mark - Text Actions; + +- (void)clearText; +{ + KIFUIObject *found = [self _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor clearTextFromElement:found.element inView:found.view]; +} + +- (void)clearTextFromFirstResponder; +{ + [self.actor clearTextFromFirstResponder]; +} + +- (void)enterText:(NSString *)text; +{ + [self enterText:text expectedResult:nil]; +} + +- (void)enterText:(NSString *)text expectedResult:(NSString *)expectedResult; +{ + KIFUIObject *found = [self _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor enterText:text intoElement:found.element inView:found.view expectedResult:expectedResult]; +} + +- (void)clearAndEnterText:(NSString *)text; +{ + [self clearAndEnterText:text expectedResult:nil]; +} + +- (void)clearAndEnterText:(NSString *)text expectedResult:(NSString *)expectedResult; +{ + [self clearText]; + [self enterText:text expectedResult:expectedResult]; +} + +- (void)enterTextIntoCurrentFirstResponder:(NSString *)text; +{ + [self.actor enterTextIntoCurrentFirstResponder:text]; +} + +- (void)enterTextIntoCurrentFirstResponder:(NSString *)text fallbackView:(UIView *)fallbackView; +{ + [self.actor enterTextIntoCurrentFirstResponder:text fallbackView:fallbackView]; +} + +- (void)expectToContainText:(NSString *)expectedResult; +{ + KIFUIObject *found = [self _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor expectView:found.view toContainText:expectedResult]; +} + + +#pragma mark - Touch Actions + +- (void)tapScreenAtPoint:(CGPoint)screenPoint; +{ + [self.actor tapScreenAtPoint:screenPoint]; +} + +- (void)swipeInDirection:(KIFSwipeDirection)direction; +{ + KIFUIObject *found = [self _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor swipeAccessibilityElement:found.element inView:found.view inDirection:direction]; +} + +#pragma mark - Scroll/Table/CollectionView Actions + +- (void)scrollByFractionOfSizeHorizontal:(CGFloat)horizontalFraction vertical:(CGFloat)verticalFraction; +{ + KIFUIObject *found = [self _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor scrollAccessibilityElement:found.element inView:found.view byFractionOfSizeHorizontal:horizontalFraction vertical:verticalFraction]; +} + +- (void)tapRowInTableViewAtIndexPath:(NSIndexPath *)indexPath; +{ + KIFUIObject *found = [[self _usingExpectedClass:[UITableView class]] _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor tapRowAtIndexPath:indexPath inTableView:(UITableView *)found.view]; +} + +- (UITableViewCell *)waitForCellInTableViewAtIndexPath:(NSIndexPath *)indexPath; +{ + KIFUIObject *found = [[self _usingExpectedClass:[UITableView class]] _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + return [self.actor waitForCellAtIndexPath:indexPath inTableView:(UITableView *)found.view]; +} + +- (void)moveRowInTableViewAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath; +{ + KIFUIObject *found = [[self _usingExpectedClass:[UITableView class]] _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor moveRowAtIndexPath:sourceIndexPath toIndexPath:destinationIndexPath inTableView:(UITableView *)found.view]; +} + + +- (void)tapCollectionViewItemAtIndexPath:(NSIndexPath *)indexPath; +{ + KIFUIObject *found = [[self _usingExpectedClass:[UICollectionView class]] _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor tapItemAtIndexPath:indexPath inCollectionView:(UICollectionView *)found.view]; +} + +- (UICollectionViewCell *)waitForCellInCollectionViewAtIndexPath:(NSIndexPath *)indexPath; +{ + KIFUIObject *found = [[self _usingExpectedClass:[UICollectionView class]] _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + return [self.actor waitForCellAtIndexPath:indexPath inCollectionView:(UICollectionView *)found.view]; +} + + +#pragma mark - UIControl Actions + +- (void)setSliderValue:(float)value; +{ + KIFUIObject *found = [[self _usingExpectedClass:[UISlider class]] _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor setValue:value forSlider:(UISlider *)found.view]; +} + +- (void)setSwitchOn:(BOOL)switchIsOn; +{ + KIFUIObject *found = [[self _usingExpectedClass:[UISwitch class]] _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor setSwitch:(UISwitch *)found.view element:found.element On:switchIsOn]; +} + +#pragma mark - Picker Actions + +- (void)selectPickerViewRowWithTitle:(NSString *)title; +{ + [self.actor selectPickerViewRowWithTitle:title]; +} + +- (void)selectPickerViewRowWithTitle:(NSString *)title inComponent:(NSInteger)component; +{ + [self.actor selectPickerViewRowWithTitle:title inComponent:component]; +} + +- (void)selectDatePickerValue:(NSArray *)datePickerColumnValues; +{ + [self.actor selectDatePickerValue:datePickerColumnValues]; +} + +- (void)choosePhotoInAlbum:(NSString *)albumName atRow:(NSInteger)row column:(NSInteger)column; +{ + [self.actor choosePhotoInAlbum:albumName atRow:row column:column]; +} + +#pragma mark - Pull to Refresh + +- (void)pullToRefresh; +{ + KIFUIObject *found = [self _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor pullToRefreshAccessibilityElement:found.element inView:found.view pullDownDuration:0]; +} + +- (void)pullToRefreshWithDuration:(KIFPullToRefreshTiming)pullDownDuration; +{ + KIFUIObject *found = [self _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + [self.actor pullToRefreshAccessibilityElement:found.element inView:found.view pullDownDuration:pullDownDuration]; + +} + +#pragma mark - Getters + +- (UIView *)view; +{ + return [self _predicateSearchWithRequiresMatch:YES mustBeTappable:NO].view; +} + +- (UIAccessibilityElement *)element; +{ + return [self _predicateSearchWithRequiresMatch:YES mustBeTappable:NO].element; +} + +- (KIFUITestActor *)actor; +{ + return [[KIFUITestActor actorInFile:self.file atLine:self.line delegate:self.delegate] usingTimeout:self.executionBlockTimeout]; +} + +#pragma mark - NSObject + +- (NSString *)description; +{ + KIFUIObject *found = [self _predicateSearchWithRequiresMatch:YES mustBeTappable:NO]; + return [NSString stringWithFormat:@"<%@; view=%@; element=%@; predicate=%@>", [super description], found.view, found.element, self.predicate]; +} + +#pragma mark - Private Methods + +- (instancetype)_usingExpectedClass:(Class)expectedClass; +{ + NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + return [evaluatedObject isKindOfClass:expectedClass]; + }]; + + predicate.kifPredicateDescription = [NSString stringWithFormat:@"is kind of Class \"%@\"", NSStringFromClass(expectedClass)]; + return [self usingPredicate:predicate]; +} + +- (void)_appendPredicate:(NSPredicate *)newPredicate; +{ + if (!self.predicate) { + self.predicate = newPredicate; + } else { + NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[ self.predicate, newPredicate ]]; + self.predicate = compoundPredicate; + } +} + +- (KIFUIObject *)_predicateSearchWithRequiresMatch:(BOOL)requiresMatch mustBeTappable:(BOOL)tappable; +{ + __block UIView *foundView = nil; + __block UIAccessibilityElement *foundElement = nil; + + if (requiresMatch) { + [self.actor waitForAccessibilityElement:&foundElement view:&foundView withElementMatchingPredicate:self.predicate tappable:tappable]; + } else { + NSError *error; + [self tryRunningBlock:^KIFTestStepResult(NSError **error) { + KIFTestWaitCondition([self.actor tryFindingAccessibilityElement:&foundElement view:&foundView withElementMatchingPredicate:self.predicate tappable:tappable error:error], error, @"Waiting on view matching %@", self.predicate.kifPredicateDescription); + return KIFTestStepResultSuccess; + } complete:nil timeout:1.0 error:&error]; + } + + if (foundView && foundElement) { + return [[KIFUIObject alloc] initWithElement:foundElement view:foundView]; + } + return nil; +} + +@end diff --git a/KIF Tests/AccessibilityIdentifierTests_ViewTestActor.m b/KIF Tests/AccessibilityIdentifierTests_ViewTestActor.m new file mode 100644 index 000000000..ba3ce2372 --- /dev/null +++ b/KIF Tests/AccessibilityIdentifierTests_ViewTestActor.m @@ -0,0 +1,78 @@ +// +// NewAccessibilityIdentifierTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + +#import +#import + +@interface AccessibilityIdentifierTests_ViewTestActor : KIFTestCase +@end + + +@implementation AccessibilityIdentifierTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"Tapping"] tap]; +} + +- (void)testWaitingForViewWithAccessibilityIdentifier +{ + // Since the tap has occurred in setup, we just need to wait for the result. + [[viewTester usingIdentifier:@"X_BUTTON"] waitForView]; + KIFExpectFailure([[[viewTester usingTimeout:0.5] usingIdentifier:@"NOT_X_BUTTON"] waitForView]); +} + +- (void)testTappingViewWithAccessibilityIdentifier +{ + [[viewTester usingIdentifier:@"X_BUTTON"] tap]; + [[[viewTester usingLabel:@"X"] usingTraits:UIAccessibilityTraitButton | UIAccessibilityTraitSelected] waitForView]; + KIFExpectFailure([[[viewTester usingTimeout:0.5] usingIdentifier:@"NOT_X_BUTTON"] tap]); +} + +- (void)testWaitingForAbscenceOfViewWithAccessibilityIdentifier +{ + // Since the tap has occurred in setup, we just need to wait for the result. + [[viewTester usingIdentifier:@"X_BUTTON"] waitForView]; + [[viewTester usingIdentifier:@"NOT_X_BUTTON"] waitForAbsenceOfView]; + KIFExpectFailure([[[viewTester usingTimeout:0.5] usingIdentifier:@"X_BUTTON"] waitForAbsenceOfView]); + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; + [[viewTester usingIdentifier:@"X_BUTTON"] waitForAbsenceOfView]; + [[viewTester usingLabel:@"Tapping"] tap]; +} + +- (void)testLongPressingViewWithAccessibilityIdentifier +{ + [[viewTester usingIdentifier:@"idGreeting"] longPressWithDuration:2]; + [[viewTester usingLabel:@"Select All"] tap]; +} + +- (void)testEnteringTextIntoViewWithAccessibilityIdentifier +{ + [[viewTester usingIdentifier:@"idGreeting"] longPressWithDuration:2]; + [[viewTester usingLabel:@"Select All"] tap]; + [[viewTester usingLabel:@"Cut"] tap]; + [[viewTester usingIdentifier:@"idGreeting"] enterText:@"Yo"]; +} + +- (void)testEnteringTextIntoViewWithAccessibilityIdentifierExpectingResults +{ + [[viewTester usingIdentifier:@"idGreeting"] enterText:@", world" expectedResult:@"Hello, world"]; + [[[viewTester usingLabel:@"Greeting"] usingValue:@"Hello, world"] waitForView]; +} + +- (void)testClearingAndEnteringTextIntoViewWithAccessibilityLabel +{ + [[viewTester usingIdentifier:@"idGreeting"] clearAndEnterText:@"Yo"]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +@end diff --git a/KIF Tests/CollectionViewTests_ViewTestActor.m b/KIF Tests/CollectionViewTests_ViewTestActor.m new file mode 100644 index 000000000..7154fb637 --- /dev/null +++ b/KIF Tests/CollectionViewTests_ViewTestActor.m @@ -0,0 +1,63 @@ +// +// NewCollectionViewTests.m +// KIF +// +// Created by Alex Odawa on 1/27/15. +// +// + +#import +#import "KIFTestStepValidation.h" + +@interface CollectionViewTests_ViewTestActor : KIFTestCase +@end + +@implementation CollectionViewTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"CollectionViews"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testTappingItems +{ + [[viewTester usingIdentifier:@"CollectionView Tests CollectionView"] tapCollectionViewItemAtIndexPath:[NSIndexPath indexPathForItem:199 inSection:0]]; + [[[viewTester usingLabel:@"Last Cell"] usingTraits:UIAccessibilityTraitSelected] waitForView]; + [[viewTester usingIdentifier:@"CollectionView Tests CollectionView"] tapCollectionViewItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]; + [[[viewTester usingLabel:@"First Cell"] usingTraits:UIAccessibilityTraitSelected] waitForView]; +} + +- (void)testTappingLastItemAndSection +{ + [[viewTester usingIdentifier:@"CollectionView Tests CollectionView"] tapCollectionViewItemAtIndexPath:[NSIndexPath indexPathForItem:-1 inSection:-1]]; + [[[viewTester usingLabel:@"Last Cell"] usingTraits:UIAccessibilityTraitSelected] waitForView]; +} + +- (void)testOutOfBounds +{ + KIFExpectFailure([[[viewTester usingTimeout:1] usingIdentifier:@"CollectionView Tests CollectionView"] tapCollectionViewItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:99]]); +} + +- (void)testUnknownCollectionView +{ + KIFExpectFailure([[[viewTester usingTimeout:1] usingIdentifier:@"Unknown CollectionView"] tapCollectionViewItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]); +} + +- (void)testTappingItemsByLabel +{ + // Tap the first item, which is already visible + [[viewTester usingLabel:@"First Cell"] tap]; + + // Tap the last item, which will need to be scrolled up + [[viewTester usingLabel:@"Last Cell"] tap]; + + // Tap the first item, which will need to be scrolled down + [[viewTester usingLabel:@"First Cell"] tap]; +} + +@end diff --git a/KIF Tests/CompositionTests_ViewTestActor.m b/KIF Tests/CompositionTests_ViewTestActor.m new file mode 100644 index 000000000..ce8364e08 --- /dev/null +++ b/KIF Tests/CompositionTests_ViewTestActor.m @@ -0,0 +1,68 @@ +// +// NewCompositionTests.m +// KIF +// +// Created by Alex Odawa on 1/27/15. +// +// + +#import +#import "UIApplication-KIFAdditions.h" +#import "UIAccessibilityElement-KIFAdditions.h" + +@interface KIFUIViewTestActor (Composition) + +- (void)tapViewIfNotSelected:(NSString *)label; +- (void)tapViewWithAccessibilityHint:(NSString *)hint; + +@end + +@implementation KIFUIViewTestActor (Composition) + +- (void)tapViewIfNotSelected:(NSString *)label +{ + UIAccessibilityElement *element = [viewTester usingLabel:label].element; + if ((element.accessibilityTraits & UIAccessibilityTraitSelected) == UIAccessibilityTraitNone) { + [[[viewTester usingLabel:label] usingPredicate:[NSPredicate predicateWithFormat:@"(accessibilityTraits & %i) == %i", UIAccessibilityTraitSelected, UIAccessibilityTraitNone]] tap]; + } +} + +- (void)tapViewWithAccessibilityHint:(NSString *)hint +{ + [[viewTester usingPredicate:[NSPredicate predicateWithFormat:@"accessibilityHint like %@", hint]] tap]; +} + +@end + +@interface CompositionTests_ViewTestActor : KIFTestCase +@end + +@implementation CompositionTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"Show/Hide"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testTappingViewWithHint +{ + [viewTester tapViewWithAccessibilityHint:@"A button for A"]; + [[[viewTester usingLabel:@"A"] usingTraits:UIAccessibilityTraitSelected] waitForView]; +} + +- (void)testTappingOnlyIfNotSelected +{ + [viewTester tapViewIfNotSelected:@"A"]; + [[[viewTester usingLabel:@"A"] usingTraits:UIAccessibilityTraitSelected] waitForView]; + + // This should not deselect the element. + [viewTester tapViewIfNotSelected:@"A"]; + [[[viewTester usingLabel:@"A"] usingTraits:UIAccessibilityTraitSelected] waitForView]; +} + +@end diff --git a/KIF Tests/ExistTests_ViewTestActor.m b/KIF Tests/ExistTests_ViewTestActor.m new file mode 100644 index 000000000..e089446d2 --- /dev/null +++ b/KIF Tests/ExistTests_ViewTestActor.m @@ -0,0 +1,32 @@ +// +// NewExistsTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + +#import + +@interface ExistTests_ViewTestActor : KIFTestCase +@end + + +@implementation ExistTests_ViewTestActor + +- (void)testExistsViewWithAccessibilityLabel +{ + if ([[viewTester usingLabel:@"Tapping"] tryFindingTappableView] && ![[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tryFindingTappableView]) { + [[viewTester usingLabel:@"Tapping"] tap]; + } else { + [viewTester fail]; + } + + if ([[viewTester usingLabel:@"Test Suite"] tryFindingTappableView] && ![[viewTester usingLabel:@"Tapping"] tryFindingTappableView]) { + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; + } else { + [viewTester fail]; + } +} + +@end diff --git a/KIF Tests/GestureTests_ViewTestActor.m b/KIF Tests/GestureTests_ViewTestActor.m new file mode 100644 index 000000000..f8450d244 --- /dev/null +++ b/KIF Tests/GestureTests_ViewTestActor.m @@ -0,0 +1,111 @@ +// +// NewGestureTests.m +// KIF +// +// Created by Alex Odawa on 1/27/15. +// +// + + +#import +#import +@implementation KIFUIViewTestActor (gesturetests) + +- (KIFUIViewTestActor *)swipeMe +{ + return [self usingLabel:@"Swipe Me"]; +} +@end + + +@interface GestureTests_ViewTestActor : KIFTestCase +@end + +@implementation GestureTests_ViewTestActor + +- (void)beforeAll +{ + [[viewTester usingLabel:@"Gestures"] tap]; + + // Wait for the push animation to complete before trying to interact with the view + [viewTester waitForTimeInterval:.25]; +} + +- (void)afterAll +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testSwipingLeft +{ + [[viewTester swipeMe] swipeInDirection:KIFSwipeDirectionLeft]; + [[viewTester usingLabel:@"Left"] waitForView]; +} + +- (void)testSwipingRight +{ + [[viewTester swipeMe] swipeInDirection:KIFSwipeDirectionRight]; + [[viewTester usingLabel:@"Right"] waitForView]; +} + +- (void)testSwipingUp +{ + [[viewTester swipeMe] swipeInDirection:KIFSwipeDirectionUp]; + [[viewTester usingLabel:@"Up"] waitForView]; +} + +- (void)testSwipingDown +{ + [[viewTester swipeMe] swipeInDirection:KIFSwipeDirectionDown]; + [[viewTester usingLabel:@"Down"] waitForView]; +} + +- (void)testMissingSwipeableElement +{ + KIFExpectFailure([[[viewTester usingTimeout:0.25] usingLabel:@"Unknown"] swipeInDirection:KIFSwipeDirectionDown]); +} + +- (void)testSwipingLeftWithTraits +{ + [[[viewTester swipeMe] usingTraits:UIAccessibilityTraitStaticText] swipeInDirection:KIFSwipeDirectionLeft]; + [[viewTester usingLabel:@"Left"] waitForView]; +} + +- (void)testSwipingRightWithTraits +{ + [[[viewTester swipeMe] usingTraits:UIAccessibilityTraitStaticText] swipeInDirection:KIFSwipeDirectionRight]; + [[viewTester usingLabel:@"Right"] waitForView]; +} + +- (void)testSwipingUpWithTraits +{ + [[[viewTester swipeMe] usingTraits:UIAccessibilityTraitStaticText] swipeInDirection:KIFSwipeDirectionUp]; + [[viewTester usingLabel:@"Up"] waitForView]; +} + +- (void)testSwipingDownWithTraits +{ + [[[viewTester swipeMe] usingTraits:UIAccessibilityTraitStaticText] swipeInDirection:KIFSwipeDirectionDown]; + [[viewTester usingLabel:@"Down"] waitForView]; +} + +- (void)testMissingSwipeableElementWithTraits +{ + KIFExpectFailure([[[[viewTester usingTimeout:0.25] usingLabel:@"Unknown"] usingTraits:UIAccessibilityTraitStaticText] swipeInDirection:KIFSwipeDirectionDown]); +} + +- (void)testScrolling +{ + // Needs to be offset from the edge to prevent the navigation controller's interactivePopGestureRecognizer from triggering + [[viewTester usingIdentifier:@"Scroll View"] scrollByFractionOfSizeHorizontal:-0.80 vertical:-0.80]; + [[viewTester usingLabel:@"Bottom Right"] waitToBecomeTappable]; + [[viewTester usingIdentifier:@"Scroll View"] scrollByFractionOfSizeHorizontal:0.80 vertical:0.80]; + [[viewTester usingLabel:@"Top Left"] waitToBecomeTappable]; +} + +- (void)testMissingScrollableElement +{ + KIFExpectFailure([[[viewTester usingTimeout:0.25] usingIdentifier:@"Unknown"] scrollByFractionOfSizeHorizontal:0.5 vertical:0.5]); +} + +@end diff --git a/KIF Tests/LandscapeTests_ViewTestActor.m b/KIF Tests/LandscapeTests_ViewTestActor.m new file mode 100644 index 000000000..aaf7ddf70 --- /dev/null +++ b/KIF Tests/LandscapeTests_ViewTestActor.m @@ -0,0 +1,40 @@ +// +// NewLandscapeTests.m +// KIF +// +// Created by Alex Odawa on 1/27/15. +// +// + +#import + +@interface LandscapeTests_ViewTestActor : KIFTestCase +@end + +@implementation LandscapeTests_ViewTestActor + +- (void)beforeAll +{ + [system simulateDeviceRotationToOrientation:UIDeviceOrientationLandscapeLeft]; + [[viewTester usingIdentifier:@"Test Suite TableView"] scrollByFractionOfSizeHorizontal:0 vertical:-0.2]; +} + +- (void)afterAll +{ + [system simulateDeviceRotationToOrientation:UIDeviceOrientationPortrait]; + [viewTester waitForTimeInterval:0.5]; +} + +- (void)beforeEach +{ + [viewTester waitForTimeInterval:0.25]; +} + +- (void)testThatAlertViewsCanBeTappedInLandscape +{ + [[viewTester usingLabel:@"UIAlertView"] tap]; + [[viewTester usingLabel:@"Continue"] tap]; + [[viewTester usingLabel:@"Message"] waitForAbsenceOfView]; +} + +@end diff --git a/KIF Tests/LongPressTests_ViewTestActor.m b/KIF Tests/LongPressTests_ViewTestActor.m new file mode 100644 index 000000000..c480d24a9 --- /dev/null +++ b/KIF Tests/LongPressTests_ViewTestActor.m @@ -0,0 +1,45 @@ +// +// ViewLongPressTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + +#import + +@interface LongPressTests_ViewTestActor : KIFTestCase +@end + + +@implementation LongPressTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"Tapping"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testLongPressingViewWithAccessibilityLabel +{ + [[viewTester usingLabel:@"Greeting"] longPressWithDuration:2]; + [[viewTester usingLabel:@"Select All"] tap]; +} + +- (void)testLongPressingViewViewWithTraits +{ + [[[viewTester usingLabel:@"Greeting"] usingValue:@"Hello"] longPressWithDuration:2]; + [[viewTester usingLabel:@"Select All"] tap]; +} + +- (void)testLongPressingViewViewWithValue +{ + [[[[viewTester usingLabel:@"Greeting"] usingValue:@"Hello"] usingTraits:UIAccessibilityTraitUpdatesFrequently] longPressWithDuration:2]; + [[viewTester usingLabel:@"Select All"] tap]; +} + +@end \ No newline at end of file diff --git a/KIF Tests/ModalViewTests_ViewTestActor.m b/KIF Tests/ModalViewTests_ViewTestActor.m new file mode 100644 index 000000000..d6e6c8e95 --- /dev/null +++ b/KIF Tests/ModalViewTests_ViewTestActor.m @@ -0,0 +1,77 @@ +// +// NewModalViewTests.m +// KIF +// +// Created by Alex Odawa on 1/27/15. +// +// + +#import + +@interface ModalViewTests_ViewTestActor : KIFTestCase +@end + +@implementation ModalViewTests_ViewTestActor + +- (void)beforeEach +{ + [viewTester waitForTimeInterval:0.25]; +} + +- (void)testInteractionWithAnAlertView +{ + [[viewTester usingLabel:@"UIAlertView"] tap]; + [[viewTester usingLabel:@"Alert View"] waitForView]; + [[viewTester usingLabel:@"Message"] waitForView]; + [[viewTester usingLabel:@"Cancel"] waitToBecomeTappable]; + [[viewTester usingLabel:@"Continue"] waitToBecomeTappable]; + [[viewTester usingLabel:@"Continue"] tap]; + [[viewTester usingLabel:@"Message"] waitForAbsenceOfView]; +} + +- (void)testInteractionWithAnActionSheet +{ + [[viewTester usingLabel:@"UIActionSheet"] tap]; + [[viewTester usingLabel:@"Action Sheet"] waitForView]; + [[viewTester usingLabel:@"Destroy"] waitToBecomeTappable]; + [[viewTester usingLabel:@"A"] waitToBecomeTappable]; + [[viewTester usingLabel:@"B"] waitToBecomeTappable]; + + [self _dismissModal]; + + [[viewTester usingLabel:@"Alert View"] waitForView]; + [[viewTester usingLabel:@"Continue"] tap]; + [[viewTester usingLabel:@"Alert View"] waitForAbsenceOfView]; +} + +- (void)testInteractionWithAnActivityViewController +{ + if (!NSClassFromString(@"UIActivityViewController")) { + return; + } + + [[viewTester usingLabel:@"UIActivityViewController"] tap]; + [[viewTester usingLabel:@"Copy"] waitToBecomeTappable]; + [[viewTester usingLabel:@"Mail"] waitToBecomeTappable]; + + // On iOS7, the activity controller appears at the bottom + // On iOS8 and beyond, it is shown in a popover control + if ([UIDevice.currentDevice.systemVersion compare:@"8.0" options:NSNumericSearch] < 0) { + [tester tapViewWithAccessibilityLabel:@"Cancel"]; + } else { + [self _dismissModal]; + } +} + +#pragma mark - Private Methods + +- (void)_dismissModal; +{ + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + [tester dismissPopover]; + } else { + [tester tapViewWithAccessibilityLabel:@"Cancel"]; + } +} + +@end diff --git a/KIF Tests/MultiFingerTests_ViewTestActor.m b/KIF Tests/MultiFingerTests_ViewTestActor.m new file mode 100644 index 000000000..a8516ba3f --- /dev/null +++ b/KIF Tests/MultiFingerTests_ViewTestActor.m @@ -0,0 +1,85 @@ +// +// NewMultiFingerTests.m +// KIF +// +// Created by Alex Odawa on 1/27/15. +// +// + + +#import +#import "KIFTestStepValidation.h" +#import + +@interface MultiFingerTests_ViewTestActor : KIFTestCase +@property (nonatomic, readwrite) BOOL twoFingerPanSuccess; +@property (nonatomic, readwrite) BOOL zoomSuccess; +@end + +@implementation MultiFingerTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"ScrollViews"] tap]; + // reset scroll view + UIScrollView *scrollView = (UIScrollView *)[viewTester usingLabel:@"Scroll View"].view; + scrollView.contentOffset = CGPointZero; + + self.twoFingerPanSuccess = NO; + self.zoomSuccess = NO; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; + self.twoFingerPanSuccess = NO; + self.zoomSuccess = NO; +} + +- (void)testTwoFingerPan +{ + CGFloat offset = 50.0; + + UIScrollView *scrollView = (UIScrollView *)[viewTester usingLabel:@"Scroll View"].view; + UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingerPanned)]; + panGestureRecognizer.minimumNumberOfTouches = 2; + [scrollView addGestureRecognizer:panGestureRecognizer]; + + CGPoint startPoint = CGPointMake(CGRectGetMidX(scrollView.bounds), CGRectGetMidY(scrollView.bounds)); + CGPoint endPoint = CGPointMake(startPoint.x, startPoint.y + offset); + [scrollView twoFingerPanFromPoint:startPoint toPoint:endPoint steps:10]; + + __KIFAssertEqual(self.twoFingerPanSuccess, YES); +} + +- (void)twoFingerPanned +{ + self.twoFingerPanSuccess = YES; +} + +- (void)testZoom +{ + CGFloat distance = 50.0; + + UIScrollView *scrollView = (UIScrollView *)[viewTester usingLabel:@"Scroll View"].view; + UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self + action:@selector(zoomed:)]; + + [scrollView addGestureRecognizer:pinchRecognizer]; + + CGPoint startPoint = CGPointMake(CGRectGetMidX(scrollView.bounds), CGRectGetMidY(scrollView.bounds)); + [scrollView zoomAtPoint:startPoint distance:distance steps:10]; + + __KIFAssertEqual(self.zoomSuccess, YES); +} + +- (void)zoomed:(UIPinchGestureRecognizer *)pinchRecognizer +{ + if (pinchRecognizer.state == UIGestureRecognizerStateChanged) { + if (pinchRecognizer.scale > 1) { + self.zoomSuccess = YES; + } + } +} + +@end diff --git a/KIF Tests/PickerTests_ViewTestActor.m b/KIF Tests/PickerTests_ViewTestActor.m new file mode 100644 index 000000000..e33ed68a2 --- /dev/null +++ b/KIF Tests/PickerTests_ViewTestActor.m @@ -0,0 +1,114 @@ +// +// NewPickerTests.m +// KIF +// +// Created by Alex Odawa on 1/27/15. +// +// + +#import + +@implementation KIFUIViewTestActor (pickertests) + +- (KIFUIViewTestActor *)dateSelector +{ + return [self usingLabel:@"Date Selection"]; +} + +- (KIFUIViewTestActor *)dateTimeSelector +{ + return [self usingLabel:@"Date Time Selection"]; +} + +- (KIFUIViewTestActor *)timeSelector +{ + return [self usingLabel:@"Time Selection"]; +} + +- (KIFUIViewTestActor * )countdownSelector +{ + return [self usingLabel:@"Countdown Selection"]; +} + +@end + + +@interface PickerTests_ViewTestActor : KIFTestCase +@end + +@implementation PickerTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"Pickers"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testSelectingDateInPast +{ + [[viewTester dateSelector] tap]; + NSArray *date = @[ @"June", @"17", @"1965" ]; + // If the UIDatePicker LocaleIdentifier would be de_DE then the date to set + // would look like this: NSArray *date = @[@"17.", @"Juni", @"1965" + [viewTester selectDatePickerValue:date]; + [[[viewTester dateSelector] usingValue:@"Jun 17, 1965"] waitForView]; +} + +- (void)testSelectingDateInFuture +{ + [[viewTester dateSelector] tap]; + NSArray *date = @[ @"December", @"31", @"2030" ]; + [viewTester selectDatePickerValue:date]; + [[[viewTester dateSelector] usingValue:@"Dec 31, 2030"] waitForView]; +} + +- (void)testSelectingDateTime +{ + [[viewTester dateTimeSelector] tap]; + NSArray *dateTime = @[ @"Jun 17", @"6", @"43", @"AM" ]; + [viewTester selectDatePickerValue:dateTime]; + [[[viewTester dateTimeSelector] usingValue:@"Jun 17, 06:43 AM"] waitForView]; +} + +- (void)testSelectingTime +{ + [[viewTester timeSelector] tap]; + NSArray *time = @[ @"7", @"44", @"AM" ]; + [viewTester selectDatePickerValue:time]; + [[[viewTester timeSelector] usingValue:@"7:44 AM"] waitForView]; +} + +- (void)testSelectingCountdown +{ + [[viewTester countdownSelector] tap]; + NSArray *countdown = @[ @"4", @"10" ]; + [viewTester selectDatePickerValue:countdown]; + [[[viewTester countdownSelector] usingValue:@"15000.000000"] waitForView]; +} + +- (void)testSelectingAPickerRow +{ + [viewTester selectPickerViewRowWithTitle:@"Charlie"]; + + NSOperatingSystemVersion iOS8 = {8, 0, 0}; + if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)] && [[NSProcessInfo new] isOperatingSystemAtLeastVersion:iOS8]) { + [[[viewTester usingLabel:@"Call Sign"] usingValue:@"Charlie"] waitForView]; + } else { + [[[viewTester usingLabel:@"Call Sign"] usingValue:@"Charlie. 3 of 3"] waitForView]; + } +} + +- (void)testSelectingRowInComponent +{ + [[viewTester dateSelector] tap]; + NSArray *date = @[ @"December", @"31", @"2030" ]; + [viewTester selectDatePickerValue:date]; + [viewTester selectPickerViewRowWithTitle:@"17" inComponent:1]; + [[[viewTester dateSelector] usingValue:@"Dec 17, 2030"] waitForView]; +} + +@end diff --git a/KIF Tests/PullToRefreshTests_ViewTestActor.m b/KIF Tests/PullToRefreshTests_ViewTestActor.m new file mode 100644 index 000000000..7a4d6da6c --- /dev/null +++ b/KIF Tests/PullToRefreshTests_ViewTestActor.m @@ -0,0 +1,41 @@ +// +// PullToRefreshTests_ViewTestActor.m +// KIF +// +// Created by Alex Odawa on 1/29/16. +// +// + +#import +#import "KIFUIViewTestActor.h" + +@interface PullToRefreshTests_ViewTestActor : KIFTestCase +@end + +@implementation PullToRefreshTests_ViewTestActor + +-(void) testPullToRefreshByAccessibilityLabelWithDuration +{ + [[viewTester usingIdentifier:@"Test Suite TableView"] waitForView]; + [[viewTester usingLabel:@"Table View"] pullToRefreshWithDuration:KIFPullToRefreshInAboutOneSecond]; + [[viewTester usingLabel:@"Bingo!"] waitForView]; + [[viewTester usingLabel:@"Bingo!"] waitForAbsenceOfView]; + [viewTester waitForTimeInterval:1.0f]; +} + +-(void) testPullToRefreshWithBigContentSize +{ + + UITableView *tableView = (id)[[viewTester usingIdentifier:@"Test Suite TableView"] waitForView]; + CGSize originalSize = tableView.contentSize; + tableView.contentSize = CGSizeMake(1000, 10000); + + [[viewTester usingLabel:@"Table View"] pullToRefreshWithDuration:KIFPullToRefreshInAboutOneSecond]; + [[viewTester usingLabel:@"Bingo!"] waitForView]; + [[viewTester usingLabel:@"Bingo!"] waitForAbsenceOfView]; + [viewTester waitForTimeInterval:1.0f]; + + tableView.contentSize = originalSize; +} + +@end diff --git a/KIF Tests/ScrollViewTests_ViewTestActor.m b/KIF Tests/ScrollViewTests_ViewTestActor.m new file mode 100644 index 000000000..9a5eb90a5 --- /dev/null +++ b/KIF Tests/ScrollViewTests_ViewTestActor.m @@ -0,0 +1,40 @@ +// +// NewScrollViewTests.m +// KIF +// +// Created by Alex Odawa on 1/27/15. +// +// + +#import +#import "KIFTestStepValidation.h" + +@interface ScrollViewTests_ViewTestActor : KIFTestCase +@end + +@implementation ScrollViewTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"ScrollViews"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testScrollingToTapOffscreenViews +{ + [[viewTester usingLabel:@"Down"] tap]; + [[viewTester usingLabel:@"Up"] tap]; + [[viewTester usingLabel:@"Right"] tap]; + [[viewTester usingLabel:@"Left"] tap]; +} + +- (void)testScrollingToTapOffscreenTextView +{ + [[viewTester usingLabel:@"TextView"] tap]; +} + +@end diff --git a/KIF Tests/SearchFieldTests_ViewTestActor.m b/KIF Tests/SearchFieldTests_ViewTestActor.m new file mode 100644 index 000000000..f166f744f --- /dev/null +++ b/KIF Tests/SearchFieldTests_ViewTestActor.m @@ -0,0 +1,37 @@ +// +// ViewSearchFieldTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + + +#import +#import + +@interface SearchFieldTests_ViewTestActor : KIFTestCase +@end + + +@implementation SearchFieldTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"TableViews"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testWaitingForSearchFieldToBecomeFirstResponder +{ + [[viewTester usingTraits:UIAccessibilityTraitSearchField] tap]; + [[viewTester usingTraits:UIAccessibilityTraitSearchField] waitToBecomeFirstResponder]; + [viewTester enterTextIntoCurrentFirstResponder:@"text"]; + [[[viewTester usingValue:@"text"] usingTraits:UIAccessibilityTraitSearchField] waitForView]; +} + +@end diff --git a/KIF Tests/SpecificControlTests_ViewTestActor.m b/KIF Tests/SpecificControlTests_ViewTestActor.m new file mode 100644 index 000000000..018dc7771 --- /dev/null +++ b/KIF Tests/SpecificControlTests_ViewTestActor.m @@ -0,0 +1,62 @@ +// +// NewSpecificControlTests.m +// KIF +// +// Created by Alex Odawa on 1/27/15. +// +// + +#import + +@interface SpecificControlTests_ViewTestActor : KIFTestCase +@end + +@implementation SpecificControlTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"Tapping"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testTogglingASwitch +{ + [[[viewTester usingLabel:@"Happy"] usingValue:@"1"] waitForView]; + [[viewTester usingLabel:@"Happy"] setSwitchOn:NO]; + [[[viewTester usingLabel:@"Happy"] usingValue:@"0"] waitForView]; + [[viewTester usingLabel:@"Happy"] setSwitchOn:YES]; + [[[viewTester usingLabel:@"Happy"] usingValue:@"1"] waitForView]; +} + +- (void)testMovingASlider +{ + [viewTester waitForTimeInterval:1]; + [[viewTester usingLabel:@"Slider"] setSliderValue:3]; + [[[viewTester usingLabel:@"Slider"] usingValue:@"3"] waitForView]; + [[viewTester usingLabel:@"Slider"] setSliderValue:0]; + [[[viewTester usingLabel:@"Slider"] usingValue:@"0"] waitForView]; + [[viewTester usingLabel:@"Slider"] setSliderValue:5]; + [[[viewTester usingLabel:@"Slider"] usingValue:@"5"] waitForView]; +} + +- (void)testPickingAPhoto +{ + // 'acknowledgeSystemAlert' can't be used on iOS7 + // The console shows a message "AX Lookup problem! 22 com.apple.iphone.axserver:-1" + if ([UIDevice.currentDevice.systemVersion compare:@"8.0" options:NSNumericSearch] < 0) { + return; + } + + [[viewTester usingLabel:@"Photos"] tap]; + [viewTester acknowledgeSystemAlert]; + [viewTester waitForTimeInterval:0.5f]; // Wait for view to stabilize + + [viewTester choosePhotoInAlbum:@"Camera Roll" atRow:1 column:2]; + [[viewTester usingLabel:@"UIImage"] waitForView]; +} + +@end diff --git a/KIF Tests/SystemAlertTests_ViewTestActor.m b/KIF Tests/SystemAlertTests_ViewTestActor.m new file mode 100644 index 000000000..983bc144d --- /dev/null +++ b/KIF Tests/SystemAlertTests_ViewTestActor.m @@ -0,0 +1,59 @@ +// +// NewSystemAlertTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + + +#import + +@interface SystemAlertTests_ViewTestActor : KIFTestCase +@end + + +@implementation SystemAlertTests_ViewTestActor + ++ (XCTestSuite *)defaultTestSuite +{ + // 'acknowledgeSystemAlert' can't be used on iOS7 + // The console shows a message "AX Lookup problem! 22 com.apple.iphone.axserver:-1" + if ([UIDevice.currentDevice.systemVersion compare:@"8.0" options:NSNumericSearch] < 0) { + return nil; + } + + return [super defaultTestSuite]; +} + +- (void)beforeEach +{ + [[viewTester usingLabel:@"System Alerts"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testAuthorizingLocationServices +{ + [tester tapViewWithAccessibilityLabel:@"Location Services and Notifications"]; + + // In a clean state this will pop two alerts, but in a dirty state it will pop one or none. + // Call acknowledgeSystemAlert 2x without checking the return value (as the alerts might not be there). + // Finally check that the final attempt is indeed false and no alerts remain on screen. + + ([tester acknowledgeSystemAlert]); + ([tester acknowledgeSystemAlert]); + XCTAssertFalse([tester acknowledgeSystemAlert]); +} + +- (void)testAuthorizingPhotosAccess +{ + [[viewTester usingLabel:@"Photos"] tap]; + [viewTester acknowledgeSystemAlert]; + [[viewTester usingLabel:@"Cancel"] tap]; +} + +@end diff --git a/KIF Tests/TableViewTests_ViewTestActor.m b/KIF Tests/TableViewTests_ViewTestActor.m new file mode 100644 index 000000000..bc6660952 --- /dev/null +++ b/KIF Tests/TableViewTests_ViewTestActor.m @@ -0,0 +1,154 @@ +// +// NewTableViewTests.m +// KIF +// +// Created by Alex Odawa on 1/27/15. +// +// + + +#import +#import "KIFTestStepValidation.h" +#import "UIApplication-KIFAdditions.h" + +@interface TableViewTests_ViewTestActor : KIFTestCase +@end + +@implementation TableViewTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"TableViews"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testTappingRows +{ + [[viewTester usingIdentifier:@"TableView Tests Table"] tapRowInTableViewAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:2]]; + [[[viewTester usingLabel:@"Last Cell"] usingTraits:UIAccessibilityTraitSelected] waitForView]; + [[viewTester usingIdentifier:@"TableView Tests Table"] tapRowInTableViewAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; + [[[viewTester usingLabel:@"First Cell"] usingTraits:UIAccessibilityTraitSelected] waitForView]; +} + +- (void)testTappingLastRowAndSection +{ + [[viewTester usingIdentifier:@"TableView Tests Table"] tapRowInTableViewAtIndexPath:[NSIndexPath indexPathForRow:-1 inSection:-1]]; + [[[viewTester usingLabel:@"Last Cell"] usingTraits:UIAccessibilityTraitSelected] waitForView]; +} + +- (void)testOutOfBounds +{ + KIFExpectFailure([[[viewTester usingTimeout:1] usingIdentifier:@"TableView Tests Table"] tapRowInTableViewAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:99]]); +} + +- (void)testUnknownTable +{ + KIFExpectFailure([[[viewTester usingTimeout:1] usingIdentifier:@"Unknown Table"] tapRowInTableViewAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]); +} + +- (void)testScrollingToTop +{ + [[viewTester usingIdentifier:@"TableView Tests Table"] tapRowInTableViewAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:2]]; + [viewTester tapStatusBar]; + + UITableView *tableView = (UITableView *)[viewTester usingIdentifier:@"TableView Tests Table"].view; + [viewTester runBlock:^KIFTestStepResult(NSError *__autoreleasing *error) { + KIFTestWaitCondition(tableView.contentOffset.y == - tableView.contentInset.top, error, @"Waited for scroll view to scroll to top, but it ended at %@", NSStringFromCGPoint(tableView.contentOffset)); + return KIFTestStepResultSuccess; + }]; +} + +- (void)testTappingRowsByLabel +{ + // Tap the first row, which is already visible + [[viewTester usingLabel:@"First Cell"] tap]; + + // Tap the last row, which will need to be scrolled up + [[viewTester usingLabel:@"Last Cell"] tap]; + + // Tap the first row, which will need to be scrolled down + [[viewTester usingLabel:@"First Cell"] tap]; +} + +- (void)testMoveRowDown +{ + [[viewTester usingLabel:@"Edit"] tap]; + + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]].textLabel.text, @"Cell 0", @""); + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:4 inSection:1]].textLabel.text, @"Cell 4", @""); + + [[viewTester usingIdentifier:@"TableView Tests Table"] moveRowInTableViewAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1] toIndexPath:[NSIndexPath indexPathForRow:4 inSection:1]]; + + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]].textLabel.text, @"Cell 1", @""); + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:4 inSection:1]].textLabel.text, @"Cell 0", @""); + + [[viewTester usingLabel:@"Done"] tap]; +} + +- (void)testMoveRowUp +{ + [[viewTester usingLabel:@"Edit"] tap]; + + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]].textLabel.text, @"Cell 0", @""); + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:4 inSection:1]].textLabel.text, @"Cell 4", @""); + + [[viewTester usingIdentifier:@"TableView Tests Table"] moveRowInTableViewAtIndexPath:[NSIndexPath indexPathForRow:4 inSection:1] toIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]]; + + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]].textLabel.text, @"Cell 4", @""); + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:4 inSection:1]].textLabel.text, @"Cell 3", @""); + + [[viewTester usingLabel:@"Done"] tap]; +} + +- (void)testMoveRowUpUsingNegativeRowIndexes +{ + [[viewTester usingLabel:@"Edit"] tap]; + + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:-3 inSection:1]].textLabel.text, @"Cell 35", @""); + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:-1 inSection:1]].textLabel.text, @"Cell 37", @""); + + [[viewTester usingIdentifier:@"TableView Tests Table"] moveRowInTableViewAtIndexPath:[NSIndexPath indexPathForRow:-1 inSection:1] toIndexPath:[NSIndexPath indexPathForRow:-3 inSection:1]]; + + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:-3 inSection:1]].textLabel.text, @"Cell 37", @""); + __KIFAssertEqualObjects([[viewTester usingIdentifier:@"TableView Tests Table"] waitForCellInTableViewAtIndexPath:[NSIndexPath indexPathForRow:-1 inSection:1]].textLabel.text, @"Cell 36", @""); + + [[viewTester usingLabel:@"Done"] tap]; +} + +- (void)testTogglingSwitch +{ + [[viewTester usingLabel:@"Table View Switch"] setSwitchOn:NO]; + [[viewTester usingLabel:@"Table View Switch"] setSwitchOn:YES]; +} + +- (void)testButtonAbsentAfterRemoveFromSuperview +{ + [[viewTester usingLabel:@"Button"] waitForView]; + + [[viewTester usingLabel:@"Button"].view removeFromSuperview]; + [[viewTester usingLabel:@"Button"] waitForAbsenceOfView]; +} + +- (void)testButtonAbsentAfterSetHidden +{ + [[viewTester usingLabel:@"Button"] waitForView]; + + UIView *button = [viewTester usingLabel:@"Button"].view; + + [button setHidden:YES]; + [[viewTester usingLabel:@"Button"] waitForAbsenceOfView]; + + [button setHidden:NO]; + [[viewTester usingLabel:@"Button"] waitForView]; +} + +- (void)testEnteringTextIntoATextFieldInATableCell +{ + [[viewTester usingLabel:@"TextField"] enterText:@"Test-Driven Development"]; +} + +@end diff --git a/KIF Tests/TappingTests_ViewTestActor.m b/KIF Tests/TappingTests_ViewTestActor.m new file mode 100644 index 000000000..147915240 --- /dev/null +++ b/KIF Tests/TappingTests_ViewTestActor.m @@ -0,0 +1,84 @@ +// +// ViewTappingTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + + +#import + +@implementation KIFUIViewTestActor (tappingtests) + +- (KIFUIViewTestActor *)xButton; +{ + return [[self usingLabel:@"X"] usingTraits:UIAccessibilityTraitButton]; +} + +- (KIFUIViewTestActor *)greeting; +{ + return [self usingLabel:@"Greeting"]; +} + +@end + +@interface TappingTests_ViewTestActor : KIFTestCase +@end + + +@implementation TappingTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"Tapping"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testTappingViewWithAccessibilityLabel +{ + // Since the tap has occurred in setup, we just need to wait for the result. + [[viewTester usingLabel:@"TapView"] waitForView]; +} + +- (void)testTappingViewWithTraits +{ + [[viewTester xButton] tap]; + [[[viewTester xButton] usingTraits:UIAccessibilityTraitSelected] waitForView]; +} + +- (void)testTappingViewWithValue +{ + [[[viewTester greeting] usingValue:@"Hello"] tap]; + [[viewTester greeting] waitToBecomeFirstResponder]; +} + +- (void)testTappingViewWithScreenAtPoint +{ + [viewTester waitForTimeInterval:0.75]; + [viewTester tapScreenAtPoint:CGPointMake(15, 200)]; + [[[viewTester xButton] usingTraits:UIAccessibilityTraitSelected] waitForView]; +} + +- (void)testTappingViewPartiallyOffscreenAndWithinScrollView +{ + [[viewTester usingLabel:@"Slightly Offscreen Button"] tap]; +} + +- (void)testTappingViewWithTapGestureRecognizer +{ + [[viewTester usingLabel:@"Label with Tap Gesture Recognizer"] tap]; +} + +- (void)testTappingLabelWithLineBreaks +{ + [[viewTester usingLabel:@"Label with\nLine Break\n\n"] tap]; + [[viewTester usingLabel:@"A\nB\nC\n\n"] tap]; +} + + +@end diff --git a/KIF Tests/TypingTests_ViewTestActor.m b/KIF Tests/TypingTests_ViewTestActor.m new file mode 100644 index 000000000..18eb2bdc6 --- /dev/null +++ b/KIF Tests/TypingTests_ViewTestActor.m @@ -0,0 +1,99 @@ +// +// ViewTypingTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + +#import +#import "KIFTestStepValidation.h" + +@interface TypingTests_ViewTestActor : KIFTestCase +@end + + +@implementation TypingTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"Tapping"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testWaitingForFirstResponder +{ + [[[viewTester usingLabel:@"Greeting"] usingValue:@"Hello"] tap]; + [[viewTester usingLabel:@"Greeting"] waitToBecomeFirstResponder]; +} + +- (void)testMissingFirstResponder +{ + KIFExpectFailure([[[viewTester usingTimeout:1] usingLabel:@"Greeting"] waitToBecomeFirstResponder]); +} + +- (void)testEnteringTextIntoFirstResponder +{ + [[[viewTester usingLabel:@"Greeting"] usingValue:@"Hello"] longPressWithDuration:2]; + [[viewTester usingLabel:@"Select All"] tap]; + [viewTester enterTextIntoCurrentFirstResponder:@"Yo"]; + [[[viewTester usingLabel:@"Greeting"] usingValue:@"Yo"] waitForView]; +} + +- (void)testFailingToEnterTextIntoFirstResponder +{ + KIFExpectFailure([[viewTester usingTimeout:1] enterTextIntoCurrentFirstResponder:@"Yo"]); +} + +- (void)testEnteringTextIntoViewWithAccessibilityLabel +{ + [[[viewTester usingLabel:@"Greeting"] usingValue:@"Hello"] longPressWithDuration:2]; + [[viewTester usingLabel:@"Select All"] tap]; + [[viewTester usingLabel:@"Cut"] tap]; + [[viewTester usingLabel:@"Greeting"] enterText:@"Yo"]; + [[[viewTester usingLabel:@"Greeting"] usingValue:@"Yo"] waitForView]; +} + +- (void)testEnteringTextIntoViewWithAccessibilityLabelExpectingResults +{ + [[viewTester usingLabel:@"Greeting"] enterText:@", world" expectedResult:@"Hello, world"]; + [[[viewTester usingLabel:@"Greeting"] usingValue:@"Hello, world"] waitForView]; +} + +- (void)testClearingAndEnteringTextIntoViewWithAccessibilityLabel +{ + [[viewTester usingLabel:@"Greeting"] clearAndEnterText:@"Yo"]; +} + +- (void)testEnteringReturnCharacterIntoViewWithAccessibilityLabel +{ + [[viewTester usingLabel:@"Other Text"] enterText:@"Hello\n"]; + [[viewTester usingLabel:@"Greeting"] waitToBecomeFirstResponder]; + [[viewTester usingLabel:@"Greeting"] waitForView]; + [[viewTester usingLabel:@"Greeting"] enterText:@", world\n" expectedResult:@"Hello, world"]; +} + +- (void)testClearingALongTextField +{ + [[viewTester usingLabel:@"Greeting"] clearAndEnterText:@"A man, a plan, a canal, Panama. Able was I, ere I saw Elba."]; + [[viewTester usingLabel:@"Greeting"] clearText]; +} + +- (void)testThatClearingTextHitsTheDelegate +{ + [[viewTester usingLabel:@"Other Text"] enterText:@"hello"]; + [[viewTester usingLabel:@"Other Text"] clearText]; + [[[viewTester usingLabel:@"Greeting"] usingValue:@"Deleted something."] waitForView]; +} + +- (void)testThatBackspaceDeletesOneCharacter +{ + [[viewTester usingLabel:@"Other Text"] enterText:@"hi\bello" expectedResult:@"hello"]; + [[[viewTester usingLabel:@"Greeting"] usingValue:@"Deleted something."] waitForView]; +} + +@end diff --git a/KIF Tests/WaitForAbscenceTests_ViewTestActor.m b/KIF Tests/WaitForAbscenceTests_ViewTestActor.m new file mode 100644 index 000000000..62504308e --- /dev/null +++ b/KIF Tests/WaitForAbscenceTests_ViewTestActor.m @@ -0,0 +1,43 @@ +// +// NewWaitForAbsenceTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + + +#import + +@interface WaitForAbscenceTests_ViewTestActor : KIFTestCase +@end + + +@implementation WaitForAbscenceTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"Tapping"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testWaitingForAbsenceOfViewWithAccessibilityLabel +{ + [[viewTester usingLabel:@"Tapping"] waitForAbsenceOfView]; +} + +- (void)testWaitingForAbsenceOfViewWithTraits +{ + [[[viewTester usingLabel:@"Tapping"] usingTraits:UIAccessibilityTraitStaticText] waitForAbsenceOfView]; +} + +- (void)testWaitingForAbsenceOfViewWithValue +{ + [[[viewTester usingLabel:@"Switch 1"] usingValue:@"1"] waitForAbsenceOfView]; +} + +@end diff --git a/KIF Tests/WaitForAnimationTests_ViewTestActor.m b/KIF Tests/WaitForAnimationTests_ViewTestActor.m new file mode 100644 index 000000000..12c2b07e8 --- /dev/null +++ b/KIF Tests/WaitForAnimationTests_ViewTestActor.m @@ -0,0 +1,35 @@ +// +// ViewWaitForAnimationTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + +#import + +@interface WaitForAnimationTests_ViewTestActor : KIFTestCase +@end + + +@implementation WaitForAnimationTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"Tapping"] tap]; + [[viewTester usingLabel:@"Animations"] tap]; +} + +- (void)afterEach +{ + [[viewTester usingLabel:@"Back"] tap]; + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testWaitForFinishingAnimation +{ + [viewTester tapScreenAtPoint:CGPointMake(100, 100)]; + [[viewTester usingLabel:@"Label"] waitForView]; +} + +@end diff --git a/KIF Tests/WaitForTappableViewTests_ViewTestActor.m b/KIF Tests/WaitForTappableViewTests_ViewTestActor.m new file mode 100644 index 000000000..fd95f94d9 --- /dev/null +++ b/KIF Tests/WaitForTappableViewTests_ViewTestActor.m @@ -0,0 +1,43 @@ +// +// ViewWaitForTappableViewTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + +#import + +@interface WaitForTappableViewTests_ViewTestActor : KIFTestCase +@end + + +@implementation WaitForTappableViewTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"Show/Hide"] tap]; + [[viewTester usingLabel:@"Cover/Uncover"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testWaitingForTappableViewWithAccessibilityLabel +{ + [[viewTester usingLabel:@"B"] waitToBecomeTappable]; +} + +- (void)testWaitingForViewWithTraits +{ + [[[viewTester usingLabel:@"B"] usingTraits:UIAccessibilityTraitButton] waitToBecomeTappable]; +} + +- (void)testWaitingForViewWithValue +{ + [[[[viewTester usingLabel:@"B"] usingValue:@"BB"] usingTraits:UIAccessibilityTraitButton] waitToBecomeTappable]; +} + +@end diff --git a/KIF Tests/WaitForViewTests_ViewTestActor.m b/KIF Tests/WaitForViewTests_ViewTestActor.m new file mode 100644 index 000000000..1f3efdb14 --- /dev/null +++ b/KIF Tests/WaitForViewTests_ViewTestActor.m @@ -0,0 +1,33 @@ +// +// ViewWaitForViewTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + + +#import + +@interface WaitForViewTests_ViewTestActor : KIFTestCase +@end + + +@implementation WaitForViewTests_ViewTestActor + +- (void)testWaitingForViewWithAccessibilityLabel +{ + [[viewTester usingLabel:@"Test Suite"] waitForView]; +} + +- (void)testWaitingForViewWithTraits +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitStaticText] waitForView]; +} + +- (void)testWaitingForViewWithValue +{ + [[[viewTester usingLabel:@"Switch 1"] usingValue:@"1"] waitForView]; +} + +@end diff --git a/KIF Tests/WebViewTests_ViewTestActor.m b/KIF Tests/WebViewTests_ViewTestActor.m new file mode 100644 index 000000000..ade4981b3 --- /dev/null +++ b/KIF Tests/WebViewTests_ViewTestActor.m @@ -0,0 +1,47 @@ +// +// NewWebViewTests.m +// KIF +// +// Created by Alex Odawa on 1/26/15. +// +// + +#import +#import +#import + +@interface WebViewTests_ViewTestActor : KIFTestCase +@end + + +@implementation WebViewTests_ViewTestActor + +- (void)beforeEach +{ + [[viewTester usingLabel:@"WebViews"] tap]; +} + +- (void)afterEach +{ + [[[viewTester usingLabel:@"Test Suite"] usingTraits:UIAccessibilityTraitButton] tap]; +} + +- (void)testTappingLinks +{ + [[viewTester usingLabel:@"A link"] tap]; + [[viewTester usingLabel:@"Page 2"] waitForView]; +} + +- (void)testScrolling +{ + // Off screen, the web view will need to be scrolled down + [[viewTester usingLabel:@"Footer"] waitForView]; +} + +- (void)testEnteringText +{ + [[viewTester usingLabel:@"Input Label"] tap]; + [viewTester enterTextIntoCurrentFirstResponder:@"Keyboard text"]; +} + +@end diff --git a/KIF.xcodeproj/project.pbxproj b/KIF.xcodeproj/project.pbxproj index 78b3237cc..c2baa0876 100644 --- a/KIF.xcodeproj/project.pbxproj +++ b/KIF.xcodeproj/project.pbxproj @@ -29,7 +29,6 @@ 84D293AF1A2C867300C10944 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D293AE1A2C867300C10944 /* CoreLocation.framework */; }; 84D293B11A2C891700C10944 /* SystemAlertTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D293B01A2C891700C10944 /* SystemAlertTests.m */; }; 84D293B81A2C8DF700C10944 /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D293B71A2C8DF700C10944 /* AddressBookUI.framework */; }; - 84D293BB1A2CC30B00C10944 /* UIAutomationHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D293B91A2CC30B00C10944 /* UIAutomationHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84D293BD1A2CC30B00C10944 /* UIAutomationHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D293BA1A2CC30B00C10944 /* UIAutomationHelper.m */; }; 85DB946E1C5A3E860025F83E /* CALayer-KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 85DB946C1C5A3E860025F83E /* CALayer-KIFAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 85DB946F1C5A3E860025F83E /* CALayer-KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 85DB946D1C5A3E860025F83E /* CALayer-KIFAdditions.m */; }; @@ -196,6 +195,38 @@ EB60ED03177F9032005A041A /* TestSuiteViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EB60ECFF177F9032005A041A /* TestSuiteViewController.m */; }; EB60ED06177F9041005A041A /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EB60ED04177F9041005A041A /* MainStoryboard.storyboard */; }; EB9FB42717A5BACB00DDF160 /* GestureViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9FB42617A5BACB00DDF160 /* GestureViewController.m */; }; + FA1C7B751A7733BA00E7DD97 /* ExistTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA1C7B741A7733BA00E7DD97 /* ExistTests_ViewTestActor.m */; }; + FA49155A1A781E6800A78E57 /* MultiFingerTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA4915591A781E6800A78E57 /* MultiFingerTests_ViewTestActor.m */; }; + FA49155C1A781F6600A78E57 /* LandscapeTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA49155B1A781F6600A78E57 /* LandscapeTests_ViewTestActor.m */; }; + FA49155E1A78206E00A78E57 /* CompositionTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA49155D1A78206E00A78E57 /* CompositionTests_ViewTestActor.m */; }; + FA4915601A7823E500A78E57 /* ScrollViewTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA49155F1A7823E500A78E57 /* ScrollViewTests_ViewTestActor.m */; }; + FA4915631A78261300A78E57 /* ModalViewTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA4915621A78261300A78E57 /* ModalViewTests_ViewTestActor.m */; }; + FA4915651A7827D000A78E57 /* PickerTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA4915641A7827D000A78E57 /* PickerTests_ViewTestActor.m */; }; + FA4915671A783C5500A78E57 /* TableViewTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA4915661A783C5500A78E57 /* TableViewTests_ViewTestActor.m */; }; + FA4915691A78449C00A78E57 /* CollectionViewTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA4915681A78449C00A78E57 /* CollectionViewTests_ViewTestActor.m */; }; + FA64D8341A78171000D96787 /* SpecificControlTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA64D8331A78171000D96787 /* SpecificControlTests_ViewTestActor.m */; }; + FA8A3C551A77157F00206350 /* LongPressTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA8A3C541A77157F00206350 /* LongPressTests_ViewTestActor.m */; }; + FA8A3C571A771B6F00206350 /* WaitForViewTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA8A3C561A771B6F00206350 /* WaitForViewTests_ViewTestActor.m */; }; + FA8A3C591A771C5500206350 /* SearchFieldTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA8A3C581A771C5500206350 /* SearchFieldTests_ViewTestActor.m */; }; + FA8A3C5B1A77281900206350 /* WebViewTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA8A3C5A1A77281900206350 /* WebViewTests_ViewTestActor.m */; }; + FA8A3C5D1A772CD100206350 /* WaitForAbscenceTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA8A3C5C1A772CD100206350 /* WaitForAbscenceTests_ViewTestActor.m */; }; + FA8A3C5F1A772E6800206350 /* AccessibilityIdentifierTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA8A3C5E1A772E6800206350 /* AccessibilityIdentifierTests_ViewTestActor.m */; }; + FA8A3C611A77320000206350 /* SystemAlertTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA8A3C601A77320000206350 /* SystemAlertTests_ViewTestActor.m */; }; + FA8BB6A81A778725003969FF /* GestureTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA8BB6A71A778725003969FF /* GestureTests_ViewTestActor.m */; }; + FA8BDCCD1A76B3A80042A989 /* KIFUIObject.h in Headers */ = {isa = PBXBuildFile; fileRef = FA8BDCCB1A76B3A80042A989 /* KIFUIObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FA8BDCCE1A76B3A80042A989 /* KIFUIObject.m in Sources */ = {isa = PBXBuildFile; fileRef = FA8BDCCC1A76B3A80042A989 /* KIFUIObject.m */; }; + FA8DA74F1A7711E900E0C644 /* WaitForTappableViewTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA8DA74E1A7711E900E0C644 /* WaitForTappableViewTests_ViewTestActor.m */; }; + FA8DA7511A7712E300E0C644 /* WaitForAnimationTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA8DA7501A7712E300E0C644 /* WaitForAnimationTests_ViewTestActor.m */; }; + FA914DB61A7707550073BB19 /* TypingTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FA914DB51A7707550073BB19 /* TypingTests_ViewTestActor.m */; }; + FA9E18791C5AC962004E5E8D /* NSString+KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = FA9E18771C5AC962004E5E8D /* NSString+KIFAdditions.h */; }; + FA9E187A1C5AC962004E5E8D /* NSString+KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = FA9E18781C5AC962004E5E8D /* NSString+KIFAdditions.m */; }; + FAB2F2481C5FDAD200ED58A5 /* UIAutomationHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D293B91A2CC30B00C10944 /* UIAutomationHelper.h */; }; + FAB4C4741A815CA900C52EDF /* NSPredicate+KIFAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = FAB4C4721A815CA900C52EDF /* NSPredicate+KIFAdditions.h */; }; + FAB4C4751A815CA900C52EDF /* NSPredicate+KIFAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = FAB4C4731A815CA900C52EDF /* NSPredicate+KIFAdditions.m */; }; + FAC3A53E1A703A8300802118 /* KIFUIViewTestActor.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC3A53C1A703A8300802118 /* KIFUIViewTestActor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FAC3A53F1A703A8300802118 /* KIFUIViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FAC3A53D1A703A8300802118 /* KIFUIViewTestActor.m */; }; + FAC3A5621C5C0CD1003B681E /* PullToRefreshTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FAC3A5611C5C0CD1003B681E /* PullToRefreshTests_ViewTestActor.m */; }; + FAE2D7631A76DDA90068B440 /* TappingTests_ViewTestActor.m in Sources */ = {isa = PBXBuildFile; fileRef = FAE2D7621A76DDA90068B440 /* TappingTests_ViewTestActor.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -342,6 +373,37 @@ EBAE488017A460E50005EE19 /* NSError-KIFAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError-KIFAdditions.m"; sourceTree = ""; }; EBAE488517A4E5C30005EE19 /* KIFTestStepValidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KIFTestStepValidation.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; EBAE488617A4E5C30005EE19 /* KIFTestStepValidation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KIFTestStepValidation.m; sourceTree = ""; }; + FA1C7B741A7733BA00E7DD97 /* ExistTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExistTests_ViewTestActor.m; sourceTree = ""; }; + FA4915591A781E6800A78E57 /* MultiFingerTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MultiFingerTests_ViewTestActor.m; sourceTree = ""; }; + FA49155B1A781F6600A78E57 /* LandscapeTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LandscapeTests_ViewTestActor.m; sourceTree = ""; }; + FA49155D1A78206E00A78E57 /* CompositionTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CompositionTests_ViewTestActor.m; sourceTree = ""; }; + FA49155F1A7823E500A78E57 /* ScrollViewTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScrollViewTests_ViewTestActor.m; sourceTree = ""; }; + FA4915621A78261300A78E57 /* ModalViewTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalViewTests_ViewTestActor.m; sourceTree = ""; }; + FA4915641A7827D000A78E57 /* PickerTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickerTests_ViewTestActor.m; sourceTree = ""; }; + FA4915661A783C5500A78E57 /* TableViewTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TableViewTests_ViewTestActor.m; sourceTree = ""; }; + FA4915681A78449C00A78E57 /* CollectionViewTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CollectionViewTests_ViewTestActor.m; sourceTree = ""; }; + FA64D8331A78171000D96787 /* SpecificControlTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SpecificControlTests_ViewTestActor.m; sourceTree = ""; }; + FA8A3C541A77157F00206350 /* LongPressTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LongPressTests_ViewTestActor.m; sourceTree = ""; }; + FA8A3C561A771B6F00206350 /* WaitForViewTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WaitForViewTests_ViewTestActor.m; sourceTree = ""; }; + FA8A3C581A771C5500206350 /* SearchFieldTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchFieldTests_ViewTestActor.m; sourceTree = ""; }; + FA8A3C5A1A77281900206350 /* WebViewTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewTests_ViewTestActor.m; sourceTree = ""; }; + FA8A3C5C1A772CD100206350 /* WaitForAbscenceTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WaitForAbscenceTests_ViewTestActor.m; sourceTree = ""; }; + FA8A3C5E1A772E6800206350 /* AccessibilityIdentifierTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AccessibilityIdentifierTests_ViewTestActor.m; sourceTree = ""; }; + FA8A3C601A77320000206350 /* SystemAlertTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SystemAlertTests_ViewTestActor.m; sourceTree = ""; }; + FA8BB6A71A778725003969FF /* GestureTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GestureTests_ViewTestActor.m; sourceTree = ""; }; + FA8BDCCB1A76B3A80042A989 /* KIFUIObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KIFUIObject.h; sourceTree = ""; }; + FA8BDCCC1A76B3A80042A989 /* KIFUIObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KIFUIObject.m; sourceTree = ""; }; + FA8DA74E1A7711E900E0C644 /* WaitForTappableViewTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WaitForTappableViewTests_ViewTestActor.m; sourceTree = ""; }; + FA8DA7501A7712E300E0C644 /* WaitForAnimationTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WaitForAnimationTests_ViewTestActor.m; sourceTree = ""; }; + FA914DB51A7707550073BB19 /* TypingTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TypingTests_ViewTestActor.m; sourceTree = ""; }; + FA9E18771C5AC962004E5E8D /* NSString+KIFAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+KIFAdditions.h"; sourceTree = ""; }; + FA9E18781C5AC962004E5E8D /* NSString+KIFAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+KIFAdditions.m"; sourceTree = ""; }; + FAB4C4721A815CA900C52EDF /* NSPredicate+KIFAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPredicate+KIFAdditions.h"; sourceTree = ""; }; + FAB4C4731A815CA900C52EDF /* NSPredicate+KIFAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSPredicate+KIFAdditions.m"; sourceTree = ""; }; + FAC3A53C1A703A8300802118 /* KIFUIViewTestActor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KIFUIViewTestActor.h; sourceTree = ""; }; + FAC3A53D1A703A8300802118 /* KIFUIViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KIFUIViewTestActor.m; sourceTree = ""; }; + FAC3A5611C5C0CD1003B681E /* PullToRefreshTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PullToRefreshTests_ViewTestActor.m; sourceTree = ""; }; + FAE2D7621A76DDA90068B440 /* TappingTests_ViewTestActor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TappingTests_ViewTestActor.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -479,6 +541,8 @@ AAB0728513971A98008AF393 /* KIF-Prefix.pch */, C194255615D83DE9004FC314 /* KIFTypist.h */, C194255715D83DE9004FC314 /* KIFTypist.m */, + FA8BDCCB1A76B3A80042A989 /* KIFUIObject.h */, + FA8BDCCC1A76B3A80042A989 /* KIFUIObject.m */, EBAE488517A4E5C30005EE19 /* KIFTestStepValidation.h */, EBAE488617A4E5C30005EE19 /* KIFTestStepValidation.m */, EABD46D31857BE8600A5F081 /* KIF-XCTestPrefix.pch */, @@ -509,6 +573,8 @@ BFE4708A1C7F42FB00580EF9 /* UIScreen+KIFAdditions.h */, BFE4708B1C7F42FB00580EF9 /* UIScreen+KIFAdditions.m */, AAB0729A13971AB2008AF393 /* UIScrollView-KIFAdditions.h */, + FAB4C4721A815CA900C52EDF /* NSPredicate+KIFAdditions.h */, + FAB4C4731A815CA900C52EDF /* NSPredicate+KIFAdditions.m */, AAB0729B13971AB2008AF393 /* UIScrollView-KIFAdditions.m */, AAB0729C13971AB2008AF393 /* UITouch-KIFAdditions.h */, AAB0729D13971AB2008AF393 /* UITouch-KIFAdditions.m */, @@ -523,6 +589,8 @@ EBAE487F17A460E50005EE19 /* NSError-KIFAdditions.h */, EBAE488017A460E50005EE19 /* NSError-KIFAdditions.m */, EABD46751857A07600A5F081 /* XCTestCase-KIFAdditions.h */, + FA9E18771C5AC962004E5E8D /* NSString+KIFAdditions.h */, + FA9E18781C5AC962004E5E8D /* NSString+KIFAdditions.m */, EABD46761857A07600A5F081 /* XCTestCase-KIFAdditions.m */, EAC809681864F19C000E819F /* NSException-KIFAdditions.h */, EAC809691864F19C000E819F /* NSException-KIFAdditions.m */, @@ -558,6 +626,8 @@ EB4C3131167BA3AC00E31109 /* KIFSystemTestActor.m */, EB4C3132167BA3AC00E31109 /* KIFUITestActor.h */, EB4C3133167BA3AC00E31109 /* KIFUITestActor.m */, + FAC3A53C1A703A8300802118 /* KIFUIViewTestActor.h */, + FAC3A53D1A703A8300802118 /* KIFUIViewTestActor.m */, EB2526461981BF7A00DBC747 /* KIFUITestActor-ConditionalTests.h */, EB2526471981BF7A00DBC747 /* KIFUITestActor-ConditionalTests.m */, ); @@ -616,6 +686,7 @@ EB60ECEF177F8DB3005A041A /* KIF Tests */ = { isa = PBXGroup; children = ( + FA8DA74D1A77117A00E0C644 /* KIFUIViewTestActor Tests */, BFE4708E1C7F44C100580EF9 /* Additions */, 2CED883D181F5EE1005ABD20 /* PickerTests.m */, EB60ED19177F90C2005A041A /* GestureTests.m */, @@ -623,7 +694,6 @@ EB60ED07177F90BA005A041A /* LongPressTests.m */, EB60ED08177F90BA005A041A /* ModalViewTests.m */, EB60ED09177F90BA005A041A /* SpecificControlTests.m */, - EB60ED0A177F90BA005A041A /* SystemTests.m */, EB60ED0B177F90BA005A041A /* TappingTests.m */, EB3F654417AA0B8400469D18 /* TableViewTests.m */, EA0F2546182979BE006FF825 /* CollectionViewTests.m */, @@ -634,7 +704,6 @@ 4A48107A19708CAB0003A32E /* ExistTests.m */, EB60ED0E177F90BA005A041A /* WaitForTappableViewTests.m */, EB60ED0F177F90BA005A041A /* WaitForViewTests.m */, - EB22B5AF17AF52640090B848 /* CascadingFailureTests.m */, EB9FC00417E144B700138266 /* LandscapeTests.m */, EB09000F17E3696A00AA15B1 /* SearchFieldTests.m */, 2EE1270F198991920031D347 /* MultiFingerTests.m */, @@ -643,7 +712,9 @@ AE62FCCF1A1D20E5002B10DA /* WebViewTests.m */, 84D293B01A2C891700C10944 /* SystemAlertTests.m */, 97E8A5D01B0A63D100124E3B /* BackgroundTests.m */, + EB22B5AF17AF52640090B848 /* CascadingFailureTests.m */, 5A62B0AD1BB205CA00A3F480 /* PullToRefreshTests.m */, + EB60ED0A177F90BA005A041A /* SystemTests.m */, 5F6A1B371C191F9600F20F22 /* UIApplicationKIFAdditionsTests.m */, EB60ECF0177F8DB3005A041A /* Supporting Files */, ); @@ -661,6 +732,36 @@ name = "Supporting Files"; sourceTree = ""; }; + FA8DA74D1A77117A00E0C644 /* KIFUIViewTestActor Tests */ = { + isa = PBXGroup; + children = ( + FA4915641A7827D000A78E57 /* PickerTests_ViewTestActor.m */, + FA8BB6A71A778725003969FF /* GestureTests_ViewTestActor.m */, + FA8DA7501A7712E300E0C644 /* WaitForAnimationTests_ViewTestActor.m */, + FA8A3C541A77157F00206350 /* LongPressTests_ViewTestActor.m */, + FA4915621A78261300A78E57 /* ModalViewTests_ViewTestActor.m */, + FA64D8331A78171000D96787 /* SpecificControlTests_ViewTestActor.m */, + FAE2D7621A76DDA90068B440 /* TappingTests_ViewTestActor.m */, + FA4915661A783C5500A78E57 /* TableViewTests_ViewTestActor.m */, + FA4915681A78449C00A78E57 /* CollectionViewTests_ViewTestActor.m */, + FA49155F1A7823E500A78E57 /* ScrollViewTests_ViewTestActor.m */, + FA49155D1A78206E00A78E57 /* CompositionTests_ViewTestActor.m */, + FA914DB51A7707550073BB19 /* TypingTests_ViewTestActor.m */, + FA8A3C5C1A772CD100206350 /* WaitForAbscenceTests_ViewTestActor.m */, + FA1C7B741A7733BA00E7DD97 /* ExistTests_ViewTestActor.m */, + FA8DA74E1A7711E900E0C644 /* WaitForTappableViewTests_ViewTestActor.m */, + FA8A3C561A771B6F00206350 /* WaitForViewTests_ViewTestActor.m */, + FAC3A5611C5C0CD1003B681E /* PullToRefreshTests_ViewTestActor.m */, + FA49155B1A781F6600A78E57 /* LandscapeTests_ViewTestActor.m */, + FA8A3C581A771C5500206350 /* SearchFieldTests_ViewTestActor.m */, + FA4915591A781E6800A78E57 /* MultiFingerTests_ViewTestActor.m */, + FA8A3C5E1A772E6800206350 /* AccessibilityIdentifierTests_ViewTestActor.m */, + FA8A3C5A1A77281900206350 /* WebViewTests_ViewTestActor.m */, + FA8A3C601A77320000206350 /* SystemAlertTests_ViewTestActor.m */, + ); + name = "KIFUIViewTestActor Tests"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -710,7 +811,11 @@ EABD46931857A0C700A5F081 /* UIAccessibilityElement-KIFAdditions.h in Headers */, 9CC967BE1AD4B55E00576D13 /* KIF-XCTestPrefix.pch in Headers */, EABD46941857A0C700A5F081 /* UIApplication-KIFAdditions.h in Headers */, + FA9E18791C5AC962004E5E8D /* NSString+KIFAdditions.h in Headers */, + FAB4C4741A815CA900C52EDF /* NSPredicate+KIFAdditions.h in Headers */, + FAB2F2481C5FDAD200ED58A5 /* UIAutomationHelper.h in Headers */, EABD46951857A0C700A5F081 /* UIScrollView-KIFAdditions.h in Headers */, + FAC3A53E1A703A8300802118 /* KIFUIViewTestActor.h in Headers */, EABD46971857A0C700A5F081 /* UITouch-KIFAdditions.h in Headers */, EABD46981857A0C700A5F081 /* UIView-KIFAdditions.h in Headers */, EABD469A1857A0C700A5F081 /* NSFileManager-KIFAdditions.h in Headers */, @@ -719,6 +824,7 @@ 85DB946E1C5A3E860025F83E /* CALayer-KIFAdditions.h in Headers */, 0EAA1C131B4B371700FFB2FB /* IOHIDEvent+KIF.h in Headers */, EABD469B1857A0C700A5F081 /* LoadableCategory.h in Headers */, + FA8BDCCD1A76B3A80042A989 /* KIFUIObject.h in Headers */, EABD469C1857A0C700A5F081 /* KIFTypist.h in Headers */, EABD469D1857A0C700A5F081 /* KIFTestActor.h in Headers */, EABD469E1857A0C700A5F081 /* KIFTestCase.h in Headers */, @@ -727,7 +833,6 @@ EABD46A11857A0C700A5F081 /* NSBundle-KIFAdditions.h in Headers */, EAC8096A1864F19C000E819F /* NSException-KIFAdditions.h in Headers */, EABD46961857A0C700A5F081 /* XCTestCase-KIFAdditions.h in Headers */, - 84D293BB1A2CC30B00C10944 /* UIAutomationHelper.h in Headers */, E977D1071AA4062B005645BF /* UIEvent+KIFAdditions.h in Headers */, BD6A1CA11BCE8DD000EF07D2 /* KIFAccessibilityEnabler.h in Headers */, EABD46A21857A0C700A5F081 /* NSError-KIFAdditions.h in Headers */, @@ -834,7 +939,7 @@ isa = PBXProject; attributes = { LastTestingUpgradeCheck = 0510; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0710; TargetAttributes = { 9CC9673A1AD4B1B600576D13 = { CreatedOnToolsVersion = 6.2; @@ -936,6 +1041,7 @@ BFE4708D1C7F42FB00580EF9 /* UIScreen+KIFAdditions.m in Sources */, EABD467B1857A0C700A5F081 /* CGGeometry-KIFAdditions.m in Sources */, 0EAA1C141B4B371700FFB2FB /* IOHIDEvent+KIF.m in Sources */, + FA9E187A1C5AC962004E5E8D /* NSString+KIFAdditions.m in Sources */, EABD467C1857A0C700A5F081 /* UIAccessibilityElement-KIFAdditions.m in Sources */, 84D293BD1A2CC30B00C10944 /* UIAutomationHelper.m in Sources */, EABD467D1857A0C700A5F081 /* UIApplication-KIFAdditions.m in Sources */, @@ -957,9 +1063,12 @@ EAC8096B1864F19C000E819F /* NSException-KIFAdditions.m in Sources */, EABD46881857A0C700A5F081 /* KIFUITestActor.m in Sources */, EABD46891857A0C700A5F081 /* NSBundle-KIFAdditions.m in Sources */, + FAB4C4751A815CA900C52EDF /* NSPredicate+KIFAdditions.m in Sources */, + FAC3A53F1A703A8300802118 /* KIFUIViewTestActor.m in Sources */, EABD468A1857A0C700A5F081 /* NSError-KIFAdditions.m in Sources */, EABD468B1857A0C700A5F081 /* KIFTestStepValidation.m in Sources */, 4D2FD4EE1AF5936700E61192 /* UIView-Debugging.m in Sources */, + FA8BDCCE1A76B3A80042A989 /* KIFUIObject.m in Sources */, BD6A1CA31BCE8DD000EF07D2 /* KIFAccessibilityEnabler.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -968,21 +1077,35 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + FA8A3C591A771C5500206350 /* SearchFieldTests_ViewTestActor.m in Sources */, + FA8A3C551A77157F00206350 /* LongPressTests_ViewTestActor.m in Sources */, + FA49155E1A78206E00A78E57 /* CompositionTests_ViewTestActor.m in Sources */, + FA8A3C5F1A772E6800206350 /* AccessibilityIdentifierTests_ViewTestActor.m in Sources */, + FA8A3C5D1A772CD100206350 /* WaitForAbscenceTests_ViewTestActor.m in Sources */, + FA8A3C5B1A77281900206350 /* WebViewTests_ViewTestActor.m in Sources */, EABD46B11857A0F300A5F081 /* SearchFieldTests.m in Sources */, EABD46B21857A0F300A5F081 /* CascadingFailureTests.m in Sources */, EABD46B31857A0F300A5F081 /* CompositionTests.m in Sources */, 4A48107B19708CAB0003A32E /* ExistTests.m in Sources */, EA4655881905B92500B2C60E /* PickerTests.m in Sources */, 3812FB631A12188700335733 /* WaitForAnimationTests.m in Sources */, + FA49155A1A781E6800A78E57 /* MultiFingerTests_ViewTestActor.m in Sources */, 5F6A1B381C191F9600F20F22 /* UIApplicationKIFAdditionsTests.m in Sources */, EB1A44DA1A0C33AD004A3F61 /* AccessibilityIdentifierTests.m in Sources */, EABD46B41857A0F300A5F081 /* LongPressTests.m in Sources */, EABD46B51857A0F300A5F081 /* ModalViewTests.m in Sources */, + FA4915671A783C5500A78E57 /* TableViewTests_ViewTestActor.m in Sources */, EABD46B61857A0F300A5F081 /* SpecificControlTests.m in Sources */, + FAE2D7631A76DDA90068B440 /* TappingTests_ViewTestActor.m in Sources */, + FA914DB61A7707550073BB19 /* TypingTests_ViewTestActor.m in Sources */, + FA8BB6A81A778725003969FF /* GestureTests_ViewTestActor.m in Sources */, + FA4915631A78261300A78E57 /* ModalViewTests_ViewTestActor.m in Sources */, EABD46B71857A0F300A5F081 /* SystemTests.m in Sources */, 5A62B0AC1BB2043B00A3F480 /* AccessibilityIdentifierPullToRefreshTests.m in Sources */, EABD46B81857A0F300A5F081 /* TappingTests.m in Sources */, EABD46B91857A0F300A5F081 /* TypingTests.m in Sources */, + FA4915691A78449C00A78E57 /* CollectionViewTests_ViewTestActor.m in Sources */, + FA8DA74F1A7711E900E0C644 /* WaitForTappableViewTests_ViewTestActor.m in Sources */, EABD46BA1857A0F300A5F081 /* WaitForAbscenceTests.m in Sources */, EA47DA2818EDFD6F0034D2F5 /* CollectionViewTests.m in Sources */, EABD46BB1857A0F300A5F081 /* WaitForTappableViewTests.m in Sources */, @@ -991,10 +1114,19 @@ 97E8A5D11B0A63D100124E3B /* BackgroundTests.m in Sources */, EABD46BD1857A0F300A5F081 /* LandscapeTests.m in Sources */, EABD46BE1857A0F300A5F081 /* TableViewTests.m in Sources */, + FA4915601A7823E500A78E57 /* ScrollViewTests_ViewTestActor.m in Sources */, EABD46BF1857A0F300A5F081 /* GestureTests.m in Sources */, + FA8A3C571A771B6F00206350 /* WaitForViewTests_ViewTestActor.m in Sources */, 2EE12710198991920031D347 /* MultiFingerTests.m in Sources */, + FA8DA7511A7712E300E0C644 /* WaitForAnimationTests_ViewTestActor.m in Sources */, + FA64D8341A78171000D96787 /* SpecificControlTests_ViewTestActor.m in Sources */, + FA8A3C611A77320000206350 /* SystemAlertTests_ViewTestActor.m in Sources */, + FA1C7B751A7733BA00E7DD97 /* ExistTests_ViewTestActor.m in Sources */, D9EA274118F05A6000D87E57 /* ScrollViewTests.m in Sources */, AE62FCD01A1D20E5002B10DA /* WebViewTests.m in Sources */, + FA49155C1A781F6600A78E57 /* LandscapeTests_ViewTestActor.m in Sources */, + FAC3A5621C5C0CD1003B681E /* PullToRefreshTests_ViewTestActor.m in Sources */, + FA4915651A7827D000A78E57 /* PickerTests_ViewTestActor.m in Sources */, 84D293B11A2C891700C10944 /* SystemAlertTests.m in Sources */, BFE470901C7F44F700580EF9 /* UIScreen+KIFAdditionsTests.m in Sources */, ); diff --git a/KIF.xcodeproj/xcshareddata/xcschemes/KIF Documentation.xcscheme b/KIF.xcodeproj/xcshareddata/xcschemes/KIF Documentation.xcscheme index f2b61e31f..f20278137 100644 --- a/KIF.xcodeproj/xcshareddata/xcschemes/KIF Documentation.xcscheme +++ b/KIF.xcodeproj/xcshareddata/xcschemes/KIF Documentation.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -42,11 +42,11 @@ Date: Wed, 2 Mar 2016 12:50:53 -0800 Subject: [PATCH 2/2] updating documentation to reflect that table views will scroll while waiting for a cel to appear --- Classes/KIFUITestActor.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Classes/KIFUITestActor.h b/Classes/KIFUITestActor.h index 5627689e9..333fcb5d4 100644 --- a/Classes/KIFUITestActor.h +++ b/Classes/KIFUITestActor.h @@ -617,7 +617,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec - (void)tapStatusBar; /*! - @abstract Waits for the cell at indexPath in a table view with the given identifier. + @abstract Scrolls a table view with the given identifier while waiting for the cell at the given indexPath to appear. @discussion This step will get the view with the specified accessibility identifier and then get the cell at the indexPath. For cases where you may need to work from the end of a table view rather than the beginning, negative sections count back from the end of the table view (-1 is the last section) and negative rows count back from the end of the section (-1 is the last row for that section). @@ -629,7 +629,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec - (UITableViewCell *)waitForCellAtIndexPath:(NSIndexPath *)indexPath inTableViewWithAccessibilityIdentifier:(NSString *)identifier; /*! - @abstract Waits for the cell at indexPath in a given table view. + @abstract Scrolls a table view while waiting for the cell at the given indexPath to appear. @discussion This step will get the cell at the indexPath. For cases where you may need to work from the end of a table view rather than the beginning, negative sections count back from the end of the table view (-1 is the last section) and negative rows count back from the end of the section (-1 is the last row for that section). @@ -641,7 +641,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec - (UITableViewCell *)waitForCellAtIndexPath:(NSIndexPath *)indexPath inTableView:(UITableView *)tableView; /*! - @abstract Waits for the cell at indexPath in a given collection view. + @abstract Scrolls a collection view while waiting for the cell at the given indexPath to appear. @discussion This step will get the cell at the indexPath. For cases where you may need to work from the end of a table view rather than the beginning, negative sections count back from the end of the table view (-1 is the last section) and negative rows count back from the end of the section (-1 is the last row for that section). @@ -654,7 +654,7 @@ static inline KIFDisplacement KIFDisplacementForSwipingInDirection(KIFSwipeDirec /*! - @abstract Waits for the cell at indexPath in a collection view with the given identifier. + @abstract Scrolls a given collection view while waiting for the item at the given indexPath to appear. @discussion This step will get the view with the specified accessibility identifier and then get the cell at indexPath. For cases where you may need to work from the end of a collection view rather than the beginning, negative sections count back from the end of the collection view (-1 is the last section) and negative items count back from the end of the section (-1 is the last item for that section).