lib/calabash-android/operations.rb in calabash-android-0.4.22.pre4 vs lib/calabash-android/operations.rb in calabash-android-0.5.0.pre1

- old
+ new

@@ -47,10 +47,24 @@ def set_default_device(device) @default_device = device end def performAction(action, *arguments) + puts "Warning: The method performAction is deprecated. Please use perform_action instead." + + perform_action(action, *arguments) + end + + def perform_action(action, *arguments) + @removed_actions = File.readlines(File.join(File.dirname(__FILE__), 'removed_actions.txt')) unless @removed_actions + @removed_actions.map! &:chomp + + if @removed_actions.include?(action) + puts "Error: The action '#{action}' was removed in calabash-android x.x.x" + puts 'For more information visit: https://github.com/calabash-android/foo/bar' + end + default_device.perform_action(action, *arguments) end def reinstall_apps default_device.reinstall_apps @@ -132,11 +146,17 @@ def query(uiquery, *args) converted_args = [] args.each do |arg| if arg.is_a?(Hash) and arg.count == 1 - converted_args << {:method_name => arg.keys.first, :arguments => [ arg.values.first ]} + if arg.values.is_a?(Array) && arg.values.count == 1 + values = arg.values.flatten + else + values = [arg.values] + end + + converted_args << {:method_name => arg.keys.first, :arguments => values} else converted_args << arg end end map(uiquery,:query,*converted_args) @@ -391,11 +411,11 @@ end File.open(path, 'wb') do |f| f.write res end else - screenshot_cmd = "java -jar #{File.join(File.dirname(__FILE__), 'lib', 'screenshotTaker.jar')} #{serial} #{path}" + screenshot_cmd = "java -jar #{File.join(File.dirname(__FILE__), 'lib', 'screenshotTaker.jar')} #{serial} \"#{path}\"" log screenshot_cmd raise "Could not take screenshot" unless system(screenshot_cmd) end @@screenshot_count += 1 @@ -702,54 +722,94 @@ screenshot_embed end raise(msg) end + def has_text?(text) + !query("* {text CONTAINS[c] '#{text}'}").empty? + end + + def assert_text(text, should_find = true) + raise "Text \"#{text}\" was #{should_find ? 'not ' : ''}found." if has_text?(text) ^ should_find + + true + end + def double_tap(uiquery, options = {}) center_x, center_y = find_coordinate(uiquery) - performAction("double_tap_coordinate", center_x, center_y) + perform_action("double_tap_coordinate", center_x, center_y) end + # Performs a "long press" operation on a selected view + # Params: + # +uiquery+: a uiquery identifying one view + # +options[:length]+: the length of the long press in milliseconds (optional) + # + # Examples: + # - long_press("* id:'my_id'") + # - long_press("* id:'my_id'", {:length=>5000}) def long_press(uiquery, options = {}) center_x, center_y = find_coordinate(uiquery) - - performAction("long_press_coordinate", center_x, center_y) + length = options[:length] + perform_action("long_press_coordinate", center_x, center_y, *(length unless length.nil?)) end def touch(uiquery, options = {}) center_x, center_y = find_coordinate(uiquery) - performAction("touch_coordinate", center_x, center_y) + perform_action("touch_coordinate", center_x, center_y) end def keyboard_enter_text(text, options = {}) - performAction('keyboard_enter_text', text) + perform_action('keyboard_enter_text', text) end def enter_text(uiquery, text, options = {}) - touch(uiquery, options) + tap_when_element_exists(uiquery, options) sleep 0.5 keyboard_enter_text(text, options) end + def clear_text(query_string, options={}) + result = query(query_string, setText: '') + + raise "No elements found. Query: #{query_string}" if result.empty? + + true + end + def find_coordinate(uiquery) raise "Cannot find nil" unless uiquery + element = execute_uiquery(uiquery) + + raise "No elements found. Query: #{uiquery}" if element.nil? + + center_x = element["rect"]["center_x"] + center_y = element["rect"]["center_y"] + + [center_x, center_y] + end + + def execute_uiquery(uiquery) if uiquery.instance_of? String elements = query(uiquery) - raise "No elements found. Query: #{uiquery}" if elements.empty? - element = elements.first + + return elements.first unless elements.empty? else - element = uiquery - element = element.first if element.instance_of?(Array) + elements = uiquery + + return elements.first if elements.instance_of?(Array) + return elements if elements.instance_of?(Hash) end - center_x = element["rect"]["center_x"] - center_y = element["rect"]["center_y"] + nil + end - [center_x, center_y] + def step_deprecated + puts 'Warning: This predefined step is deprecated.' end def http(path, data = {}, options = {}) default_device.http(path, data, options) end @@ -757,21 +817,57 @@ def html(q) query(q).map {|e| e['html']} end def set_text(uiquery, txt) - view,arguments = uiquery.split(" ",2) - raise "Currently queries are only supported for webviews" unless view.downcase == "webview" + puts "set_text is deprecated. Use enter_text instead" + enter_text(uiquery, txt) + end - if arguments =~ /(css|xpath):\s*(.*)/ - r = performAction("set_text", $1, $2, txt) + def press_back_button + perform_action('go_back') + end + + def press_menu_button + perform_action('press_menu') + end + + def select_options_menu_item(text, options={}) + press_menu_button + tap_when_element_exists("DropDownListView * marked:'#{text}'", options) + end + + def select_context_menu_item(view_uiquery, menu_item_query_string) + long_press(view_uiquery) + + container_class = 'com.android.internal.view.menu.ListMenuItemView' + wait_for_element_exists(container_class) + + combined_query_string = "#{container_class} descendant #{menu_item_query_string}" + touch(combined_query_string) + end + + def tap_when_element_exists(query_string, options={}) + options.merge!({action: lambda {|q| touch(q)}}) + + if options[:scroll] == true + scroll_to(query_string, options) else - raise "Invalid query #{arguments}" + when_element_exists(query_string, options) end end + def long_press_when_element_exists(query_string, options={}) + options.merge!({action: lambda {|q| long_press(q)}}) + if options[:scroll] == true + scroll_to(query_string, options) + else + when_element_exists(query_string, options) + end + end + def swipe(dir,options={}) ni end def cell_swipe(options={}) @@ -780,14 +876,88 @@ def done ni end - def scroll(uiquery,direction) - ni + def scroll_up + scroll("android.widget.ScrollView", :up) end + def scroll_down + scroll("android.widget.ScrollView", :down) + end + + def scroll(query_string, direction) + if direction != :up && direction != :down + raise 'Only upwards and downwards scrolling is supported for now' + end + + scroll_x = 0 + scroll_y = 0 + + action = lambda do + element = query(query_string).first + raise "No elements found. Query: #{query_string}" if element.nil? + + width = element['rect']['width'] + height = element['rect']['height'] + + if direction == :up + scroll_y = -height/2 + else + scroll_y = height/2 + end + + query(query_string, {scrollBy: [scroll_x.to_i, scroll_y.to_i]}) + end + + when_element_exists(query_string, action: action) + end + + def scroll_to(query_string, options={}) + options[:action] ||= lambda {} + + all_query_string = query_string + + unless all_query_string.chomp.downcase.start_with?('all') + all_query_string = "all #{all_query_string}" + end + + wait_for_element_exists(all_query_string) + + visibility_query_string = all_query_string[4..-1] + + unless query(visibility_query_string).empty? + when_element_exists(visibility_query_string, options) + return + end + + element = query(all_query_string).first + raise "No elements found. Query: #{all_query_string}" if element.nil? + element_center_y = element['rect']['center_y'] + + scroll_view_query_string = "#{all_query_string} parent android.widget.ScrollView index:0" + scroll_element = query(scroll_view_query_string).first + + raise "Could not find parent scroll view. Query: #{scroll_view_query_string}" if element.nil? + + scroll_element_y = scroll_element['rect']['y'] + scroll_element_height = scroll_element['rect']['height'] + + if element_center_y > scroll_element_y + scroll_element_height + scroll_by_y = element_center_y - (scroll_element_y + scroll_element_height) + 2 + else + scroll_by_y = element_center_y - scroll_element_y - 2 + end + + result = query(scroll_view_query_string, {scrollBy: [0, scroll_by_y.to_i]}).first + raise 'Could not scroll parent view' if result != '<VOID>' + + visibility_query_string = all_query_string[4..-1] + when_element_exists(visibility_query_string, options) + end + def scroll_to_row(uiquery,number) query(uiquery, {:smoothScrollToPosition => number}) puts "TODO:detect end of scroll - use sleep for now" end @@ -856,10 +1026,16 @@ def record_end(file_name) ni end def backdoor(sel, arg) - ni + result = perform_action("backdoor", sel, arg) + if !result["success"] + screenshot_and_raise(result["message"]) + end + + # for android results are returned in bonusInformation + result["bonusInformation"].first end def map(query, method_name, *method_args) operation_map = { :method_name => method_name,