From 698be5465bf5a5b6c2b7c5f92647478d93e05890 Mon Sep 17 00:00:00 2001 From: Jordan Zucker Date: Thu, 24 Apr 2014 09:21:26 -0700 Subject: [PATCH 1/5] Added tests for TableViewCell and NavigationBar ax containers. Need to fill out subliminal methods for abstracting these concepts. --- .../Tests/SLNavigationBarTests.m | 58 +++++ .../SLNavigationBarTestsViewController.m | 67 ++++++ .../SLNavigationBarTestsViewController.xib | 33 +++ .../Tests/SLTableViewCellChildElementsTest.m | 217 ++++++++++++++++++ ...eViewCellChildElementsTestViewController.m | 154 +++++++++++++ ...iewCellChildElementsTestViewController.xib | 34 +++ .../Tests/heart_empty_icon&32.png | Bin 0 -> 3855 bytes Integration Tests/Tests/heart_icon&32.png | Bin 0 -> 3510 bytes Subliminal.xcodeproj/project.pbxproj | 48 ++++ 9 files changed, 611 insertions(+) create mode 100644 Integration Tests/Tests/SLNavigationBarTests.m create mode 100644 Integration Tests/Tests/SLNavigationBarTestsViewController.m create mode 100644 Integration Tests/Tests/SLNavigationBarTestsViewController.xib create mode 100644 Integration Tests/Tests/SLTableViewCellChildElementsTest.m create mode 100644 Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.m create mode 100644 Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.xib create mode 100755 Integration Tests/Tests/heart_empty_icon&32.png create mode 100755 Integration Tests/Tests/heart_icon&32.png diff --git a/Integration Tests/Tests/SLNavigationBarTests.m b/Integration Tests/Tests/SLNavigationBarTests.m new file mode 100644 index 0000000..df1a6da --- /dev/null +++ b/Integration Tests/Tests/SLNavigationBarTests.m @@ -0,0 +1,58 @@ +// +// SLNavigationBarTests.m +// Subliminal +// +// Created by Jordan Zucker on 4/4/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLIntegrationTest.h" + +@interface SLNavigationBarTests : SLIntegrationTest + +@end + +@implementation SLNavigationBarTests + ++ (NSString *)testCaseViewControllerClassName { + return @"SLNavigationBarTestsViewController"; +} + +// If you override set-up methods, +// you must call super at the beginning of your implementations. + +// If you override tear-down methods, +// you must call super at the *end* of your implementations. + +- (void)testRightButtonBroadMatching { + SLButton *rightButton = [SLButton elementWithAccessibilityLabel:@"Right"]; + SLAssertTrue([UIAElement(rightButton) isValidAndVisible], @"Right button didn't appear"); + + [UIAElement(rightButton) tap]; +} + +//- (void)testRightButtonWithNewMethod +//{ +// SLAccessibilityContainer *navBar = [SLAccessibilityContainer containerWithIdentifier:@"NavigationBar" andContainerType:SLAccessibilityContainerTypeNavigationBar]; +// SLLogAsync(@"navBar is %@", navBar); +// SLAssertTrue([UIAElement(navBar) isValidAndVisible], @"Couldn't find nav bar matching specifications"); +// SLButton *rightButton = [navBar childElementMatching:[SLButton elementWithAccessibilityLabel:@"Right"]]; +// SLAssertTrue([UIAElement(rightButton) isValidAndVisible], @"Couldn't find right button bar"); +// +// [UIAElement(rightButton) tap]; +// +//} +// +//- (void)testTitleLabel +//{ +// SLAccessibilityContainer *navBar = [SLAccessibilityContainer containerWithIdentifier:@"NavigationBar" andContainerType:SLAccessibilityContainerTypeNavigationBar]; +// SLLogAsync(@"navBar is %@", navBar); +// SLAssertTrue([UIAElement(navBar) isValidAndVisible], @"Couldn't find nav bar matching specifications"); +// SLElement *title = [navBar childElementMatching:[SLElement elementWithAccessibilityLabel:@"Testing" value:nil traits:UIAccessibilityTraitStaticText]]; +// SLAssertTrue([UIAElement(title) isValidAndVisible], @"title isn't valid and visible"); +// SLLogAsync(@"title is %@", title.label); +// SLAssertTrue([UIAElement(title.label) isEqualToString:@"Testing"], @"title doesn't match expected string"); +// +//} + +@end diff --git a/Integration Tests/Tests/SLNavigationBarTestsViewController.m b/Integration Tests/Tests/SLNavigationBarTestsViewController.m new file mode 100644 index 0000000..e4b7d52 --- /dev/null +++ b/Integration Tests/Tests/SLNavigationBarTestsViewController.m @@ -0,0 +1,67 @@ +// +// SLNavigationBarTestsViewController.m +// Subliminal +// +// Created by Jordan Zucker on 4/4/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLTestCaseViewController.h" + +#import + +@interface SLNavigationBarTestsViewController : SLTestCaseViewController + +@end + +@interface SLNavigationBarTestsViewController () +// Connect IBOutlets here. +@property (nonatomic, weak) IBOutlet UINavigationBar *navBar; +@end + +@implementation SLNavigationBarTestsViewController + ++ (NSString *)nibNameForTestCase:(SEL)testCase { + return @"SLNavigationBarTestsViewController"; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + // Do any additional setup after loading the view from its nib. + // Test case specific configuration is best done using app hooks + // triggered from -[SLNavigationBarTests setUpTestCaseWithSelector:]. + UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"Right" style:UIBarButtonItemStylePlain target:self action:@selector(tapRightButton:)]; + rightButton.accessibilityLabel = @"Right"; + _navBar.topItem.rightBarButtonItem = rightButton; + + _navBar.accessibilityIdentifier = @"NavigationBar"; + + _navBar.topItem.title = @"Testing"; + _navBar.topItem.title.isAccessibilityElement = YES; + _navBar.topItem.title.accessibilityLabel = _navBar.topItem.title; +} + +- (IBAction)tapRightButton:(id)sender +{ + NSLog(@"hey"); +} + +- (instancetype)initWithTestCaseWithSelector:(SEL)testCase { + self = [super initWithTestCaseWithSelector:testCase]; + if (self) { + // Register for app hooks, e.g. + // [[SLTestController sharedTestController] registerTarget:<#(id)#> forAction:<#(SEL)#>]; + } + return self; +} + +// Deregister for app hooks, if any +//- (void)dealloc { +// [[SLTestController sharedTestController] deregisterTarget:self]; +//} + +//#pragma mark - App hooks +// Put any app hooks below here + +@end diff --git a/Integration Tests/Tests/SLNavigationBarTestsViewController.xib b/Integration Tests/Tests/SLNavigationBarTestsViewController.xib new file mode 100644 index 0000000..518af47 --- /dev/null +++ b/Integration Tests/Tests/SLNavigationBarTestsViewController.xib @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Integration Tests/Tests/SLTableViewCellChildElementsTest.m b/Integration Tests/Tests/SLTableViewCellChildElementsTest.m new file mode 100644 index 0000000..f370604 --- /dev/null +++ b/Integration Tests/Tests/SLTableViewCellChildElementsTest.m @@ -0,0 +1,217 @@ +// +// SLTableViewCellChildElementsTest.m +// Subliminal +// +// Created by Jordan Zucker on 3/20/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLIntegrationTest.h" + +@interface focus_SLTableViewCellChildElementsTest : SLIntegrationTest + +@end + +@implementation focus_SLTableViewCellChildElementsTest + ++ (NSString *)testCaseViewControllerClassName { + return @"SLTableViewCellChildElementsTestViewController"; +} + +// If you override set-up methods, +// you must call super at the beginning of your implementations. + +// If you override tear-down methods, +// you must call super at the *end* of your implementations. + +- (void)testTapBroadMatchingTableViewCellButton { + [[SLDevice currentDevice] captureScreenshotWithFilename:@"start"]; + + SLButton *favoriteButton = [SLButton elementWithAccessibilityLabel:@"Favorite"]; + SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not originally off"); + SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); + [favoriteButton captureScreenshotWithFilename:@"fb: starting"]; + + [UIAElement(favoriteButton) tap]; + + [self wait:1]; + [[SLDevice currentDevice] captureScreenshotWithFilename:@"after tap"]; + [favoriteButton captureScreenshotWithFilename:@"fb: after first tap"]; + + SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"favorite button is not valid and visible after first time tapping"); + SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"on"], @"Favorite button does not has ax value of on"); + [UIAElement(favoriteButton) tap]; + + [self wait:1]; + + SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not off at end of test"); + SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); + [favoriteButton captureScreenshotWithFilename:@"fb: ending"]; + + + [[SLDevice currentDevice] captureScreenshotWithFilename:@"end of test"]; +} + +- (void)testMatchingTableViewCellByMatchingTableViewCellAndTableView +{ + [[SLDevice currentDevice] captureScreenshotWithFilename:@"start"]; + SLButton *favoriteButton = [SLButton elementMatching:^BOOL(NSObject *obj) { + + if ([obj.accessibilityLabel isEqualToString:@"Favorite"]) { + + id accessibilityParent = [obj slAccessibilityParent]; + + while (accessibilityParent && ![[accessibilityParent accessibilityLabel] isEqualToString:@"Cell 2"]) { + + accessibilityParent = [accessibilityParent slAccessibilityParent]; + + } + + + id doubleAccessibilityParent = [accessibilityParent slAccessibilityParent]; + + while (doubleAccessibilityParent && ![doubleAccessibilityParent isKindOfClass:[UITableView class]]) { + doubleAccessibilityParent = [doubleAccessibilityParent slAccessibilityParent]; + } + + if (doubleAccessibilityParent) { + return YES; + } + else { + return NO; + } + + + } + + return NO; + + } withDescription:@"searching for favoritebutton"]; + + SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not originally off"); + SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); + [favoriteButton captureScreenshotWithFilename:@"fb: starting"]; + + [UIAElement(favoriteButton) tap]; + + [self wait:1]; + [[SLDevice currentDevice] captureScreenshotWithFilename:@"after tap"]; + [favoriteButton captureScreenshotWithFilename:@"fb: after first tap"]; + + SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"favorite button is not valid and visible after first time tapping"); + SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"on"], @"Favorite button does not has ax value of on"); + [UIAElement(favoriteButton) tap]; + + [self wait:1]; + + SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not off at end of test"); + SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); + [favoriteButton captureScreenshotWithFilename:@"fb: ending"]; + + + [[SLDevice currentDevice] captureScreenshotWithFilename:@"end of test"]; +} + +//- (void)testMatchingTableViewCellWithAccessibilityContainerMethod +//{ +// [[SLDevice currentDevice] captureScreenshotWithFilename:@"start"]; +// SLAccessibilityContainer *tableViewCell = [SLAccessibilityContainer containerWithLabel:@"Cell 2" andContainerType:SLAccessibilityContainerTypeTableViewCell]; +// SLButton *favoriteButton = [tableViewCell childElementMatching:[SLButton elementWithAccessibilityLabel:@"Favorite"]]; +// +// SLLogAsync(@"favoriteButton.value is %@", UIAElement(favoriteButton.value)); +// +// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not originally off"); +// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); +// [favoriteButton captureScreenshotWithFilename:@"fb: starting"]; +// +// [UIAElement(favoriteButton) tap]; +// +// [self wait:1]; +// [[SLDevice currentDevice] captureScreenshotWithFilename:@"after tap"]; +// [favoriteButton captureScreenshotWithFilename:@"fb: after first tap"]; +// +// [UIAElement(favoriteButton) isValidAndVisible]; +// +// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"favorite button is not valid and visible after first time tapping"); +// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"on"], @"Favorite button does not has ax value of on"); +// [UIAElement(favoriteButton) tap]; +// +// [self wait:1]; +// +// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not off at end of test"); +// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); +// [favoriteButton captureScreenshotWithFilename:@"fb: ending"]; +// +// +// [[SLDevice currentDevice] captureScreenshotWithFilename:@"end of test"]; +//} +// +//- (void)testMatchingTableViewCellWithTableViewCellMethodSubclass +//{ +// [[SLDevice currentDevice] captureScreenshotWithFilename:@"start"]; +// SLTableViewCell *tableViewCell = [SLTableViewCell cellWithLabel:@"Cell 2"]; +// SLButton *favoriteButton = [tableViewCell childElementMatching:[SLButton elementWithAccessibilityLabel:@"Favorite"]]; +// +// SLLogAsync(@"favoriteButton.value is %@", UIAElement(favoriteButton.value)); +// +// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not originally off"); +// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); +// [favoriteButton captureScreenshotWithFilename:@"fb: starting"]; +// +// [UIAElement(favoriteButton) tap]; +// +// [self wait:1]; +// [[SLDevice currentDevice] captureScreenshotWithFilename:@"after tap"]; +// [favoriteButton captureScreenshotWithFilename:@"fb: after first tap"]; +// +// [UIAElement(favoriteButton) isValidAndVisible]; +// +// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"favorite button is not valid and visible after first time tapping"); +// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"on"], @"Favorite button does not has ax value of on"); +// [UIAElement(favoriteButton) tap]; +// +// [self wait:1]; +// +// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not off at end of test"); +// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); +// [favoriteButton captureScreenshotWithFilename:@"fb: ending"]; +// +// +// [[SLDevice currentDevice] captureScreenshotWithFilename:@"end of test"]; +//} + +//- (void)testMatchingTableViewCellWithTableViewCellMethodSubclassIndex +//{ +// [[SLDevice currentDevice] captureScreenshotWithFilename:@"start"]; +// SLTableViewCell *tableViewCell = [SLTableViewCell cellAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]]; +// SLButton *favoriteButton = [tableViewCell childElementMatching:[SLButton elementWithAccessibilityLabel:@"Favorite"]]; +// +// SLLogAsync(@"favoriteButton.value is %@", UIAElement(favoriteButton.value)); +// +// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not originally off"); +// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); +// [favoriteButton captureScreenshotWithFilename:@"fb: starting"]; +// +// [UIAElement(favoriteButton) tap]; +// +// [self wait:1]; +// [[SLDevice currentDevice] captureScreenshotWithFilename:@"after tap"]; +// [favoriteButton captureScreenshotWithFilename:@"fb: after first tap"]; +// +// [UIAElement(favoriteButton) isValidAndVisible]; +// +// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"favorite button is not valid and visible after first time tapping"); +// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"on"], @"Favorite button does not has ax value of on"); +// [UIAElement(favoriteButton) tap]; +// +// [self wait:1]; +// +// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not off at end of test"); +// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); +// [favoriteButton captureScreenshotWithFilename:@"fb: ending"]; +// +// +// [[SLDevice currentDevice] captureScreenshotWithFilename:@"end of test"]; +//} + +@end diff --git a/Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.m b/Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.m new file mode 100644 index 0000000..79e0043 --- /dev/null +++ b/Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.m @@ -0,0 +1,154 @@ +// +// SLTableViewCellChildElementsTestViewController.m +// Subliminal +// +// Created by Jordan Zucker on 3/20/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLTestCaseViewController.h" + +#import + +@interface SLTableViewCellChildElementsTestViewController : SLTestCaseViewController + +@end + +@interface SLTableViewCellChildElementsTestViewController () +@property (nonatomic, weak) IBOutlet UITableView *tableView; +@property (nonatomic, strong) NSArray *tableViewElements; +@property (nonatomic, strong) NSMutableArray *tableViewFavorites; +@end + +@implementation SLTableViewCellChildElementsTestViewController + ++ (NSString *)nibNameForTestCase:(SEL)testCase { + return @"SLTableViewCellChildElementsTestViewController"; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + _tableViewElements = @[@"Cell 0", @"Cell 1", @"Cell 2", @"Cell 3"]; + _tableViewFavorites = [[NSMutableArray alloc] initWithObjects:@(NO), @(NO), @(NO), @(NO), nil]; + + // Do any additional setup after loading the view from its nib. + // Test case specific configuration is best done using app hooks + // triggered from -[SLTableViewCellChildElementsTests setUpTestCaseWithSelector:]. +} + +- (instancetype)initWithTestCaseWithSelector:(SEL)testCase { + self = [super initWithTestCaseWithSelector:testCase]; + if (self) { + // Register for app hooks, e.g. + // [[SLTestController sharedTestController] registerTarget:<#(id)#> forAction:<#(SEL)#>]; + } + return self; +} + +// Deregister for app hooks, if any +//- (void)dealloc { +// [[SLTestController sharedTestController] deregisterTarget:self]; +//} + +//#pragma mark - App hooks +// Put any app hooks below here + +#pragma mark - UIButton method + +- (IBAction)pressButton:(id)sender +{ + UIButton *favoriteButton = (UIButton *)sender; + NSNumber *oldFavoriteBool = [_tableViewFavorites objectAtIndex:favoriteButton.tag]; + [self setFavoriteButton:favoriteButton withFavoriteStatus:(![oldFavoriteBool boolValue])]; + // NSNumber *oldFavoriteBool = [_tableViewFavorites objectAtIndex:favoriteButton.tag]; + // NSNumber *updatedFavoriteBool; + // NSString *updatedFavoriteButtonAccessibilityValue; + // UIImage *updatedFavoriteButtonImage; + // if ([oldFavoriteBool boolValue] == YES) { + // updatedFavoriteBool = @(NO); + // updatedFavoriteButtonAccessibilityValue = @"off"; + // updatedFavoriteButtonImage = [UIImage imageNamed:@"heart_empty_icon&32.png"]; + // + // } + // else { + // updatedFavoriteBool = @(YES); + // updatedFavoriteButtonAccessibilityValue = @"on"; + // updatedFavoriteButtonImage = [UIImage imageNamed:@"heart_icon&32.png"]; + // } + // [_tableViewFavorites setObject:updatedFavoriteBool atIndexedSubscript:favoriteButton.tag]; + // favoriteButton.accessibilityValue = updatedFavoriteButtonAccessibilityValue; + // [favoriteButton setImage:updatedFavoriteButtonImage forState:UIControlStateNormal]; + + // if ([favoriteButton.titleLabel.text isEqualToString:@"Favorite"]) { + // [favoriteButton setTitle:@"Unfavorite" forState:UIControlStateNormal]; + // } + // else { + // [favoriteButton setTitle:@"Favorite" forState:UIControlStateNormal]; + // } + //[favoriteButton setImage:[UIImage imageNamed:@"heart_icon&32.png"] forState:UIControlStateNormal]; +} + +- (void) setFavoriteButton:(UIButton *)favoriteButton withFavoriteStatus:(BOOL)favoriteBool +{ + //NSNumber *oldFavoriteBool = [_tableViewFavorites objectAtIndex:favoriteButton.tag]; + // NSNumber *updatedFavoriteBool; + NSString *updatedFavoriteButtonAccessibilityValue; + UIImage *updatedFavoriteButtonImage; + if (favoriteBool == YES) { + // updatedFavoriteBool = @(NO); + updatedFavoriteButtonAccessibilityValue = @"on"; + updatedFavoriteButtonImage = [UIImage imageNamed:@"heart_icon&32.png"]; + + } + else { + // updatedFavoriteBool = @(YES); + updatedFavoriteButtonAccessibilityValue = @"off"; + updatedFavoriteButtonImage = [UIImage imageNamed:@"heart_empty_icon&32.png"]; + } + [_tableViewFavorites setObject:@(favoriteBool) atIndexedSubscript:favoriteButton.tag]; + favoriteButton.accessibilityValue = updatedFavoriteButtonAccessibilityValue; + [favoriteButton setImage:updatedFavoriteButtonImage forState:UIControlStateNormal]; +} + +#pragma mark - UITableViewDataSource + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [_tableViewElements count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"Cell"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; + } + + cell.textLabel.text = [_tableViewElements objectAtIndex:indexPath.row]; + //UIButton *favoriteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + //[favoriteButton setTitle:@"Favorite" forState:UIControlStateNormal]; + UIButton *favoriteButton = [UIButton buttonWithType:UIButtonTypeCustom]; + //[favoriteButton setImage:[UIImage imageNamed:@"heart_empty_icon&32.png"] forState:UIControlStateNormal]; + favoriteButton.accessibilityLabel = @"Favorite"; + //favoriteButton.accessibilityValue = @"off"; + favoriteButton.tag = indexPath.row; + + favoriteButton.frame = CGRectMake(160.0f, 5.0f, 32.0f, 32.0f); + [self setFavoriteButton:favoriteButton withFavoriteStatus:[[_tableViewFavorites objectAtIndex:indexPath.row] boolValue]]; + [favoriteButton addTarget:self action:@selector(pressButton:) forControlEvents:UIControlEventTouchUpInside]; + [cell addSubview:favoriteButton]; + + cell.accessibilityLabel = cell.textLabel.text; + cell.accessibilityValue = cell.textLabel.text; + + return cell; +} + +@end diff --git a/Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.xib b/Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.xib new file mode 100644 index 0000000..4483677 --- /dev/null +++ b/Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.xib @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Integration Tests/Tests/heart_empty_icon&32.png b/Integration Tests/Tests/heart_empty_icon&32.png new file mode 100755 index 0000000000000000000000000000000000000000..9c324dcae4870583d1e9e693c693dac84baa343d GIT binary patch literal 3855 zcmb_f4Ommx8IIyFYO7PH_UYPdbZU#qO#%^emw@?UfRf-yG)$-Ea_>oUCAl}=djkQt zYK4j-N}YCnioflAWctkN{1-(KEZ9-4RUdVAFhw2y%QH80t<#-*^J7A(U46y_fpgCH zz2AG@?>pZ)ET3UX8xs3UtVALil96u8hQATvXFxyr$rTs>QzD7&N7-`t9CIc{FdjKh zGI>Dm_juvDM50acdvPKk@JJqTQnXHb|8SiYp-7$7t~M*oUL$Z(>BTIt7F%pYaXz6T zr76j=T0aH>Jb=d$zsF5;m|rIqaWVL}FpWwP(S*;}N%cZNB*#1hF)}Pb)N+N4P)t!E zQrX z78c42s*Ui{$e!jWK6UB<-QwyN3!5sA{AZIJ`0yGkDG8Fss;;3DN`tADz!}+kEzv|QW>XE!tx2(o6T4T&G9%*fDDsP z3c=+RMPeFbyjq{APD)a#l2RdtCP`y7D)dUdNue^Rjj9ND6GQlf1cuznALgC~D}|zQ z_Y1)Yg^OsPDKeA8oxlcI4=1h!idygH1EavuO$n8ZxpCSF_bVfT1NXUkX|j<8I8PM- zcnUophUO4G&$CpXPdE%R3quRjfF&s0jkqZS&>YaB!WnT>!C2xb6ih3WRWMK8SZPTD zBZOcK8^O{F7DTg5PJ^PlAv*#fgpcDH55hByI}c|OiV*mbfTNsrPb5NETC`gzAvAOg zo$-k9A>P48@LeL=DHb?b+yf9O5fe?QCnh0SkxBQ+0vpbkHy;qe1c`mjfIGVh5!}77 z>mD~9%4>3zKGAf-HW6UlcbHH#4_Hz6o+J(<`Kaf!aekixk8}CqbVhRtj6za~>P0Fg zC>Q9kKRkv1?>djBqK)jym>7#;jSReM2tI>$Fyc)TZ9~mu-FAkBH(|t`x(^qz7!5&saW7fsH+#f?b0x`X2-m?;{MR2=+Ril*0=EDRy|+T?0$hi{24o zghCg9(9ge*!p4LPc4y&gLxsnZaGeD!;9IHr)=mStGetGIz#M!a!Iv2tewx8S_;Ckl z7>tEax6x_VMex}-hEL7mt&D>[H-ywJp=%LX`EwBR$K72bw|kv`LA!<`bFi{cRY z&AWiuo)HHN8}_pnE>tm`1A$cz;Q%j3F6Q4j4slEZPB@K{=N(W4UPQ8po5;c-Ccsh! z;?2b^Y~8gP;-w1D*$4&Tl;p(-9vSxN73iBT06rrqz`Z!hoFy%NC6buD43pmG|LTbS zq~+4oq5C&1e$bpRcnY9ec+l)n6@=X@^a|esaaw^GpfpYTA_TSbIjd?$%%;{bp4~Fx}mLY z-mKz;l$0-C{a{_`CG#NuC-2HVTT(};`n~nq>WSIEb0L6i-%0+wM++0#pB0F*Y*O=z$ zpkMgwN_XU}-FR;9;F@^@t)G^amEGR6XV1V>m8({rZ@f`ID`tOke7x1((A?Zyb6)@3 zuE8I+__Z7FtX+^h=gd4~tl?MH_a|JOU+)-(J!x2cy6h!v*ZA_&c&E=Yu()` zmdxDh)Yxei^;@J-3{gg?bTbi`fF#mPumC0;_fPvH5#hjziCW!sSIl}P_T)Sr5P!_M|qliDxJ>rSwz z3d{FcTBlw$kGmZ6a(U^TFWU}opFiUexBio@X-T#RU!FbN*tzuI9S>&5UH<&)Rifpa zas0!xt*xG7&HmZT&bV&fyt!@rzI8P0Z$Jr6fO|$CN$Kt+vI=)fi j|9jSn^>w2k!KoIgI_iv1#0M%?t&dS0Q9<3iJVyD z{%^nk-+%XxriMkcatm__f|%v2^ETuE!1z7;Ec{oG$Bz?4?pZ>h6}9^78BUR`EU&af zYfMt{Izc$Eh^Z{s0TF12AwhPL-#xdF1Oo3OTgv@5zv_Wup)Rh$CGmy;7w_O4Jb6V` zt~17900|-%#3WJHnV5?-aT)yGn5IZznxGCB={5p_R(})lC>jLiR-1*hU1kH9(N?;& ztfHc#1lVn~jk4J(+HRpMm{L1qvw`FfS(OW%8Xshuy;mlK;gO3BBcw7E6^%x%(Ne3T zg(%wLa2OzVy9HZV^e!2(F^jBUU_c}=yin&fK}CWh0|S$7S0czol6W1Yb|R_GLMV*% zbO>2bYKGOLVysHhRvV?6HdLl3&!t_|h$fnxc#eW1l%R}s>_%tV`&7i0VHpio(w>+c zXL{<0r!pSe*eVg zl9a_tN41?;*JO^y6;Ka!sgP=hx)RYiSlfvuy1)#IsU;G?_*tz3;z|r?5tv$H{J6S! z7O`FyVbyTq&=wnQv6lzvQl`9|q3L29jmsxx@Aor4Sx2nQL7&$}VsNV<@JwZ`*XyV( zudKA&D{C=^qtfB=*xa<+YqQssd+ZtRUWJPo2~4^3|INJ-SBfCB;-p}V!UfLLiY(RH z5DY*~(#@4bQM*Ny7$t_HU{o?AvT_LT*TTaf8xav%<OP%qI@G0KOM(}qcwFnvv zYODkSmPpAaG#--_tjT0-WP^NeHqIQ`HX^hHn!ec##Qnuq{NM$1=XyM+2 z8+)CAyN1^FF9b60BL=4k_c|A;vz?GPJ3Q{Li6vpOcSIT?8ip8p;`=CV%!P4xHm)|x zcq|#$S+WBDlA6ElG?6=RR+CH2;Rh0anNjJd86Kn`cTmQ`H2ie?>A5vE_}N#0YFp6~ zC5WP|28qNA%`CcR$nssw4nn8#HZ+Xf^??8zA_8GS2l#`+&}`2jsNsfvx`i86jOSot zRR=mmR`71e$RNh?8aU}R5)&OzfG;9T#!b|q058;pPV?r{mmk^LkMU}a=WK=oc#4=D z!RKe6D8#;X2HbyCP zZ4Lb{_u=zKrr)_R>~fFpxP18;`jpb6IbXd-_H4f7=!?hqmOb#u8-sz;Qy)9#+*9%6 zvE@JB^x1)&L!WC!y`jFsp=Fy-ZDjN3_C9_6<3BGxpLjNsUsT=5yuN<__c?E#d1T-z13m#g$k>!PlF zX=us5kCZL-t%8X*ryuN!E39(DosRaj0%fPCcc@N~}|N6%eact(vY4h8v*5rTFxH@O$ zKu+PB;m=ild}Ifu6wlnlAIK*?FOe($Yq z+v{ibRew7r@X^b1(fj_Zx4+d=GVjwVZ3B+A^&c)+UgKppzObeE$uH5PqZg4|FW#R! z+|lA2?fq`m2cH~=m)?I*ciFlfvqrnCwr-kPec`>n>F@68on5*I9cq7~|L*xeYzUI8 zPZZBNc5uz`MXrL`a`E7&%l6ejxbXIo%^}a5!;9Yt&s{rmol3tt18cmkqv8AbhPn&M zYrj>u7wp-#>pd~pa?Vk;vLv^szbAj8_a#N%wAeGyv|zBZFW$fVzAw5?E;@NfkG}8g b?in`XsyI0K^O1F1jk5C9Hh6c`wDtT6rTv@G literal 0 HcmV?d00001 diff --git a/Subliminal.xcodeproj/project.pbxproj b/Subliminal.xcodeproj/project.pbxproj index 4199fc4..0779e39 100644 --- a/Subliminal.xcodeproj/project.pbxproj +++ b/Subliminal.xcodeproj/project.pbxproj @@ -41,6 +41,14 @@ 50F2B7C818E9C0D700F21635 /* SLDispatchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F2B7C718E9C0D700F21635 /* SLDispatchTests.m */; }; 50F3E18C1783A5CB00C6BD1B /* SLGeometry.h in Headers */ = {isa = PBXBuildFile; fileRef = 50F3E18A1783A5CB00C6BD1B /* SLGeometry.h */; settings = {ATTRIBUTES = (Public, ); }; }; 50F3E18E1783A60100C6BD1B /* SLGeometry.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F3E18B1783A5CB00C6BD1B /* SLGeometry.m */; }; + 9764EF6D1909715E009E6B68 /* SLNavigationBarTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9764EF6A1909715E009E6B68 /* SLNavigationBarTests.m */; }; + 9764EF6E1909715F009E6B68 /* SLNavigationBarTestsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9764EF6B1909715E009E6B68 /* SLNavigationBarTestsViewController.m */; }; + 9764EF6F1909715F009E6B68 /* SLNavigationBarTestsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9764EF6C1909715E009E6B68 /* SLNavigationBarTestsViewController.xib */; }; + 9764EF751909716B009E6B68 /* heart_empty_icon&32.png in Resources */ = {isa = PBXBuildFile; fileRef = 9764EF701909716B009E6B68 /* heart_empty_icon&32.png */; }; + 9764EF761909716B009E6B68 /* heart_icon&32.png in Resources */ = {isa = PBXBuildFile; fileRef = 9764EF711909716B009E6B68 /* heart_icon&32.png */; }; + 9764EF771909716B009E6B68 /* SLTableViewCellChildElementsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 9764EF721909716B009E6B68 /* SLTableViewCellChildElementsTest.m */; }; + 9764EF781909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9764EF731909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.m */; }; + 9764EF791909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9764EF741909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.xib */; }; CA75E78216697A1200D57E92 /* SLDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = CA75E78016697A1200D57E92 /* SLDevice.h */; settings = {ATTRIBUTES = (Public, ); }; }; CA75E78516697C0000D57E92 /* SLDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = CA75E78116697A1200D57E92 /* SLDevice.m */; }; CAC388051641CD7500F995F9 /* SLStringUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = CAC388031641CD7500F995F9 /* SLStringUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -274,6 +282,14 @@ 50F2B7C718E9C0D700F21635 /* SLDispatchTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLDispatchTests.m; sourceTree = ""; }; 50F3E18A1783A5CB00C6BD1B /* SLGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLGeometry.h; sourceTree = ""; }; 50F3E18B1783A5CB00C6BD1B /* SLGeometry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLGeometry.m; sourceTree = ""; }; + 9764EF6A1909715E009E6B68 /* SLNavigationBarTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLNavigationBarTests.m; sourceTree = ""; }; + 9764EF6B1909715E009E6B68 /* SLNavigationBarTestsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLNavigationBarTestsViewController.m; sourceTree = ""; }; + 9764EF6C1909715E009E6B68 /* SLNavigationBarTestsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SLNavigationBarTestsViewController.xib; sourceTree = ""; }; + 9764EF701909716B009E6B68 /* heart_empty_icon&32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "heart_empty_icon&32.png"; sourceTree = ""; }; + 9764EF711909716B009E6B68 /* heart_icon&32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "heart_icon&32.png"; sourceTree = ""; }; + 9764EF721909716B009E6B68 /* SLTableViewCellChildElementsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLTableViewCellChildElementsTest.m; sourceTree = ""; }; + 9764EF731909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLTableViewCellChildElementsTestViewController.m; sourceTree = ""; }; + 9764EF741909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SLTableViewCellChildElementsTestViewController.xib; sourceTree = ""; }; CA75E78016697A1200D57E92 /* SLDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLDevice.h; sourceTree = ""; }; CA75E78116697A1200D57E92 /* SLDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLDevice.m; sourceTree = ""; }; CAC388031641CD7500F995F9 /* SLStringUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLStringUtilities.h; sourceTree = ""; }; @@ -518,6 +534,28 @@ name = "SLGeometry Tests"; sourceTree = ""; }; + 9764EF6519097135009E6B68 /* SLTableViewCell Tests */ = { + isa = PBXGroup; + children = ( + 9764EF701909716B009E6B68 /* heart_empty_icon&32.png */, + 9764EF711909716B009E6B68 /* heart_icon&32.png */, + 9764EF721909716B009E6B68 /* SLTableViewCellChildElementsTest.m */, + 9764EF731909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.m */, + 9764EF741909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.xib */, + ); + name = "SLTableViewCell Tests"; + sourceTree = ""; + }; + 9764EF6919097141009E6B68 /* SLNavigationBar Tests */ = { + isa = PBXGroup; + children = ( + 9764EF6A1909715E009E6B68 /* SLNavigationBarTests.m */, + 9764EF6B1909715E009E6B68 /* SLNavigationBarTestsViewController.m */, + 9764EF6C1909715E009E6B68 /* SLNavigationBarTestsViewController.xib */, + ); + name = "SLNavigationBar Tests"; + sourceTree = ""; + }; CAC388011641CD4800F995F9 /* Internal */ = { isa = PBXGroup; children = ( @@ -896,6 +934,8 @@ F0AC80BE16BB542400C5D5C0 /* Tests */ = { isa = PBXGroup; children = ( + 9764EF6919097141009E6B68 /* SLNavigationBar Tests */, + 9764EF6519097135009E6B68 /* SLTableViewCell Tests */, DB2627D817B96704009DA3A6 /* SLStatusBar Tests */, 50A59BD317848CEE002A863A /* SLGeometry Tests */, F07DA31F16E439B7004C2282 /* SLAlert Tests */, @@ -1205,10 +1245,13 @@ 068D3E4D16DE9008004E7E28 /* SLTableViewChildElementMatchingTestViewController.xib in Resources */, 0696BA5A16E013D600DD70CF /* SLElementDraggingTestViewController.xib in Resources */, F01EBC9E1701429400FF6A7C /* SLWebTextField.html in Resources */, + 9764EF6F1909715F009E6B68 /* SLNavigationBarTestsViewController.xib in Resources */, F077D70F16D9D77900908FF5 /* SLElementVisibilityTestCovered.xib in Resources */, F090AE7016D9E01D000F0B6F /* SLElementVisibilityTestHidden.xib in Resources */, F090AE7116D9E01D000F0B6F /* SLElementVisibilityTestLowAlpha.xib in Resources */, + 9764EF761909716B009E6B68 /* heart_icon&32.png in Resources */, F090AE7216D9E01D000F0B6F /* SLElementVisibilityTestOffscreen.xib in Resources */, + 9764EF791909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.xib in Resources */, F090AE7416D9E1D1000F0B6F /* SLElementVisibilityTestSuperviewHidden.xib in Resources */, F0E80D8816DB2CEB00945D25 /* SLElementVisibilityTestElementContainerHidden.xib in Resources */, F0E80D8916DB2CEB00945D25 /* SLElementVisibilityTestElementCovered.xib in Resources */, @@ -1222,6 +1265,7 @@ 064B6FC7173DCE9A004AB1BF /* SLElementVisibilityWithSubviews.xib in Resources */, F0C27CDF1741694900335A41 /* SLElementStateTestMidpointCovered.xib in Resources */, F0C27CE917416EC400335A41 /* SLElementStateTestCompletelyCovered.xib in Resources */, + 9764EF751909716B009E6B68 /* heart_empty_icon&32.png in Resources */, F00800C9174B3349001927AC /* SLButtonTestViewController.xib in Resources */, F00F3B5E1778E05100119580 /* SLElementTapTestScrollViewCases.xib in Resources */, F00F3B6717790B4C00119580 /* SLStaticElementTestScrollView.xib in Resources */, @@ -1327,6 +1371,7 @@ F0AC80A416BB299500C5D5C0 /* SLIntegrationTestsAppDelegate.m in Sources */, F0AC80BD16BB50FF00C5D5C0 /* SLTestsViewController.m in Sources */, F0AC80C416BC355D00C5D5C0 /* SLTerminalTest.m in Sources */, + 9764EF6E1909715F009E6B68 /* SLNavigationBarTestsViewController.m in Sources */, F0AC80C116BB559F00C5D5C0 /* SLIntegrationTest.m in Sources */, F0AC80C816BC367E00C5D5C0 /* SLTestViewController.m in Sources */, F078C04A1808BF24000767D2 /* SLWebViewTestViewController.m in Sources */, @@ -1358,13 +1403,16 @@ F05D2B071746B55C0089DB9E /* SLStaticElementTestViewController.m in Sources */, F00800C7174B3349001927AC /* SLButtonTest.m in Sources */, F00800C8174B3349001927AC /* SLButtonTestViewController.m in Sources */, + 9764EF781909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.m in Sources */, F00800E2174C2E0A001927AC /* SLPopoverTest.m in Sources */, F00800E3174C2E0A001927AC /* SLPopoverTestViewController.m in Sources */, 0640035A178FDE7800479173 /* SLElementTouchAndHoldTestViewController.m in Sources */, F0A3F63D17A7172E007529C3 /* SLTextViewTest.m in Sources */, F0A3F63E17A7172E007529C3 /* SLTextViewTestViewController.m in Sources */, + 9764EF6D1909715E009E6B68 /* SLNavigationBarTests.m in Sources */, DB2627DE17B96727009DA3A6 /* SLStatusBarTest.m in Sources */, F078C0491808BF24000767D2 /* SLWebViewTest.m in Sources */, + 9764EF771909716B009E6B68 /* SLTableViewCellChildElementsTest.m in Sources */, DB2627DF17B96727009DA3A6 /* SLStatusBarTestViewController.m in Sources */, 50A59BD81784908D002A863A /* SLGeometryTest.m in Sources */, 50A59BDB178490C2002A863A /* SLGeometryTestViewController.m in Sources */, From a3358bd905ba248b3f58530d6bbd34ae309d67a2 Mon Sep 17 00:00:00 2001 From: Jordan Zucker Date: Thu, 24 Apr 2014 13:53:08 -0700 Subject: [PATCH 2/5] First version of real AccessibilityParent solution. This has basic docs (needs fleshing out). But a working version of a solution for child and parent accessibility elements, along with implementations for UINavigationBar and UITableViewCell. --- .../Tests/SLNavigationBarTests.m | 51 +++--- .../Tests/SLTableViewCellChildElementsTest.m | 145 +++++------------- ...eViewCellChildElementsTestViewController.m | 45 ------ .../NSObject+SLAccessibilityHierarchy.m | 4 + .../User Interface Elements/SLNavigationBar.h | 31 ++++ .../User Interface Elements/SLNavigationBar.m | 30 ++++ .../User Interface Elements/SLTableViewCell.h | 31 ++++ .../User Interface Elements/SLTableViewCell.m | 58 +++++++ .../SLUIAElement+Subclassing.h | 11 ++ Sources/Subliminal.h | 2 + Subliminal.xcodeproj/project.pbxproj | 16 ++ 11 files changed, 240 insertions(+), 184 deletions(-) create mode 100644 Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.h create mode 100644 Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.m create mode 100644 Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.h create mode 100644 Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m diff --git a/Integration Tests/Tests/SLNavigationBarTests.m b/Integration Tests/Tests/SLNavigationBarTests.m index df1a6da..2117613 100644 --- a/Integration Tests/Tests/SLNavigationBarTests.m +++ b/Integration Tests/Tests/SLNavigationBarTests.m @@ -9,7 +9,6 @@ #import "SLIntegrationTest.h" @interface SLNavigationBarTests : SLIntegrationTest - @end @implementation SLNavigationBarTests @@ -18,12 +17,6 @@ + (NSString *)testCaseViewControllerClassName { return @"SLNavigationBarTestsViewController"; } -// If you override set-up methods, -// you must call super at the beginning of your implementations. - -// If you override tear-down methods, -// you must call super at the *end* of your implementations. - - (void)testRightButtonBroadMatching { SLButton *rightButton = [SLButton elementWithAccessibilityLabel:@"Right"]; SLAssertTrue([UIAElement(rightButton) isValidAndVisible], @"Right button didn't appear"); @@ -31,28 +24,26 @@ - (void)testRightButtonBroadMatching { [UIAElement(rightButton) tap]; } -//- (void)testRightButtonWithNewMethod -//{ -// SLAccessibilityContainer *navBar = [SLAccessibilityContainer containerWithIdentifier:@"NavigationBar" andContainerType:SLAccessibilityContainerTypeNavigationBar]; -// SLLogAsync(@"navBar is %@", navBar); -// SLAssertTrue([UIAElement(navBar) isValidAndVisible], @"Couldn't find nav bar matching specifications"); -// SLButton *rightButton = [navBar childElementMatching:[SLButton elementWithAccessibilityLabel:@"Right"]]; -// SLAssertTrue([UIAElement(rightButton) isValidAndVisible], @"Couldn't find right button bar"); -// -// [UIAElement(rightButton) tap]; -// -//} -// -//- (void)testTitleLabel -//{ -// SLAccessibilityContainer *navBar = [SLAccessibilityContainer containerWithIdentifier:@"NavigationBar" andContainerType:SLAccessibilityContainerTypeNavigationBar]; -// SLLogAsync(@"navBar is %@", navBar); -// SLAssertTrue([UIAElement(navBar) isValidAndVisible], @"Couldn't find nav bar matching specifications"); -// SLElement *title = [navBar childElementMatching:[SLElement elementWithAccessibilityLabel:@"Testing" value:nil traits:UIAccessibilityTraitStaticText]]; -// SLAssertTrue([UIAElement(title) isValidAndVisible], @"title isn't valid and visible"); -// SLLogAsync(@"title is %@", title.label); -// SLAssertTrue([UIAElement(title.label) isEqualToString:@"Testing"], @"title doesn't match expected string"); -// -//} +- (void)testRightButtonWithNewMethod +{ + SLNavigationBar *navBar = [SLNavigationBar elementWithAccessibilityIdentifier:@"NavigationBar"]; + SLLogAsync(@"navBar is %@", navBar); + SLAssertTrue([UIAElement(navBar) isValidAndVisible], @"Couldn't find nav bar matching specifications"); + SLButton *rightButton = [navBar childElementMatching:[SLButton elementWithAccessibilityLabel:@"Right"]]; + SLAssertTrue([UIAElement(rightButton) isValidAndVisible], @"Couldn't find right button bar"); + + [UIAElement(rightButton) tap]; +} + +- (void)testTitleLabel +{ + SLNavigationBar *navBar = [SLNavigationBar elementWithAccessibilityIdentifier:@"NavigationBar"]; + SLLogAsync(@"navBar is %@", navBar); + SLAssertTrue([UIAElement(navBar) isValidAndVisible], @"Couldn't find nav bar matching specifications"); + SLElement *title = [navBar childElementMatching:[SLElement elementWithAccessibilityLabel:@"Testing" value:nil traits:UIAccessibilityTraitStaticText]]; + SLAssertTrue([UIAElement(title) isValidAndVisible], @"title isn't valid and visible"); + SLLogAsync(@"title is %@", title.label); + SLAssertTrue([UIAElement(title.label) isEqualToString:@"Testing"], @"title doesn't match expected string"); +} @end diff --git a/Integration Tests/Tests/SLTableViewCellChildElementsTest.m b/Integration Tests/Tests/SLTableViewCellChildElementsTest.m index f370604..330ef55 100644 --- a/Integration Tests/Tests/SLTableViewCellChildElementsTest.m +++ b/Integration Tests/Tests/SLTableViewCellChildElementsTest.m @@ -8,22 +8,16 @@ #import "SLIntegrationTest.h" -@interface focus_SLTableViewCellChildElementsTest : SLIntegrationTest +@interface SLTableViewCellChildElementsTest : SLIntegrationTest @end -@implementation focus_SLTableViewCellChildElementsTest +@implementation SLTableViewCellChildElementsTest + (NSString *)testCaseViewControllerClassName { return @"SLTableViewCellChildElementsTestViewController"; } -// If you override set-up methods, -// you must call super at the beginning of your implementations. - -// If you override tear-down methods, -// you must call super at the *end* of your implementations. - - (void)testTapBroadMatchingTableViewCellButton { [[SLDevice currentDevice] captureScreenshotWithFilename:@"start"]; @@ -112,106 +106,39 @@ - (void)testMatchingTableViewCellByMatchingTableViewCellAndTableView [[SLDevice currentDevice] captureScreenshotWithFilename:@"end of test"]; } -//- (void)testMatchingTableViewCellWithAccessibilityContainerMethod -//{ -// [[SLDevice currentDevice] captureScreenshotWithFilename:@"start"]; -// SLAccessibilityContainer *tableViewCell = [SLAccessibilityContainer containerWithLabel:@"Cell 2" andContainerType:SLAccessibilityContainerTypeTableViewCell]; -// SLButton *favoriteButton = [tableViewCell childElementMatching:[SLButton elementWithAccessibilityLabel:@"Favorite"]]; -// -// SLLogAsync(@"favoriteButton.value is %@", UIAElement(favoriteButton.value)); -// -// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not originally off"); -// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); -// [favoriteButton captureScreenshotWithFilename:@"fb: starting"]; -// -// [UIAElement(favoriteButton) tap]; -// -// [self wait:1]; -// [[SLDevice currentDevice] captureScreenshotWithFilename:@"after tap"]; -// [favoriteButton captureScreenshotWithFilename:@"fb: after first tap"]; -// -// [UIAElement(favoriteButton) isValidAndVisible]; -// -// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"favorite button is not valid and visible after first time tapping"); -// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"on"], @"Favorite button does not has ax value of on"); -// [UIAElement(favoriteButton) tap]; -// -// [self wait:1]; -// -// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not off at end of test"); -// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); -// [favoriteButton captureScreenshotWithFilename:@"fb: ending"]; -// -// -// [[SLDevice currentDevice] captureScreenshotWithFilename:@"end of test"]; -//} -// -//- (void)testMatchingTableViewCellWithTableViewCellMethodSubclass -//{ -// [[SLDevice currentDevice] captureScreenshotWithFilename:@"start"]; -// SLTableViewCell *tableViewCell = [SLTableViewCell cellWithLabel:@"Cell 2"]; -// SLButton *favoriteButton = [tableViewCell childElementMatching:[SLButton elementWithAccessibilityLabel:@"Favorite"]]; -// -// SLLogAsync(@"favoriteButton.value is %@", UIAElement(favoriteButton.value)); -// -// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not originally off"); -// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); -// [favoriteButton captureScreenshotWithFilename:@"fb: starting"]; -// -// [UIAElement(favoriteButton) tap]; -// -// [self wait:1]; -// [[SLDevice currentDevice] captureScreenshotWithFilename:@"after tap"]; -// [favoriteButton captureScreenshotWithFilename:@"fb: after first tap"]; -// -// [UIAElement(favoriteButton) isValidAndVisible]; -// -// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"favorite button is not valid and visible after first time tapping"); -// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"on"], @"Favorite button does not has ax value of on"); -// [UIAElement(favoriteButton) tap]; -// -// [self wait:1]; -// -// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not off at end of test"); -// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); -// [favoriteButton captureScreenshotWithFilename:@"fb: ending"]; -// -// -// [[SLDevice currentDevice] captureScreenshotWithFilename:@"end of test"]; -//} - -//- (void)testMatchingTableViewCellWithTableViewCellMethodSubclassIndex -//{ -// [[SLDevice currentDevice] captureScreenshotWithFilename:@"start"]; -// SLTableViewCell *tableViewCell = [SLTableViewCell cellAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]]; -// SLButton *favoriteButton = [tableViewCell childElementMatching:[SLButton elementWithAccessibilityLabel:@"Favorite"]]; -// -// SLLogAsync(@"favoriteButton.value is %@", UIAElement(favoriteButton.value)); -// -// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not originally off"); -// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); -// [favoriteButton captureScreenshotWithFilename:@"fb: starting"]; -// -// [UIAElement(favoriteButton) tap]; -// -// [self wait:1]; -// [[SLDevice currentDevice] captureScreenshotWithFilename:@"after tap"]; -// [favoriteButton captureScreenshotWithFilename:@"fb: after first tap"]; -// -// [UIAElement(favoriteButton) isValidAndVisible]; -// -// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"favorite button is not valid and visible after first time tapping"); -// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"on"], @"Favorite button does not has ax value of on"); -// [UIAElement(favoriteButton) tap]; -// -// [self wait:1]; -// -// SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not off at end of test"); -// SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); -// [favoriteButton captureScreenshotWithFilename:@"fb: ending"]; -// -// -// [[SLDevice currentDevice] captureScreenshotWithFilename:@"end of test"]; -//} +- (void)testMatchingTableViewCellWithAccessibilityContainerMethod +{ + [[SLDevice currentDevice] captureScreenshotWithFilename:@"start"]; + SLTableViewCell *tableViewCell = [SLTableViewCell elementWithAccessibilityLabel:@"Cell 2"]; + SLAssertTrue([UIAElement(tableViewCell) isValidAndVisible], @"table view cell matching cell 2 not valid and visible"); + SLButton *favoriteButton = [tableViewCell childElementMatching:[SLButton elementWithAccessibilityLabel:@"Favorite"]]; + + SLLogAsync(@"favoriteButton.value is %@", UIAElement(favoriteButton.value)); + + SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not originally off"); + SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); + [favoriteButton captureScreenshotWithFilename:@"fb: starting"]; + + [UIAElement(favoriteButton) tap]; + + [self wait:1]; + [[SLDevice currentDevice] captureScreenshotWithFilename:@"after tap"]; + [favoriteButton captureScreenshotWithFilename:@"fb: after first tap"]; + + [UIAElement(favoriteButton) isValidAndVisible]; + + SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"favorite button is not valid and visible after first time tapping"); + SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"on"], @"Favorite button does not has ax value of on"); + [UIAElement(favoriteButton) tap]; + + [self wait:1]; + + SLAssertTrue([UIAElement(favoriteButton.value) isEqualToString:@"off"], @"favorite button is not off at end of test"); + SLAssertTrue([UIAElement(favoriteButton) isValidAndVisible], @"Favorite button is not valid and visible"); + [favoriteButton captureScreenshotWithFilename:@"fb: ending"]; + + + [[SLDevice currentDevice] captureScreenshotWithFilename:@"end of test"]; +} @end diff --git a/Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.m b/Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.m index 79e0043..fc7da0e 100644 --- a/Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.m +++ b/Integration Tests/Tests/SLTableViewCellChildElementsTestViewController.m @@ -31,26 +31,15 @@ - (void)viewDidLoad { _tableViewElements = @[@"Cell 0", @"Cell 1", @"Cell 2", @"Cell 3"]; _tableViewFavorites = [[NSMutableArray alloc] initWithObjects:@(NO), @(NO), @(NO), @(NO), nil]; - - // Do any additional setup after loading the view from its nib. - // Test case specific configuration is best done using app hooks - // triggered from -[SLTableViewCellChildElementsTests setUpTestCaseWithSelector:]. } - (instancetype)initWithTestCaseWithSelector:(SEL)testCase { self = [super initWithTestCaseWithSelector:testCase]; if (self) { - // Register for app hooks, e.g. - // [[SLTestController sharedTestController] registerTarget:<#(id)#> forAction:<#(SEL)#>]; } return self; } -// Deregister for app hooks, if any -//- (void)dealloc { -// [[SLTestController sharedTestController] deregisterTarget:self]; -//} - //#pragma mark - App hooks // Put any app hooks below here @@ -61,48 +50,18 @@ - (IBAction)pressButton:(id)sender UIButton *favoriteButton = (UIButton *)sender; NSNumber *oldFavoriteBool = [_tableViewFavorites objectAtIndex:favoriteButton.tag]; [self setFavoriteButton:favoriteButton withFavoriteStatus:(![oldFavoriteBool boolValue])]; - // NSNumber *oldFavoriteBool = [_tableViewFavorites objectAtIndex:favoriteButton.tag]; - // NSNumber *updatedFavoriteBool; - // NSString *updatedFavoriteButtonAccessibilityValue; - // UIImage *updatedFavoriteButtonImage; - // if ([oldFavoriteBool boolValue] == YES) { - // updatedFavoriteBool = @(NO); - // updatedFavoriteButtonAccessibilityValue = @"off"; - // updatedFavoriteButtonImage = [UIImage imageNamed:@"heart_empty_icon&32.png"]; - // - // } - // else { - // updatedFavoriteBool = @(YES); - // updatedFavoriteButtonAccessibilityValue = @"on"; - // updatedFavoriteButtonImage = [UIImage imageNamed:@"heart_icon&32.png"]; - // } - // [_tableViewFavorites setObject:updatedFavoriteBool atIndexedSubscript:favoriteButton.tag]; - // favoriteButton.accessibilityValue = updatedFavoriteButtonAccessibilityValue; - // [favoriteButton setImage:updatedFavoriteButtonImage forState:UIControlStateNormal]; - - // if ([favoriteButton.titleLabel.text isEqualToString:@"Favorite"]) { - // [favoriteButton setTitle:@"Unfavorite" forState:UIControlStateNormal]; - // } - // else { - // [favoriteButton setTitle:@"Favorite" forState:UIControlStateNormal]; - // } - //[favoriteButton setImage:[UIImage imageNamed:@"heart_icon&32.png"] forState:UIControlStateNormal]; } - (void) setFavoriteButton:(UIButton *)favoriteButton withFavoriteStatus:(BOOL)favoriteBool { - //NSNumber *oldFavoriteBool = [_tableViewFavorites objectAtIndex:favoriteButton.tag]; - // NSNumber *updatedFavoriteBool; NSString *updatedFavoriteButtonAccessibilityValue; UIImage *updatedFavoriteButtonImage; if (favoriteBool == YES) { - // updatedFavoriteBool = @(NO); updatedFavoriteButtonAccessibilityValue = @"on"; updatedFavoriteButtonImage = [UIImage imageNamed:@"heart_icon&32.png"]; } else { - // updatedFavoriteBool = @(YES); updatedFavoriteButtonAccessibilityValue = @"off"; updatedFavoriteButtonImage = [UIImage imageNamed:@"heart_empty_icon&32.png"]; } @@ -132,12 +91,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } cell.textLabel.text = [_tableViewElements objectAtIndex:indexPath.row]; - //UIButton *favoriteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - //[favoriteButton setTitle:@"Favorite" forState:UIControlStateNormal]; UIButton *favoriteButton = [UIButton buttonWithType:UIButtonTypeCustom]; - //[favoriteButton setImage:[UIImage imageNamed:@"heart_empty_icon&32.png"] forState:UIControlStateNormal]; favoriteButton.accessibilityLabel = @"Favorite"; - //favoriteButton.accessibilityValue = @"off"; favoriteButton.tag = indexPath.row; favoriteButton.frame = CGRectMake(160.0f, 5.0f, 32.0f, 32.0f); diff --git a/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m b/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m index bae1799..d231d5b 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m +++ b/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m @@ -376,6 +376,10 @@ @implementation UITableViewCell (SLAccessibilityHierarchy) - (BOOL)classForcesPresenceOfMockingViewsInAccessibilityHierarchy { return YES; } +- (BOOL)classForcesPresenceInAccessibilityHierarchy +{ + return YES; +} @end diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.h b/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.h new file mode 100644 index 0000000..a43444f --- /dev/null +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.h @@ -0,0 +1,31 @@ +// +// SLNavigationBar.h +// Subliminal +// +// Created by Jordan Zucker on 4/24/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLElement.h" +#import "SLUIAElement+Subclassing.h" + +/** + `SLNavigationBar` matches against instances of `UINavigationBar`. + + Will find an element matching the parameters that appears inside + a navigationBar. + */ +@interface SLNavigationBar : SLElement + +/** + Returns the child element matching one provided that is child of caller + + This is implemented specially for UITableViewCell. + + @param childElement A `SLElement` with your provided specifications. + + @return `SLElement` matching specifications of the parameter and appearing as an accessibilityChild of the caller. + */ +- (id)childElementMatching:(SLElement *)childElement; + +@end diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.m b/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.m new file mode 100644 index 0000000..cba20a6 --- /dev/null +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.m @@ -0,0 +1,30 @@ +// +// SLNavigationBar.m +// Subliminal +// +// Created by Jordan Zucker on 4/24/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLNavigationBar.h" +#import "NSObject+SLAccessibilityHierarchy.h" + +@implementation SLNavigationBar + +- (BOOL)matchesObject:(NSObject *)object +{ + return [super matchesObject:object] && [object isKindOfClass:[UINavigationBar class]]; +} + +- (id)childElementMatching:(SLElement *)childElement +{ + return [SLElement elementMatching:^BOOL(NSObject *obj) { + if ([childElement matchesObject:obj]) { + id accessibilityParent = [obj slAccessibilityParent]; + return [self matchesObject:accessibilityParent]; + } + return NO; + } withDescription:@"nav bar child"]; +} + +@end diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.h b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.h new file mode 100644 index 0000000..d5c9d9a --- /dev/null +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.h @@ -0,0 +1,31 @@ +// +// SLTableViewCell.h +// Subliminal +// +// Created by Jordan Zucker on 4/24/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLElement.h" +#import "SLUIAElement+Subclassing.h" + +/** + `SLTableViewCell` matches against instances of `UITableViewCell`. + + Will find an element matching the parameters that appears inside + a table view. + */ +@interface SLTableViewCell : SLElement + +/** + Returns the child element matching one provided that is child of caller + + This is implemented specially for UITableViewCell. + + @param childElement A `SLElement` with your provided specifications. + + @return `SLElement` matching specifications of the parameter and appearing as an accessibilityChild of the caller. + */ +- (id)childElementMatching:(SLElement *)childElement; + +@end diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m new file mode 100644 index 0000000..4ad2084 --- /dev/null +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m @@ -0,0 +1,58 @@ +// +// SLTableViewCell.m +// Subliminal +// +// Created by Jordan Zucker on 4/24/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLTableViewCell.h" +#import "NSObject+SLAccessibilityHierarchy.h" + +@implementation SLTableViewCell + +- (BOOL)matchesObject:(NSObject *)object +{ + id accessibilityParent = [object slAccessibilityParent]; + id objectSuperview = nil; + if ([object respondsToSelector:@selector(superview)]) { + objectSuperview = [object performSelector:@selector(superview)]; + } + id doubleSuperview = nil; + if ([objectSuperview respondsToSelector:@selector(superview)]) { + doubleSuperview = [objectSuperview performSelector:@selector(superview)]; + } + id doubleAccessibilityParent = [accessibilityParent slAccessibilityParent]; + if (![super matchesObject:object]) { + return NO; + } + if ([accessibilityParent isKindOfClass:[UITableView class]] && (objectSuperview == nil)) { + return YES; + } + if ([doubleAccessibilityParent isKindOfClass:[UITableView class]] && ([doubleSuperview isKindOfClass:[UITableView class]])) { + return YES; + } + return NO; +} + +- (id)childElementMatching:(SLElement *)childElement +{ + return [SLElement elementMatching:^BOOL(NSObject *obj) { + if ([childElement matchesObject:obj]) { + id objAccessibilityParent = [obj slAccessibilityParent]; + id objDoubleAccessibilityParent = [objAccessibilityParent slAccessibilityParent]; + // ax element is direct child + if ([self matchesObject:objAccessibilityParent]) { + return YES; + } + // real view is two layers deep because of content view + if ([self matchesObject:objDoubleAccessibilityParent]) { + return YES; + } + return NO; + } + return NO; + } withDescription:@"container child"]; +} + +@end diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLUIAElement+Subclassing.h b/Sources/Classes/UIAutomation/User Interface Elements/SLUIAElement+Subclassing.h index 533d655..7d3f050 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/SLUIAElement+Subclassing.h +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLUIAElement+Subclassing.h @@ -199,4 +199,15 @@ */ - (void)examineMatchingObject:(void (^)(NSObject *object))block; +/** + Allows the caller to return a child object matching the specificed `SLElement`. + + Must be implemented by the caller. + + @param childElement A `SLElement` with your provided specifications. + + @return `SLElement` matching specifications of the parameter and appearing as an accessibilityChild of the caller. + */ +- (id)childElementMatching:(SLElement *)childElement; + @end diff --git a/Sources/Subliminal.h b/Sources/Subliminal.h index 2942072..55b17ab 100644 --- a/Sources/Subliminal.h +++ b/Sources/Subliminal.h @@ -29,6 +29,8 @@ #import "NSObject+SLAccessibilityDescription.h" #import "NSObject+SLAccessibilityHierarchy.h" #import "SLStaticElement.h" +#import "SLTableViewCell.h" +#import "SLNavigationBar.h" #import "SLAlert.h" #import "SLButton.h" #import "SLKeyboard.h" diff --git a/Subliminal.xcodeproj/project.pbxproj b/Subliminal.xcodeproj/project.pbxproj index 0779e39..cca2192 100644 --- a/Subliminal.xcodeproj/project.pbxproj +++ b/Subliminal.xcodeproj/project.pbxproj @@ -49,6 +49,10 @@ 9764EF771909716B009E6B68 /* SLTableViewCellChildElementsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 9764EF721909716B009E6B68 /* SLTableViewCellChildElementsTest.m */; }; 9764EF781909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9764EF731909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.m */; }; 9764EF791909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9764EF741909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.xib */; }; + 9764EF7E19097353009E6B68 /* SLTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 9764EF7C19097353009E6B68 /* SLTableViewCell.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9764EF7F19097353009E6B68 /* SLTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9764EF7D19097353009E6B68 /* SLTableViewCell.m */; }; + 9764EF8519099714009E6B68 /* SLNavigationBar.h in Headers */ = {isa = PBXBuildFile; fileRef = 9764EF8319099714009E6B68 /* SLNavigationBar.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9764EF8619099714009E6B68 /* SLNavigationBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 9764EF8419099714009E6B68 /* SLNavigationBar.m */; }; CA75E78216697A1200D57E92 /* SLDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = CA75E78016697A1200D57E92 /* SLDevice.h */; settings = {ATTRIBUTES = (Public, ); }; }; CA75E78516697C0000D57E92 /* SLDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = CA75E78116697A1200D57E92 /* SLDevice.m */; }; CAC388051641CD7500F995F9 /* SLStringUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = CAC388031641CD7500F995F9 /* SLStringUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -290,6 +294,10 @@ 9764EF721909716B009E6B68 /* SLTableViewCellChildElementsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLTableViewCellChildElementsTest.m; sourceTree = ""; }; 9764EF731909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLTableViewCellChildElementsTestViewController.m; sourceTree = ""; }; 9764EF741909716B009E6B68 /* SLTableViewCellChildElementsTestViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SLTableViewCellChildElementsTestViewController.xib; sourceTree = ""; }; + 9764EF7C19097353009E6B68 /* SLTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLTableViewCell.h; sourceTree = ""; }; + 9764EF7D19097353009E6B68 /* SLTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLTableViewCell.m; sourceTree = ""; }; + 9764EF8319099714009E6B68 /* SLNavigationBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLNavigationBar.h; sourceTree = ""; }; + 9764EF8419099714009E6B68 /* SLNavigationBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLNavigationBar.m; sourceTree = ""; }; CA75E78016697A1200D57E92 /* SLDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLDevice.h; sourceTree = ""; }; CA75E78116697A1200D57E92 /* SLDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLDevice.m; sourceTree = ""; }; CAC388031641CD7500F995F9 /* SLStringUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLStringUtilities.h; sourceTree = ""; }; @@ -820,6 +828,10 @@ F0C07A371703F95B00C93F93 /* SLAlert.m */, F0C07A451703FEF600C93F93 /* SLButton.h */, F0C07A461703FEF600C93F93 /* SLButton.m */, + 9764EF7C19097353009E6B68 /* SLTableViewCell.h */, + 9764EF7D19097353009E6B68 /* SLTableViewCell.m */, + 9764EF8319099714009E6B68 /* SLNavigationBar.h */, + 9764EF8419099714009E6B68 /* SLNavigationBar.m */, 2CE9AA4A17E3A747007EF0B5 /* SLSwitch.h */, 2CE9AA4B17E3A747007EF0B5 /* SLSwitch.m */, F0C07A511704011300C93F93 /* SLKeyboard.h */, @@ -1056,6 +1068,7 @@ F0CEDA3116BF5FA5005FE8B9 /* SLTest+Internal.h in Headers */, F016493D16D42E3C000AEB50 /* SLTestController+Internal.h in Headers */, F0C07A381703F95B00C93F93 /* SLAlert.h in Headers */, + 9764EF8519099714009E6B68 /* SLNavigationBar.h in Headers */, F0C07A3F1703F9A900C93F93 /* SLUIAElement+Subclassing.h in Headers */, F0C07A471703FEF600C93F93 /* SLButton.h in Headers */, F0C07A4B1704002100C93F93 /* SLTextField.h in Headers */, @@ -1075,6 +1088,7 @@ F04346A7175AD10200D91F7F /* NSObject+SLVisibility.h in Headers */, F0A3F63417A715AE007529C3 /* SLTextView.h in Headers */, DB501DC917B9669A001658CB /* SLStatusBar.h in Headers */, + 9764EF7E19097353009E6B68 /* SLTableViewCell.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1341,9 +1355,11 @@ F0271B00162E0B950098F5F2 /* SLTestController+AppHooks.m in Sources */, F02DF30917EC064F00BE28BF /* UIScrollView+SLProgrammaticScrolling.m in Sources */, CAC388061641CD7500F995F9 /* SLStringUtilities.m in Sources */, + 9764EF7F19097353009E6B68 /* SLTableViewCell.m in Sources */, CAC388401643503C00F995F9 /* NSObject+SLAccessibilityHierarchy.m in Sources */, CA75E78516697C0000D57E92 /* SLDevice.m in Sources */, F0C07A391703F95B00C93F93 /* SLAlert.m in Sources */, + 9764EF8619099714009E6B68 /* SLNavigationBar.m in Sources */, F0C07A481703FEF600C93F93 /* SLButton.m in Sources */, F0C07A4C1704002100C93F93 /* SLTextField.m in Sources */, F0C07A501704009E00C93F93 /* SLWindow.m in Sources */, From 3562e7538527e3345cb5de150ac034b8088a1b61 Mon Sep 17 00:00:00 2001 From: Jordan Zucker Date: Thu, 24 Apr 2014 14:40:11 -0700 Subject: [PATCH 3/5] Updated UITableView presence and mocking view BOOL values On iOS 6, table view cells themselves appear in the accessibility hierarchy. On iOS 7, mock cells (instances of `UITableViewCellAccessibilityElement`) appear in the hierarchy instead. --- .../NSObject+SLAccessibilityHierarchy.m | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m b/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m index d231d5b..358244d 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m +++ b/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m @@ -373,12 +373,11 @@ - (BOOL)accessibilityAncestorPreventsPresenceInAccessibilityHierarchy { @implementation UITableViewCell (SLAccessibilityHierarchy) -- (BOOL)classForcesPresenceOfMockingViewsInAccessibilityHierarchy { - return YES; +- (BOOL)classForcesPresenceInAccessibilityHierarchy { + return kCFCoreFoundationVersionNumber <= kCFCoreFoundationVersionNumber_iOS_6_1; } -- (BOOL)classForcesPresenceInAccessibilityHierarchy -{ - return YES; +- (BOOL)classForcesPresenceOfMockingViewsInAccessibilityHierarchy { + return kCFCoreFoundationVersionNumber > kCFCoreFoundationVersionNumber_iOS_6_1; } @end From c129333b43eef18cd7639fd4e185c9a26ff03acc Mon Sep 17 00:00:00 2001 From: Jordan Zucker Date: Thu, 24 Apr 2014 16:45:39 -0700 Subject: [PATCH 4/5] Fixed UITableViewCell and child elements for iOS 6 and iOS 7. Documented view and accessibility view heirarchy for iOS 6 and 7 for UITableViewCells. It is slightly different and needed to be accounted for. --- .../NSObject+SLAccessibilityHierarchy.m | 8 ++-- .../User Interface Elements/SLTableViewCell.m | 39 ++++++++++--------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m b/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m index 358244d..dee2a89 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m +++ b/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m @@ -373,11 +373,11 @@ - (BOOL)accessibilityAncestorPreventsPresenceInAccessibilityHierarchy { @implementation UITableViewCell (SLAccessibilityHierarchy) -- (BOOL)classForcesPresenceInAccessibilityHierarchy { - return kCFCoreFoundationVersionNumber <= kCFCoreFoundationVersionNumber_iOS_6_1; -} - (BOOL)classForcesPresenceOfMockingViewsInAccessibilityHierarchy { - return kCFCoreFoundationVersionNumber > kCFCoreFoundationVersionNumber_iOS_6_1; + return YES; +} +- (BOOL)classForcesPresenceInAccessibilityHierarchy { + return YES; } @end diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m index 4ad2084..74fd05e 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m @@ -13,25 +13,23 @@ @implementation SLTableViewCell - (BOOL)matchesObject:(NSObject *)object { - id accessibilityParent = [object slAccessibilityParent]; - id objectSuperview = nil; - if ([object respondsToSelector:@selector(superview)]) { - objectSuperview = [object performSelector:@selector(superview)]; - } - id doubleSuperview = nil; - if ([objectSuperview respondsToSelector:@selector(superview)]) { - doubleSuperview = [objectSuperview performSelector:@selector(superview)]; - } - id doubleAccessibilityParent = [accessibilityParent slAccessibilityParent]; if (![super matchesObject:object]) { return NO; } - if ([accessibilityParent isKindOfClass:[UITableView class]] && (objectSuperview == nil)) { + // When we are matching for corresponding `UITableViewCell` instances for + // isVisible checking and such, we need to take iOS version into account. + // On iOS 6 `UITableViewCell` is a direct descendant of `UITableView`. + // On iOS 7, there is a `UITableViewWrapperView` between `UITableView` + // and `UITableViewCell`. + id accessibilityParent = [object slAccessibilityParent]; + if (accessibilityParent && [accessibilityParent isKindOfClass:[UITableView class]]) { return YES; } - if ([doubleAccessibilityParent isKindOfClass:[UITableView class]] && ([doubleSuperview isKindOfClass:[UITableView class]])) { - return YES; + if (kCFCoreFoundationVersionNumber > kCFCoreFoundationVersionNumber_iOS_6_1) { + id doubleAccessibilityParent = [accessibilityParent slAccessibilityParent]; + return [doubleAccessibilityParent isKindOfClass:[UITableView class]]; } + return NO; } @@ -40,14 +38,19 @@ - (id)childElementMatching:(SLElement *)childElement return [SLElement elementMatching:^BOOL(NSObject *obj) { if ([childElement matchesObject:obj]) { id objAccessibilityParent = [obj slAccessibilityParent]; - id objDoubleAccessibilityParent = [objAccessibilityParent slAccessibilityParent]; - // ax element is direct child + // On iOS 6, views and accessibility mock views are + // direct children of `UITableViewCell`. + // On iOS 7, there is a `UITableViewCellScrollView` that is + // a child of `UITableViewCell` and all views contained therein + // are children of that `UITableViewCellScrollView`, which is + // a hidden class if ([self matchesObject:objAccessibilityParent]) { return YES; } - // real view is two layers deep because of content view - if ([self matchesObject:objDoubleAccessibilityParent]) { - return YES; + if (kCFCoreFoundationVersionNumber > kCFCoreFoundationVersionNumber_iOS_6_1) { + // UITableViewCellScrollView + id doubleAccessibilityParent = [objAccessibilityParent slAccessibilityParent]; + return [self matchesObject:doubleAccessibilityParent]; } return NO; } From aae955a388624aeed4a9cca15a76d14d68bc64ac Mon Sep 17 00:00:00 2001 From: Jordan Zucker Date: Thu, 24 Apr 2014 17:16:12 -0700 Subject: [PATCH 5/5] All SLElements now have access to child element matching method. Extended to all elements and allowed `SLTableViewCell` to override. --- .../User Interface Elements/SLElement.h | 15 +++++++++++++++ .../User Interface Elements/SLElement.m | 14 ++++++++++++++ .../User Interface Elements/SLNavigationBar.h | 11 ----------- .../User Interface Elements/SLNavigationBar.m | 11 ----------- .../User Interface Elements/SLTableViewCell.h | 12 ------------ .../User Interface Elements/SLTableViewCell.m | 1 + .../SLUIAElement+Subclassing.h | 11 ----------- 7 files changed, 30 insertions(+), 45 deletions(-) diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLElement.h b/Sources/Classes/UIAutomation/User Interface Elements/SLElement.h index d20be7c..4e9e6ee 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/SLElement.h +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLElement.h @@ -133,6 +133,21 @@ */ + (instancetype)anyElement; +#pragma mark - Hierarchy + +/** + Allows the caller to return a child object matching the specificed `SLElement`. + + Superclass method assumes element and view are both direct descendants. This + will need to be overriden in `SLTableViewCell`, amongst others. + + @param childElement A `SLElement` with your provided specifications. + + @return `instancetype` matching specifications of the parameter and appearing as an + accessibilityChild of the caller. If there are no accessibilityChildren then it returns nil + */ +- (id)childElementMatching:(SLElement *)childElement; + #pragma mark - Gestures and Actions /// ------------------------------------------ /// @name Gestures and Actions diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLElement.m b/Sources/Classes/UIAutomation/User Interface Elements/SLElement.m index f97859f..1ed7bf6 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/SLElement.m +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLElement.m @@ -303,6 +303,20 @@ - (void)examineMatchingObject:(void (^)(NSObject *))block timeout:(NSTimeInterva if (examinationException) @throw examinationException; } +- (id) childElementMatching:(SLElement *)childElement +{ + if ([self accessibilityElementCount] == 0) { + return nil; + } + return [SLElement elementMatching:^BOOL(NSObject *obj) { + if ([childElement matchesObject:obj]) { + id accessibilityParent = [obj slAccessibilityParent]; + return [self matchesObject:accessibilityParent]; + } + return NO; + } withDescription:@"nav bar child"]; +} + - (BOOL)isValid { // isValid evaluates the current state, no waiting to resolve the element SLAccessibilityPath *accessibilityPath = [self accessibilityPathWithTimeout:0.0]; diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.h b/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.h index a43444f..fcde3fd 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.h +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.h @@ -17,15 +17,4 @@ */ @interface SLNavigationBar : SLElement -/** - Returns the child element matching one provided that is child of caller - - This is implemented specially for UITableViewCell. - - @param childElement A `SLElement` with your provided specifications. - - @return `SLElement` matching specifications of the parameter and appearing as an accessibilityChild of the caller. - */ -- (id)childElementMatching:(SLElement *)childElement; - @end diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.m b/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.m index cba20a6..8ab4348 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.m +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLNavigationBar.m @@ -16,15 +16,4 @@ - (BOOL)matchesObject:(NSObject *)object return [super matchesObject:object] && [object isKindOfClass:[UINavigationBar class]]; } -- (id)childElementMatching:(SLElement *)childElement -{ - return [SLElement elementMatching:^BOOL(NSObject *obj) { - if ([childElement matchesObject:obj]) { - id accessibilityParent = [obj slAccessibilityParent]; - return [self matchesObject:accessibilityParent]; - } - return NO; - } withDescription:@"nav bar child"]; -} - @end diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.h b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.h index d5c9d9a..5de9afb 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.h +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.h @@ -7,7 +7,6 @@ // #import "SLElement.h" -#import "SLUIAElement+Subclassing.h" /** `SLTableViewCell` matches against instances of `UITableViewCell`. @@ -17,15 +16,4 @@ */ @interface SLTableViewCell : SLElement -/** - Returns the child element matching one provided that is child of caller - - This is implemented specially for UITableViewCell. - - @param childElement A `SLElement` with your provided specifications. - - @return `SLElement` matching specifications of the parameter and appearing as an accessibilityChild of the caller. - */ -- (id)childElementMatching:(SLElement *)childElement; - @end diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m index 74fd05e..bd450da 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m @@ -8,6 +8,7 @@ #import "SLTableViewCell.h" #import "NSObject+SLAccessibilityHierarchy.h" +#import "SLUIAElement+Subclassing.h" @implementation SLTableViewCell diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLUIAElement+Subclassing.h b/Sources/Classes/UIAutomation/User Interface Elements/SLUIAElement+Subclassing.h index 7d3f050..533d655 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/SLUIAElement+Subclassing.h +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLUIAElement+Subclassing.h @@ -199,15 +199,4 @@ */ - (void)examineMatchingObject:(void (^)(NSObject *object))block; -/** - Allows the caller to return a child object matching the specificed `SLElement`. - - Must be implemented by the caller. - - @param childElement A `SLElement` with your provided specifications. - - @return `SLElement` matching specifications of the parameter and appearing as an accessibilityChild of the caller. - */ -- (id)childElementMatching:(SLElement *)childElement; - @end