Class: Appium::Driver

Inherits:
Object
  • Object
show all
Defined in:
lib/appium_lib/driver.rb,
lib/appium_lib/android/dynamic.rb

Constant Summary collapse

@@loaded =
false
@@map =
{
  1 => [ 'text(String text)', 'SELECTOR_TEXT', 1],
  2 => [ 'textStartsWith(String text)', 'SELECTOR_START_TEXT', 2],
  3 => [ 'textContains(String text)', 'SELECTOR_CONTAINS_TEXT', 3],
  4 => [ 'className(String className)', 'SELECTOR_CLASS', 4],
  5 => [ 'description(String desc)', 'SELECTOR_DESCRIPTION',  5],
  6 => [ 'descriptionStartsWith(String desc)', 'SELECTOR_START_DESCRIPTION', 6],
  7 => [ 'descriptionContains(String desc)', 'SELECTOR_CONTAINS_DESCRIPTION', 7],
  8 => [ 'index(final int index)', 'SELECTOR_INDEX', 8],
  9 => [ 'instance(final int instance)', 'SELECTOR_INSTANCE', 9],
  10 => [ 'enabled(boolean val)', 'SELECTOR_ENABLED', 10],
  11 => [ 'focused(boolean val)', 'SELECTOR_FOCUSED', 11],
  12 => [ 'focusable(boolean val)', 'SELECTOR_FOCUSABLE', 12],
  13 => [ 'scrollable(boolean val)', 'SELECTOR_SCROLLABLE', 13],
  14 => [ 'clickable(boolean val)', 'SELECTOR_CLICKABLE', 14],
  15 => [ 'checked(boolean val)', 'SELECTOR_CHECKED', 15],
  16 => [ 'selected(boolean val)', 'SELECTOR_SELECTED',  16],
  # // SELECTOR_ID = 17; // nothing.
  18 => [ 'packageName(String name)', 'SELECTOR_PACKAGE_NAME', 18],
  # // SELECTOR_CHILD              = 19; // childSelector(UiSelector selector)
  # // SELECTOR_CONTAINER          = 20; // containerSelector(UiSelector selector)
  # // SELECTOR_PATTERN            = 21; // ! private ! patternSelector(UiSelector selector)
  # // SELECTOR_PARENT             = 22; // fromParent(UiSelector selector)
  # // SELECTOR_COUNT              = 23; // nothing.
  24 => [ 'longClickable(boolean val)', 'SELECTOR_LONG_CLICKABLE', 24],
  25 => [ 'textMatches(String regex)', 'SELECTOR_TEXT_REGEX', 25],
  26 => [ 'classNameMatches(String regex)', 'SELECTOR_CLASS_REGEX', 26],
  27 => [ 'descriptionMatches(String regex)', 'SELECTOR_DESCRIPTION_REGEX', 27],
  28 => [ 'packageNameMatches(String regex)', 'SELECTOR_PACKAGE_NAME_REGEX', 28],
  # // start internal methods at 100
  100 => [ 'getStringAttribute("name")', 'GET_NAME', 100]
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Driver

Creates a new driver.

“‘ruby # Options include: :app_path, :app_name, :app_package, :app_activity, :app_wait_activity, :sauce_username, :sauce_access_key, :port, :os, :debug

require ‘rubygems’ require ‘appium_lib’

# Start iOS driver app = { app_path: ‘/path/to/MyiOS.app’} Appium::Driver.new(app).start_driver

# Start Android driver apk = { app_path: ‘/path/to/the.apk’,

app_package: 'com.example.pkg',
app_activity: 'act.Start',
app_wait_activity: 'act.Start'

}

Appium::Driver.new(apk).start_driver “‘

Parameters:

  • opts (Object) (defaults to: {})

    A hash containing various options.



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/appium_lib/driver.rb', line 117

def initialize opts={}
  # quit last driver
  $driver.driver_quit if $driver
  opts = {} if opts.nil?
  # convert to downcased symbols
  opts.each_pair { |k,v| opts[k.to_s.downcase.strip.intern] = v }

  @default_wait = opts.fetch :wait, 30

  # Path to the .apk, .app or .app.zip.
  # The path can be local or remote for Sauce.
  @app_path = opts.fetch :app_path, ENV['APP_PATH']
  raise 'APP_PATH must be set.' if @app_path.nil?

  # The name to use for the test run on Sauce.
  @app_name = opts.fetch :app_name, ENV['APP_NAME']

  # If Android, this will toggle selendroid as a device
  @selendroid = opts.fetch :selendroid, ENV['SELENDROID']
  @selendroid = 'selendroid' if @selendroid

  # Android app package
  @app_package = opts.fetch :app_package, ENV['APP_PACKAGE']

  # Android app starting activity.
  @app_activity = opts.fetch :app_activity, ENV['APP_ACTIVITY']

  # Android app waiting activity
  @app_wait_activity = opts.fetch :app_wait_activity, ENV['APP_WAIT_ACTIVITY']

  # Sauce Username
  @sauce_username = opts.fetch :sauce_username, ENV['SAUCE_USERNAME']

  # Sauce Key
  @sauce_access_key = opts.fetch :sauce_access_key, ENV['SAUCE_ACCESS_KEY']

  @port = opts.fetch :port, ENV['PORT'] || 4723

  @os = :ios
  @os = :android if @app_path.match /\.apk/i

  # load common methods
  extend Appium::Common
  if @os == :android
    raise 'APP_ACTIVITY must be set.' if @app_activity.nil?

    # load Android specific methods
    extend Appium::Android
  else
    # load iOS specific methods
    extend Appium::Ios
  end

  # apply os specific patches
  patch_webdriver_element

  # enable debug patch
  # !!'constant' == true
  @debug = opts.fetch :debug, !!defined?(Pry)
  puts "Debug is: #{@debug}"
  if @debug
    ap opts unless opts.empty?
    puts "OS is: #{@os}"
    patch_webdriver_bridge
  end

  # Save global reference to last created Appium driver for top level methods.
  $driver = self

  # Promote exactly once the first time the driver is created.
  # Subsequent drivers do not trigger promotion.
  unless @@loaded
    @@loaded = true
    # Promote Appium driver methods to Object instance methods.
    $driver.public_methods(false).each do | m |
      Object.class_eval do
        define_method m do | *args, &block |
          $driver.send m, *args, &block
        end
      end
    end
  end

  self # return newly created driver
end

Instance Attribute Details

#app_activityObject (readonly)

Returns the value of attribute app_activity.



87
88
89
# File 'lib/appium_lib/driver.rb', line 87

def app_activity
  @app_activity
end

#app_nameObject (readonly)

Returns the value of attribute app_name.



87
88
89
# File 'lib/appium_lib/driver.rb', line 87

def app_name
  @app_name
end

#app_packageObject (readonly)

Returns the value of attribute app_package.



87
88
89
# File 'lib/appium_lib/driver.rb', line 87

def app_package
  @app_package
end

#app_pathObject (readonly)

Returns the value of attribute app_path.



87
88
89
# File 'lib/appium_lib/driver.rb', line 87

def app_path
  @app_path
end

#app_wait_activityObject (readonly)

Returns the value of attribute app_wait_activity.



87
88
89
# File 'lib/appium_lib/driver.rb', line 87

def app_wait_activity
  @app_wait_activity
end

#debugObject (readonly)

Returns the value of attribute debug.



87
88
89
# File 'lib/appium_lib/driver.rb', line 87

def debug
  @debug
end

#default_waitInteger (readonly)

Returns the default client side wait. This value is independent of what the server is using

Returns:

  • (Integer)


344
345
346
# File 'lib/appium_lib/driver.rb', line 344

def default_wait
  @default_wait
end

#osObject (readonly)

Returns the value of attribute os.



87
88
89
# File 'lib/appium_lib/driver.rb', line 87

def os
  @os
end

#portObject (readonly)

Returns the value of attribute port.



87
88
89
# File 'lib/appium_lib/driver.rb', line 87

def port
  @port
end

#sauce_access_keyObject (readonly)

Returns the value of attribute sauce_access_key.



87
88
89
# File 'lib/appium_lib/driver.rb', line 87

def sauce_access_key
  @sauce_access_key
end

#sauce_usernameObject (readonly)

Returns the value of attribute sauce_username.



87
88
89
# File 'lib/appium_lib/driver.rb', line 87

def sauce_username
  @sauce_username
end

#selendroidObject (readonly)

Returns the value of attribute selendroid.



87
88
89
# File 'lib/appium_lib/driver.rb', line 87

def selendroid
  @selendroid
end

Instance Method Details

#absolute_app_pathString

Converts environment variable APP_PATH to an absolute path.

Returns:

  • (String)

    APP_PATH as an absolute path



251
252
253
254
255
256
257
258
259
260
261
# File 'lib/appium_lib/driver.rb', line 251

def absolute_app_path
  raise 'APP_PATH environment variable not set!' if @app_path.nil? || @app_path.empty?
  return @app_path if @app_path.match(/^http/) # public URL for Sauce
  if @app_path.match(/^\//) # absolute file path
    raise "App doesn't exist. #{@app_path}" unless File.exist? @app_path
    return @app_path
  end
  file = File.join(File.dirname(__FILE__), @app_path)
  raise "App doesn't exist #{file}" unless File.exist? file
  file
end

#android_capabilitiesObject

WebDriver capabilities. Must be valid for Sauce to work. github.com/jlipps/appium/blob/master/app/android.js



217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/appium_lib/driver.rb', line 217

def android_capabilities
  {
    browserName: 'Android',
    platform: 'LINUX',
    version: '4.2',
    device: @selendroid || 'Android',
    name: @app_name || 'Ruby Console Android Appium',
    app: absolute_app_path,
    :'app-package' => @app_package,
    :'app-activity' => @app_activity,
    :'app-wait-activity' => @app_wait_activity || @app_activity
  }
end

#capabilitiesObject



245
246
247
# File 'lib/appium_lib/driver.rb', line 245

def capabilities
  @os == :ios ? ios_capabilities : android_capabilities
end

#driverDriver

Returns the driver

Returns:



282
283
284
# File 'lib/appium_lib/driver.rb', line 282

def driver
  @driver
end

#driver_quitvoid

This method returns an undefined value.

Quits the driver



298
299
300
301
# File 'lib/appium_lib/driver.rb', line 298

def driver_quit
  # rescue NoSuchDriverError
  begin; @driver.quit unless @driver.nil?; rescue; end
end

#dynamic_code_to_string(code, value = false) ⇒ Object



39
40
41
42
43
# File 'lib/appium_lib/android/dynamic.rb', line 39

def dynamic_code_to_string code, value=false
  result = @@map[code].first
  return result unless value
  result.split('(').first + "( \"#{value}\" )"
end

#execute_script(script, *args) ⇒ Object

The same as @driver.execute_script

Parameters:

  • script (String)

    the script to execute

  • args (*args)

    the args to pass to the script

Returns:

  • (Object)


382
383
384
# File 'lib/appium_lib/driver.rb', line 382

def execute_script script, *args
  @driver.execute_script script, *args
end

#exists(pre_check = 0, post_check = @default_wait, &search_block) ⇒ Boolean

Returns existence of element.

Example:

exists { button(‘sign in’) } ? puts(‘true’) : puts(‘false’)

Parameters:

  • pre_check (Integer) (defaults to: 0)

    the amount in seconds to set the wait to before checking existance

  • post_check (Integer) (defaults to: @default_wait)

    the amount in seconds to set the wait to after checking existance

  • search_block (Block)

    the block to call

Returns:

  • (Boolean)


360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/appium_lib/driver.rb', line 360

def exists pre_check=0, post_check=@default_wait, &search_block
  set_wait pre_check # set wait to zero

  # the element exists unless an error is raised.
  exists = true

  begin
    search_block.call # search for element
  rescue
    exists = false # error means it's not there
  end

  # restore wait
  set_wait post_check if post_check != pre_check

  exists
end

#find_element(*args) ⇒ Element

Calls @driver.find_elements

Parameters:

  • args (*args)

    the args to use

Returns:

  • (Element)


417
418
419
# File 'lib/appium_lib/driver.rb', line 417

def find_element *args
  @driver.find_element *args
end

#find_elements(*args) ⇒ Array<Element>

Calls @driver.find_elements

Parameters:

  • args (*args)

    the args to use

Returns:

  • (Array<Element>)

    Array is empty when no elements are found.



409
410
411
# File 'lib/appium_lib/driver.rb', line 409

def find_elements *args
  @driver.find_elements *args
end

#ios_capabilitiesObject

WebDriver capabilities. Must be valid for Sauce to work.



233
234
235
236
237
238
239
240
241
242
# File 'lib/appium_lib/driver.rb', line 233

def ios_capabilities
  {
    browserName: 'iOS 6.0',
    platform: 'Mac 10.8',
    version: '6.0',
    device: 'iPhone Simulator',
    name: @app_name || 'Ruby Console iOS Appium',
    app: absolute_app_path
  }
end

#mobile(method, *args) ⇒ Object

Helper method for mobile gestures

github.com/appium/appium/wiki/Automating-mobile-gestures

driver.execute_script ‘mobile: swipe’, endX: 100, endY: 100, duration: 0.01

becomes

mobile :swipe, endX: 100, endY: 100, duration: 0.01

Parameters:

  • method (String, Symbol)

    the method to execute

  • args (*args)

    the args to pass to the method

Returns:

  • (Object)


398
399
400
401
402
403
# File 'lib/appium_lib/driver.rb', line 398

def mobile method, *args
  raise 'Method must not be nil' if method.nil?
  raise 'Method must have .to_s' unless method.respond_to? :to_s

  @driver.execute_script "mobile: #{method.to_s}", *args
end

#no_waitObject

Set implicit wait to zero.



330
331
332
# File 'lib/appium_lib/driver.rb', line 330

def no_wait
  @driver.manage.timeouts.implicit_wait = 0
end

#restartDriver

Restarts the driver

Returns:



275
276
277
278
# File 'lib/appium_lib/driver.rb', line 275

def restart
  driver_quit
  start_driver
end

#screenshot(png_save_path) ⇒ void

This method returns an undefined value.

Takes a png screenshot and saves to the target path.

Example: screenshot ‘/tmp/hi.png’

Parameters:

  • png_save_path (String)

    the full path to save the png



292
293
294
# File 'lib/appium_lib/driver.rb', line 292

def screenshot png_save_path
  @driver.save_screenshot png_save_path
end

#server_urlString

Get the server url for sauce or local based on env vars.

Returns:

  • (String)

    the server url



265
266
267
268
269
270
271
# File 'lib/appium_lib/driver.rb', line 265

def server_url
  if !@sauce_username.nil? && !@sauce_access_key.nil?
    "http://#{@sauce_username}:#{@sauce_access_key}@ondemand.saucelabs.com:80/wd/hub"
  else
    "http://127.0.0.1:#{@port}/wd/hub"
  end
end

#server_versionString

Returns the server’s version string

Returns:

  • (String)


210
211
212
# File 'lib/appium_lib/driver.rb', line 210

def server_version
  status['value']['build']['version']
end

#set_wait(timeout = @default_wait) ⇒ void

This method returns an undefined value.

Set implicit wait to timeout, defaults to 30.

Parameters:

  • timeout (Integer) (defaults to: @default_wait)

    the timeout in seconds



337
338
339
# File 'lib/appium_lib/driver.rb', line 337

def set_wait timeout=@default_wait
  @driver.manage.timeouts.implicit_wait = timeout
end

#start_driverSelenium::WebDriver

Creates a new global driver and quits the old one if it exists.

Returns:

  • (Selenium::WebDriver)

    the new global driver



306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/appium_lib/driver.rb', line 306

def start_driver
  @client = @client || Selenium::WebDriver::Remote::Http::Default.new
  @client.timeout = 999999

  begin
    @driver = Selenium::WebDriver.for :remote, http_client: @client, desired_capabilities: capabilities, url: server_url
    # Load touch methods. Required for Selendroid.
    @driver.extend Selenium::WebDriver::DriverExtensions::HasTouchScreen
  rescue Errno::ECONNREFUSED
    raise 'ERROR: Unable to connect to Appium. Is the server running?'
  end

  # Set timeout to a large number so that Appium doesn't quit
  # when no commands are entered after 60 seconds.
  # broken on selendroid: https://github.com/appium/appium/issues/513
  mobile :setCommandTimeout, timeout: 9999 unless @selendroid

  # Set implicit wait by default unless we're using Pry.
  @driver.manage.timeouts.implicit_wait = @default_wait unless defined? Pry

  @driver
end

#statusObject

Returns the status payload



204
205
206
# File 'lib/appium_lib/driver.rb', line 204

def status
  driver.status.payload
end

#xvoid

This method returns an undefined value.

Quit the driver and Pry. quit and exit are reserved by Pry.



424
425
426
427
# File 'lib/appium_lib/driver.rb', line 424

def x
  driver_quit
  exit # exit pry
end