diff --git a/Frank.xcodeproj/project.pbxproj b/Frank.xcodeproj/project.pbxproj index e8cd93f..30a336e 100644 --- a/Frank.xcodeproj/project.pbxproj +++ b/Frank.xcodeproj/project.pbxproj @@ -200,6 +200,13 @@ remoteGlobalIDString = 305CA782164205F800C4ACE5; remoteInfo = CocoaHTTPServerMac; }; + 3092C0F3189EF7EB00371BF9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C18A5F16160D528C00DC25F6 /* PublicAutomation.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = C194253715D838BD004FC314; + remoteInfo = PublicAutomation; + }; 65DBDDB616A89D97007D3D43 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; @@ -1073,6 +1080,7 @@ buildRules = ( ); dependencies = ( + 3092C0F4189EF7EB00371BF9 /* PBXTargetDependency */, ABA9E46815C81C8D00112290 /* PBXTargetDependency */, ); name = Frank; @@ -1310,6 +1318,11 @@ target = 305CA782164205F800C4ACE5 /* CocoaHTTPServerMac */; targetProxy = 30228E1D1642146F00B1F9E7 /* PBXContainerItemProxy */; }; + 3092C0F4189EF7EB00371BF9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PublicAutomation; + targetProxy = 3092C0F3189EF7EB00371BF9 /* PBXContainerItemProxy */; + }; 65DBDDB716A89D97007D3D43 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 65DBDD7216A89CCA007D3D43 /* CocoaAsyncSocket */; @@ -1342,7 +1355,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + ARCHS = "$(ARCHS_STANDARD)"; COPY_PHASE_STRIP = NO; DSTROOT = /tmp/Frank.dst; GCC_DYNAMIC_NO_PIC = NO; @@ -1351,6 +1364,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = src/Frank_Prefix.pch; INSTALL_PATH = /usr/local/lib; + IPHONEOS_DEPLOYMENT_TARGET = 5.1.1; LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = ( "-ObjC", @@ -1358,7 +1372,7 @@ ); PRODUCT_NAME = Frank; SDKROOT = iphoneos; - USER_HEADER_SEARCH_PATHS = lib/Shelley/Shelley; + USER_HEADER_SEARCH_PATHS = "lib/Shelley/Shelley lib/PublicAutomation\""; }; name = Debug; }; @@ -1366,10 +1380,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = ( - "$(ARCHS_STANDARD_32_BIT)", - armv6, - ); + ARCHS = "$(ARCHS_STANDARD)"; DSTROOT = /tmp/Frank.dst; GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -1382,14 +1393,14 @@ ); PRODUCT_NAME = Frank; SDKROOT = iphoneos; - USER_HEADER_SEARCH_PATHS = lib/Shelley/Shelley; + USER_HEADER_SEARCH_PATHS = "lib/Shelley/Shelley lib/PublicAutomation\""; }; name = Release; }; 1DEB922308733DC00010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + ARCHS = "$(ARCHS_STANDARD)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_OPTIMIZATION_LEVEL = 0; GCC_WARN_ABOUT_RETURN_TYPE = YES; @@ -1403,7 +1414,7 @@ 1DEB922408733DC00010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + ARCHS = "$(ARCHS_STANDARD)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; diff --git a/Frank.xcodeproj/xcshareddata/xcschemes/Frank.xcscheme b/Frank.xcodeproj/xcshareddata/xcschemes/Frank.xcscheme index 0628871..6242d25 100644 --- a/Frank.xcodeproj/xcshareddata/xcschemes/Frank.xcscheme +++ b/Frank.xcodeproj/xcshareddata/xcschemes/Frank.xcscheme @@ -67,6 +67,15 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" allowLocationSimulation = "YES"> + + + + diff --git a/gem/frank-cucumber.gemspec b/gem/frank-cucumber.gemspec index 3a03925..ec0214d 100644 --- a/gem/frank-cucumber.gemspec +++ b/gem/frank-cucumber.gemspec @@ -20,15 +20,15 @@ Gem::Specification.new do |s| s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] - s.add_dependency( "cucumber" ) - s.add_dependency( "rspec", [">=2.0"] ) - s.add_dependency( "sim_launcher", [">=0.4.6"] ) - s.add_dependency( "i18n" ) - s.add_dependency( "plist" ) - s.add_dependency( "json" ) # TODO: figure out how to be more permissive as to which JSON gems we allow - s.add_dependency( "dnssd" ) - s.add_dependency( "thor" ) - s.add_dependency( "xcodeproj", [">=0.5.3"] ) + s.add_dependency( "cucumber", ["~>1.3.10"] ) + s.add_dependency( "rspec", ["~>2.14.1"] ) + s.add_dependency( "sim_launcher", ["~>0.4.6"] ) + s.add_dependency( "i18n", ["~>0.6.9"] ) + s.add_dependency( "plist", ["~>3.1.0"] ) + s.add_dependency( "json", ["1.8.1"] ) # TODO: figure out how to be more permissive as to which JSON gems we allow + s.add_dependency( "dnssd", ["~>2.0"] ) + s.add_dependency( "thor", ["~>0.18.1"] ) + s.add_dependency( "xcodeproj", ["~>0.14.1"] ) s.add_development_dependency( "rr" ) s.add_development_dependency( "yard" ) diff --git a/gem/frank-skeleton/libCocoaAsyncSocket.a b/gem/frank-skeleton/libCocoaAsyncSocket.a index 43a2ec2..2e40d02 100644 Binary files a/gem/frank-skeleton/libCocoaAsyncSocket.a and b/gem/frank-skeleton/libCocoaAsyncSocket.a differ diff --git a/gem/frank-skeleton/libCocoaAsyncSocketMac.a b/gem/frank-skeleton/libCocoaAsyncSocketMac.a index c5787b1..620c1b2 100644 Binary files a/gem/frank-skeleton/libCocoaAsyncSocketMac.a and b/gem/frank-skeleton/libCocoaAsyncSocketMac.a differ diff --git a/gem/frank-skeleton/libCocoaHTTPServer.a b/gem/frank-skeleton/libCocoaHTTPServer.a index 94e1d1e..ebd91a0 100644 Binary files a/gem/frank-skeleton/libCocoaHTTPServer.a and b/gem/frank-skeleton/libCocoaHTTPServer.a differ diff --git a/gem/frank-skeleton/libCocoaHTTPServerMac.a b/gem/frank-skeleton/libCocoaHTTPServerMac.a index e5ae2f3..43971fd 100644 Binary files a/gem/frank-skeleton/libCocoaHTTPServerMac.a and b/gem/frank-skeleton/libCocoaHTTPServerMac.a differ diff --git a/gem/frank-skeleton/libCocoaLumberjack.a b/gem/frank-skeleton/libCocoaLumberjack.a index 3cd2432..46ddcc3 100644 Binary files a/gem/frank-skeleton/libCocoaLumberjack.a and b/gem/frank-skeleton/libCocoaLumberjack.a differ diff --git a/gem/frank-skeleton/libCocoaLumberjackMac.a b/gem/frank-skeleton/libCocoaLumberjackMac.a index a74d7c4..efc9657 100644 Binary files a/gem/frank-skeleton/libCocoaLumberjackMac.a and b/gem/frank-skeleton/libCocoaLumberjackMac.a differ diff --git a/gem/frank-skeleton/libFrank.a b/gem/frank-skeleton/libFrank.a index b94040f..a3fa853 100644 Binary files a/gem/frank-skeleton/libFrank.a and b/gem/frank-skeleton/libFrank.a differ diff --git a/gem/frank-skeleton/libFrankMac.a b/gem/frank-skeleton/libFrankMac.a index d6f12dc..3642294 100644 Binary files a/gem/frank-skeleton/libFrankMac.a and b/gem/frank-skeleton/libFrankMac.a differ diff --git a/gem/frank-skeleton/libShelley.a b/gem/frank-skeleton/libShelley.a index 7f7ab37..715dc2a 100644 Binary files a/gem/frank-skeleton/libShelley.a and b/gem/frank-skeleton/libShelley.a differ diff --git a/gem/frank-skeleton/libShelleyMac.a b/gem/frank-skeleton/libShelleyMac.a index 2aec0dc..407da29 100644 Binary files a/gem/frank-skeleton/libShelleyMac.a and b/gem/frank-skeleton/libShelleyMac.a differ diff --git a/gem/lib/frank-cucumber/cli.rb b/gem/lib/frank-cucumber/cli.rb index 2d67dfb..cbe7b8e 100644 --- a/gem/lib/frank-cucumber/cli.rb +++ b/gem/lib/frank-cucumber/cli.rb @@ -167,6 +167,7 @@ def build_and_launch desc "launch", "open the Frankified app in the simulator" method_option :debug, :type => :boolean, :default => false method_option :idiom, :banner => 'iphone|ipad', :type => :string, :default => (ENV['FRANK_SIM_IDIOM'] || 'iphone') + method_option :sdk, :type => :string, :default => nil def launch $DEBUG = options[:debug] version = case options[:idiom].downcase @@ -188,7 +189,7 @@ def launch say "LAUNCHING APP..." - launch_app(frankified_app_dir, nil, version, false) + launch_app(frankified_app_dir, options[:sdk], version, false) end end diff --git a/gem/lib/frank-cucumber/core_frank_steps.rb b/gem/lib/frank-cucumber/core_frank_steps.rb index 4e6985b..3907ae4 100644 --- a/gem/lib/frank-cucumber/core_frank_steps.rb +++ b/gem/lib/frank-cucumber/core_frank_steps.rb @@ -20,19 +20,19 @@ Then /^I should see a navigation bar titled "([^\"]*)"$/ do |expected_mark| quote = get_selector_quote(expected_mark) - check_element_exists( "navigationItemView marked:#{quote}#{expected_mark}#{quote}" ) + quoted_text = "#{quote}#{expected_mark}#{quote}" + navigation_title_exists_with_text("#{quoted_text}").should be_true, "expected to see a navigation bar titled #{quoted_text}" end -Then /^I wait to see a navigation bar titled "([^\"]*)"$/ do |expected_mark| - quote = get_selector_quote(expected_mark) - wait_until( :timeout => 30, :message => "waited to see a navigation bar titled #{quote}#{expected_mark}#{quote}" ) { - element_exists( "navigationItemView marked:#{quote}#{expected_mark}#{quote}" ) - } +Then /^I wait to see a navigation bar titled "([^\"]*)"$/ do |expected_title| + wait_until(message: "waited to see a navigation bar titled #{quoted_text}") do + navigation_title_with_text_exists(expected_title) + end end Then /^I wait to not see a navigation bar titled "([^\"]*)"$/ do |expected_mark| quote = get_selector_quote(expected_mark) - wait_until( :timeout => 30, :message => "waited to not see a navigation bar titled #{quote}#{expected_mark}#{quote}" ) { + wait_until( :message => "waited to not see a navigation bar titled #{quote}#{expected_mark}#{quote}" ) { !element_exists( "navigationItemView marked:#{quote}#{expected_mark}#{quote}" ) } end @@ -66,7 +66,11 @@ end Then /^I should see an alert view titled "([^\"]*)"$/ do |expected_mark| - values = frankly_map( 'alertView', 'title') + if frankly_os_version.to_f >= 7.0 + values = frankly_map( "view:'_UIModalItemRepresentationView' label", 'text') + else + values = frankly_map( 'alertView', 'title') + end values.should include(expected_mark) end @@ -76,7 +80,11 @@ end Then /^I should not see an alert view$/ do - check_element_does_not_exist( 'alertView' ) + if frankly_os_version.to_f >= 7.0 + check_element_does_not_exist( '_UIModalItemRepresentationView' ) + else + check_element_does_not_exist( 'alertView' ) + end end Then /^I should see an element of class "([^\"]*)" with name "([^\"]*)" with the following labels: "([^\"]*)"$/ do |className, classLabel, listOfLabels| diff --git a/gem/lib/frank-cucumber/frank_helper.rb b/gem/lib/frank-cucumber/frank_helper.rb index 2c91374..433c503 100644 --- a/gem/lib/frank-cucumber/frank_helper.rb +++ b/gem/lib/frank-cucumber/frank_helper.rb @@ -155,6 +155,25 @@ def view_with_mark_exists(expected_mark) element_exists( "view marked:#{quote}#{expected_mark}#{quote}" ) end + # Indicate whether the title of the navigation bar matches the expected title. + # @param [String] expected_title the expected title of the navigation bar + # @return [Boolean] + def navigation_title_with_text_exists(expected_title) + quoted_text = "#{quote}#{expected_title}#{quote}" + + navFrame = frankly_map('view:"UINavigationBar"', 'frame').first + navCenter = navFrame["size"]["width"] / 2.0 + + frame = frankly_map("view:'UINavigationBar' view:'UINavigationItemView' marked:#{quoted_text}", 'frame').first + return false unless frame && frame["origin"] && frame["size"] + + left = frame["origin"]["x"] + right = frame["origin"]["x"] + frame["size"]["width"] + return false unless left && right && left < right + + (left < navCenter) && (navCenter < right) + end + # Assert whether there are any views in the current view heirarchy which contain the specified accessibility label. # @param [String] expected_mark the expected accessibility label # @raise an rspec exception if the assertion fails @@ -173,6 +192,26 @@ def check_view_with_mark_does_not_exist(expected_mark) check_element_does_not_exist( "view marked:#{quote}#{expected_mark}#{quote}" ) end + # Assert the title of the navigation bar. + # @param [String] expected_title the expected title of the navigation bar + # @raise an rspec exception if the assertion fails + # @raise an rspec exception if the navigation bar and its subview `UINavigationItemView` cannot be found + # @raise an rspec exception if the `UINavigationItemView` does not cover the center x of the navigation bar + def check_navigation_title_with_text_exists(expected_title) + quoted_text = "#{quote}#{expected_title}#{quote}" + + navFrame = frankly_map('view:"UINavigationBar"', 'frame').first + navCenter = navFrame["size"]["width"] / 2.0 + + frame = frankly_map("view:'UINavigationBar' view:'UINavigationItemView' marked:#{quoted_text}", 'frame').first + raise "Could not find navigation bar with title (#{expected_title})" unless frame && frame["origin"] && frame["size"] + + left = frame["origin"]["x"] + right = frame["origin"]["x"] + frame["size"]["width"] + raise "Expected title (#{expected_title}) not in center of navigation bar" unless left && right && left < right + + ((left < navCenter) && (navCenter < right)).should be_true, "Could not find navigation title in center of navigation bar matching text (#{expected_title})" + end # Waits for any of the specified selectors to match a view. # diff --git a/gem/lib/frank-cucumber/version.rb b/gem/lib/frank-cucumber/version.rb index 87d6660..4bbf4d7 100644 --- a/gem/lib/frank-cucumber/version.rb +++ b/gem/lib/frank-cucumber/version.rb @@ -1,5 +1,5 @@ module Frank module Cucumber - VERSION = "1.2.2" + VERSION = "1.2.5" end end diff --git a/src/AccessibilityCheckCommand.m b/src/AccessibilityCheckCommand.m index cb6d2ff..8d35d8e 100644 --- a/src/AccessibilityCheckCommand.m +++ b/src/AccessibilityCheckCommand.m @@ -29,15 +29,15 @@ + (BOOL) accessibilitySeemsToBeTurnedOn { #if __MAC_OS_X_VERSION_MAX_ALLOWED < 1090 -extern Boolean AXIsProcessTrustedWithOptions(CFDictionaryRef options); -extern CFStringRef kAXTrustedCheckOptionPrompt; +extern Boolean AXIsProcessTrustedWithOptions(CFDictionaryRef options) __attribute__((weak_import)); +extern CFStringRef kAXTrustedCheckOptionPrompt __attribute__((weak_import)); #endif // __MAC_OS_X_VERSION_MAX_ALLOWED < 1090 + (BOOL) accessibilitySeemsToBeTurnedOn { BOOL returnValue = NO; - if (AXIsProcessTrusted != NULL) + if (AXIsProcessTrustedWithOptions != NULL) { NSDictionary* options = @{ (id) kAXTrustedCheckOptionPrompt : @YES }; return AXIsProcessTrustedWithOptions((CFDictionaryRef) options); diff --git a/src/FrankLoader.m b/src/FrankLoader.m index b95727e..617ce57 100644 --- a/src/FrankLoader.m +++ b/src/FrankLoader.m @@ -25,13 +25,13 @@ @implementation FrankLoader + (void)applicationDidBecomeActive:(NSNotification *)notification{ + static dispatch_once_t frankDidBecomeActiveToken; #if TARGET_OS_IPHONE - FrankServer *server = [[FrankServer alloc] initWithDefaultBundle]; - [server startServer]; - + dispatch_once(&frankDidBecomeActiveToken, ^{ + FrankServer *server = [[FrankServer alloc] initWithDefaultBundle]; + [server startServer]; + }); #else - static dispatch_once_t frankDidBecomeActiveToken; - dispatch_once(&frankDidBecomeActiveToken, ^{ FrankServer *server = [[FrankServer alloc] initWithDefaultBundle]; [server startServer]; @@ -86,6 +86,26 @@ + (void)load{ selector:@selector(applicationDidBecomeActive:) name:notificationName object:nil]; + +#if TARGET_OS_IPHONE + NSArray *iOSVersionComponents = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:@"."]; + int majorVersion = [[iOSVersionComponents objectAtIndex:0] intValue]; + + if (majorVersion >= 9) + { + // iOS9 is installed. The UIApplicationDidBecomeActiveNotification may have been fired *before* + // this code is called. + // See also: + // http://stackoverflow.com/questions/31785878/ios-9-uiapplicationdidbecomeactivenotification-callback-not-called + + // Call applicationDidBecomeActive: after 0.5 second. + // Delay execution of my block for 10 seconds. + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 500 * USEC_PER_SEC), dispatch_get_main_queue(), ^{ + NSLog(@"Forcefully invoking applicationDidBecomeActive"); + [FrankLoader applicationDidBecomeActive:nil]; + }); + } +#endif } @end diff --git a/src/MapOperationCommand.m b/src/MapOperationCommand.m index eadd139..27b5de9 100644 --- a/src/MapOperationCommand.m +++ b/src/MapOperationCommand.m @@ -58,7 +58,15 @@ - (NSString *)handleCommandWithRequestBody:(NSString *)requestBody { for (FrankMapViewType *view in viewsToMap) { @try { id result = [self performOperation:operation onView:view]; - [results addObject:[ViewJSONSerializer jsonify:result]]; + NSString *resultValue = [ViewJSONSerializer jsonify:result]; + + // Can't add nil objects to an array. + if(resultValue == nil) + { + resultValue = @""; + } + + [results addObject:resultValue]; } @catch (NSException * e) { NSLog( @"Exception while performing operation %@\n%@", operation, e ); diff --git a/src/OrientationCommand.m b/src/OrientationCommand.m index 51de2f5..df5128b 100644 --- a/src/OrientationCommand.m +++ b/src/OrientationCommand.m @@ -83,7 +83,7 @@ - (NSString *)getOrientationDescriptionViaDevice{ - (NSString *)handleGet{ NSDictionary *orientationDescription = [self getOrientationRepresentationViaDevice]; if( !orientationDescription ) - orientationDescription = [self getOrientationRepresentationViaDevice]; + orientationDescription = [self getOrientationRepresentationViaStatusBar]; return TO_JSON(orientationDescription); }