Class: Maze::Driver::Appium

Inherits:
Object
  • Object
show all
Defined in:
lib/maze/driver/appium.rb

Overview

Provide a thin layer of abstraction above @see Appium::Core::Driver

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server_url, capabilities, locator = :id) ⇒ Appium

Creates the Appium driver

Parameters:

  • server_url (String)

    URL of the Appium server

  • capabilities (Hash)

    a hash of capabilities to be used in this test run

  • locator (Symbol) (defaults to: :id)

    the primary locator strategy Appium should use to find elements



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/maze/driver/appium.rb', line 31

def initialize(server_url, capabilities, locator = :id)
  # Sets up identifiers for ease of connecting jobs
  capabilities ||= {}

  @failed = false
  @failure_reason = ''
  @element_locator = locator
  @capabilities = capabilities

  # Timers
  @find_element_timer = Maze.timers.add 'Appium - find element'
  @click_element_timer = Maze.timers.add 'Appium - click element'
  opts = {
    :caps => @capabilities,
    :appium_lib => {
      server_url: server_url
    }
  }
  @core = ::Appium::Core.for(opts)
end

Instance Attribute Details

#app_idString

Returns The app_id derived from session_capabilities (appPackage on Android, bundleID on iOS).

Returns:

  • (String)

    The app_id derived from session_capabilities (appPackage on Android, bundleID on iOS)



16
17
18
# File 'lib/maze/driver/appium.rb', line 16

def app_id
  @app_id
end

#capabilitiesObject (readonly)

Returns the value of attribute capabilities.



24
25
26
# File 'lib/maze/driver/appium.rb', line 24

def capabilities
  @capabilities
end

#device_typeObject (readonly)

Returns the value of attribute device_type.



20
21
22
# File 'lib/maze/driver/appium.rb', line 20

def device_type
  @device_type
end

Instance Method Details

#activate_app(app_id) ⇒ Object



243
244
245
# File 'lib/maze/driver/appium.rb', line 243

def activate_app(app_id)
  @driver.activate_app(app_id)
end

#app_state(app_id) ⇒ Object



239
240
241
# File 'lib/maze/driver/appium.rb', line 239

def app_state(app_id)
  @driver.app_state(app_id)
end

#appium_server_versionObject



93
94
95
# File 'lib/maze/driver/appium.rb', line 93

def appium_server_version
  @core.appium_server_version
end

#backObject



283
284
285
# File 'lib/maze/driver/appium.rb', line 283

def back
  @driver.back
end

#background_app(seconds) ⇒ Object



251
252
253
# File 'lib/maze/driver/appium.rb', line 251

def background_app(seconds)
  @driver.background_app(seconds)
end

#click_element(element_id) ⇒ Object

Clicks a given element

Parameters:

  • element_id (String)

    the element to click



173
174
175
176
177
178
179
180
181
182
# File 'lib/maze/driver/appium.rb', line 173

def click_element(element_id)
  element = find_element_timed(element_id)
  @click_element_timer.time do
    element.click
  end
rescue Selenium::WebDriver::Error::ServerError => e
  # Assume the remote appium session has stopped, so crash out of the session
  fail_driver(e)
  raise e
end

#click_element_if_present(element_id) ⇒ Boolean

Clicks a given element, ignoring any NoSuchElementError

Parameters:

  • element_id (String)

    the element to click

Returns:

  • (Boolean)

    True is the element was clicked



188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/maze/driver/appium.rb', line 188

def click_element_if_present(element_id)
  element = find_element_timed(element_id)
  @click_element_timer.time do
    element.click
  end
  true
rescue Selenium::WebDriver::Error::NoSuchElementError
  false
rescue Selenium::WebDriver::Error::ServerError => e
  # Assume the remote appium session has stopped, so crash out of the session
  fail_driver(e)
  raise e
end

#close_appObject

A wrapper around close_app adding extra error handling



151
152
153
154
155
156
157
# File 'lib/maze/driver/appium.rb', line 151

def close_app
  @driver.close_app
rescue Selenium::WebDriver::Error::ServerError => e
  # Assume the remote appium session has stopped, so crash out of the session
  fail_driver(e)
  raise e
end

#device_infoObject



223
224
225
# File 'lib/maze/driver/appium.rb', line 223

def device_info
  @driver.execute_script('mobile:deviceInfo')
end

#driver_quitObject



295
296
297
# File 'lib/maze/driver/appium.rb', line 295

def driver_quit
  @driver.quit
end

#execute_script(type, script) ⇒ Object



287
288
289
# File 'lib/maze/driver/appium.rb', line 287

def execute_script(type, script)
  @driver.execute_script(type, script)
end

#fail_driver(reason) ⇒ Object

Marks the driver as failed



76
77
78
79
80
# File 'lib/maze/driver/appium.rb', line 76

def fail_driver(reason)
  $logger.error "Appium driver failed: #{reason}"
  @failed = true
  @failure_reason = reason
end

#failed?Boolean

Whether the driver has known to have failed (it may still have failed and us not know yet)

Returns:

  • (Boolean)


67
68
69
# File 'lib/maze/driver/appium.rb', line 67

def failed?
  @failed
end

#failure_reasonObject



71
72
73
# File 'lib/maze/driver/appium.rb', line 71

def failure_reason
  @failure_reason
end

#find_element(*args) ⇒ Object



291
292
293
# File 'lib/maze/driver/appium.rb', line 291

def find_element(*args)
  @driver.find_element(*args)
end

#find_element_timed(element_id) ⇒ Object

A wrapper around find_element adding timer functionality



160
161
162
163
164
165
166
167
168
# File 'lib/maze/driver/appium.rb', line 160

def find_element_timed(element_id)
  @find_element_timer.time do
    find_element(@element_locator, element_id)
  end
rescue Selenium::WebDriver::Error::ServerError => e
  # Assume the remote appium session has stopped, so crash out of the session
  fail_driver(e)
  raise e
end

#get_available_log_typesObject



271
272
273
# File 'lib/maze/driver/appium.rb', line 271

def get_available_log_types
  @driver.logs.available_types
end

#get_logs(type) ⇒ Object



275
276
277
# File 'lib/maze/driver/appium.rb', line 275

def get_logs(type)
  @driver.logs.get(type)
end

#javascript?Boolean

Returns:

  • (Boolean)


82
83
84
85
86
87
# File 'lib/maze/driver/appium.rb', line 82

def javascript?
  return false if Maze.config.browser.nil?
  @driver.execute_script('return true')
rescue Selenium::WebDriver::Error::UnsupportedOperationError
  false
end

#launch_appObject

A wrapper around launch_app adding extra error handling



142
143
144
145
146
147
148
# File 'lib/maze/driver/appium.rb', line 142

def launch_app
  @driver.launch_app
rescue Selenium::WebDriver::Error::ServerError => e
  # Assume the remote appium session has stopped, so crash out of the session
  fail_driver(e)
  raise e
end

#local_storage?Boolean

Provided for mobile browsers - check if the browser supports local storage

Returns:

  • (Boolean)


98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/maze/driver/appium.rb', line 98

def local_storage?
  # Assume we can use local storage if we aren't able to verify by running JavaScript
  return true unless javascript?

  result = @driver.execute_script <<-JAVASCRIPT
try {
  window.localStorage.setItem('__localstorage_test__', 1234)
  window.localStorage.removeItem('__localstorage_test__')
  return true
} catch (err) {
  return err
}
  JAVASCRIPT

  result == true
end

#page_sourceObject

Gets the application hierarchy XML



203
204
205
# File 'lib/maze/driver/appium.rb', line 203

def page_source
  @driver.page_source
end

#perform_actions(actions) ⇒ Object



255
256
257
# File 'lib/maze/driver/appium.rb', line 255

def perform_actions(actions)
  @driver.perform_actions(actions)
end

#pull_file(path) ⇒ Object



263
264
265
# File 'lib/maze/driver/appium.rb', line 263

def pull_file(path)
  @driver.pull_file(path)
end

#pull_folder(path) ⇒ Object



267
268
269
# File 'lib/maze/driver/appium.rb', line 267

def pull_folder(path)
  @driver.pull_folder(path)
end

#push_file(path, contents) ⇒ Object



235
236
237
# File 'lib/maze/driver/appium.rb', line 235

def push_file(path, contents)
  @driver.push_file(path, contents)
end

#remote_statusObject



89
90
91
# File 'lib/maze/driver/appium.rb', line 89

def remote_status
  @driver.remote_status
end

#session_capabilitiesObject



231
232
233
# File 'lib/maze/driver/appium.rb', line 231

def session_capabilities
  @driver.session_capabilities
end

#session_idObject



227
228
229
# File 'lib/maze/driver/appium.rb', line 227

def session_id
  @driver.session_id
end

#set_rotation(orientation) ⇒ Object

Sets the rotation of the device

Parameters:

  • orientation (Symbol)

    :portrait or :landscape



215
216
217
# File 'lib/maze/driver/appium.rb', line 215

def set_rotation(orientation)
  @driver.rotation = orientation
end

#start_driverObject

Starts the Appium driver



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/maze/driver/appium.rb', line 53

def start_driver
  begin
    time = Time.now
    @driver = @core.start_driver
    $logger.info "Appium driver started in #{(Time.now - time).to_i}s"
  rescue => error
    $logger.warn "Appium driver failed to start in #{(Time.now - time).to_i}s"
    $logger.warn "#{error.class} occurred with message: #{error.message}"
    # Do not Bugsnag.notify here as we re-raise the error
    raise error
  end
end

#terminate_app(app_id) ⇒ Object



247
248
249
# File 'lib/maze/driver/appium.rb', line 247

def terminate_app(app_id)
  @driver.terminate_app(app_id)
end

#unlockObject

Unlocks the device



208
209
210
# File 'lib/maze/driver/appium.rb', line 208

def unlock
  @driver.unlock
end

#wait_for_element(element_id, timeout = 15, retry_if_stale = true) ⇒ Object

Checks for an element, waiting until it is present or the method times out

Parameters:

  • element_id (String)

    the element to search for

  • timeout (Integer) (defaults to: 15)

    the maximum time to wait for an element to be present in seconds

  • retry_if_stale (Boolean) (defaults to: true)

    enables the method to retry acquiring the element if a StaleObjectException occurs



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/maze/driver/appium.rb', line 121

def wait_for_element(element_id, timeout = 15, retry_if_stale = true)
  wait = Selenium::WebDriver::Wait.new(timeout: timeout)
  wait.until { find_element(@element_locator, element_id).displayed? }
rescue Selenium::WebDriver::Error::TimeoutError
  false
rescue Selenium::WebDriver::Error::StaleElementReferenceError => e
  if retry_if_stale
    wait_for_element(element_id, timeout, false)
  else
    $logger.warn "StaleElementReferenceError occurred: #{e}"
    false
  end
rescue Selenium::WebDriver::Error::ServerError => e
  # Assume the remote appium session has stopped, so crash out of the session
  fail_driver(e)
  raise e
else
  true
end

#window_sizeObject



219
220
221
# File 'lib/maze/driver/appium.rb', line 219

def window_size
  @driver.window_size
end