eyes_selenium_ruby 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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