require 'edn'
require 'json'
module Calabash
module Cucumber
module UIA
def uia(command,options={})
res = http({:method => :post, :path => 'uia'}, {:command => command}.merge(options))
res = JSON.parse(res)
if res['outcome'] != 'SUCCESS'
raise "uia action failed because: #{res['reason']}\n#{res['details']}"
end
res['results'].first
end
def uia_query(*queryparts)
#TODO escape '\n etc in query
uia_handle_command(:query, queryparts)
end
def uia_query_el(*queryparts)
#TODO escape '\n etc in query
uia_handle_command(:queryEl, queryparts)
end
def uia_query_windows(*queryparts)
#TODO escape '\n etc in query
uia_handle_command(:queryWindows, queryparts)
end
def uia_names(*queryparts)
#TODO escape '\n etc in query
uia_handle_command(:names, queryparts)
end
def uia_tap(*queryparts)
uia_handle_command(:tap, queryparts)
end
def uia_tap_mark(mark)
uia_handle_command(:tapMark, mark)
end
def uia_tap_offset(offset)
uia_handle_command(:tapOffset, offset)
end
def uia_double_tap(*queryparts)
uia_handle_command(:doubleTap, queryparts)
end
def uia_double_tap_mark(mark)
uia_double_tap(:view, {:marked => mark})
end
def uia_double_tap_offset(offset)
uia_handle_command(:doubleTapOffset, offset)
end
def uia_two_finger_tap(*queryparts)
uia_handle_command(:twoFingerTap, queryparts)
end
def uia_two_finger_tap_offset(offset)
uia_handle_command(:twoFingerTapOffset, offset)
end
def uia_flick_offset(from, to)
uia_handle_command(:flickOffset, from, to)
end
def uia_touch_hold(duration, *queryparts)
uia_handle_command(:touchHold, duration, queryparts)
end
def uia_touch_hold_offset(duration, offset)
uia_handle_command(:touchHoldOffset, duration, offset)
end
def uia_pan(from_q, to_q)
uia_handle_command(:pan, from_q, to_q)
end
def uia_pan_offset(from, to, options)
uia_handle_command(:panOffset, from, to, options)
end
def uia_swipe(*queryparts)
uia_handle_command(:swipe, queryparts)
end
def uia_swipe_offset(offset, options)
uia_handle_command(:swipeOffset, offset, options)
end
def uia_pinch(*queryparts)
uia_handle_command(:pinch, queryparts)
end
def uia_pinch_offset(in_or_out, offset, duration)
uia_handle_command(:pinchOffset, in_or_out, offset, duration)
end
def uia_scroll_to(*queryparts)
uia_handle_command(:scrollTo, queryparts)
end
def uia_element_exists?(*queryparts)
uia_handle_command(:elementExists, queryparts)
end
def uia_element_does_not_exist?(*queryparts)
uia_handle_command(:elementDoesNotExist, queryparts)
end
def uia_screenshot(name)
uia_handle_command(:screenshot, name)
end
def uia_type_string(string)
res = uia_handle_command(:typeString, string)
status = res['status']
if status.eql?('error')
value = res['value']
raise "could not type '#{string}' - '#{value}'"
end
end
def uia_enter
uia_handle_command(:enter)
end
def uia_set_location(options)
validate_hash_is_location!(options)
if options[:place]
place = options[:place]
search_results = Geocoder.search(place)
raise "Got no results for #{place}" if search_results.empty?
loc = search_results.first
loc_data = {'latitude'=>loc.latitude, 'longitude'=>loc.longitude}
elsif options.is_a?(Hash)
loc_data = options
end
uia_handle_command(:setLocation, loc_data)
end
def uia_send_app_to_background(secs)
uia_handle_command(:deactivate, secs)
end
def uia_call(args_arr, *opts)
uia_call_method(:queryEl, args_arr, *opts)
end
def uia_call_method(cmd, args_arr, *opts)
if opts.empty?
return uia_handle_command(cmd, args_arr)
end
js_cmd = uia_serialize_command(cmd, args_arr)
js_args = []
opts.each do |invocation|
js_args << case invocation
when Symbol
"#{invocation}()"
when Hash
m = invocation.keys.first
args = invocation[m]
if args.is_a?(Array)
serialized_args = (args.map &:to_json).join(',')
else
serialized_args = args.to_json
end
"#{m}(#{serialized_args})"
else
raise "Invalid invocation spec #{invocation}"
end
end
command = "#{js_cmd}.#{js_args.join('.')}"
if ENV['DEBUG'] == '1'
puts 'Sending UIA command'
puts command
end
uia_result(uia(command))
end
def uia_handle_command(cmd, *query_args)
command = uia_serialize_command(cmd, *query_args)
if ENV['DEBUG'] == '1'
puts 'Sending UIA command'
puts command
end
s = uia(command)
uia_result(s)
end
def uia_serialize_command(cmd, *query_args)
args = uia_serialize_arguments(query_args)
%Q[uia.#{cmd}(#{args.join(', ')})]
end
def uia_serialize_arguments(args)
args.map do |part|
uia_serialize_argument(part)
end
end
def uia_serialize_argument(part)
if part.is_a?(String)
"'#{escape_uia_string(part)}'"
else
"'#{escape_uia_string(part.to_edn)}'"
end
end
def escape_uia_string(string)
#TODO escape '\n in query
escape_quotes string
end
# DEPRECATED: Use uia("...javascript..", options) instead.
# deprecated because the method signature is poor
def send_uia_command(opts ={})
# TODO formally deprecate send_uia_command with _deprecated function
#cmd = opts[:command]
#new_opts = cmd.select{|x| x != :command}
#_deprecated('0.9.163',
# "use 'uia(#{cmd}, #{new_opts})' instead",
# :warn)
uia(opts[:command], opts)
end
private
def validate_hash_is_location!(options)
return if options[:latitude] and options[:longitude]
if (options[:latitude] and not options[:longitude]) ||
(options[:longitude] and not options[:latitude])
raise 'Both latitude and longitude must be specified if either is.'
elsif not options[:place]
raise 'Either :place or :latitude and :longitude must be specified.'
end
end
def uia_result(s)
if ENV['DEBUG'] == '1'
puts 'Result'
p s
end
if s['status'] == 'success'
s['value']
else
s
end
end
end
end
end