lib/icuke/cucumber.rb in iCuke-0.5.5 vs lib/icuke/cucumber.rb in iCuke-0.6.0

- old
+ new

@@ -1,14 +1,16 @@ require 'nokogiri' +require 'icuke/sdk' require 'icuke/simulator' require 'icuke/simulate' +require 'icuke/screen' class ICukeWorld include ICuke::Simulate::Gestures - attr_reader :response + attr_reader :response, :simulator def initialize @simulator = ICuke::Simulator.new end @@ -18,87 +20,81 @@ def quit @simulator.quit end - def page - @xml ||= Nokogiri::XML::Document.parse(response).root + def screen + @screen ||= Screen.new(response) end def response @response ||= @simulator.view end def record @simulator.record end - def can_see?(text, scope = '') - page.xpath(%Q{#{scope}//*[contains(., "#{text}") or contains(@label, "#{text}") or contains(@value, "#{text}")]}).any? - end - - def onscreen?(x, y) - return x >= 0 && y >= 0 && x < 320 && y < 480 - end - def tap(label, options = {}, &block) options = { :pause => true }.merge(options) - element = - page.xpath( - %Q{//*[#{trait(:button, :updates_frequently, :keyboard_key)} and @label="#{label}" and frame]}, - %Q{//*[#{trait(:link)} and @value="#{label}" and frame]}, - %Q{//*[@label="#{label}" and frame]} - ).first + element = screen.first_tappable_element(label) + x, y = screen.element_center(element) - raise %Q{No element labelled "#{label}" found in: #{page}} unless element - - # This seems brittle, revist how to fetch the frame without relying on it being the only child - frame = element.child - - x = frame['x'].to_f - y = frame['y'].to_f - - # Hit the element in the middle - x += (frame['width'].to_f / 2) - y += (frame['height'].to_f / 2) - - raise %Q{Element "#{label}" is off screen in: #{page}} unless onscreen?(x, y) - @simulator.fire_event(Tap.new(x, y, options)) sleep(options[:pause] ? 2 : 0.2) refresh yield element if block_given? end def swipe(direction, options = {}) - modifier = [:up, :left].include?(direction) ? -1 : 1 + x, y, x2, y2 = screen.swipe_coordinates(direction) + @simulator.fire_event(Swipe.new(x, y, x2, y2, 0.015, options)) + sleep(1) + refresh + end + + def drag(source_x, source_y, dest_x, dest_y, options = {}) + @simulator.fire_event(Drag.new(source_x, source_y, dest_x, dest_y, 0.15, options)) + sleep(1) + refresh + end + + def drag_with_source(source, destination) + sources = source.split(',').collect {|val| val.strip.to_i} + destinations = destination.split(',').collect {|val| val.strip.to_i} + drag(sources[0], sources[1], destinations[0], destinations[1]) + end + + def drag_slider_to(label, direction, distance) + element = screen.first_slider_element(label) + x, y = screen.find_slider_button(element) - # Just swipe from the middle of an iPhone-dimensioned screen for now - x = 320 / 2 - y = 480 / 2 - x2 = x - y2 = y + dest_x, dest_y = x, y + modifier = direction_modifier(direction) if [:up, :down].include?(direction) - y2 = y + (y * modifier) + dest_y += modifier * distance else - x2 = x + (x * modifier) + dest_x += modifier * distance end - @simulator.fire_event(Swipe.new(x, y, x2, y2, options)) - - sleep(1) - - refresh + drag(x, y, dest_x, dest_y) end - + + def drag_slider_to_percentage(label, percentage) + element = screen.first_slider_element(label) + x, y = screen.find_slider_button(element) + dest_x, dest_y = screen.find_slider_percentage_location(element, percentage) + drag(x, y, dest_x, dest_y) + end + def type(textfield, text, options = {}) tap(textfield, :hold_for => 0.75) do |field| if field['value'] tap('Select All') tap('Delete') @@ -144,70 +140,103 @@ end end end def scroll_to(text, options = {}) + x, y, x2, y2 = screen.swipe_coordinates(swipe_direction(options[:direction])) previous_response = response.dup - while page.xpath(%Q{//*[contains(., "#{text}") or contains(@label, "#{text}") or contains(@value, "#{text}")]}).empty? do - scroll(options[:direction]) - raise %Q{Content "#{text}" not found in: #{page}} if response == previous_response + until screen.visible?(text) do + @simulator.fire_event(Swipe.new(x, y, x2, y2, 0.15, options)) + refresh + raise %Q{Content "#{text}" not found in: #{screen}} if response == previous_response end end def scroll(direction) - swipe_directions = { :up => :down, :down => :up, :left => :right, :right => :left } - swipe(swipe_directions[direction]) + swipe(swipe_direction(direction)) end def set_application_defaults(defaults) @simulator.set_defaults(defaults) end private - def trait(*traits) - "(#{traits.map { |t| %Q{contains(@traits, "#{t}")} }.join(' or ')})" - end - def refresh @response = nil - @xml = nil + @screen = nil end + + def swipe_direction(direction) + swipe_directions = { :up => :down, :down => :up, :left => :right, :right => :left } + swipe_directions[direction] + end + + def direction_modifier(direction) + [:up, :left].include?(direction) ? -1 : 1 + end + end World do ICukeWorld.new end -After do - quit +After do |scenario| + quit unless scenario.failed? end -LIBICUKE = File.expand_path(File.dirname(__FILE__) + '/../../ext/iCuke/libicuke.dylib') - -Given /^(?:"([^\"]*)" from )?"([^\"]*)" is loaded in the simulator(?: using sdk (.*))?$/ do |target, project, sdk| +Given /^(?:"([^\"]*)" from )?"([^\"]*)" is loaded in the (?:(iphone|ipad) )?simulator(?: with SDK ([0-9.]+))?$/ do |target, project, platform, sdk_version| + if sdk_version + ICuke::SDK.use(sdk_version) + elsif platform + ICuke::SDK.use_latest(platform.downcase.to_sym) + else + ICuke::SDK.use_latest + end + launch File.expand_path(project), :target => target, - :env => { 'DYLD_INSERT_LIBRARIES' => LIBICUKE } + :platform => platform, + :env => { + 'DYLD_INSERT_LIBRARIES' => ICuke::SDK.dylib_fullpath + } end +Given /^the module "([^\"]*)" is loaded in the simulator$/ do |path| + path.sub!(/#{File.basename(path)}$/, ICuke::SDK.dylib(File.basename(path))) + simulator.load_module(File.expand_path(path)) +end + Then /^I should see "([^\"]*)"(?: within "([^\"]*)")?$/ do |text, scope| - raise %Q{Content "#{text}" not found in: #{page}} unless can_see?(text, scope) + raise %Q{Content "#{text}" not found in: #{screen.xml}} unless screen.visible?(text, scope) end Then /^I should not see "([^\"]*)"(?: within "([^\"]*)")?$/ do |text, scope| - raise %Q{Content "#{text}" was found but was not expected in: #{page}} if can_see?(text, scope) + raise %Q{Content "#{text}" was found but was not expected in: #{screen.xml}} if screen.visible?(text, scope) end When /^I tap "([^\"]*)"$/ do |label| tap(label) end When /^I type "([^\"]*)" in "([^\"]*)"$/ do |text, textfield| type(textfield, text) end +When /^I drag from (.*) to (.*)$/ do |source, destination| + drag_with_source(source, destination) +end + +When /^I select the "(.*)" slider and drag (.*) pixels (down|up|left|right)$/ do |label, distance, direction| + drag_slider_to(label, direction.to_sym, distance.to_i) +end + +When /^I move the "([^\"]*)" slider to (.*) percent$/ do |label, percent| + drag_slider_to_percentage(label, percent.to_i) +end + When /^I scroll (down|up|left|right)(?: to "([^\"]*)")?$/ do |direction, text| if text scroll_to(text, :direction => direction.to_sym) else scroll(direction.to_sym) @@ -217,7 +246,7 @@ Then /^I put the phone into recording mode$/ do record end Then /^show me the screen$/ do - puts page.to_s + puts screen.xml.to_s end