Class: Appium::Driver

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

Constant Summary collapse

@@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]
}
@@loaded =
false

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Driver

Creates a new driver. :device is :android, :ios, or :selendroid

“‘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 = { device: :ios, app_path: ‘/path/to/MyiOS.app’} Appium::Driver.new(app).start_driver

# Start Android driver apk = { device: :android

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.



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/appium_lib/driver.rb', line 230

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 }

  @export_session = opts.fetch :export_session, false

  @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']

  # 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

  # device as used in device capabilities.
  # iOS only.
  #
  # Android is always Android or Selendroid so there's no
  # override required.
  @device_cap = opts.fetch :device_cap, false

  # :ios, :android, :selendroid
  @device = opts.fetch :device, ENV['DEVICE'] || :ios
  @device = @device.intern # device must be a symbol

  # load common methods
  extend Appium::Common
  if @device == :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 "Device is: #{@device}"
    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 only on Minitest::Spec (minitest 5) by default
    Appium.promote_appium_methods ::Minitest::Spec
  end

  self # return newly created driver
end

Instance Attribute Details

#app_activityObject (readonly)

Returns the value of attribute app_activity.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

def app_activity
  @app_activity
end

#app_nameObject (readonly)

Returns the value of attribute app_name.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

def app_name
  @app_name
end

#app_packageObject (readonly)

Returns the value of attribute app_package.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

def app_package
  @app_package
end

#app_pathObject (readonly)

Returns the value of attribute app_path.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

def app_path
  @app_path
end

#app_wait_activityObject (readonly)

Returns the value of attribute app_wait_activity.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

def app_wait_activity
  @app_wait_activity
end

#debugObject (readonly)

Returns the value of attribute debug.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

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)


490
491
492
# File 'lib/appium_lib/driver.rb', line 490

def default_wait
  @default_wait
end

#deviceObject (readonly)

Returns the value of attribute device.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

def device
  @device
end

#device_capObject (readonly)

Returns the value of attribute device_cap.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

def device_cap
  @device_cap
end

#export_sessionObject (readonly)

Returns the value of attribute export_session.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

def export_session
  @export_session
end

#global_webdriver_http_sleepObject

The amount to sleep in seconds before every webdriver http call.



200
201
202
# File 'lib/appium_lib/driver.rb', line 200

def global_webdriver_http_sleep
  @global_webdriver_http_sleep
end

#portObject (readonly)

Returns the value of attribute port.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

def port
  @port
end

#sauce_access_keyObject (readonly)

Returns the value of attribute sauce_access_key.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

def sauce_access_key
  @sauce_access_key
end

#sauce_usernameObject (readonly)

Returns the value of attribute sauce_username.



194
195
196
# File 'lib/appium_lib/driver.rb', line 194

def sauce_username
  @sauce_username
end

Instance Method Details

#absolute_app_pathString

Converts environment variable APP_PATH to an absolute path.

Returns:

  • (String)

    APP_PATH as an absolute path



380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/appium_lib/driver.rb', line 380

def absolute_app_path
  raise 'APP_PATH not set!' if @app_path.nil? || @app_path.empty?
  # Sauce storage API. http://saucelabs.com/docs/rest#storage
  return @app_path if @app_path.start_with? 'sauce-storage:'
  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

  # if it doesn't contain a slash then it's a bundle id
  return @app_path unless @app_path.match(/[\/\\]/)

  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



346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/appium_lib/driver.rb', line 346

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

#capabilitiesObject



372
373
374
375
376
# File 'lib/appium_lib/driver.rb', line 372

def capabilities
  caps = @device == :ios ? ios_capabilities : android_capabilities
  caps[:app] = absolute_app_path unless @app_path.nil? || @app_path.empty?
  caps
end

#driverDriver

Returns the driver

Returns:



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

def driver
  @driver
end

#driver_quitvoid

This method returns an undefined value.

Quits the driver



434
435
436
437
# File 'lib/appium_lib/driver.rb', line 434

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)


528
529
530
# File 'lib/appium_lib/driver.rb', line 528

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)


506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
# File 'lib/appium_lib/driver.rb', line 506

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)


563
564
565
# File 'lib/appium_lib/driver.rb', line 563

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.



555
556
557
# File 'lib/appium_lib/driver.rb', line 555

def find_elements *args
  @driver.find_elements *args
end

#ios_capabilitiesObject

WebDriver capabilities. Must be valid for Sauce to work.



361
362
363
364
365
366
367
368
369
# File 'lib/appium_lib/driver.rb', line 361

def ios_capabilities
  {
    browserName: 'iOS 6.0',
    platform: 'Mac 10.8',
    version: '6.0',
    device: @device_cap || 'iPhone Simulator',
    name: @app_name || 'Ruby Console iOS Appium'
  }
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)


544
545
546
547
548
549
# File 'lib/appium_lib/driver.rb', line 544

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.



476
477
478
# File 'lib/appium_lib/driver.rb', line 476

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

#restartDriver

Restarts the driver

Returns:



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

def restart
  driver_quit
  start_driver
end

#screenshot(png_save_path) ⇒ nil

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

Returns:

  • (nil)


427
428
429
430
# File 'lib/appium_lib/driver.rb', line 427

def screenshot png_save_path
  @driver.save_screenshot png_save_path
  nil
end

#server_urlString

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

Returns:

  • (String)

    the server url



400
401
402
403
404
405
406
# File 'lib/appium_lib/driver.rb', line 400

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)


339
340
341
# File 'lib/appium_lib/driver.rb', line 339

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



483
484
485
# File 'lib/appium_lib/driver.rb', line 483

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



442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
# File 'lib/appium_lib/driver.rb', line 442

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

    # export session
    if @export_session
      begin
        File.open('/tmp/appium_lib_session', 'w') do |f|
          f.puts @driver.session_id
        end
      rescue
      end
    end
  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 @device == :selendroid

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

  @driver
end

#statusJSON

Returns the status payload

“‘ruby

"value"=>
 {"build"=>
   {"version"=>"0.8.2",
    "revision"=>"f2a2bc3782e4b0370d97a097d7e04913cf008995"},
"sessionId"=>"8f4b34a7-a9a9-4ac5-b125-36258143446a"}

“‘

Discover the Appium rev running on the server.

status[“build“]` `f2a2bc3782e4b0370d97a097d7e04913cf008995`

Returns:

  • (JSON)


333
334
335
# File 'lib/appium_lib/driver.rb', line 333

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.



570
571
572
573
# File 'lib/appium_lib/driver.rb', line 570

def x
  driver_quit
  exit # exit pry
end