eyes_selenium_ruby 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. data/.gitignore +17 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +13 -0
  5. data/README.md +66 -0
  6. data/Rakefile +1 -0
  7. data/eyes_selenium_ruby.gemspec +30 -0
  8. data/lib/eyes_selenium_ruby/capybara.rb +21 -0
  9. data/lib/eyes_selenium_ruby/eyes/agent_connecter.rb +39 -0
  10. data/lib/eyes_selenium_ruby/eyes/batch_info.rb +14 -0
  11. data/lib/eyes_selenium_ruby/eyes/driver.rb +145 -0
  12. data/lib/eyes_selenium_ruby/eyes/element.rb +78 -0
  13. data/lib/eyes_selenium_ruby/eyes/environment.rb +13 -0
  14. data/lib/eyes_selenium_ruby/eyes/eyes.rb +179 -0
  15. data/lib/eyes_selenium_ruby/eyes/eyes_keyboard.rb +25 -0
  16. data/lib/eyes_selenium_ruby/eyes/eyes_mouse.rb +60 -0
  17. data/lib/eyes_selenium_ruby/eyes/failure_reports.rb +4 -0
  18. data/lib/eyes_selenium_ruby/eyes/match_level.rb +7 -0
  19. data/lib/eyes_selenium_ruby/eyes/match_window_data.rb +18 -0
  20. data/lib/eyes_selenium_ruby/eyes/match_window_task.rb +71 -0
  21. data/lib/eyes_selenium_ruby/eyes/mouse_trigger.rb +19 -0
  22. data/lib/eyes_selenium_ruby/eyes/region.rb +22 -0
  23. data/lib/eyes_selenium_ruby/eyes/screenshot_taker.rb +18 -0
  24. data/lib/eyes_selenium_ruby/eyes/session.rb +14 -0
  25. data/lib/eyes_selenium_ruby/eyes/start_info.rb +33 -0
  26. data/lib/eyes_selenium_ruby/eyes/target_app.rb +17 -0
  27. data/lib/eyes_selenium_ruby/eyes/test_results.rb +21 -0
  28. data/lib/eyes_selenium_ruby/eyes/text_trigger.rb +15 -0
  29. data/lib/eyes_selenium_ruby/eyes/viewport_size.rb +109 -0
  30. data/lib/eyes_selenium_ruby/eyes_logger.rb +18 -0
  31. data/lib/eyes_selenium_ruby/utils/image_delta_compressor.rb +147 -0
  32. data/lib/eyes_selenium_ruby/utils.rb +5 -0
  33. data/lib/eyes_selenium_ruby/version.rb +3 -0
  34. data/lib/eyes_selenium_ruby.rb +41 -0
  35. data/spec/capybara_spec.rb +33 -0
  36. data/spec/driver_spec.rb +10 -0
  37. data/spec/eyes_spec.rb +156 -0
  38. data/spec/spec_helper.rb +29 -0
  39. data/spec/test_app.rb +11 -0
  40. data/test_script.rb +22 -0
  41. metadata +225 -0
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in applitools.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2013 Applitools
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # Applitools
2
+
3
+ Applitools Ruby SDK.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'eyes_selenium_ruby'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install eyes_selenium_ruby
18
+
19
+ ## Standalone Usage
20
+
21
+ ```ruby
22
+ Applitools::Eyes.config[:apikey] = 'XXX'
23
+
24
+ eyes = Applitools::Eyes.new
25
+ eyes.test(app_name: 'my app', test_name: 'my test') do |eyes, driver|
26
+ driver.get 'http://www.mywebsite.com'
27
+ eyes.check_window('home page')
28
+ driver.find_element(:css, "li#pricing").click
29
+ eyes.check_window('pricing')
30
+ end
31
+ ```
32
+
33
+ ## Integrated within your Capybara tests:
34
+ initializer:
35
+ ```ruby
36
+ Applitools::Eyes.config[:apikey] = 'XXX'
37
+ ```
38
+
39
+ spec:
40
+ ```ruby
41
+ require 'eyes_selenium_ruby/capybara'
42
+
43
+ describe 'some test'
44
+ let(:eyes) do
45
+ Applitools::Eyes.new
46
+ end
47
+ it 'should navigate from home page to pricing page'
48
+ eyes.test(app_name: 'my app', test_name: 'my test') do |eyes|
49
+ visit root_path
50
+ page.should have_content('login')
51
+ eyes.check_window('home page')
52
+ click_link 'Pricing'
53
+ eyes.check_window('pricing')
54
+ page.should have_content('gold')
55
+ end
56
+ end
57
+ end
58
+ ```
59
+
60
+ ## Contributing
61
+
62
+ 1. Fork it
63
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
64
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
65
+ 4. Push to the branch (`git push origin my-new-feature`)
66
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'eyes_selenium_ruby/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "eyes_selenium_ruby"
8
+ spec.version = Applitools::VERSION
9
+ spec.authors = ["Applitools team"]
10
+ spec.email = ["team@applitools.com"]
11
+ spec.description = "Applitools Ruby SDK"
12
+ spec.summary = "Applitools Ruby SDK"
13
+ spec.homepage = "http://www.applitools.com"
14
+ spec.license = "Apache License, Version 2.0"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "selenium-webdriver", ["~> 2.0"]
22
+ spec.add_dependency "httparty"
23
+ spec.add_dependency "oily_png", [">= 1.1.0"]
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec", [">= 2.2.0"]
28
+ spec.add_development_dependency "capybara", [">= 2.1.0"]
29
+ spec.add_development_dependency "sinatra"
30
+ end
@@ -0,0 +1,21 @@
1
+ require 'eyes_selenium_ruby'
2
+
3
+ # Override create driver to inject into capybara's driver
4
+ class Applitools::Eyes
5
+ def test(params={}, &block)
6
+ begin
7
+ previous_driver = Capybara.current_driver
8
+ previous_browser = Capybara.current_session.driver.instance_variable_get(:@browser)
9
+ Capybara.current_driver = :selenium
10
+ Capybara.current_session.driver.instance_variable_set(:@browser, driver)
11
+ open(params)
12
+ yield(self, driver)
13
+ close
14
+ rescue Applitools::EyesError
15
+ ensure
16
+ abort_if_not_closed
17
+ Capybara.current_session.driver.instance_variable_set(:@browser, previous_browser)
18
+ Capybara.current_driver = previous_driver
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ require 'httparty'
2
+ class Applitools::AgentConnector
3
+ include HTTParty
4
+ headers 'Accept' => 'application/json'
5
+ #debug_output $stdout # comment out when not debugging
6
+
7
+ attr_reader :uri, :auth
8
+ def initialize(base_uri, username, password)
9
+ # Remove trailing slashes in base uri and add the running sessions endpoint uri.
10
+ @uri = base_uri.gsub(/\/$/,"") + "/api/sessions/running"
11
+ @auth = { username: username, password: password }
12
+ end
13
+
14
+ def match_window(session, data)
15
+ self.class.headers 'Content-Type' => 'application/octet-stream'
16
+ json_data = data.to_hash.to_json.encode('UTF-8') # Notice that this does not include the screenshot
17
+ body = [json_data.length].pack('L>') + json_data + data.screenshot
18
+
19
+ res = self.class.post(uri + "/#{session.id}",basic_auth: auth, body: body)
20
+ raise Applitools::EyesError.new("could not connect to server") if res.code != 200
21
+ res.parsed_response["asExpected"]
22
+ end
23
+
24
+ def start_session(session_start_info)
25
+ self.class.headers 'Content-Type' => 'application/json'
26
+ res = self.class.post(uri, basic_auth: auth, body: { startInfo: session_start_info.to_hash }.to_json)
27
+ status_code = res.response.message
28
+ parsed_res = res.parsed_response
29
+ Applitools::Session.new(parsed_res["id"], parsed_res["url"], status_code == "Created" )
30
+ end
31
+
32
+ def stop_session(session, aborted=nil)
33
+ self.class.headers 'Content-Type' => 'application/json'
34
+ res = self.class.delete(uri + "/#{session.id}", basic_auth: auth, params: { aborted: aborted.to_s })
35
+ parsed_res = res.parsed_response
36
+ parsed_res.delete("$id")
37
+ Applitools::TestResults.new(*parsed_res.values)
38
+ end
39
+ end
@@ -0,0 +1,14 @@
1
+ class Applitools::BatchInfo
2
+ attr_reader :name, :started_at
3
+ def initialize(name=nil, started_at = Time.now)
4
+ @name = name
5
+ @started_at = started_at
6
+ end
7
+
8
+ def to_hash
9
+ {
10
+ name: name,
11
+ startedAt: started_at.iso8601
12
+ }
13
+ end
14
+ end
@@ -0,0 +1,145 @@
1
+ require 'socket'
2
+ require 'selenium-webdriver'
3
+ class Applitools::Driver
4
+
5
+ include Selenium::WebDriver::DriverExtensions::HasInputDevices
6
+
7
+ attr_reader :remote_server_url, :remote_session_id, :user_agent, :screenshot_taker
8
+ attr_accessor :user_inputs, :browser
9
+
10
+ DEFAULT_DRIVER = :firefox
11
+ DRIVER_METHODS = [
12
+ :title, :execute_script, :execute_async_script, :quit, :close, :get,
13
+ :post, :page_source, :window_handles, :window_handle, :switch_to,
14
+ :navigate, :manage, :capabilities
15
+ ]
16
+
17
+ ## If driver is not provided, Applitools::Driver will default to Firefox driver
18
+ ## Driver param can be a Selenium::WebDriver or a named symbol (:chrome)
19
+ #
20
+ ## Example:
21
+ # eyes.open(browser: :chrome) ##=> will create chrome webdriver
22
+ # eyes.open(browser: Selenium::WebDriver.for(:chrome) ##=> will create the same thing
23
+ # eyes.open ##=> will create a webdriver according to Applitools::Driver::DEFAULT_DRIVER
24
+ def initialize(options={})
25
+ browser_obj = options.delete(:browser) || DEFAULT_DRIVER
26
+ @browser ||= case browser_obj
27
+ when Symbol
28
+ Selenium::WebDriver.for browser_obj
29
+ else
30
+ browser_obj
31
+ end
32
+ at_exit { quit rescue nil }
33
+
34
+ @user_inputs = []
35
+ @remote_server_url = address_of_remote_server
36
+ @remote_session_id = remote_session_id
37
+ @user_agent = get_user_agent
38
+ begin
39
+ if browser.capabilities.takes_screenshot?
40
+ @screenshot_taker = false
41
+ else
42
+ @screenshot_taker = Applitools::ScreenshotTaker.new(@remote_server_url, @remote_session_id)
43
+ end
44
+ rescue => e
45
+ raise Applitools::EyesError.new "Can't take screenshots (#{e.message})"
46
+ end
47
+ end
48
+
49
+ DRIVER_METHODS.each do |method|
50
+ define_method method do |*args, &block|
51
+ browser.send(method,*args, &block)
52
+ end
53
+ end
54
+
55
+ def screenshot_as(output_type)
56
+ return browser.screenshot_as(output_type) if !screenshot_taker
57
+
58
+ if output_type.downcase.to_sym != :base64
59
+ raise Applitools::EyesError.new("#{output_type} ouput type not supported for screenshot")
60
+ end
61
+ screenshot_taker.screenshot
62
+ end
63
+
64
+ def mouse
65
+ Applitools::EyesMouse.new(self, browser.mouse)
66
+ end
67
+
68
+ def keyboard
69
+ Applitools::EyesKeyboard.new(self, browser.keyboard)
70
+ end
71
+
72
+ def find_element(by, selector)
73
+ Applitools::Element.new(self, browser.find_element(by, selector))
74
+ end
75
+
76
+ def find_elements(by, selector)
77
+ browser.find_elements(by, selector).map { |el| Applitools::Element.new(self, el) }
78
+ end
79
+
80
+ def create_application
81
+ Applitools::TargetApp.new(remote_server_url, remote_session_id, user_agent)
82
+ end
83
+
84
+ def clear_user_inputs
85
+ user_inputs.clear
86
+ end
87
+
88
+ def ie?
89
+ browser.to_s == 'ie'
90
+ end
91
+
92
+ def firefox?
93
+ browser.to_s == 'firefox'
94
+ end
95
+
96
+ private
97
+
98
+ def address_of_remote_server
99
+ uri = URI(browser.current_url)
100
+ raise Applitools::EyesError.new("Failed to get remote web driver url") if uri.to_s.empty?
101
+
102
+ webdriver_host = uri.host
103
+ if ['127.0.0.1', 'localhost'].include?(webdriver_host) && !firefox? && !ie?
104
+ uri.host = get_local_ip || 'localhost'
105
+ end
106
+
107
+ uri
108
+ end
109
+
110
+ def remote_session_id
111
+ browser.remote_session_id
112
+ end
113
+
114
+ def get_user_agent
115
+ execute_script "return navigator.userAgent"
116
+ rescue => e
117
+ puts "getUserAgent(): Failed to obtain user-agent string (#{e.message})"
118
+ end
119
+
120
+ def get_local_ip
121
+ begin
122
+ Socket.ip_address_list.detect do |intf|
123
+ intf.ipv4? and !intf.ipv4_loopback? and !intf.ipv4_multicast?
124
+ end.ip_address
125
+ rescue SocketError => e
126
+ raise Applitools::EyesError.new("Failed to get local IP! (#{e})")
127
+ end
128
+ end
129
+
130
+ end
131
+
132
+ ## .bridge, .session_id and .server_url are private methods in Selenium::WebDriver gem
133
+ module Selenium::WebDriver
134
+ class Driver
135
+ def remote_session_id
136
+ bridge.session_id
137
+ end
138
+ end
139
+
140
+ class Remote::Http::Common
141
+ def get_server_url
142
+ server_url
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,78 @@
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.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.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
@@ -0,0 +1,13 @@
1
+ class Applitools::Environment
2
+
3
+ attr_accessor :os, :hosting_app, :display_size
4
+ def initialize(os=nil, hosting_app=nil, display_size=nil)
5
+ @os = os
6
+ @hosting_app = hosting_app
7
+ @display_size = display_size
8
+ end
9
+
10
+ def to_hash
11
+ { os: os, hostingApp: hosting_app, displaySize: Hash[display_size.each_pair.to_a] }
12
+ end
13
+ end
@@ -0,0 +1,179 @@
1
+ class Applitools::Eyes
2
+ DEFAULT_MATCH_TIMEOUT = 2.0
3
+
4
+ class << self
5
+ attr_accessor :config
6
+ end
7
+
8
+ @config = {
9
+ server_url: 'https://eyes.applitools.com',
10
+ user: 'eyes.selenium.ruby'
11
+ # apikey: 'please supply an apikey in your initializer'
12
+ }
13
+
14
+ attr_reader :agent_connector, :disabled
15
+ attr_accessor :app_name, :test_name, :session, :is_open, :aborted, :viewport_size, :match_timeout,
16
+ :failure_reports, :test_batch, :match_level, :driver, :host_os, :host_app, :branch_name, :parent_branch_name,
17
+ :should_match_window_run_once_on_timeout, :session_start_info, :match_window_task
18
+
19
+ def config
20
+ self.class.config
21
+ end
22
+
23
+ def initialize(params={})
24
+ raise "Please supply an apikey: Eyes.config[:apikey] = ..." unless config[:apikey]
25
+
26
+ @disabled = params[:disabled]
27
+
28
+ @driver = create_driver(params)
29
+ return if disabled?
30
+
31
+ @agent_connector = Applitools::AgentConnector.new(config[:server_url], config[:user], config[:apikey])
32
+ @match_timeout = DEFAULT_MATCH_TIMEOUT
33
+ @failure_reports = Applitools::FailureReports::ON_CLOSE
34
+ end
35
+
36
+ def create_driver(params)
37
+ Applitools::Driver.new(browser: params.fetch(:browser, nil))
38
+ end
39
+
40
+ def open(params={})
41
+ return driver if disabled?
42
+
43
+ if open?
44
+ abort_if_not_closed
45
+ msg = 'a test is alread running'
46
+ EyesLogger.info(msg) and raise Applitools::EyesError.new(msg)
47
+ end
48
+
49
+ self.app_name = params.fetch(:app_name)
50
+ self.failure_reports = params.fetch(:failure_reports, self.failure_reports)
51
+ self.match_level = params.fetch(:match_level,MatchLevel::EXACT)
52
+ self.test_name = params.fetch(:test_name)
53
+ self.viewport_size = params.fetch(:view_port_size, nil)
54
+
55
+ self.is_open = true
56
+ driver
57
+ end
58
+
59
+ def open?
60
+ self.is_open
61
+ end
62
+
63
+ def check_window(tag)
64
+ return if disabled?
65
+ raise Applitools::EyesError.new("Eyes not open") if !open?
66
+ if !session
67
+ start_session
68
+ self.match_window_task = Applitools::MatchWindowTask.new(agent_connector, session, driver, match_timeout)
69
+ end
70
+
71
+ as_expected = match_window_task.match_window(tag, should_match_window_run_once_on_timeout)
72
+ if !as_expected
73
+ self.should_match_window_run_once_on_timeout = true
74
+ if !session.new_session?
75
+ EyesLogger.info %( "mismatch! #{ tag ? "" : "(#{tag})" } )
76
+ if failure_reports.to_i == Applitools::FailureReports::IMMEDIATE
77
+ raise Applitools::TestFailedError.new("Mismatch found in '#{start_info.scenario_id_or_name}'"\
78
+ " of '#{start_info.app_id_or_name}'")
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ def close
85
+ return if disabled?
86
+ self.is_open = false
87
+ return Applitools::TestResults.new if !session
88
+
89
+ session_results_url = session.url
90
+ results = agent_connector.stop_session(session,false)
91
+ new_session = session.new_session?
92
+ self.session = nil
93
+
94
+ if new_session
95
+ instructions = "Please approve the new baseline at #{session_results_url}"
96
+ EyesLogger.info "--- New test ended. #{instructions}"
97
+ message = "' #{session_start_info.scenario_id_or_name} of"\
98
+ " #{session_start_info.app_id_or_name}. #{instructions}"
99
+ raise Applitools::NewTestError.new(message, results)
100
+ elsif 0 < results.mismatches || 0 < results.missing
101
+ EyesLogger.info "--- Failed test ended. See details at #{session_results_url}"
102
+ message = "' #{session_start_info.scenario_id_or_name} of"\
103
+ " #{session_start_info.app_id_or_name}'. See details at #{session_results_url}"
104
+ raise Applitools::TestFailedError.new(message, results)
105
+ end
106
+
107
+ EyesLogger.info "--- Test passed. See details at #{session_results_url}"
108
+ end
109
+
110
+ ## Use this method to perform seamless testing with selenium through eyes driver.
111
+ ## Using Selenium methods inside the 'test' block will send the messages to Selenium
112
+ ## after creating the Eyes triggers for them.
113
+ ##
114
+ ## Example:
115
+ # eyes.test(app_name: 'my app1', test_name: 'my test') do |d|
116
+ # get "http://www.google.com"
117
+ # check_window("initial")
118
+ # end
119
+ def test(params={}, &block)
120
+ begin
121
+ open(params)
122
+ yield(self, driver)
123
+ close
124
+ rescue Applitools::EyesError
125
+ ensure
126
+ abort_if_not_closed
127
+ end
128
+ end
129
+
130
+
131
+ def abort_if_not_closed
132
+ return if disabled?
133
+ self.is_open = false
134
+ if session
135
+ begin
136
+ agent_connector.stop_session(session,true)
137
+ rescue Applitools::EyesError => e
138
+ EyesLogger.info "Failed to abort server session -> #{e.message} "
139
+ ensure
140
+ self.session = nil
141
+ end
142
+ end
143
+ end
144
+
145
+ private
146
+
147
+ def disabled?
148
+ disabled
149
+ end
150
+
151
+ def start_session
152
+ assign_viewport_size
153
+ test_batch ||= Applitools::BatchInfo.new
154
+ app_env = Applitools::Environment.new(host_os, host_app, viewport_size)
155
+ application = driver.create_application
156
+ self.session_start_info = Applitools::StartInfo.new(
157
+ app_name, test_name, test_batch, app_env, application,
158
+ match_level,nil, branch_name, parent_branch_name
159
+ )
160
+ self.session = agent_connector.start_session(session_start_info)
161
+ self.should_match_window_run_once_on_timeout = session.new_session?
162
+ end
163
+
164
+ def viewport_size?
165
+ self.viewport_size
166
+ end
167
+
168
+ def assign_viewport_size
169
+ if viewport_size?
170
+ self.viewport_size = Applitools::ViewportSize.new(driver, viewport_size).set
171
+ else
172
+ self.viewport_size = Applitools::ViewportSize.new(driver).extract_viewport_from_browser!
173
+ end
174
+ end
175
+
176
+ def to_hash
177
+ Hash[dimension.each_pair.to_a]
178
+ end
179
+ end
@@ -0,0 +1,25 @@
1
+ class Applitools::EyesKeyboard
2
+ attr_reader :keyboard, :driver
3
+
4
+ def initialize(driver, keyboard)
5
+ @driver = driver
6
+ @keyboard = keyboard
7
+ end
8
+
9
+ def send_keys(*keys)
10
+ active_element = Applitools::Element.new(driver, driver.switch_to.active_element)
11
+ current_control = active_element.region
12
+ Selenium::WebDriver::Keys.encode(keys).each do |key|
13
+ driver.user_inputs << Applitools::TextTrigger.new(key.to_s, current_control)
14
+ end
15
+ keyboard.send_keys(*keys)
16
+ end
17
+
18
+ def press(key)
19
+ keyboard.press(key)
20
+ end
21
+
22
+ def release(key)
23
+ keyboard.release(key)
24
+ end
25
+ end