automation_helpers 4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +13 -0
  3. data/README.md +49 -0
  4. data/lib/automation_helpers/drivers/browserstack.rb +9 -0
  5. data/lib/automation_helpers/drivers/local.rb +9 -0
  6. data/lib/automation_helpers/drivers/remote.rb +9 -0
  7. data/lib/automation_helpers/drivers/v4/browserstack.rb +135 -0
  8. data/lib/automation_helpers/drivers/v4/capabilities.rb +106 -0
  9. data/lib/automation_helpers/drivers/v4/local.rb +92 -0
  10. data/lib/automation_helpers/drivers/v4/options.rb +52 -0
  11. data/lib/automation_helpers/drivers/v4/remote.rb +64 -0
  12. data/lib/automation_helpers/drivers/v4.rb +7 -0
  13. data/lib/automation_helpers/drivers.rb +6 -0
  14. data/lib/automation_helpers/extensions/array.rb +18 -0
  15. data/lib/automation_helpers/extensions/capybara/node/element.rb +31 -0
  16. data/lib/automation_helpers/extensions/cucumber/core/test/case.rb +26 -0
  17. data/lib/automation_helpers/extensions/selenium/webdriver/logs.rb +47 -0
  18. data/lib/automation_helpers/extensions/string.rb +34 -0
  19. data/lib/automation_helpers/extensions.rb +7 -0
  20. data/lib/automation_helpers/logger.rb +21 -0
  21. data/lib/automation_helpers/patches/base.rb +52 -0
  22. data/lib/automation_helpers/patches/capybara.rb +27 -0
  23. data/lib/automation_helpers/patches/parallel_cucumber.rb +86 -0
  24. data/lib/automation_helpers/patches/selenium_logger.rb +24 -0
  25. data/lib/automation_helpers/patches/selenium_manager.rb +43 -0
  26. data/lib/automation_helpers/patches/selenium_options.rb +72 -0
  27. data/lib/automation_helpers/patches.rb +8 -0
  28. data/lib/automation_helpers/version.rb +5 -0
  29. data/lib/automation_helpers.rb +68 -0
  30. metadata +201 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e31fd999ded8a53243daee17b49c7d85c65c54c0c75ab657669b4e8753f0efc4
4
+ data.tar.gz: e0abb956e546004f43b9367f0c5e5bf6dbb51770f575642d6e00bfd1b5b0bcbf
5
+ SHA512:
6
+ metadata.gz: 8f981fb29c66cd31b7a08459f4804cdf0917550547aeafddc1397b861b9f0935d03270db452e7cccbabd954425ab5d19e96b8c307a727b1123c842688cb5d558
7
+ data.tar.gz: 61a8a6dcbb015412438984f39983ea02073f15c9097428ba8cde64cfb4716b50c6dc73e68d0da9efea64b4cd86a197dfdea5e1030642c8c365191c734445a5ee
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2020-2021, The SitePrism team & Marcelo Nicolosi Santos
2
+
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6
+
7
+ Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8
+
9
+ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
10
+
11
+ Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # Automation Helpers
2
+
3
+ #### The new OSS name for the gem formerly known as ca_testing
4
+
5
+ This package will allow you to extend your automated testing frameworks with the following
6
+ - Driver creation: Allowing you to simply reference your drivers with a simple method
7
+ (**No more confusing capability classes / methods**)
8
+ - Simple extensions to regular classes (A bit like ActiveSupport where it's needed / common)
9
+ - Extensions to the commonly used Automation Packages (Selenium / Capybara e.t.c.), DSL's
10
+ (Think of things like enhancing `Capybara::Node::Element` e.t.c.)
11
+ - Patches required to allow instant fixing of bugs in upstream repos whilst fixes are
12
+ in PR and being reviewed / merged
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'automation_helpers'
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ ```shell
25
+ $ bundle
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ Either require all of the extensions required, or require individual bits and pieces
31
+
32
+ ## Development
33
+
34
+ ```
35
+ $ bundle
36
+ # Code anything relevant - Add tests for each public method!
37
+ $ bundle exec rake
38
+ # Ensure it's all green! Then commit and push
39
+ ```
40
+
41
+ ## Contributing
42
+
43
+ Bug reports and pull requests are welcome on GitHub at
44
+ https://github.com/site-prism/automation_helpers
45
+
46
+ ## Verbose Documentation
47
+
48
+ This will come in time. Meanwhile if you check the gem code some of the methods are now
49
+ beginning to get documented. Also check the specs
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'automation_helpers/drivers/v4/browserstack'
4
+
5
+ module AutomationHelpers
6
+ module Drivers
7
+ Browserstack = V4::Browserstack
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'automation_helpers/drivers/v4/local'
4
+
5
+ module AutomationHelpers
6
+ module Drivers
7
+ Local = V4::Local
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'automation_helpers/drivers/v4/remote'
4
+
5
+ module AutomationHelpers
6
+ module Drivers
7
+ Remote = V4::Remote
8
+ end
9
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'selenium/webdriver'
5
+
6
+ require 'automation_helpers/drivers/v4/capabilities'
7
+ require 'automation_helpers/drivers/v4/options'
8
+
9
+ module AutomationHelpers
10
+ module Drivers
11
+ module V4
12
+ #
13
+ # {AutomationHelpers::Drivers::V4::Browserstack}
14
+ #
15
+ # The Browserstack Driver that will connect to a hosted grid
16
+ # Requires a series of pre-set values to be passed in
17
+ #
18
+ class Browserstack
19
+ attr_reader :browser, :browserstack_options, :device_options
20
+ private :browser, :browserstack_options, :device_options
21
+
22
+ # #### Initial setup options
23
+ #
24
+ # - **browser** (required) - When instantiating, the first argument must be the symbol that represents what browser to use
25
+ # - **browserstack_options** (required) - A Hash of all required options that will be parsed and used to setup the driver
26
+ # - :build_name (String) -> The build name to be stored on browserstack servers
27
+ # - :project_name (String) -> The project name to be stored on browserstack servers
28
+ # - :session_name (String) -> The session name to be stored on browserstack servers
29
+ # - :browserstack_debug_mode (Boolean) -> Set this to true to run in browserstack debug mode (Note this runs slower!)
30
+ # - :config (String) -> This is an underscore separated key that distils the granular running information
31
+ # i.e. Windows_7_86 means run on Windows Operating System, OS Version 7, Browser Version 86
32
+ # i.e. OSX_Mojave_12 means run on Mac Operating System, OS Version Mojave, Browser Version 12
33
+ # i.e. Windows_10_92 means run on Windows Operating System, OS Version 10, Browser Version 92
34
+ # - :username (String) -> The username for Browserstack
35
+ # - :api_key (String) -> The api key for Browserstack
36
+ #
37
+ def initialize(browser, browserstack_options, device_options = {})
38
+ @browser = browser
39
+ @browserstack_options = browserstack_options
40
+ @device_options = device_options
41
+ end
42
+
43
+ # @return [Nil]
44
+ #
45
+ # Register a new driver with the default selenium name for use in a remote browserstack setup
46
+ def register
47
+ Capybara.register_driver :selenium do |app|
48
+ Capybara::Selenium::Driver.new(
49
+ app,
50
+ browser: :remote,
51
+ capabilities: [desired_capabilities, options],
52
+ url: browserstack_hub_url
53
+ )
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def desired_capabilities
60
+ Selenium::WebDriver::Remote::Capabilities.new(
61
+ ::Faraday::Utils.deep_merge(
62
+ # Browserstack Capabilities and General Capabilities are at different levels, so we merge first
63
+ browserstack_capabilities.merge(browser_version_capability),
64
+ # Then we deep merge with anything specifically passed into the driver registration (as these can be nested)
65
+ browser_specific_capabilities.as_json
66
+ )
67
+ )
68
+ end
69
+
70
+ def browserstack_capabilities
71
+ ::Faraday::Utils.deep_merge(configurable_capabilities, static_capabilities)
72
+ end
73
+
74
+ def configurable_capabilities
75
+ {
76
+ 'bstack:options' => {
77
+ 'buildName' => browserstack_options[:build_name],
78
+ 'projectName' => browserstack_options[:project_name],
79
+ 'sessionName' => browserstack_options[:session_name],
80
+ 'debug' => browserstack_options[:browserstack_debug_mode],
81
+ 'os' => os,
82
+ 'osVersion' => os_version
83
+ }
84
+ }
85
+ end
86
+
87
+ def static_capabilities
88
+ {
89
+ 'bstack:options' => {
90
+ 'local' => 'false',
91
+ 'seleniumVersion' => '4.0.0-alpha-6',
92
+ 'consoleLogs' => 'verbose',
93
+ 'networkLogs' => 'true',
94
+ 'resolution' => '1920x1080'
95
+ }
96
+ }
97
+ end
98
+
99
+ def browser_specific_capabilities
100
+ Capabilities.for(browser, device_options)
101
+ end
102
+
103
+ def browser_version_capability
104
+ return {} if device?
105
+
106
+ { 'browserVersion' => browser_version }
107
+ end
108
+
109
+ def options
110
+ Options.for(browser)
111
+ end
112
+
113
+ def browserstack_hub_url
114
+ "https://#{browserstack_options[:username]}:#{browserstack_options[:api_key]}@hub-cloud.browserstack.com/wd/hub"
115
+ end
116
+
117
+ def os
118
+ browserstack_options[:config].split('_')[0]
119
+ end
120
+
121
+ def os_version
122
+ browserstack_options[:config].split('_')[1]
123
+ end
124
+
125
+ def browser_version
126
+ browserstack_options[:config].split('_')[2]
127
+ end
128
+
129
+ def device?
130
+ %i[android ios].include?(browser)
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'selenium/webdriver'
4
+
5
+ module AutomationHelpers
6
+ module Drivers
7
+ module V4
8
+ #
9
+ # {AutomationHelpers::Drivers::V4::Capabilities}
10
+ #
11
+ # The Capabilities object that will be used to instantiate whatever driver you
12
+ # are configuring
13
+ #
14
+ class Capabilities
15
+ class << self
16
+ # @return [Selenium::WebDriver::Remote::Capabilities]
17
+ #
18
+ # Returns the Capabilities hash relevant to the browser specified to be passed to the driver instantiation
19
+ def for(browser, device_options = {})
20
+ ::Selenium::WebDriver::Remote::Capabilities.new(capabilities_hash(browser, device_options))
21
+ end
22
+
23
+ private
24
+
25
+ def capabilities_hash(browser, device_options)
26
+ case browser
27
+ when :android; then android_capabilities(device_options)
28
+ when :chrome; then chrome_capabilities
29
+ when :firefox; then firefox_capabilities
30
+ when :internet_explorer; then internet_explorer_capabilities
31
+ when :ios; then ios_capabilities(device_options)
32
+ else {}
33
+ end
34
+ end
35
+
36
+ def android_capabilities(device_options)
37
+ {
38
+ 'bstack:options' => {
39
+ 'deviceName' => device_options[:device_name],
40
+ 'realMobile' => 'true',
41
+ 'appiumVersion' => android_appium_version(device_options[:os_version])
42
+ }
43
+ }
44
+ end
45
+
46
+ def chrome_capabilities
47
+ {
48
+ 'browserName' => 'chrome',
49
+ 'goog:loggingPrefs' => {
50
+ 'browser' => 'ALL',
51
+ 'driver' => 'ALL'
52
+ }
53
+ }
54
+ end
55
+
56
+ def firefox_capabilities
57
+ {
58
+ 'browserName' => 'firefox'
59
+ }
60
+ end
61
+
62
+ def internet_explorer_capabilities
63
+ {
64
+ 'browserName' => 'internet explorer',
65
+ 'bstack:options' => {
66
+ 'ie' => {
67
+ # This is a minor hack until the IEDriver catches up and releases a V4 compliant copy
68
+ # It is confirmed to be compliant with V4 selenium jars e.t.c.
69
+ 'driver' => '3.141.59',
70
+ 'arch' => 'x32'
71
+ }
72
+ }
73
+ }
74
+ end
75
+
76
+ def ios_capabilities(device_options)
77
+ {
78
+ 'bstack:options' => {
79
+ 'deviceName' => device_options[:device_name],
80
+ 'realMobile' => 'true',
81
+ 'appiumVersion' => ios_appium_version(device_options[:os_version])
82
+ }
83
+ }
84
+ end
85
+
86
+ def android_appium_version(android_version)
87
+ case android_version.to_f
88
+ when 10..; then '1.21.0'
89
+ when 9..; then '1.20.2'
90
+ else raise ArgumentError, "Your Android Version is too low. Please don't use lower than Android Pie (9)."
91
+ end
92
+ end
93
+
94
+ def ios_appium_version(ios_version)
95
+ case ios_version.to_f
96
+ when 13..; then '1.21.0'
97
+ when 12..; then '1.20.2'
98
+ when 11..; then '1.16.0'
99
+ else raise ArgumentError, "Your iOS Version is too low. Please don't use lower than iOS 11."
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'selenium/webdriver'
4
+
5
+ require 'automation_helpers/drivers/v4/options'
6
+
7
+ module AutomationHelpers
8
+ module Drivers
9
+ module V4
10
+ #
11
+ # {AutomationHelpers::Drivers::V4::Local}
12
+ #
13
+ # The Local Driver that will spin up and run on your machine (Without connecting to any grid)
14
+ #
15
+ class Local
16
+ attr_reader :browser
17
+ private :browser
18
+
19
+ # #### Initial setup options
20
+ #
21
+ # - **browser** (required) - When instantiating, the first argument must be the symbol that represents what browser to use
22
+ #
23
+ def initialize(browser)
24
+ @browser = browser
25
+ end
26
+
27
+ # @return [Nil]
28
+ #
29
+ # Register a new driver with the default selenium name for use locally
30
+ def register
31
+ Capybara.register_driver :selenium do |app|
32
+ Capybara::Selenium::Driver.new(
33
+ app,
34
+ browser: browser,
35
+ service: service,
36
+ capabilities: capabilities
37
+ )
38
+ end
39
+ end
40
+
41
+ # @return [Array]
42
+ #
43
+ # The order of these capabilities is important because in the internal configuration
44
+ # for the driver; these 2 objects are merged (And both will contain a browserName)
45
+ # as such we need to ensure the browserName we manually set in `desired_capabilities`
46
+ # is retained as this is the one required by safari
47
+ def capabilities
48
+ if safari?
49
+ [options, desired_capabilities]
50
+ else
51
+ [desired_capabilities, options]
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ # This is required to make local drivers work exclusively with Safari TP
58
+ # This is required in V13 of Safari as the driver there is notoriously flaky
59
+ # In V12 it doesn't hinder it
60
+ # Safari V11 is unsupported.
61
+ def service
62
+ return unless safari?
63
+
64
+ ::Selenium::WebDriver::Safari.technology_preview!
65
+ ::Selenium::WebDriver::Service.safari(args: ['--diagnose'])
66
+ end
67
+
68
+ # This is required because Capybara and Safari aren't quite sure what the difference
69
+ # is between the two browsers. So to compensate an illegal browserName value is
70
+ # set that allows easy distinction between the two browsers
71
+ #
72
+ # NB: Whilst using Safari TP this is required.
73
+ def desired_capabilities
74
+ ::Selenium::WebDriver::Remote::Capabilities.new.tap do |capabilities|
75
+ if safari?
76
+ capabilities['browserName'] = 'Safari Technology Preview'
77
+ AutomationHelpers.logger.warn('Altering Browser Name request to alleviate Capybara failure with STP.')
78
+ end
79
+ end
80
+ end
81
+
82
+ def options
83
+ Options.for(browser)
84
+ end
85
+
86
+ def safari?
87
+ browser == :safari
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'selenium/webdriver'
4
+
5
+ module AutomationHelpers
6
+ module Drivers
7
+ module V4
8
+ #
9
+ # {AutomationHelpers::Drivers::V4::Options}
10
+ #
11
+ # The Options object that will be used to instantiate whatever driver you
12
+ # are configuring
13
+ #
14
+ class Options
15
+ class << self
16
+ # @return [Selenium::Webdriver::Options]
17
+ #
18
+ # Returns the Options payload relevant to the browser specified to be passed to the driver instantiation
19
+ def for(browser)
20
+ initial_options(browser).tap { |opts| opts.headless! if headless? }
21
+ end
22
+
23
+ private
24
+
25
+ def initial_options(browser)
26
+ case browser
27
+ when :chrome; then ::Selenium::WebDriver::Chrome::Options.new
28
+ when :firefox; then ::Selenium::WebDriver::Firefox::Options.new(log_level: 'trace')
29
+ when :edge; then ::Selenium::WebDriver::Edge::Options.new
30
+ when :safari; then ::Selenium::WebDriver::Safari::Options.new(automatic_inspection: true)
31
+ when :internet_explorer; then internet_explorer_options
32
+ else {}
33
+ end
34
+ end
35
+
36
+ # Constantly fire mouseOver events on click actions (Should help mitigate flaky clicks)
37
+ def internet_explorer_options
38
+ ::Selenium::WebDriver::IE::Options.new(persistent_hover: true).tap do |opts|
39
+ # This can be removed once we migrate past Se4 proper (As the space version name is present there)
40
+ AutomationHelpers.logger.info('Removing `browser_name` key from options payload.')
41
+ opts.options.delete(:browser_name)
42
+ end
43
+ end
44
+
45
+ def headless?
46
+ ENV['HEADLESS'] == 'true'
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'automation_helpers/drivers/v4/capabilities'
4
+ require 'automation_helpers/drivers/v4/options'
5
+
6
+ module AutomationHelpers
7
+ module Drivers
8
+ module V4
9
+ #
10
+ # {AutomationHelpers::Drivers::V4::Remote}
11
+ #
12
+ # The Remote Driver that will connect to a dockerised self-hosted grid
13
+ # Expects the grid to be live and accepting node requests
14
+ #
15
+ class Remote
16
+ attr_reader :browser
17
+ private :browser
18
+
19
+ # #### Initial setup options
20
+ #
21
+ # - **browser** (required) - When instantiating, the first argument must be the symbol that represents what browser to use
22
+ # - **ENV["HUB_URL"]** (required) - The environment variable HUB_URL must be set to the actively running dockerised grid
23
+ # (By default this should be +http://hub:4444/wd/hub+)
24
+ def initialize(browser)
25
+ @browser = browser
26
+ end
27
+
28
+ # @return [Nil]
29
+ #
30
+ # Register a new driver with the default selenium name for use in a (localised), remote grid setup
31
+ def register
32
+ Capybara.register_driver :selenium do |app|
33
+ Capybara::Selenium::Driver.new(
34
+ app,
35
+ browser: :remote,
36
+ capabilities: [browser_capabilities, options],
37
+ url: hub_url
38
+ )
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def browser_capabilities
45
+ raise ArgumentError, 'You must use a supported browser' unless supported_browser?
46
+
47
+ Capabilities.for(browser)
48
+ end
49
+
50
+ def options
51
+ Options.for(browser)
52
+ end
53
+
54
+ def hub_url
55
+ ENV['HUB_URL']
56
+ end
57
+
58
+ def supported_browser?
59
+ %i[chrome firefox].include?(browser)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'automation_helpers/drivers/v4/browserstack'
4
+ require 'automation_helpers/drivers/v4/capabilities'
5
+ require 'automation_helpers/drivers/v4/local'
6
+ require 'automation_helpers/drivers/v4/options'
7
+ require 'automation_helpers/drivers/v4/remote'
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'automation_helpers/drivers/browserstack'
4
+ require 'automation_helpers/drivers/local'
5
+ require 'automation_helpers/drivers/remote'
6
+ require 'automation_helpers/drivers/v4'
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Additional useful methods to extend the Array class with
4
+ class Array
5
+ # @return [Boolean]
6
+ #
7
+ # Test whether an array is wholly unique
8
+ def uniq?
9
+ uniq == self
10
+ end
11
+
12
+ # @return [Array]
13
+ #
14
+ # Return the non-unique items of an array
15
+ def non_uniq
16
+ tally.select { |_key, count| count > 1 }.map(&:first)
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capybara
4
+ module Node
5
+ #
6
+ # Additional useful methods to extend the Capybara::Node::Element class with
7
+ #
8
+ class Element
9
+ # @return [Integer]
10
+ #
11
+ # The Left-Most pixel's horizontal position in the DOM (From element.rect)
12
+ def horizontal_position
13
+ native.rect.x.to_i
14
+ end
15
+
16
+ # @return [Integer]
17
+ #
18
+ # The Left-Most pixel's vertical position in the DOM (From element.rect)
19
+ def vertical_position
20
+ native.rect.y.to_i
21
+ end
22
+
23
+ # @return [Boolean]
24
+ #
25
+ # Whether the element is in a stale state or not
26
+ def stale?
27
+ inspect == 'Obsolete #<Capybara::Node::Element>'
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cucumber
4
+ module Core
5
+ module Test
6
+ #
7
+ # Additional useful methods to extend the Cucumber::Core::Test::Case class with
8
+ #
9
+ class Case
10
+ # @return [String]
11
+ #
12
+ # The file name of the feature being ran (Without the .feature extension)
13
+ def feature_file_name
14
+ feature_file_path.split('/').last&.split('.')&.first.to_s
15
+ end
16
+
17
+ # @return [String]
18
+ #
19
+ # The fully qualified location of the feature being ran
20
+ def feature_file_path
21
+ location.to_s
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end