diff --git a/Integration Tests/Tests/SLDeviceTest.m b/Integration Tests/Tests/SLDeviceTest.m index bd084e5..43640a3 100644 --- a/Integration Tests/Tests/SLDeviceTest.m +++ b/Integration Tests/Tests/SLDeviceTest.m @@ -90,6 +90,14 @@ - (void)testCanRotateDevice } } +// Exercises a bug in iOS 5.1 and 7.1. See https://github.com/inkling/Subliminal/pull/180#issuecomment-40891098 +- (void)testThatDeviceOrientationPersistsThroughDeactivation { + UIDeviceOrientation currentOrientation = [UIDevice currentDevice].orientation; + [[SLDevice currentDevice] deactivateAppForDuration:3.0]; + SLAssertTrue([UIDevice currentDevice].orientation == currentOrientation, + @"The device orientation should not have changed."); +} + - (void)rotateToAndCheckOrientation:(UIDeviceOrientation)orientation { [[SLDevice currentDevice] setOrientation:orientation]; diff --git a/Integration Tests/Tests/SLElementMatchingTest.m b/Integration Tests/Tests/SLElementMatchingTest.m index 2861575..6e4ea27 100644 --- a/Integration Tests/Tests/SLElementMatchingTest.m +++ b/Integration Tests/Tests/SLElementMatchingTest.m @@ -34,6 +34,16 @@ + (NSString *)testCaseViewControllerClassName { return @"SLElementMatchingTestViewController"; } ++ (BOOL)testCaseWithSelectorSupportsCurrentPlatform:(SEL)testCaseSelector { + if (![super testCaseWithSelectorSupportsCurrentPlatform:testCaseSelector]) return NO; + + if (testCaseSelector == @selector(testMatchingCollectionViewCellChildElement)) { + return kCFCoreFoundationVersionNumber > kCFCoreFoundationVersionNumber_iOS_5_1; + } + + return YES; +} + - (void)setUpTestCaseWithSelector:(SEL)testCaseSelector { [super setUpTestCaseWithSelector:testCaseSelector]; @@ -263,6 +273,14 @@ - (void)testMatchingTableViewHeaderChildElements { SLAssertTrue([rightLabel isValid], @"Could not match UITableView header child element."); } +#pragma mark - Collection views + +- (void)testMatchingCollectionViewCellChildElement { + SLButton *fooButton = [SLButton elementWithAccessibilityLabel:@"fooButton"]; + SLAssertTrue([[UIAElement(fooButton) label] isEqualToString:@"fooButton"], + @"Could not match `UICollectionViewCell` child element."); +} + #pragma mark - Web views // This test case is restricted to the iPhone to guarantee the properties of diff --git a/Integration Tests/Tests/SLElementMatchingTestViewController.m b/Integration Tests/Tests/SLElementMatchingTestViewController.m index 8ce32f9..d2575ea 100644 --- a/Integration Tests/Tests/SLElementMatchingTestViewController.m +++ b/Integration Tests/Tests/SLElementMatchingTestViewController.m @@ -29,15 +29,15 @@ @interface SLElementMatchingTestViewController : SLTestCaseViewController @end -#pragma mark - SLElementMatchingTestCell +#pragma mark - SLElementMatchingTestTableViewCell -@interface SLElementMatchingTestCell : UITableViewCell +@interface SLElementMatchingTestTableViewCell : UITableViewCell - (void)configureAccessibility; @end -@implementation SLElementMatchingTestCell { +@implementation SLElementMatchingTestTableViewCell { SEL _testCase; UISwitch *_switch; UILabel *_weatherCity, *_weatherTemp; @@ -107,15 +107,15 @@ - (void)layoutSubviews { @end -#pragma mark - SLElementMatchingTestHeader +#pragma mark - SLElementMatchingTestTableViewHeader -@interface SLElementMatchingTestHeader : UIView +@interface SLElementMatchingTestTableViewHeader : UIView - (instancetype)initWithTestCaseWithSelector:(SEL)testCase; @end -@implementation SLElementMatchingTestHeader { +@implementation SLElementMatchingTestTableViewHeader { UIView *_leftView, *_rightView; } @@ -167,9 +167,50 @@ - (void)removeRightView { @end +#pragma mark - SLElementMatchingTestCollectionViewCell + +@interface SLElementMatchingTestCollectionViewCell : UICollectionViewCell + ++ (CGSize)defaultSize; + +@end + +@implementation SLElementMatchingTestCollectionViewCell { + UIButton *_button; +} + ++ (CGSize)defaultSize { + return CGSizeMake(100.0f, 50.0f); +} + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor greenColor]; + + _button = [UIButton buttonWithType:UIButtonTypeCustom]; + _button.backgroundColor = [UIColor blueColor]; + [_button setTitle:@"fooButton" forState:UIControlStateNormal]; + [self.contentView addSubview:_button]; + } + return self; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + [_button sizeToFit]; + _button.center = self.center; +} + +@end + + #pragma mark - SLElementMatchingTestViewController -@interface SLElementMatchingTestViewController () +@interface SLElementMatchingTestViewController () < UITableViewDataSource, UITableViewDelegate, + UICollectionViewDataSource, UICollectionViewDelegate, + UIWebViewDelegate > // fooButton is purposely strong so that we can hold onto it // while it's removed from the view hierarchy in testElementsWaitToMatchValidObjects @@ -185,9 +226,10 @@ @interface SLElementMatchingTestViewController () + +@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..8770d75 --- /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 SLTableViewCellChildElementsTest : SLIntegrationTest + +@end + +@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"]; + + 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 0000000..9c324dc Binary files /dev/null and b/Integration Tests/Tests/heart_empty_icon&32.png differ diff --git a/Integration Tests/Tests/heart_icon&32.png b/Integration Tests/Tests/heart_icon&32.png new file mode 100755 index 0000000..ba444e8 Binary files /dev/null and b/Integration Tests/Tests/heart_icon&32.png differ diff --git a/Sources/Classes/Internal/NSObject+SLVisibility.m b/Sources/Classes/Internal/NSObject+SLVisibility.m index 08ee502..e5d678e 100644 --- a/Sources/Classes/Internal/NSObject+SLVisibility.m +++ b/Sources/Classes/Internal/NSObject+SLVisibility.m @@ -133,7 +133,7 @@ - (BOOL)slAccessibilityIsVisible { // if another element comes before us/our parent in the array // (thus is z-ordered before us/our parent) // and contains our hitpoint, it covers us - if (CGRectContainsPoint([element accessibilityFrame], testPoint)) return NO; + if (![NSStringFromClass([element class]) isEqualToString:@"UITableTextAccessibilityElement"] && CGRectContainsPoint([element accessibilityFrame], testPoint)) return NO; } // we should eventually reach a container that is a view diff --git a/Sources/Classes/UIAutomation/SLDevice.m b/Sources/Classes/UIAutomation/SLDevice.m index 9510727..483c9ef 100644 --- a/Sources/Classes/UIAutomation/SLDevice.m +++ b/Sources/Classes/UIAutomation/SLDevice.m @@ -39,7 +39,18 @@ + (SLDevice *)currentDevice { } - (void)deactivateAppForDuration:(NSTimeInterval)duration { + UIDeviceOrientation currentOrientation = [UIDevice currentDevice].orientation; + [[SLTerminal sharedTerminal] evalWithFormat:@"UIATarget.localTarget().deactivateAppForDuration(%g)", duration]; + + // On iPads running iOS 5.1 and 7.1, `UIDevice` forgets its orientation after deactivation. + // This is not only unexpected but can mess with `-[SLElement isVisible]`. + // See https://github.com/inkling/Subliminal/pull/180#issuecomment-40891098 + if (([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) && + ((kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_6_0) || + (kCFCoreFoundationVersionNumber > kCFCoreFoundationVersionNumber_iOS_6_1))) { + [self setOrientation:currentOrientation]; + } } #pragma mark - Device Rotation @@ -60,8 +71,8 @@ - (void)deactivateAppForDuration:(NSTimeInterval)duration { - (void)setOrientation:(UIDeviceOrientation)deviceOrientation { [[SLTerminal sharedTerminal] evalWithFormat:@"UIATarget.localTarget().setDeviceOrientation(%@)", SLUIADeviceOrientationFromUIDeviceOrientation(deviceOrientation)]; - // Delay slightly to ensure that UIDevice registers the new orientation - [NSThread sleepForTimeInterval:0.3]; + // Delay to ensure that the rotation completes and UIDevice registers the new orientation + [NSThread sleepForTimeInterval:1.0]; } #pragma mark - Screenshots diff --git a/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m b/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m index 52dca79..bae1799 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m +++ b/Sources/Classes/UIAutomation/User Interface Elements/NSObject+SLAccessibilityHierarchy.m @@ -379,6 +379,18 @@ - (BOOL)classForcesPresenceOfMockingViewsInAccessibilityHierarchy { @end +// On iOS 6, collection view cells themselves appear in the accessibility hierarchy. +// On iOS 7, mock cells (instances of `UICollectionViewCellAccessibilityElement`) appear in the hierarchy instead. +@implementation UICollectionViewCell (SLAccessibilityHierarchy) +- (BOOL)classForcesPresenceInAccessibilityHierarchy { + return kCFCoreFoundationVersionNumber <= kCFCoreFoundationVersionNumber_iOS_6_1; +} +- (BOOL)classForcesPresenceOfMockingViewsInAccessibilityHierarchy { + return kCFCoreFoundationVersionNumber > kCFCoreFoundationVersionNumber_iOS_6_1; +} +@end + + @implementation UIScrollView (SLAccessibilityHierarchy) - (BOOL)classForcesPresenceInAccessibilityHierarchy { return YES; diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLAccessibilityContainer.h b/Sources/Classes/UIAutomation/User Interface Elements/SLAccessibilityContainer.h new file mode 100644 index 0000000..82fa4d2 --- /dev/null +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLAccessibilityContainer.h @@ -0,0 +1,32 @@ +// +// SLAccessibilityContainer.h +// Subliminal +// +// Created by Jordan Zucker on 4/2/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLElement.h" + +typedef NS_ENUM(NSInteger, SLAccessibilityContainerType) { + SLAccessibilityContainerTypeTableViewCell, + SLAccessibilityContainerTypeCollectionViewCell, + SLAccessibilityContainerTypeNavigationBar, + SLAccessibilityContainerTypeToolbar, + SLAccessibilityContainerTypeTabBar +}; + +@interface SLAccessibilityContainer : SLElement + +@property (nonatomic, assign) SLAccessibilityContainerType containerType; + ++ (instancetype)containerWithElement:(SLElement *)element andContainerType:(SLAccessibilityContainerType)accessibilityContainerType; + ++ (instancetype)containerWithIdentifier:(NSString *)identifer andContainerType:(SLAccessibilityContainerType)accessibilityContainerType; ++ (instancetype)containerWithLabel:(NSString *)label andContainerType:(SLAccessibilityContainerType)accessibilityContainerType; ++ (instancetype)containerWithLabel:(NSString *)label value:(NSString *)value traits:(UIAccessibilityTraits)traits andContainerType:(SLAccessibilityContainerType)accessibilityContainerType; + +- (id)childElementMatching:(SLElement *)childElement; ++ (id)childElementMatching:(SLElement *)childElement inContainerElement:(SLElement *)containerElement ofContainerType:(SLAccessibilityContainerType)accessibilityContainerType; + +@end diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLAccessibilityContainer.m b/Sources/Classes/UIAutomation/User Interface Elements/SLAccessibilityContainer.m new file mode 100644 index 0000000..4e915a6 --- /dev/null +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLAccessibilityContainer.m @@ -0,0 +1,115 @@ +// +// SLAccessibilityContainer.m +// Subliminal +// +// Created by Jordan Zucker on 4/2/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLAccessibilityContainer.h" +#import "SLUIAElement+Subclassing.h" +#import "NSObject+SLAccessibilityHierarchy.h" + +@implementation SLAccessibilityContainer + ++ (instancetype)containerWithElement:(SLElement *)element andContainerType:(SLAccessibilityContainerType)accessibilityContainerType +{ + SLAccessibilityContainer *container = [SLAccessibilityContainer elementMatching:^BOOL(NSObject *obj) { + return [element matchesObject:obj]; + } withDescription:@"container"]; + container.containerType = accessibilityContainerType; + return container; +} + ++ (instancetype)containerWithIdentifier:(NSString *)identifer andContainerType:(SLAccessibilityContainerType)accessibilityContainerType +{ + SLAccessibilityContainer *container = [SLAccessibilityContainer elementMatching:^BOOL(NSObject *obj) { + return [[SLElement elementWithAccessibilityIdentifier:identifer] matchesObject:obj]; + } withDescription:@"container"]; + container.containerType = accessibilityContainerType; + return container; +} ++ (instancetype)containerWithLabel:(NSString *)label andContainerType:(SLAccessibilityContainerType)accessibilityContainerType +{ + SLAccessibilityContainer *container = [SLAccessibilityContainer elementMatching:^BOOL(NSObject *obj) { + return [[SLElement elementWithAccessibilityLabel:label] matchesObject:obj]; + } withDescription:@"container"]; + container.containerType = accessibilityContainerType; + return container; +} ++ (instancetype)containerWithLabel:(NSString *)label value:(NSString *)value traits:(UIAccessibilityTraits)traits andContainerType:(SLAccessibilityContainerType)accessibilityContainerType +{ + SLAccessibilityContainer *container = [SLAccessibilityContainer elementMatching:^BOOL(NSObject *obj) { + return [[SLElement elementWithAccessibilityLabel:label value:value traits:traits] matchesObject:obj]; + } withDescription:@"container"]; + container.containerType = accessibilityContainerType; + return container; +} + +- (id)childElementMatching:(SLElement *)childElement +{ + return [SLElement elementMatching:^BOOL(NSObject *obj) { + // first match child element + if ([childElement matchesObject:obj]) { + + id accessibilityParent = [obj slAccessibilityParent]; + + // then look for child element having matching parent + while (accessibilityParent && ![self matchesObject:accessibilityParent]) { + + accessibilityParent = [accessibilityParent slAccessibilityParent]; + + } + Class compareClass; + switch (_containerType) { + case SLAccessibilityContainerTypeTableViewCell: + compareClass = [UITableView class]; + break; + case SLAccessibilityContainerTypeCollectionViewCell: + compareClass = [UICollectionView class]; + break; + case SLAccessibilityContainerTypeNavigationBar: + compareClass = [UINavigationBar class]; + break; + case SLAccessibilityContainerTypeTabBar: + compareClass = [UITabBar class]; + break; + case SLAccessibilityContainerTypeToolbar: + compareClass = [UIToolbar class]; + break; + + default: + compareClass = [UIView class]; + break; + } + if ((_containerType == SLAccessibilityContainerTypeTabBar) || (_containerType == SLAccessibilityContainerTypeNavigationBar) || (_containerType == SLAccessibilityContainerTypeToolbar)) { + return [accessibilityParent isKindOfClass:compareClass]; + } + + + id doubleAccessibilityParent = [accessibilityParent slAccessibilityParent]; + + while (doubleAccessibilityParent && ![doubleAccessibilityParent isKindOfClass:compareClass]) { + doubleAccessibilityParent = [doubleAccessibilityParent slAccessibilityParent]; + } + + if (doubleAccessibilityParent) { + return YES; + } + else { + return NO; + } + + + } + + return NO; + } withDescription:@"searching for child element"]; +} ++ (id)childElementMatching:(SLElement *)childElement inContainerElement:(SLElement *)containerElement ofContainerType:(SLAccessibilityContainerType)accessibilityContainerType +{ + SLAccessibilityContainer *container = [SLAccessibilityContainer containerWithElement:containerElement andContainerType:accessibilityContainerType]; + return [container childElementMatching:childElement]; +} + +@end diff --git a/Sources/Classes/UIAutomation/User Interface Elements/SLElement.m b/Sources/Classes/UIAutomation/User Interface Elements/SLElement.m index 91a765b..f97859f 100644 --- a/Sources/Classes/UIAutomation/User Interface Elements/SLElement.m +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLElement.m @@ -324,6 +324,12 @@ - (BOOL)isValid { they will be visible, and must depend on UIAutomation to confirm visibility. */ - (BOOL)isVisible { + // Temporarily use UIAutomation to check visibility if the device is in a non-portrait orientation + // to work around https://github.com/inkling/Subliminal/issues/135 + if ([UIDevice currentDevice].orientation != UIDeviceOrientationPortrait) { + return [super isVisible]; + } + __block BOOL isVisible = NO; __block BOOL matchedObjectOfUnknownClass = NO; // isVisible evaluates the current state, no waiting to resolve the element @@ -333,7 +339,7 @@ - (BOOL)isVisible { } timeout:0.0]; if (isVisible && matchedObjectOfUnknownClass) { - isVisible = [[self waitUntilTappable:NO thenSendMessage:@"isVisible()"] boolValue]; + isVisible = [super isVisible]; } return isVisible; 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..e3d6ec0 --- /dev/null +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.h @@ -0,0 +1,26 @@ +// +// SLTableViewCell.h +// Subliminal +// +// Created by Jordan Zucker on 4/2/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLAccessibilityContainer.h" + +@interface SLTableViewCell : SLAccessibilityContainer + + ++ (instancetype)cellWithElement:(SLElement *)element; +//+ (instancetype)cellWithElement:(SLElement *)element inTableViewWithIdentifier:(NSString *)identifier; + ++ (instancetype)cellWithIdentifier:(NSString *)identifer; ++ (instancetype)cellWithLabel:(NSString *)label; ++ (instancetype)cellWithLabel:(NSString *)label value:(NSString *)value traits:(UIAccessibilityTraits)traits; + +//+ (instancetype)tableViewCellAtIndexPath:(NSIndexPath *)indexPath; + +//- (id)childElementMatching:(SLElement *)childElement; ++ (id)childElementMatching:(SLElement *)childElement inContainerElement:(SLElement *)containerElement; + +@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..1291cae --- /dev/null +++ b/Sources/Classes/UIAutomation/User Interface Elements/SLTableViewCell.m @@ -0,0 +1,73 @@ +// +// SLTableViewCell.m +// Subliminal +// +// Created by Jordan Zucker on 4/2/14. +// Copyright (c) 2014 Inkling. All rights reserved. +// + +#import "SLTableViewCell.h" +#import "SLUIAElement+Subclassing.h" +#import "NSObject+SLAccessibilityHierarchy.h" + +@implementation SLTableViewCell + ++ (instancetype)cellWithElement:(SLElement *)element +{ + return [SLTableViewCell containerWithElement:element andContainerType:SLAccessibilityContainerTypeTableViewCell]; +} + ++ (instancetype)cellWithIdentifier:(NSString *)identifer +{ + return [SLTableViewCell containerWithIdentifier:identifer andContainerType:SLAccessibilityContainerTypeTableViewCell]; +} ++ (instancetype)cellWithLabel:(NSString *)label +{ + return [SLTableViewCell containerWithLabel:label andContainerType:SLAccessibilityContainerTypeTableViewCell]; +} ++ (instancetype)cellWithLabel:(NSString *)label value:(NSString *)value traits:(UIAccessibilityTraits)traits +{ + return [SLTableViewCell containerWithLabel:label value:value traits:traits andContainerType:SLAccessibilityContainerTypeTableViewCell]; +} ++ (id)childElementMatching:(SLElement *)childElement inContainerElement:(SLElement *)containerElement +{ + return [SLTableViewCell childElementMatching:childElement inContainerElement:containerElement ofContainerType:SLAccessibilityContainerTypeTableViewCell]; +} + +//+ (id)tableViewCellAtIndexPath:(NSIndexPath *)indexPath +//{ +// SLTableViewCell *cell = [SLTableViewCell elementMatching:^BOOL(NSObject *obj) { +// id accessibilityParent = [obj slAccessibilityParent]; +// +// // then look for child element having matching parent +// while (accessibilityParent && ![accessibilityParent isKindOfClass:[UITableView class]]) { +// +// accessibilityParent = [accessibilityParent slAccessibilityParent]; +// +// } +// if ([accessibilityParent isKindOfClass:[UITableView class]]) { +// //NSIndexPath * +// NSLog(@"----------------------------------------------- Properties for object %@", self); +// +// @autoreleasepool { +// unsigned int numberOfProperties = 0; +// objc_property_t *propertyArray = class_copyPropertyList([self class], &numberOfProperties); +// for (NSUInteger i = 0; i < numberOfProperties; i++) { +// objc_property_t property = propertyArray[i]; +// NSString *name = [[NSString alloc] initWithUTF8String:property_getName(property)]; +// NSLog(@"Property %@ Value: %@", name, [self valueForKey:name]); +// SLLogAsync(@"Property %@ Value: %@", name, [self valueForKey:name]); +// } +// free(propertyArray); +// } +// NSLog(@"-----------------------------------------------"); +// return NO; +// //return [indexPath compare:[]]; +// } +// return NO; +// } withDescription:@"container"]; +// cell.containerType = SLTableViewAccessibilityContainer; +// return cell; +//} + +@end diff --git a/Sources/Subliminal.h b/Sources/Subliminal.h index 2942072..c5f70f9 100644 --- a/Sources/Subliminal.h +++ b/Sources/Subliminal.h @@ -28,6 +28,8 @@ #import "SLElement.h" #import "NSObject+SLAccessibilityDescription.h" #import "NSObject+SLAccessibilityHierarchy.h" +#import "SLAccessibilityContainer.h" +#import "SLTableViewCell.h" #import "SLStaticElement.h" #import "SLAlert.h" #import "SLButton.h" diff --git a/Subliminal.xcodeproj/project.pbxproj b/Subliminal.xcodeproj/project.pbxproj index d291a12..5ff5ce7 100644 --- a/Subliminal.xcodeproj/project.pbxproj +++ b/Subliminal.xcodeproj/project.pbxproj @@ -41,6 +41,18 @@ 50F2B7C818E9C0D700F21635 /* SLDispatchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F2B7C718E9C0D700F21635 /* SLDispatchTests.m */; }; 50F3E18C1783A5CB00C6BD1B /* SLGeometry.h in Headers */ = {isa = PBXBuildFile; fileRef = 50F3E18A1783A5CB00C6BD1B /* SLGeometry.h */; }; 50F3E18E1783A60100C6BD1B /* SLGeometry.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F3E18B1783A5CB00C6BD1B /* SLGeometry.m */; }; + 97068F8C18ECB5AF005FE660 /* heart_empty_icon&32.png in Resources */ = {isa = PBXBuildFile; fileRef = 97068F8718ECB5AF005FE660 /* heart_empty_icon&32.png */; }; + 97068F8D18ECB5AF005FE660 /* heart_icon&32.png in Resources */ = {isa = PBXBuildFile; fileRef = 97068F8818ECB5AF005FE660 /* heart_icon&32.png */; }; + 97068F8E18ECB5AF005FE660 /* SLTableViewCellChildElementsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 97068F8918ECB5AF005FE660 /* SLTableViewCellChildElementsTest.m */; }; + 97068F8F18ECB5AF005FE660 /* SLTableViewCellChildElementsTestViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 97068F8A18ECB5AF005FE660 /* SLTableViewCellChildElementsTestViewController.m */; }; + 97068F9018ECB5AF005FE660 /* SLTableViewCellChildElementsTestViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 97068F8B18ECB5AF005FE660 /* SLTableViewCellChildElementsTestViewController.xib */; }; + 97068F9718ECB5EA005FE660 /* SLAccessibilityContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 97068F9518ECB5EA005FE660 /* SLAccessibilityContainer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 97068F9818ECB5EA005FE660 /* SLAccessibilityContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 97068F9618ECB5EA005FE660 /* SLAccessibilityContainer.m */; }; + 97068F9B18ECCFCB005FE660 /* SLTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 97068F9918ECCFCB005FE660 /* SLTableViewCell.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 97068F9C18ECCFCB005FE660 /* SLTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 97068F9A18ECCFCB005FE660 /* SLTableViewCell.m */; }; + 97AC17D718EF2B0F00B42B66 /* SLNavigationBarTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 97AC17D418EF2B0F00B42B66 /* SLNavigationBarTests.m */; }; + 97AC17D818EF2B0F00B42B66 /* SLNavigationBarTestsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 97AC17D518EF2B0F00B42B66 /* SLNavigationBarTestsViewController.m */; }; + 97AC17D918EF2B0F00B42B66 /* SLNavigationBarTestsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 97AC17D618EF2B0F00B42B66 /* SLNavigationBarTestsViewController.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 +286,18 @@ 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 = ""; }; + 97068F8718ECB5AF005FE660 /* heart_empty_icon&32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "heart_empty_icon&32.png"; sourceTree = ""; }; + 97068F8818ECB5AF005FE660 /* heart_icon&32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "heart_icon&32.png"; sourceTree = ""; }; + 97068F8918ECB5AF005FE660 /* SLTableViewCellChildElementsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLTableViewCellChildElementsTest.m; sourceTree = ""; }; + 97068F8A18ECB5AF005FE660 /* SLTableViewCellChildElementsTestViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLTableViewCellChildElementsTestViewController.m; sourceTree = ""; }; + 97068F8B18ECB5AF005FE660 /* SLTableViewCellChildElementsTestViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SLTableViewCellChildElementsTestViewController.xib; sourceTree = ""; }; + 97068F9518ECB5EA005FE660 /* SLAccessibilityContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLAccessibilityContainer.h; sourceTree = ""; }; + 97068F9618ECB5EA005FE660 /* SLAccessibilityContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLAccessibilityContainer.m; sourceTree = ""; }; + 97068F9918ECCFCB005FE660 /* SLTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLTableViewCell.h; sourceTree = ""; }; + 97068F9A18ECCFCB005FE660 /* SLTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLTableViewCell.m; sourceTree = ""; }; + 97AC17D418EF2B0F00B42B66 /* SLNavigationBarTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLNavigationBarTests.m; sourceTree = ""; }; + 97AC17D518EF2B0F00B42B66 /* SLNavigationBarTestsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SLNavigationBarTestsViewController.m; sourceTree = ""; }; + 97AC17D618EF2B0F00B42B66 /* SLNavigationBarTestsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SLNavigationBarTestsViewController.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 +542,28 @@ name = "SLGeometry Tests"; sourceTree = ""; }; + 97068F9418ECB5B2005FE660 /* SLTableViewCellChildElements Tests */ = { + isa = PBXGroup; + children = ( + 97068F8718ECB5AF005FE660 /* heart_empty_icon&32.png */, + 97068F8818ECB5AF005FE660 /* heart_icon&32.png */, + 97068F8918ECB5AF005FE660 /* SLTableViewCellChildElementsTest.m */, + 97068F8A18ECB5AF005FE660 /* SLTableViewCellChildElementsTestViewController.m */, + 97068F8B18ECB5AF005FE660 /* SLTableViewCellChildElementsTestViewController.xib */, + ); + name = "SLTableViewCellChildElements Tests"; + sourceTree = ""; + }; + 97AC17DD18EF2B1B00B42B66 /* SLNavigationBar Tests */ = { + isa = PBXGroup; + children = ( + 97AC17D418EF2B0F00B42B66 /* SLNavigationBarTests.m */, + 97AC17D518EF2B0F00B42B66 /* SLNavigationBarTestsViewController.m */, + 97AC17D618EF2B0F00B42B66 /* SLNavigationBarTestsViewController.xib */, + ); + name = "SLNavigationBar Tests"; + sourceTree = ""; + }; CAC388011641CD4800F995F9 /* Internal */ = { isa = PBXGroup; children = ( @@ -772,6 +818,10 @@ F0695DD8160138DF000B05D0 /* SLUIAElement.m */, F0A04E1B1749F70F002C7520 /* SLElement.h */, F0A04E1C1749F70F002C7520 /* SLElement.m */, + 97068F9518ECB5EA005FE660 /* SLAccessibilityContainer.h */, + 97068F9618ECB5EA005FE660 /* SLAccessibilityContainer.m */, + 97068F9918ECCFCB005FE660 /* SLTableViewCell.h */, + 97068F9A18ECCFCB005FE660 /* SLTableViewCell.m */, F043469D175ACE3A00D91F7F /* NSObject+SLAccessibilityDescription.h */, F043469E175ACE3A00D91F7F /* NSObject+SLAccessibilityDescription.m */, CAC3883D1643503C00F995F9 /* NSObject+SLAccessibilityHierarchy.h */, @@ -896,6 +946,7 @@ F0AC80BE16BB542400C5D5C0 /* Tests */ = { isa = PBXGroup; children = ( + 97068F9418ECB5B2005FE660 /* SLTableViewCellChildElements Tests */, DB2627D817B96704009DA3A6 /* SLStatusBar Tests */, 50A59BD317848CEE002A863A /* SLGeometry Tests */, F07DA31F16E439B7004C2282 /* SLAlert Tests */, @@ -914,6 +965,7 @@ F013798E16D0843B009BAF22 /* SLTerminal Tests */, F078C0431808BF0D000767D2 /* SLWebView Tests */, F089F98E17458B7400DF1F25 /* SLWindow Tests */, + 97AC17DD18EF2B1B00B42B66 /* SLNavigationBar Tests */, ); path = Tests; sourceTree = ""; @@ -1006,8 +1058,10 @@ F0695E1C16014491000B05D0 /* Subliminal.h in Headers */, F0695E1D16014491000B05D0 /* SLTestController.h in Headers */, F0695E1E16014491000B05D0 /* SLTest.h in Headers */, + 97068F9B18ECCFCB005FE660 /* SLTableViewCell.h in Headers */, F0695E1F16014491000B05D0 /* SLTerminal.h in Headers */, F0695E2016014491000B05D0 /* SLUIAElement.h in Headers */, + 97068F9718ECB5EA005FE660 /* SLAccessibilityContainer.h in Headers */, F0695E2116014491000B05D0 /* SLLogger.h in Headers */, F0271AFF162E0B950098F5F2 /* SLTestController+AppHooks.h in Headers */, CAC388051641CD7500F995F9 /* SLStringUtilities.h in Headers */, @@ -1213,15 +1267,19 @@ F0E80D8816DB2CEB00945D25 /* SLElementVisibilityTestElementContainerHidden.xib in Resources */, F0E80D8916DB2CEB00945D25 /* SLElementVisibilityTestElementCovered.xib in Resources */, F0E80D8A16DB2CEB00945D25 /* SLElementVisibilityTestElementOffscreen.xib in Resources */, + 97AC17D918EF2B0F00B42B66 /* SLNavigationBarTestsViewController.xib in Resources */, F043A9BE1729CFFE00A4FD1D /* SLElementVisibilityTestElementHidden.xib in Resources */, F043A9C01729EFD100A4FD1D /* SLElementVisibilityTestUserInteractionDisabled.xib in Resources */, F043A9C7172A160600A4FD1D /* SLElementVisibilityTest.html in Resources */, F08005591730762C00198F6F /* Inklings~iPhone.webarchive in Resources */, F0C4DB4817388ACA00111149 /* SLElementVisibilityTestSuperviewWithVisibleSubview.xib in Resources */, + 97068F8C18ECB5AF005FE660 /* heart_empty_icon&32.png in Resources */, 064B6F55173B13E9004AB1BF /* SLElementVisibilityTestCoveredByClearRegion.xib in Resources */, + 97068F9018ECB5AF005FE660 /* SLTableViewCellChildElementsTestViewController.xib in Resources */, 064B6FC7173DCE9A004AB1BF /* SLElementVisibilityWithSubviews.xib in Resources */, F0C27CDF1741694900335A41 /* SLElementStateTestMidpointCovered.xib in Resources */, F0C27CE917416EC400335A41 /* SLElementStateTestCompletelyCovered.xib in Resources */, + 97068F8D18ECB5AF005FE660 /* heart_icon&32.png in Resources */, F00800C9174B3349001927AC /* SLButtonTestViewController.xib in Resources */, F00F3B5E1778E05100119580 /* SLElementTapTestScrollViewCases.xib in Resources */, F00F3B6717790B4C00119580 /* SLStaticElementTestScrollView.xib in Resources */, @@ -1301,10 +1359,12 @@ CA75E78516697C0000D57E92 /* SLDevice.m in Sources */, F0C07A391703F95B00C93F93 /* SLAlert.m in Sources */, F0C07A481703FEF600C93F93 /* SLButton.m in Sources */, + 97068F9C18ECCFCB005FE660 /* SLTableViewCell.m in Sources */, F0C07A4C1704002100C93F93 /* SLTextField.m in Sources */, F0C07A501704009E00C93F93 /* SLWindow.m in Sources */, F0C07A541704011400C93F93 /* SLKeyboard.m in Sources */, F0C07A58170401E500C93F93 /* SLWebView.m in Sources */, + 97068F9818ECB5EA005FE660 /* SLAccessibilityContainer.m in Sources */, F05C4F91171406EF00A381BC /* SLTerminal+ConvenienceFunctions.m in Sources */, F05C51E6171C8AE000A381BC /* SLMainThreadRef.m in Sources */, F0A04E1E1749F70F002C7520 /* SLElement.m in Sources */, @@ -1323,12 +1383,15 @@ buildActionMask = 2147483647; files = ( 2C903BC017F525E700555317 /* SLSwitchTest.m in Sources */, + 97AC17D818EF2B0F00B42B66 /* SLNavigationBarTestsViewController.m in Sources */, F0AC80A016BB299500C5D5C0 /* main.m in Sources */, F0AC80A416BB299500C5D5C0 /* SLIntegrationTestsAppDelegate.m in Sources */, F0AC80BD16BB50FF00C5D5C0 /* SLTestsViewController.m in Sources */, + 97068F8E18ECB5AF005FE660 /* SLTableViewCellChildElementsTest.m in Sources */, F0AC80C416BC355D00C5D5C0 /* SLTerminalTest.m in Sources */, F0AC80C116BB559F00C5D5C0 /* SLIntegrationTest.m in Sources */, F0AC80C816BC367E00C5D5C0 /* SLTestViewController.m in Sources */, + 97AC17D718EF2B0F00B42B66 /* SLNavigationBarTests.m in Sources */, F078C04A1808BF24000767D2 /* SLWebViewTestViewController.m in Sources */, F0AC80E616BCF91800C5D5C0 /* SLTestCaseViewController.m in Sources */, 06953E3F178FDA7100B3D1B7 /* SLElementTouchAndHoldTest.m in Sources */, @@ -1366,6 +1429,7 @@ DB2627DE17B96727009DA3A6 /* SLStatusBarTest.m in Sources */, F078C0491808BF24000767D2 /* SLWebViewTest.m in Sources */, DB2627DF17B96727009DA3A6 /* SLStatusBarTestViewController.m in Sources */, + 97068F8F18ECB5AF005FE660 /* SLTableViewCellChildElementsTestViewController.m in Sources */, 50A59BD81784908D002A863A /* SLGeometryTest.m in Sources */, 50A59BDB178490C2002A863A /* SLGeometryTestViewController.m in Sources */, );