eyes_selenium 2.15.0 → 2.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -2
  3. data/.travis.yml +16 -0
  4. data/Gemfile +1 -1
  5. data/README.md +14 -4
  6. data/Rakefile +8 -1
  7. data/eyes_selenium.gemspec +26 -17
  8. data/lib/applitools/base/batch_info.rb +19 -0
  9. data/lib/applitools/base/dimension.rb +21 -0
  10. data/lib/applitools/base/environment.rb +19 -0
  11. data/lib/applitools/base/mouse_trigger.rb +33 -0
  12. data/lib/applitools/base/point.rb +21 -0
  13. data/lib/applitools/base/region.rb +77 -0
  14. data/lib/applitools/base/server_connector.rb +113 -0
  15. data/lib/applitools/base/session.rb +15 -0
  16. data/lib/applitools/base/start_info.rb +34 -0
  17. data/lib/applitools/base/test_results.rb +36 -0
  18. data/lib/applitools/base/text_trigger.rb +22 -0
  19. data/lib/applitools/eyes.rb +393 -0
  20. data/lib/applitools/eyes_logger.rb +40 -0
  21. data/lib/applitools/method_tracer.rb +22 -0
  22. data/lib/applitools/selenium/driver.rb +194 -0
  23. data/lib/applitools/selenium/element.rb +66 -0
  24. data/lib/applitools/selenium/keyboard.rb +27 -0
  25. data/lib/applitools/selenium/match_window_data.rb +24 -0
  26. data/lib/applitools/selenium/match_window_task.rb +190 -0
  27. data/lib/applitools/selenium/mouse.rb +62 -0
  28. data/lib/applitools/selenium/viewport_size.rb +128 -0
  29. data/lib/applitools/utils/image_delta_compressor.rb +150 -0
  30. data/lib/applitools/utils/image_utils.rb +63 -0
  31. data/lib/applitools/utils/utils.rb +52 -0
  32. data/lib/applitools/version.rb +3 -0
  33. data/lib/eyes_selenium.rb +9 -29
  34. data/spec/driver_passthrough_spec.rb +25 -25
  35. data/spec/spec_helper.rb +5 -8
  36. data/test/appium_example_script.rb +57 -0
  37. data/{test_script.rb → test/test_script.rb} +7 -9
  38. data/{watir_test.rb → test/watir_test_script.rb} +6 -4
  39. metadata +120 -48
  40. data/appium_eyes_example.rb +0 -56
  41. data/lib/eyes_selenium/capybara.rb +0 -21
  42. data/lib/eyes_selenium/eyes/agent_connector.rb +0 -76
  43. data/lib/eyes_selenium/eyes/batch_info.rb +0 -19
  44. data/lib/eyes_selenium/eyes/dimension.rb +0 -15
  45. data/lib/eyes_selenium/eyes/driver.rb +0 -266
  46. data/lib/eyes_selenium/eyes/element.rb +0 -78
  47. data/lib/eyes_selenium/eyes/environment.rb +0 -15
  48. data/lib/eyes_selenium/eyes/eyes.rb +0 -396
  49. data/lib/eyes_selenium/eyes/eyes_keyboard.rb +0 -25
  50. data/lib/eyes_selenium/eyes/eyes_mouse.rb +0 -60
  51. data/lib/eyes_selenium/eyes/failure_reports.rb +0 -4
  52. data/lib/eyes_selenium/eyes/match_level.rb +0 -8
  53. data/lib/eyes_selenium/eyes/match_window_data.rb +0 -18
  54. data/lib/eyes_selenium/eyes/match_window_task.rb +0 -182
  55. data/lib/eyes_selenium/eyes/mouse_trigger.rb +0 -23
  56. data/lib/eyes_selenium/eyes/region.rb +0 -72
  57. data/lib/eyes_selenium/eyes/screenshot_taker.rb +0 -18
  58. data/lib/eyes_selenium/eyes/session.rb +0 -14
  59. data/lib/eyes_selenium/eyes/start_info.rb +0 -32
  60. data/lib/eyes_selenium/eyes/test_results.rb +0 -32
  61. data/lib/eyes_selenium/eyes/text_trigger.rb +0 -19
  62. data/lib/eyes_selenium/eyes/viewport_size.rb +0 -105
  63. data/lib/eyes_selenium/eyes_logger.rb +0 -47
  64. data/lib/eyes_selenium/utils.rb +0 -6
  65. data/lib/eyes_selenium/utils/image_delta_compressor.rb +0 -149
  66. data/lib/eyes_selenium/utils/image_utils.rb +0 -76
  67. data/lib/eyes_selenium/version.rb +0 -3
@@ -1,78 +0,0 @@
1
- class Applitools::Element
2
- attr_accessor :driver, :web_element
3
-
4
- ELEMENT_METHODS = [
5
- :hash, :id, :id=, :bridge=, :submit, :clear, :tag_name, :attribute,
6
- :selected?, :enabled?, :displayed?, :text, :css_value, :find_element,
7
- :find_elements, :location, :size, :location_once_scrolled_into_view,
8
- :ref, :to_json, :as_json
9
- ]
10
-
11
- ELEMENT_METHODS.each do |method|
12
- define_method method do |*args, &block|
13
- web_element.send(method,*args, &block)
14
- end
15
- end
16
- alias_method :style, :css_value
17
- alias_method :first, :find_element
18
- alias_method :all, :find_elements
19
- alias_method :[], :attribute
20
-
21
-
22
-
23
- def initialize(driver, element)
24
- @driver = driver
25
- @web_element = element
26
- end
27
-
28
- def click
29
- current_control = region
30
- offset = current_control.middle_offset
31
- driver.eyes.user_inputs << Applitools::MouseTrigger.new(:click, current_control, offset)
32
-
33
- web_element.click
34
- end
35
-
36
- def inspect
37
- "EyesWebElement" + web_element.inspect
38
- end
39
-
40
- def ==(other)
41
- other.kind_of?(web_element.class) && web_element == other
42
- end
43
- alias_method :eql?, :==
44
-
45
- def send_keys(*args)
46
- current_control = region
47
- Selenium::WebDriver::Keys.encode(args).each do |key|
48
- driver.eyes.user_inputs << Applitools::TextTrigger.new(key.to_s, current_control)
49
- end
50
-
51
- web_element.send_keys(*args)
52
- end
53
- alias_method :send_key, :send_keys
54
-
55
- def region
56
- point = location
57
- left, top, width, height = point.x, point.y, 0, 0
58
-
59
- begin
60
- dimension = size
61
- width, height = dimension.width, dimension.height
62
- rescue
63
- # Not supported on all platforms.
64
- end
65
-
66
- if left < 0
67
- width = [0, width + left].max
68
- left = 0
69
- end
70
-
71
- if top < 0
72
- height = [0, height + top].max
73
- top = 0
74
- end
75
-
76
- return Applitools::Region.new(left, top, width, height)
77
- end
78
- end
@@ -1,15 +0,0 @@
1
- class Applitools::Environment
2
-
3
- attr_accessor :os, :hosting_app, :display_size, :inferred
4
- def initialize(os=nil, hosting_app=nil, display_size=nil, inferred=nil)
5
- @os = os
6
- @hosting_app = hosting_app
7
- @display_size = display_size
8
- @inferred = inferred
9
- end
10
-
11
- def to_hash
12
- # display_size is an Applitools::ViewportSize object
13
- { os: os, hostingApp: hosting_app, displaySize: display_size.to_hash, inferred: inferred}
14
- end
15
- end
@@ -1,396 +0,0 @@
1
- class Applitools::Eyes
2
-
3
- DEFAULT_MATCH_TIMEOUT = 2.0 # Seconds
4
- BASE_AGENT_ID = 'eyes.selenium.ruby/' + Applitools::VERSION
5
- DEFAULT_EYES_SERVER = 'https://eyessdk.applitools.com'
6
-
7
- private
8
- attr_reader :agent_connector, :full_agent_id
9
- attr_accessor :session, :session_start_info, :match_window_task, :should_match_window_run_once_on_timeout,
10
- :dont_get_title
11
-
12
- public
13
- #
14
- # Attributes:
15
- #
16
- # +app_name+:: +String+ The application name which was provided as an argument to +open+.
17
- # +test_name+:: +String+ The test name which was provided as an argument to +open+.
18
- # +is_open+:: +boolean+ Is there an open session.
19
- # +viewport_size+:: +Hash+ The viewport size which was provided as an argument to +open+. Should include +width+
20
- # and +height+.
21
- # +driver+:: +Applitools::Driver+ The driver instance wrapping the driver which was provided as an argument to +open+.
22
- # +api_key+:: +String+ The user's API key.
23
- # +match_timeout+:: +Float+ The default timeout for check_XXXX operations. (Seconds)
24
- # +batch+:: +BatchInfo+ The current tests grouping, if any.
25
- # +host_os+:: +String+ A string identifying the OS running the AUT. Set this if you wish to override Eyes' automatic
26
- # inference.
27
- # +host_app+:: +String+ A string identifying the container application running the AUT (e.g., Firefox). Set this if
28
- # you wish to override Eyes' automatic inference.
29
- # +branch_name+:: +String+ If set, names the branch in which the test should run.
30
- # +parent_branch_name+:: +String+ If set, names the parent branch of the branch in which the test should run.
31
- # +user_inputs+:: +Applitools::MouseTrigger+/+Applitools::KeyboardTrigger+ Mouse/Keyboard events which happened after
32
- # the last visual validation.
33
- # +save_new_tests+:: +boolean+ Whether or not new tests should be automatically accepted as baseline.
34
- # +save_failed_tests+:: +boolean+ Whether or not failed tests should be automatically accepted as baseline.
35
- # +match_level+:: +String+ The default match level for the entire session. See +Applitools::MatchLevel+.
36
- # +baseline_name+:: +String+ A string identifying the baseline which the test will be compared against. Set this if
37
- # you wish to override Eyes' automatic baseline inference.
38
- # +is_disabled+:: +boolean+ Set to +true+ if you wish to disable Eyes without deleting code (Eyes' methods act as a
39
- # mock, and will do nothing).
40
- # +server_url+:: +String+ The Eyes' server. Set this if you wish to override the default Eyes server URL.
41
- # +agent_id+:: +String+ An optional string identifying the current library using the SDK.
42
- # +log_handler+:: +Logger+ The logger to which Eyes will send info/debug messages.
43
- # +failure_reports+:: +String+ Whether the current test will report mismatches immediately or when it is finished.
44
- # See +Applitools::FailureReports+.
45
- # +rotation+:: +Integer+|+nil+ The degrees by which to rotate the screenshots received from the driver. Set this to
46
- # override Eyes' automatic rotation inference. Positive values = clockwise rotation,
47
- # negative values = counter-clockwise, 0 = force no rotation, +nil+ = use Eyes' automatic rotation
48
- # inference.
49
- #
50
- attr_reader :app_name, :test_name, :is_open, :viewport_size, :driver
51
- attr_accessor :match_timeout, :batch, :host_os, :host_app, :branch_name, :parent_branch_name, :user_inputs,
52
- :save_new_tests, :save_failed_tests, :api_key, :is_disabled, :server_url, :agent_id, :log_handler,
53
- :failure_reports, :match_level, :baseline_name, :rotation
54
-
55
- def log_handler
56
- EyesLogger.log_handler
57
- end
58
-
59
- def log_handler=(handler)
60
- EyesLogger.log_handler = handler
61
- end
62
-
63
- def api_key
64
- @agent_connector.api_key
65
- end
66
-
67
- def api_key=(api_key)
68
- @agent_connector.api_key = api_key
69
- end
70
-
71
- def server_url
72
- @agent_connector.server_url
73
- end
74
-
75
- def server_url=(server_url)
76
- if server_url.nil?
77
- @agent_connector.server_url = DEFAULT_EYES_SERVER
78
- else
79
- @agent_connector.server_url = server_url
80
- end
81
- end
82
-
83
- def full_agent_id
84
- if agent_id.nil?
85
- return BASE_AGENT_ID
86
- end
87
- "#{agent_id} [#{BASE_AGENT_ID}]"
88
- end
89
-
90
- def title
91
- unless dont_get_title
92
- begin
93
- return driver.title
94
- rescue
95
- self.dont_get_title = true
96
- end
97
- end
98
- ''
99
- end
100
-
101
- def initialize(params={})
102
-
103
- @is_disabled = false
104
-
105
- return if disabled?
106
-
107
- @api_key = nil
108
- @user_inputs = []
109
- server_url = params.fetch(:server_url, DEFAULT_EYES_SERVER)
110
- @agent_connector = Applitools::AgentConnector.new(server_url)
111
- @match_timeout = DEFAULT_MATCH_TIMEOUT
112
- @match_level = Applitools::MatchLevel::EXACT
113
- @failure_reports = Applitools::FailureReports::ON_CLOSE
114
- @save_new_tests = true
115
- @save_failed_tests = false
116
- @dont_get_title = false
117
- end
118
-
119
- def open(params={})
120
- @driver = get_driver(params)
121
- return driver if disabled?
122
-
123
- if api_key.nil?
124
- #noinspection RubyQuotedStringsInspection
125
- raise Applitools::EyesError.new(
126
- "API key not set! Log in to https://applitools.com to obtain your API Key and use 'api_key' to set it.")
127
- end
128
-
129
- if driver.is_a?(Selenium::WebDriver::Driver)
130
- @driver = Applitools::Driver.new(self, {driver: driver})
131
- elsif defined?(Appium::Driver) && driver.is_a?(Appium::Driver)
132
- @driver = Applitools::Driver.new(self, {driver: driver.driver, is_mobile_device: true})
133
- elsif defined?(Watir::Browser) && driver.is_a?(Watir::Browser)
134
- @driver = Applitools::Driver.new(self, {driver: driver.driver})
135
- else
136
- unless driver.is_a?(Applitools::Driver)
137
- raise Applitools::EyesError.new("Driver is not a Selenium::WebDriver::Driver (#{driver.class.name})")
138
- end
139
- end
140
-
141
- if open?
142
- abort_if_not_closed
143
- msg = 'a test is already running'
144
- EyesLogger.info(msg) and raise Applitools::EyesError.new(msg)
145
- end
146
-
147
- @user_inputs = []
148
- @app_name = params.fetch(:app_name)
149
- @test_name = params.fetch(:test_name)
150
- @viewport_size = params.fetch(:viewport_size, nil)
151
-
152
- @is_open = true
153
- driver
154
- end
155
-
156
- def open?
157
- is_open
158
- end
159
-
160
- def clear_user_inputs
161
- user_inputs.clear
162
- end
163
-
164
- def check_region(how, what, tag=nil, specific_timeout=-1)
165
- EyesLogger.debug 'check_region called'
166
- return if disabled?
167
- # We have to start the session if it's not started, since we want the viewport size to be set before getting the
168
- # element's position and size
169
- raise Applitools::EyesError.new('Eyes not open') if !open?
170
- unless session
171
- EyesLogger.debug 'Starting session...'
172
- start_session
173
- EyesLogger.debug 'Done! Creating match window task...'
174
- self.match_window_task = Applitools::MatchWindowTask.new(self, agent_connector, session, driver, match_timeout)
175
- EyesLogger.debug 'Done!'
176
- end
177
-
178
- EyesLogger.debug 'Finding element...'
179
- element_to_check = driver.find_element(how, what)
180
- EyesLogger.debug 'Done! Getting element location...'
181
- location = element_to_check.location
182
- EyesLogger.debug 'Done! Getting element size...'
183
- size = element_to_check.size
184
- EyesLogger.debug 'Done! Creating region...'
185
- region = Applitools::Region.new(location.x, location.y, size.width, size.height)
186
- EyesLogger.debug 'Done! Checking region...'
187
- check_region_(region, tag, specific_timeout)
188
- EyesLogger.debug 'Done!'
189
- end
190
-
191
- def check_window(tag=nil, specific_timeout=-1)
192
- check_region_(Applitools::Region::EMPTY, tag, specific_timeout)
193
- end
194
-
195
- def close(raise_ex=true)
196
- return if disabled?
197
- @is_open = false
198
-
199
- # if there's no running session, the test was never started (never reached checkWindow)
200
- if !session
201
- EyesLogger.debug 'close(): Server session was not started'
202
- EyesLogger.info 'close(): --- Empty test ended.'
203
- return Applitools::TestResults.new
204
- end
205
-
206
- session_results_url = session.url
207
- new_session = session.new_session?
208
- EyesLogger.debug "close(): Ending server session..."
209
- save = (new_session && save_new_tests) || (!new_session && save_failed_tests)
210
- results = agent_connector.stop_session(session, false, save)
211
- results.is_new = new_session
212
- results.url = session_results_url
213
- EyesLogger.debug "close(): #{results}"
214
-
215
- self.session = nil
216
-
217
- if new_session
218
- instructions = "Please approve the new baseline at #{session_results_url}"
219
- EyesLogger.info "--- New test ended. #{instructions}"
220
- if raise_ex
221
- message = "'#{session_start_info.scenario_id_or_name}' of"\
222
- " '#{session_start_info.app_id_or_name}'. #{instructions}"
223
- raise Applitools::NewTestError.new(message, results)
224
- end
225
- return results
226
- end
227
-
228
- if !results.is_passed
229
- # Test failed
230
- EyesLogger.info "--- Failed test ended. See details at #{session_results_url}"
231
- if raise_ex
232
- message = "'#{session_start_info.scenario_id_or_name}' of"\
233
- " '#{session_start_info.app_id_or_name}'. see details at #{session_results_url}"
234
- raise Applitools::TestFailedError.new(message, results)
235
- end
236
- return results
237
- end
238
-
239
- # Test passed
240
- EyesLogger.info "--- Test passed. See details at #{session_results_url}"
241
- results
242
- end
243
-
244
- ## Use this method to perform seamless testing with selenium through eyes driver.
245
- ## Using Selenium methods inside the 'test' block will send the messages to Selenium
246
- ## after creating the Eyes triggers for them.
247
- ##
248
- ## Example:
249
- # eyes.test(app_name: 'my app1', test_name: 'my test') do |d|
250
- # get "http://www.google.com"
251
- # check_window("initial")
252
- # end
253
- #noinspection RubyUnusedLocalVariable
254
- def test(params={}, &block)
255
- begin
256
- open(params)
257
- yield(driver)
258
- close
259
- ensure
260
- abort_if_not_closed
261
- end
262
- end
263
-
264
-
265
- def abort_if_not_closed
266
- return if disabled?
267
- @is_open = false
268
- if session
269
- begin
270
- agent_connector.stop_session(session, true, false)
271
- rescue Applitools::EyesError => e
272
- EyesLogger.info "Failed to abort server session -> #{e.message} "
273
- ensure
274
- self.session = nil
275
- end
276
- end
277
- end
278
-
279
- private
280
-
281
- def disabled?
282
- is_disabled
283
- end
284
-
285
- def get_driver(params)
286
- # TODO remove the "browser" related block when possible. It's for backward compatibility.
287
- if params.has_key?(:browser)
288
- EyesLogger.info('"browser" key is deprecated, please use "driver" instead.')
289
- return params[:browser]
290
- end
291
- params.fetch(:driver, nil)
292
- end
293
-
294
- def inferred_environment
295
- user_agent = driver.user_agent
296
- if user_agent
297
- "useragent:#{user_agent}"
298
- else
299
- nil
300
- end
301
- end
302
-
303
- # Application environment is the environment (e.g., the host OS) which runs the application under test.
304
- #
305
- # Returns:
306
- # +Applitools::Environment+ The application environment.
307
- def app_environment
308
- os = host_os
309
- if os.nil?
310
- EyesLogger.info 'No OS set, checking for mobile OS...'
311
- if driver.mobile_device?
312
- platform_name = nil
313
- EyesLogger.info 'Mobile device detected! Checking device type..'
314
- if driver.android?
315
- EyesLogger.info 'Android detected.'
316
- platform_name = 'Android'
317
- elsif driver.ios?
318
- EyesLogger.info 'iOS detected.'
319
- platform_name = 'iOS'
320
- else
321
- EyesLogger.info 'Unknown device type.'
322
- end
323
- # We only set the OS if we identified the device type.
324
- unless platform_name.nil?
325
- platform_version = driver.platform_version
326
- if platform_version.nil?
327
- os = platform_name
328
- else
329
- # Notice that Ruby's +split+ function's +limit+ is the number of elements, whereas in Python it is the
330
- # maximum splits performed (which is why they are set differently).
331
- major_version = platform_version.split('.', 2)[0]
332
- os = "#{platform_name} #{major_version}"
333
- end
334
- EyesLogger.info "Setting OS: #{os}"
335
- end
336
- else
337
- EyesLogger.info 'No mobile OS detected.'
338
- end
339
- end
340
- # Create and return the environment object.
341
- Applitools::Environment.new(os, host_app, viewport_size, inferred_environment)
342
- end
343
-
344
- def start_session
345
- assign_viewport_size
346
- self.batch ||= Applitools::BatchInfo.new
347
- app_env = app_environment
348
- self.session_start_info = Applitools::StartInfo.new(
349
- full_agent_id, app_name, test_name, batch, baseline_name, app_env, match_level, nil, branch_name, parent_branch_name
350
- )
351
- self.session = agent_connector.start_session(session_start_info)
352
- self.should_match_window_run_once_on_timeout = session.new_session?
353
- end
354
-
355
- def viewport_size?
356
- viewport_size
357
- end
358
-
359
- def assign_viewport_size
360
- if viewport_size?
361
- @viewport_size = Applitools::ViewportSize.new(driver, viewport_size)
362
- viewport_size.set
363
- else
364
- @viewport_size = Applitools::ViewportSize.new(driver).extract_viewport_from_browser!
365
- end
366
- end
367
-
368
- def check_region_(region, tag=nil, specific_timeout=-1)
369
- return if disabled?
370
- EyesLogger.info "check_region_('#{tag}', #{specific_timeout})"
371
- raise Applitools::EyesError.new('region cannot be nil!') if region.nil?
372
- raise Applitools::EyesError.new('Eyes not open') if !open?
373
-
374
- unless session
375
- EyesLogger.debug 'Starting session...'
376
- start_session
377
- EyesLogger.debug 'Done! Creating match window task...'
378
- self.match_window_task = Applitools::MatchWindowTask.new(self, agent_connector, session, driver, match_timeout)
379
- EyesLogger.debug 'Done!'
380
- end
381
-
382
- EyesLogger.debug 'Starting match task...'
383
- as_expected = match_window_task.match_window(region, specific_timeout, tag, rotation, should_match_window_run_once_on_timeout)
384
- EyesLogger.debug 'Match window done!'
385
- unless as_expected
386
- self.should_match_window_run_once_on_timeout = true
387
- unless session.new_session?
388
- EyesLogger.info %( mismatch #{ tag ? '' : "(#{tag})" } )
389
- if failure_reports.to_i == Applitools::FailureReports::IMMEDIATE
390
- raise Applitools::TestFailedError.new("Mismatch found in '#{session_start_info.scenario_id_or_name}'"\
391
- " of '#{session_start_info.app_id_or_name}'")
392
- end
393
- end
394
- end
395
- end
396
- end