diff --git a/.gitmodules b/.gitmodules index 4589c97..5d202a0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "Vendor/SSPullToRefresh"] path = Vendor/SSPullToRefresh url = https://github.com/samsoffes/sspulltorefresh.git +[submodule "Vendor/symbiote"] + path = Vendor/symbiote + url = https://github.com/moredip/symbiote.git diff --git a/Cheddar for iOS.xcodeproj/project.pbxproj b/Cheddar for iOS.xcodeproj/project.pbxproj index 6007743..b9d6ecb 100644 --- a/Cheddar for iOS.xcodeproj/project.pbxproj +++ b/Cheddar for iOS.xcodeproj/project.pbxproj @@ -1439,10 +1439,16 @@ ); INFOPLIST_FILE = "Resources/Cheddar-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 5.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(FRANK_LIBRARY_SEARCH_PATHS)", + ); OTHER_CFLAGS = "-DDEBUG"; OTHER_LDFLAGS = ( + "$(inherited)", "-all_load", "-ObjC", + "$(FRANK_LDFLAGS)", ); PRODUCT_NAME = Cheddar; PROVISIONING_PROFILE = ""; diff --git a/Classes/CDIListsViewController.m b/Classes/CDIListsViewController.m index f126dc1..bb573ed 100644 --- a/Classes/CDIListsViewController.m +++ b/Classes/CDIListsViewController.m @@ -64,6 +64,7 @@ - (void)dealloc { - (void)viewDidLoad { [super viewDidLoad]; UIImageView *title = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"nav-title"]]; + title.accessibilityLabel = @"Cheddar"; title.frame = CGRectMake(0.0f, 0.0f, 116.0f, 21.0f); self.navigationItem.titleView = title; self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Lists" style:UIBarButtonItemStyleBordered target:nil action:nil]; diff --git a/Frank/features/overall_flow.feature b/Frank/features/overall_flow.feature new file mode 100644 index 0000000..98983da --- /dev/null +++ b/Frank/features/overall_flow.feature @@ -0,0 +1,15 @@ +Feature: High-level flow through the application + +Background: + Given I launch the app + +Scenario: list creation flow + Given I am on the Lists screen + When I choose to add a list called "Monkeys" + Then I should be on the Tasks screen for the "Monkeys" list + And I should be prompted for my first task + + When I enter a task name of "Bonobo" + And I tap out of task entry mode + Then I should see a tasks list of: + |Bonobo| diff --git a/Frank/features/step_definitions/launch_steps.rb b/Frank/features/step_definitions/launch_steps.rb new file mode 100644 index 0000000..d0673c5 --- /dev/null +++ b/Frank/features/step_definitions/launch_steps.rb @@ -0,0 +1,20 @@ +def app_path + ENV['APP_BUNDLE_PATH'] || (defined?(APP_BUNDLE_PATH) && APP_BUNDLE_PATH) +end + +Given /^I launch the app$/ do + # latest sdk and iphone by default + launch_app app_path +end + +Given /^I launch the app using iOS (\d\.\d)$/ do |sdk| + # You can grab a list of the installed SDK with sim_launcher + # > run sim_launcher from the command line + # > open a browser to http://localhost:8881/showsdks + # > use one of the sdk you see in parenthesis (e.g. 4.2) + launch_app app_path, sdk +end + +Given /^I launch the app using iOS (\d\.\d) and the (iphone|ipad) simulator$/ do |sdk, version| + launch_app app_path, sdk, version +end diff --git a/Frank/features/step_definitions/list_screen_steps.rb b/Frank/features/step_definitions/list_screen_steps.rb new file mode 100644 index 0000000..272d2da --- /dev/null +++ b/Frank/features/step_definitions/list_screen_steps.rb @@ -0,0 +1,7 @@ +Given /^I am on the Lists screen$/ do + ListScreen.new.wait_to_be_on_screen +end + +When /^I choose to add a list called "(.*?)"$/ do |list_name| + ListScreen.new.choose_to_add_a_list( list_name ) +end diff --git a/Frank/features/step_definitions/screens/list_screen.rb b/Frank/features/step_definitions/screens/list_screen.rb new file mode 100644 index 0000000..11a1e2d --- /dev/null +++ b/Frank/features/step_definitions/screens/list_screen.rb @@ -0,0 +1,18 @@ +class ListScreen + include Frank::Cucumber::FrankHelper + + def wait_to_be_on_screen + # kind of a crappy way to tell if we're on the right screen, but it'll do for now + wait_for_element_to_exist( "view:'UINavigationBar' view marked:'Cheddar'" ) + end + + def choose_to_add_a_list(list_name = false) + touch "view:'UINavigationButton' marked:'plus'" + type_new_list_name(list_name) if list_name + end + + def type_new_list_name( list_name ) + type_into_keyboard( list_name ) + end + +end diff --git a/Frank/features/step_definitions/screens/tasks_screen.rb b/Frank/features/step_definitions/screens/tasks_screen.rb new file mode 100644 index 0000000..aa3442e --- /dev/null +++ b/Frank/features/step_definitions/screens/tasks_screen.rb @@ -0,0 +1,37 @@ +class TasksScreen + include Frank::Cucumber::FrankHelper + + def self.with + screen = self.new + screen.wait_to_be_on_screen + yield screen if block_given? + screen + end + + def wait_to_be_on_screen + wait_for_element_to_exist( "view:'UINavigationItemButtonView' marked:'Lists'" ) + end + + def list_name_is(list_name) + element_exists( "view:'UINavigationItemView' marked:'#{list_name}'" ) + end + + def task_text_field_is_first_responder + results = frankly_map( "view:'CDIAddTaskView' view:'SSTextField'", 'isFirstResponder' ) + results.length == 1 && results.first == true + end + + def has_task_list_of expected_task_list + actual_task_list = frankly_map( "view:'CDITaskTableViewCell' view:'CDIAttributedLabel'", "text" ) + actual_task_list.sort == expected_task_list.sort + end + + def task_text_field_resign_first_responder + touch 'tableView' + end + + def type_new_task_name( task_name ) + type_into_keyboard( task_name ) + end + +end diff --git a/Frank/features/step_definitions/tasks_screen_steps.rb b/Frank/features/step_definitions/tasks_screen_steps.rb new file mode 100644 index 0000000..1a52319 --- /dev/null +++ b/Frank/features/step_definitions/tasks_screen_steps.rb @@ -0,0 +1,33 @@ +Then /^I should be on the Tasks screen for the "(.*?)" list$/ do |list_name| + TasksScreen.with do |screen| + wait_until{ screen.list_name_is(list_name) } + end +end + +Then /^I should be prompted for my first task$/ do + TasksScreen.with do |screen| + wait_until{ screen.task_text_field_is_first_responder } + end +end + +Then /^I should see a tasks list of:$/ do |table| + expected_task_list = table.raw.flatten + TasksScreen.with do |screen| + wait_until{ screen.has_task_list_of( expected_task_list ) } + end +end + +When /^I enter a task name of "(.*?)"$/ do |task_name| + TasksScreen.with do |screen| + wait_until{ screen.task_text_field_is_first_responder } + screen.type_new_task_name( task_name ) + end +end + +When /^I tap out of task entry mode$/ do + TasksScreen.with do |screen| + if screen.task_text_field_is_first_responder + screen.task_text_field_resign_first_responder + end + end +end diff --git a/Frank/features/support/env.rb b/Frank/features/support/env.rb new file mode 100644 index 0000000..0c581bd --- /dev/null +++ b/Frank/features/support/env.rb @@ -0,0 +1,8 @@ +require 'frank-cucumber' + +# UIQuery is deprecated. Please use the shelley selector engine. +Frank::Cucumber::FrankHelper.use_shelley_from_now_on + +# This constant must be set to the full, absolute path for your Frankified target's app bundle. +# See the "Given I launch the app" step definition in launch_steps.rb for more details +APP_BUNDLE_PATH = File.expand_path( '../../../frankified_build/Frankified.app', __FILE__ ) diff --git a/Frank/frank_static_resources.bundle b/Frank/frank_static_resources.bundle new file mode 120000 index 0000000..b952fa9 --- /dev/null +++ b/Frank/frank_static_resources.bundle @@ -0,0 +1 @@ +../Vendor/symbiote/ \ No newline at end of file diff --git a/Frank/frankify.xcconfig b/Frank/frankify.xcconfig new file mode 100644 index 0000000..348c1a6 --- /dev/null +++ b/Frank/frankify.xcconfig @@ -0,0 +1,4 @@ +INSTALL_PATH = /./ + +FRANK_LDFLAGS = -all_load -ObjC -framework CFNetwork -framework Security -lShelley -lCocoaHTTPServer -lFrank +GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS = FRANKIFIED diff --git a/Frank/libCocoaHTTPServer.a b/Frank/libCocoaHTTPServer.a new file mode 100644 index 0000000..751c923 Binary files /dev/null and b/Frank/libCocoaHTTPServer.a differ diff --git a/Frank/libFrank.a b/Frank/libFrank.a new file mode 100644 index 0000000..e792cfc Binary files /dev/null and b/Frank/libFrank.a differ diff --git a/Frank/libShelley.a b/Frank/libShelley.a new file mode 100644 index 0000000..e41a7ec Binary files /dev/null and b/Frank/libShelley.a differ diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..5c7120d --- /dev/null +++ b/Gemfile @@ -0,0 +1,5 @@ +source "https://rubygems.org" + +group :test do + gem "frank-cucumber", "~> 0.9.5.pre7" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..1d0b75c --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,57 @@ +GEM + remote: https://rubygems.org/ + specs: + activesupport (3.2.7) + i18n (~> 0.6) + multi_json (~> 1.0) + builder (3.0.0) + cucumber (1.2.1) + builder (>= 2.1.2) + diff-lcs (>= 1.1.3) + gherkin (~> 2.11.0) + json (>= 1.4.6) + diff-lcs (1.1.3) + dnssd (2.0) + frank-cucumber (0.9.5.pre7) + cucumber + dnssd + i18n + json + plist + rspec (>= 2.0) + sim_launcher (= 0.3.8) + thor + xcodeproj + gherkin (2.11.1) + json (>= 1.4.6) + i18n (0.6.0) + json (1.7.4) + multi_json (1.3.6) + plist (3.1.0) + rack (1.4.1) + rack-protection (1.2.0) + rack + rspec (2.11.0) + rspec-core (~> 2.11.0) + rspec-expectations (~> 2.11.0) + rspec-mocks (~> 2.11.0) + rspec-core (2.11.1) + rspec-expectations (2.11.2) + diff-lcs (~> 1.1.3) + rspec-mocks (2.11.1) + sim_launcher (0.3.8) + sinatra + sinatra (1.3.2) + rack (~> 1.3, >= 1.3.6) + rack-protection (~> 1.2) + tilt (~> 1.3, >= 1.3.3) + thor (0.15.4) + tilt (1.3.3) + xcodeproj (0.3.1) + activesupport (~> 3.2.6) + +PLATFORMS + ruby + +DEPENDENCIES + frank-cucumber (~> 0.9.5.pre7) diff --git a/Rakefile b/Rakefile index 666d845..ddc3b3f 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,6 @@ + # let's be nice and not force people to install testing infrastructure if they don't want to +begin require 'cucumber/rake/task' rescue LoadError nil end + class String def self.colorize(text, color_code) "\e[#{color_code}m#{text}\e[0m" @@ -56,3 +59,17 @@ task :'setup:private' do # Done! puts 'Done! You\'re ready to get started!'.green end + +if defined? Cucumber + desc 'build a Frankified version of the app for acceptance testing' + task 'acceptance_build' do + sh 'frank build' + end + + Cucumber::Rake::Task.new(:acceptance_without_build, 'Run Frank acceptance tests') do |t| + t.cucumber_opts = "Frank/features" + end + + desc "rebuild app and run acceptance tests. Use acceptance_without_build if you'd like to skip the rebuild part." + task 'acceptance' => %w{acceptance_build acceptance_without_build} +end diff --git a/Vendor/symbiote b/Vendor/symbiote new file mode 160000 index 0000000..2f022f4 --- /dev/null +++ b/Vendor/symbiote @@ -0,0 +1 @@ +Subproject commit 2f022f4e89ba9462561baf67ddbd0c2f8e621bf6