eyes_selenium 1.25.0 → 1.26.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YjUxOTYxOWFiOTBjZGJiNzk1MzA3YzU2YWY5M2ExZWU3MGFiMzczMg==
4
+ ODUwYjE0ZmI1ODE3ZjNiZTFlODMwOGNlNGRjODJlMmUyOTBmMzQzZg==
5
5
  data.tar.gz: !binary |-
6
- NTFlOThmMjM1MmM5MzE5M2IyMWJjMzM5ODQ1MWQ2ZDY0MmZjODEyYw==
6
+ NmI0YjkyYWRhMmQ5NTMxY2NkZWNhZDc1YTc0ZDJiNjBlMDk5NWM1NA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZGNiOGIyODhiZDM0MjA5ZDZhMDZjY2ZjNzIzYTQwNzdiYWZlYjk0OTZhYWVk
10
- NDE2NjM1YmVjMmFmYmU4MjJhZDEyZTY5ZjNkZTUzZTFmMmUwMGI1ZDZkNjgw
11
- NmI4MTk4MmM4ODlhNGFiYzNhZmVlYWYyNmYwZTVlMjEzMzIxYmM=
9
+ OThkYjg4YTZkZDhhMTRhODE2MTk2Y2VlOGM2Zjk3NTk3NDYxOTA1N2MwODZj
10
+ OWZkN2QwMDIwMzcyYmU5MGQ1YjgwMThjMzg5ZGU4ZDI1MGE2ZGVhY2QxYTFk
11
+ YjEzMmQ2NDcyZWUzNjIzMzI2ODUxOTNmZjAxOTA4MTg1ZDkwNTk=
12
12
  data.tar.gz: !binary |-
13
- NjJlYTgxZGU3NTVkYzZmMzQ0MTc2YjY4NDY2MGZmNzhiMzJhODRkYzU4MDE5
14
- NjU4YzliOWVmZTAxYTkxZGJkZjkzMGQ5YTA3OTVkMWFhZjkwYmVkNWZkYzI3
15
- ODRlOWJlMWYwZGViZGFmMGQ1N2ZjZTBiMjAwMjM5NDZlODkzOTk=
13
+ YzcwZDA5MzZhOTRkYWUxYmRmNmQ5ZDdjMThiNTU0YmM3ODVkYWQxMGZmZGUz
14
+ MmVmZTczODhmOTExZTU1YzEyOTQ5NDliOTg4ZWUzZDBkZTM3YzM5YThiNWVk
15
+ YmFlY2M4OWNjOWQ1ZDY3NzM5MTgxZTA0MTg1MDkwY2Y5ZWUwMzA=
@@ -15,7 +15,7 @@ class Applitools::AgentConnector
15
15
 
16
16
  def match_window(session, data)
17
17
  self.class.headers 'Content-Type' => 'application/octet-stream'
18
- json_data = data.to_hash.to_json.encode('UTF-8') # Notice that this does not include the screenshot
18
+ json_data = data.to_hash.to_json.encode('BINARY') # Notice that this does not include the screenshot
19
19
  body = [json_data.length].pack('L>') + json_data + data.screenshot
20
20
 
21
21
  res = self.class.post(uri + "/#{session.id}",basic_auth: auth, body: body)
@@ -74,7 +74,7 @@ class Applitools::Driver
74
74
  def user_agent
75
75
  execute_script 'return navigator.userAgent'
76
76
  rescue => e
77
- puts "getUserAgent(): Failed to obtain user-agent string (#{e.message})"
77
+ EyesLogger.info "getUserAgent(): Failed to obtain user-agent string (#{e.message})"
78
78
  end
79
79
 
80
80
  private
@@ -100,25 +100,16 @@ class Applitools::Eyes
100
100
  user_inputs.clear
101
101
  end
102
102
 
103
- def check_window(tag=nil)
104
- return if disabled?
105
- raise Applitools::EyesError.new('Eyes not open') if !open?
106
- unless session
107
- start_session
108
- self.match_window_task = Applitools::MatchWindowTask.new(self, agent_connector, session, driver, match_timeout)
109
- end
103
+ def check_region(how, what, tag=nil)
104
+ element_to_check = driver.find_element(how, what)
105
+ location = element_to_check.location
106
+ size = element_to_check.size
107
+ region = Applitools::Region.new(location.x, location.y, size.width, size.height)
108
+ check_region_(region, tag)
109
+ end
110
110
 
111
- as_expected = match_window_task.match_window(tag, should_match_window_run_once_on_timeout)
112
- unless as_expected
113
- self.should_match_window_run_once_on_timeout = true
114
- unless session.new_session?
115
- EyesLogger.info %( "mismatch #{ tag ? '' : "(#{tag})" } )
116
- if failure_reports.to_i == Applitools::FailureReports::IMMEDIATE
117
- raise Applitools::TestFailedError.new("Mismatch found in '#{session_start_info.scenario_id_or_name}'"\
118
- " of '#{session_start_info.app_id_or_name}'")
119
- end
120
- end
121
- end
111
+ def check_window(tag=nil)
112
+ check_region_(Applitools::Region::EMPTY, tag)
122
113
  end
123
114
 
124
115
  def close
@@ -238,4 +229,27 @@ class Applitools::Eyes
238
229
  @viewport_size = Applitools::ViewportSize.new(driver).extract_viewport_from_browser!
239
230
  end
240
231
  end
232
+
233
+ def check_region_(region, tag=nil)
234
+ return if disabled?
235
+ raise Applitools::EyesError.new('region cannot be nil!') if region.nil?
236
+ raise Applitools::EyesError.new('Eyes not open') if !open?
237
+
238
+ unless session
239
+ start_session
240
+ self.match_window_task = Applitools::MatchWindowTask.new(self, agent_connector, session, driver, match_timeout)
241
+ end
242
+
243
+ as_expected = match_window_task.match_window(region, tag, should_match_window_run_once_on_timeout)
244
+ unless as_expected
245
+ self.should_match_window_run_once_on_timeout = true
246
+ unless session.new_session?
247
+ EyesLogger.info %( "mismatch #{ tag ? '' : "(#{tag})" } )
248
+ if failure_reports.to_i == Applitools::FailureReports::IMMEDIATE
249
+ raise Applitools::TestFailedError.new("Mismatch found in '#{session_start_info.scenario_id_or_name}'"\
250
+ " of '#{session_start_info.app_id_or_name}'")
251
+ end
252
+ end
253
+ end
254
+ end
241
255
  end
@@ -7,7 +7,7 @@ class Applitools::MatchWindowTask
7
7
  MATCH_INTERVAL = 0.5
8
8
  AppOutput = Struct.new(:title, :screenshot64)
9
9
 
10
- attr_reader :eyes, :agent_connector, :session, :driver, :max_window_load_time
10
+ attr_reader :eyes, :agent_connector, :session, :driver, :max_window_load_time, :last_checked_window ,:last_screenshot_bounds
11
11
 
12
12
  public
13
13
  ## max_load_time: maximum wait time for check window, in seconds
@@ -18,65 +18,94 @@ class Applitools::MatchWindowTask
18
18
  @driver = driver
19
19
  @max_window_load_time = max_window_load_time
20
20
  @last_checked_window = nil # +ChunkyPNG::Canvas+
21
+ @last_screenshot_bounds = Applitools::Region::EMPTY # +Applitools::Region+
21
22
  @current_screenshot = nil # +ChunkyPNG::Canvas+
22
23
  end
23
24
 
24
- def match_window(tag,run_once_after_wait=false)
25
+ def match_window(region, tag,run_once_after_wait=false)
25
26
  res = if max_window_load_time.zero?
26
- run(tag)
27
- elsif run_once_after_wait
28
- run(tag, max_window_load_time)
29
- else
30
- run_with_intervals(tag, max_window_load_time)
31
- end
27
+ run(region, tag)
28
+ elsif run_once_after_wait
29
+ run(region, tag, max_window_load_time)
30
+ else
31
+ run_with_intervals(region, tag, max_window_load_time)
32
+ end
33
+ @last_checked_window = @current_screenshot
34
+ @last_screenshot_bounds = region.empty? ? Applitools::Region.new(0, 0, last_checked_window.width, last_checked_window.height) : region
32
35
  #noinspection RubyUnnecessaryReturnStatement
33
36
  driver.eyes.clear_user_inputs and return res
34
37
  end
35
38
 
36
- def run(tag, wait_before_run=nil)
39
+ def run(region, tag, wait_before_run=nil)
37
40
  sleep(wait_before_run) if wait_before_run
38
- match(tag)
41
+ match(region, tag)
39
42
  end
40
43
 
41
- def run_with_intervals(tag, total_run_time)
44
+ def run_with_intervals(region, tag, total_run_time)
42
45
  start = Time.now
43
46
  match_retry = total_run_time
44
47
  while match_retry > 0
45
48
  sleep(MATCH_INTERVAL)
46
- return true if match(tag, true)
49
+ return true if match(region, tag, true)
47
50
  match_retry -= (Time.now - start)
48
51
  end
49
52
  ## lets try one more time if we still don't have a match
50
- match(tag)
53
+ match(region, tag)
51
54
  end
52
55
 
53
56
  private
54
57
 
55
- def prep_match_data(tag, ignore_mismatch)
58
+ def prep_match_data(region, tag, ignore_mismatch)
56
59
  title = eyes.title
60
+ # 'encoded', as in 'png'.
57
61
  current_screenshot_encoded = Base64.decode64(driver.screenshot_as(:base64))
58
62
  @current_screenshot = ChunkyPNG::Image.from_blob(current_screenshot_encoded)
63
+ # If a region was defined, we refer to the sub-image defined by the region.
64
+ unless region.empty?
65
+ @current_screenshot.crop!(region.left, region.top, region.width, region.height)
66
+ current_screenshot_encoded = @current_screenshot.to_blob.force_encoding('BINARY')
67
+ end
59
68
  compressed_screenshot = Applitools::Utils::ImageDeltaCompressor.compress_by_raw_blocks(@current_screenshot,
60
69
  current_screenshot_encoded,
61
- @last_checked_window)
70
+ last_checked_window)
62
71
  app_output = AppOutput.new(title, nil)
63
72
  user_inputs = []
64
- if @last_checked_window.nil?
65
- user_inputs = driver.eyes.user_inputs
66
- else
73
+ if !last_checked_window.nil?
67
74
  driver.eyes.user_inputs.each do |trigger|
68
- if trigger.is_a? Applitools::MouseTrigger
75
+ if trigger.is_a?(Applitools::MouseTrigger)
76
+ updated_trigger = nil
69
77
  trigger_left = trigger.control.left + trigger.location.x
70
78
  trigger_top = trigger.control.top + trigger.location.y
71
- if trigger_left <= @last_checked_window.width && trigger_top <= @last_checked_window.height
72
- user_inputs << trigger
79
+ if last_screenshot_bounds.contains?(trigger_left, trigger_top)
80
+ trigger.control.intersect(last_screenshot_bounds)
81
+ if trigger.control.empty?
82
+ trigger_left = trigger_left - last_screenshot_bounds.left
83
+ trigger_top = trigger_top -last_screenshot_bounds.top
84
+ updated_trigger = Applitools::MouseTrigger.new(trigger.mouse_action, trigger.control, Selenium::WebDriver::Point.new(trigger_left, trigger_top))
85
+ else
86
+ trigger_left = trigger_left - trigger.control.left
87
+ trigger_top = trigger_top - trigger.control.top
88
+ control_left = trigger.control.left - last_screenshot_bounds.left
89
+ control_top = trigger.control.top - last_screenshot_bounds.top
90
+ updated_control = Applitools::Region.new(control_left, control_top, trigger.control.width, trigger.control.height)
91
+ updated_trigger = Applitools::MouseTrigger.new(trigger.mouse_action, updated_control, Selenium::WebDriver::Point.new(trigger_left, trigger_top))
92
+ end
93
+ user_inputs << updated_trigger
73
94
  else
74
95
  EyesLogger.info "Trigger ignored: #{trigger} (out of bounds)"
75
96
  end
76
- elsif trigger.is_a? Applitools::TextTrigger
77
- last_screenshot_bounds = Applitools::Region.new(0, 0, @last_checked_window.width, @last_checked_window.height)
78
- if trigger.control.intersecting?last_screenshot_bounds
79
- user_inputs << trigger
97
+ elsif trigger.is_a?(Applitools::TextTrigger)
98
+ unless trigger.control.empty?
99
+ trigger.control.intersect(last_screenshot_bounds)
100
+ unless trigger.control.empty?
101
+ control_left = trigger.control.left - last_screenshot_bounds.left
102
+ control_top = trigger.control.top - last_screenshot_bounds.top
103
+ updated_control = Applitools::Region.new(control_left, control_top, trigger.control.width, trigger.control.height)
104
+ updated_trigger = Applitools::TextTrigger.new(trigger.text, updated_control)
105
+ user_inputs << updated_trigger
106
+ else
107
+ EyesLogger.info "Trigger ignored: #{trigger} (control out of bounds)"
108
+ end
80
109
  else
81
110
  EyesLogger.info "Trigger ignored: #{trigger} (out of bounds)"
82
111
  end
@@ -84,17 +113,14 @@ class Applitools::MatchWindowTask
84
113
  EyesLogger.info "Trigger ignored: #{trigger} (Unrecognized trigger)"
85
114
  end
86
115
  end
116
+ else
117
+ EyesLogger.info 'Triggers ignored: no previous window checked'
87
118
  end
88
119
  Applitools::MatchWindowData.new(app_output, user_inputs, tag, ignore_mismatch, compressed_screenshot)
89
120
  end
90
121
 
91
- def match(tag, ignore_mismatch=false)
92
- data = prep_match_data(tag, ignore_mismatch)
93
- as_expected = agent_connector.match_window(session, data)
94
- # If the server stored this image, it will be used as a base for our next screenshot compression
95
- unless ignore_mismatch
96
- @last_checked_window = @current_screenshot
97
- end
98
- as_expected
122
+ def match(region, tag, ignore_mismatch=false)
123
+ data = prep_match_data(region, tag, ignore_mismatch)
124
+ agent_connector.match_window(session, data)
99
125
  end
100
126
  end
@@ -5,14 +5,14 @@ class Applitools::MouseTrigger
5
5
  attr_reader :mouse_action, :control, :location
6
6
 
7
7
  def initialize(mouse_action, control, location)
8
- @mouse_action = MOUSE_ACTION[mouse_action]
8
+ @mouse_action = mouse_action
9
9
  @control = control
10
10
  @location = location
11
11
  end
12
12
 
13
13
  def to_hash
14
14
  {
15
- "$type" => "Applitools.Models.MouseTrigger, Core", mouseAction: mouse_action,
15
+ "$type" => "Applitools.Models.MouseTrigger, Core", mouseAction: MOUSE_ACTION[mouse_action],
16
16
  control: control.to_hash, location: Hash[location.each_pair.to_a]
17
17
  }
18
18
  end
@@ -49,6 +49,11 @@ class Applitools::Region
49
49
  self.height = i_bottom - i_top
50
50
  end
51
51
 
52
+ def contains?(other_left, other_top)
53
+ other_left >= left && other_left <= right && \
54
+ other_top >= top && other_top <= bottom
55
+ end
56
+
52
57
  def middle_offset
53
58
  mid_x = width / 2
54
59
  mid_y = height / 2
@@ -1,3 +1,3 @@
1
1
  module Applitools
2
- VERSION = '1.25.0'
2
+ VERSION = '1.26.0'
3
3
  end
data/test_script.rb CHANGED
@@ -14,6 +14,7 @@ begin
14
14
  eyes.test(app_name: 'Ruby SDK', test_name: 'Applitools website test', viewport_size: {width: 1024, height: 768}, driver: my_webdriver) do |driver|
15
15
  driver.get "http://www.applitools.com"
16
16
  eyes.check_window("initial")
17
+ eyes.check_region(:css, 'li.pricing', 'Pricing button')
17
18
  driver.find_element(:css, "li.pricing a").click
18
19
  eyes.check_window("pricing page")
19
20
  el = driver.find_elements(:css, ".footer-row a").first
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eyes_selenium
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.25.0
4
+ version: 1.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Applitools team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-01 00:00:00.000000000 Z
11
+ date: 2014-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: selenium-webdriver