testcentricity_web 4.1.3 → 4.1.6
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.
- checksums.yaml +4 -4
- data/.gitignore +18 -0
- data/.simplecov +5 -0
- data/CHANGELOG.md +30 -1
- data/Gemfile.lock +170 -0
- data/README.md +287 -102
- data/Rakefile +37 -1
- data/config/cucumber.yml +150 -0
- data/docker-compose-v3.yml +48 -0
- data/features/basic_test_page_css.feature +24 -0
- data/features/basic_test_page_xpath.feature +24 -0
- data/features/step_definitions/generic_steps.rb.rb +37 -0
- data/features/support/env.rb +43 -0
- data/features/support/hooks.rb +245 -0
- data/features/support/pages/basic_css_test_page.rb +49 -0
- data/features/support/pages/basic_test_page.rb +238 -0
- data/features/support/pages/basic_xpath_test_page.rb +49 -0
- data/features/support/pages/media_page.rb +11 -0
- data/features/support/world_pages.rb +15 -0
- data/lib/testcentricity_web/data_objects/environment.rb +4 -0
- data/lib/testcentricity_web/version.rb +1 -1
- data/lib/testcentricity_web/web_core/page_object.rb +13 -6
- data/lib/testcentricity_web/web_core/page_objects_helper.rb +41 -8
- data/lib/testcentricity_web/web_core/page_section.rb +1 -16
- data/lib/testcentricity_web/web_core/webdriver_helper.rb +78 -120
- data/lib/testcentricity_web/web_elements/select_list.rb +18 -7
- data/lib/testcentricity_web/web_elements/ui_elements_helper.rb +13 -0
- data/reports/.keep +1 -0
- data/test_site/basic_test_page.html +240 -0
- data/test_site/images/Granny.jpg +0 -0
- data/test_site/images/Wilder.jpg +0 -0
- data/test_site/images/You_Betcha.jpg +0 -0
- data/test_site/media/MP4_small.mp4 +0 -0
- data/test_site/media/MPS_sample.mp3 +0 -0
- data/test_site/media_page.html +33 -0
- data/testcentricity_web.gemspec +5 -0
- metadata +105 -4
- data/test_site/test_page.html +0 -11
data/Rakefile
CHANGED
@@ -1 +1,37 @@
|
|
1
|
-
require '
|
1
|
+
require 'rubygems'
|
2
|
+
require 'cucumber'
|
3
|
+
require 'cucumber/rake/task'
|
4
|
+
require 'rake'
|
5
|
+
|
6
|
+
|
7
|
+
namespace :features do
|
8
|
+
Cucumber::Rake::Task.new(:edge) do |t|
|
9
|
+
t.profile = 'edge'
|
10
|
+
end
|
11
|
+
|
12
|
+
Cucumber::Rake::Task.new(:chrome) do |t|
|
13
|
+
t.profile = 'chrome'
|
14
|
+
end
|
15
|
+
|
16
|
+
Cucumber::Rake::Task.new(:edge_headless) do |t|
|
17
|
+
t.profile = 'edge_headless'
|
18
|
+
end
|
19
|
+
|
20
|
+
Cucumber::Rake::Task.new(:chrome_headless) do |t|
|
21
|
+
t.profile = 'chrome_headless'
|
22
|
+
end
|
23
|
+
|
24
|
+
Cucumber::Rake::Task.new(:safari) do |t|
|
25
|
+
t.profile = 'safari'
|
26
|
+
end
|
27
|
+
|
28
|
+
Cucumber::Rake::Task.new(:firefox) do |t|
|
29
|
+
t.profile = 'firefox'
|
30
|
+
end
|
31
|
+
|
32
|
+
Cucumber::Rake::Task.new(:firefox_headless) do |t|
|
33
|
+
t.profile = 'firefox_headless'
|
34
|
+
end
|
35
|
+
|
36
|
+
task :all => [:edge, :edge_headless, :chrome, :chrome_headless, :safari]
|
37
|
+
end
|
data/config/cucumber.yml
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
<% desktop = "--require features BROWSER_TILE=true BROWSER_SIZE=1300,1000 --publish-quiet" %>
|
2
|
+
<% tablet = "--tags @desktop --require features BROWSER_TILE=true --publish-quiet" %>
|
3
|
+
<% mobile = "--tags @mobile --require features BROWSER_TILE=true --publish-quiet" %>
|
4
|
+
<% reports = "--require features --format pretty --format html --out reports/test_results.html --format junit --out reports --format json --out reports/test_results.json" %>
|
5
|
+
|
6
|
+
|
7
|
+
#==============
|
8
|
+
# generic test context profiles
|
9
|
+
#==============
|
10
|
+
|
11
|
+
failing: --tags '@failing and not @wip'
|
12
|
+
wip: --tags '@wip and not @failing'
|
13
|
+
dev: --tags '@dev and (not @wip and not @failing)'
|
14
|
+
|
15
|
+
|
16
|
+
#==============
|
17
|
+
# test reporting profiles
|
18
|
+
#==============
|
19
|
+
|
20
|
+
report: <%= reports %> REPORTING=true
|
21
|
+
parallel: PARALLEL=true REPORTING=true --require features --format pretty --format html --out reports/test_results<%= ENV['TEST_ENV_NUMBER'] %>.html --format junit --out reports --format json --out reports/test_results<%= ENV['TEST_ENV_NUMBER'] %>.json
|
22
|
+
|
23
|
+
|
24
|
+
#==============
|
25
|
+
# profiles for locally hosted desktop web browsers
|
26
|
+
#==============
|
27
|
+
|
28
|
+
chrome: WEB_BROWSER=chrome <%= desktop %>
|
29
|
+
firefox: WEB_BROWSER=firefox <%= desktop %>
|
30
|
+
edge: WEB_BROWSER=edge <%= desktop %>
|
31
|
+
safari: WEB_BROWSER=safari <%= desktop %>
|
32
|
+
|
33
|
+
firefox_headless: WEB_BROWSER=firefox_headless <%= desktop %>
|
34
|
+
chrome_headless: WEB_BROWSER=chrome_headless <%= desktop %>
|
35
|
+
edge_headless: WEB_BROWSER=edge_headless <%= desktop %>
|
36
|
+
|
37
|
+
|
38
|
+
#==============
|
39
|
+
# profile for Selenium Grid and Dockerized Selenium Grid hosted desktop web browsers
|
40
|
+
#==============
|
41
|
+
grid: SELENIUM=remote REMOTE_ENDPOINT="http://localhost:4444/wd/hub"
|
42
|
+
|
43
|
+
|
44
|
+
#==============
|
45
|
+
# profiles for mobile device screen orientation
|
46
|
+
#==============
|
47
|
+
|
48
|
+
landscape: ORIENTATION=landscape
|
49
|
+
portrait: ORIENTATION=portrait
|
50
|
+
|
51
|
+
|
52
|
+
#==============
|
53
|
+
# profile to start Appium Server prior to running mobile browser tests on iOS or Android simulators or physical devices
|
54
|
+
#==============
|
55
|
+
run_appium: APPIUM_SERVER=run
|
56
|
+
|
57
|
+
|
58
|
+
#==============
|
59
|
+
# profiles for mobile Safari web browsers hosted within XCode iOS simulators
|
60
|
+
# NOTE: Requires installation of XCode, iOS version specific target simulators, Appium, and the appium_capybara gem
|
61
|
+
#==============
|
62
|
+
|
63
|
+
appium_ios: WEB_BROWSER=appium AUTOMATION_ENGINE=XCUITest APP_PLATFORM_NAME="ios" APP_BROWSER="Safari" NEW_COMMAND_TIMEOUT=30 SHOW_SIM_KEYBOARD=false <%= desktop %>
|
64
|
+
app_ios_15: --profile appium_ios APP_VERSION="15.4"
|
65
|
+
|
66
|
+
ipad_pro_12_15_sim: --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="iPad Pro (12.9-inch) (5th generation)"
|
67
|
+
ipad_air_15_sim: --profile app_ios_15 DEVICE_TYPE=tablet APP_DEVICE="iPad Air (5th generation)" <%= desktop %>
|
68
|
+
|
69
|
+
|
70
|
+
#==============
|
71
|
+
# profiles for Android mobile web browsers hosted within Android Studio Android Virtual Device emulators
|
72
|
+
# NOTE: Requires installation of Android Studio, Android version specific virtual device simulators, Appium, and the appium_capybara gem
|
73
|
+
#==============
|
74
|
+
|
75
|
+
appium_android: WEB_BROWSER=appium APP_PLATFORM_NAME="Android" <%= desktop %>
|
76
|
+
app_android_12: --profile appium_android APP_BROWSER="Chrome" APP_VERSION="12.0"
|
77
|
+
pixel_c_api31_sim: --profile app_android_12 DEVICE_TYPE=tablet APP_DEVICE="Pixel_C_API_31"
|
78
|
+
|
79
|
+
|
80
|
+
#==============
|
81
|
+
# profiles for remotely hosted web browsers on the BrowserStack service
|
82
|
+
#==============
|
83
|
+
|
84
|
+
browserstack: WEB_BROWSER=browserstack BS_USERNAME="<INSERT USER NAME HERE>" BS_AUTHKEY="<INSERT PASSWORD HERE>" AUTOMATE_PROJECT="TC_Web_Sample - BrowserStack"
|
85
|
+
bs_desktop: --profile browserstack <%= desktop %> RESOLUTION="1920x1080"
|
86
|
+
bs_mobile: --profile browserstack <%= mobile %>
|
87
|
+
|
88
|
+
# BrowserStack macOS desktop browser profiles
|
89
|
+
bs_macos_monterey: --profile bs_desktop BS_OS="OS X" BS_OS_VERSION="Monterey"
|
90
|
+
bs_chrome_monterey: --profile bs_macos_monterey BS_BROWSER="Chrome" BS_VERSION="latest"
|
91
|
+
bs_edge_monterey: --profile bs_macos_monterey BS_BROWSER="Edge" BS_VERSION="latest"
|
92
|
+
bs_safari_monterey: --profile bs_macos_monterey BS_BROWSER="Safari" BS_VERSION="latest"
|
93
|
+
|
94
|
+
# BrowserStack iOS mobile browser profiles
|
95
|
+
bs_ipad: --profile bs_mobile BS_OS=ios BS_BROWSER=Safari DEVICE_TYPE=tablet BS_REAL_MOBILE="true"
|
96
|
+
bs_ipad_pro_12: --profile bs_ipad BS_DEVICE="iPad Pro 12.9 2018" BS_OS_VERSION="15"
|
97
|
+
|
98
|
+
# BrowserStack Android mobile browser profiles
|
99
|
+
bs_android: --profile bs_mobile BS_OS=android BS_BROWSER=Chrome DEVICE_TYPE=tablet BS_REAL_MOBILE="true"
|
100
|
+
bs_android_tablet: --profile bs_android BS_DEVICE="Samsung Galaxy Tab S7" BS_OS_VERSION="10.0"
|
101
|
+
|
102
|
+
|
103
|
+
#==============
|
104
|
+
# profiles for remotely hosted web browsers on the LambdaTest service
|
105
|
+
#==============
|
106
|
+
|
107
|
+
lambdatest: WEB_BROWSER=lambdatest LT_USERNAME="<INSERT USER NAME HERE>" LT_AUTHKEY="<INSERT PASSWORD HERE>" AUTOMATE_PROJECT="TC_Web_Sample - LambdaTest"
|
108
|
+
lt_desktop: --profile lambdatest <%= desktop %> RESOLUTION="2560x1440"
|
109
|
+
|
110
|
+
# LambdaTest macOS desktop browser profiles
|
111
|
+
lt_macos_monterey: --profile lt_desktop LT_OS="MacOS Monterey"
|
112
|
+
lt_chrome_monterey: --profile lt_macos_monterey LT_BROWSER="Chrome" LT_VERSION="98.0"
|
113
|
+
lt_edge_monterey: --profile lt_macos_monterey LT_BROWSER="MicrosoftEdge" LT_VERSION="97.0"
|
114
|
+
|
115
|
+
|
116
|
+
#==============
|
117
|
+
# profiles for remotely hosted web browsers on the TestingBot service
|
118
|
+
#==============
|
119
|
+
|
120
|
+
testingbot: WEB_BROWSER=testingbot TB_USERNAME="<INSERT USER NAME HERE>" TB_AUTHKEY="<INSERT PASSWORD HERE>" AUTOMATE_PROJECT="TC_Web_Sample - TestingBot"
|
121
|
+
tb_desktop: --profile testingbot <%= desktop %> RESOLUTION="1920x1200"
|
122
|
+
|
123
|
+
# TestingBot macOS desktop browser profiles
|
124
|
+
tb_macos_monterey: --profile tb_desktop TB_OS="MONTEREY"
|
125
|
+
tb_chrome_monterey: --profile tb_macos_monterey TB_BROWSER="chrome" TB_VERSION="latest"
|
126
|
+
tb_edge_monterey: --profile tb_macos_monterey TB_BROWSER="microsoftedge" TB_VERSION="latest"
|
127
|
+
|
128
|
+
|
129
|
+
#==============
|
130
|
+
# profiles for remotely hosted web browsers on the SauceLabs service
|
131
|
+
#==============
|
132
|
+
|
133
|
+
saucelabs: WEB_BROWSER=saucelabs SL_USERNAME="<INSERT USER NAME HERE>" SL_AUTHKEY="<INSERT PASSWORD HERE>" DATA_CENTER="us-west-1" AUTOMATE_PROJECT="TC_Web_Sample - SauceLabs"
|
134
|
+
sl_desktop: --profile saucelabs <%= desktop %>
|
135
|
+
sl_mobile: --profile saucelabs <%= mobile %>
|
136
|
+
|
137
|
+
# SauceLabs macOS desktop browser profiles
|
138
|
+
sl_macos_monterey: --profile sl_desktop SL_OS="macOS 12" RESOLUTION="1920x1440"
|
139
|
+
sl_chrome_monterey: --profile sl_macos_monterey SL_BROWSER="chrome" SL_VERSION="latest"
|
140
|
+
sl_edge_monterey: --profile sl_macos_monterey SL_BROWSER="MicrosoftEdge" SL_VERSION="latest"
|
141
|
+
sl_firefox_monterey: --profile sl_macos_monterey SL_BROWSER="Firefox" SL_VERSION="latest"
|
142
|
+
|
143
|
+
# SauceLabs Windows desktop browser profiles
|
144
|
+
sl_windows: --profile sl_desktop RESOLUTION="1920x1200"
|
145
|
+
sl_edge_win11: --profile sl_windows SL_OS="Windows 11" SL_BROWSER="MicrosoftEdge" SL_VERSION="latest"
|
146
|
+
sl_ie_win10: --profile sl_windows SL_OS="Windows 10" SL_BROWSER="internet explorer" SL_VERSION="11"
|
147
|
+
|
148
|
+
# SauceLabs iOS mobile browser profiles
|
149
|
+
sl_ipad: --profile sl_mobile DEVICE_TYPE=tablet SL_PLATFORM=iOS SL_BROWSER=Safari
|
150
|
+
sl_ipad_pro_12: --profile sl_ipad SL_DEVICE="iPad Pro (12.9 inch) (5th generation) Simulator" SL_VERSION="15.0"
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# To execute this docker-compose yml file use `docker-compose -f docker-compose-v3.yml up`
|
2
|
+
# Add the `-d` flag at the end for detached execution
|
3
|
+
# To stop the execution, hit Ctrl+C, and then `docker-compose -f docker-compose-v3.yml down`
|
4
|
+
version: "3"
|
5
|
+
services:
|
6
|
+
chrome:
|
7
|
+
image: selenium/node-chrome:4.1.2-20220217
|
8
|
+
shm_size: 2gb
|
9
|
+
depends_on:
|
10
|
+
- selenium-hub
|
11
|
+
environment:
|
12
|
+
- SE_EVENT_BUS_HOST=selenium-hub
|
13
|
+
- SE_EVENT_BUS_PUBLISH_PORT=4442
|
14
|
+
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
|
15
|
+
- SE_NODE_MAX_SESSIONS=4
|
16
|
+
- SE_NODE_OVERRIDE_MAX_SESSIONS=true
|
17
|
+
|
18
|
+
edge:
|
19
|
+
image: selenium/node-edge:4.1.2-20220217
|
20
|
+
shm_size: 2gb
|
21
|
+
depends_on:
|
22
|
+
- selenium-hub
|
23
|
+
environment:
|
24
|
+
- SE_EVENT_BUS_HOST=selenium-hub
|
25
|
+
- SE_EVENT_BUS_PUBLISH_PORT=4442
|
26
|
+
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
|
27
|
+
- SE_NODE_MAX_SESSIONS=4
|
28
|
+
- SE_NODE_OVERRIDE_MAX_SESSIONS=true
|
29
|
+
|
30
|
+
firefox:
|
31
|
+
image: selenium/node-firefox:4.1.2-20220217
|
32
|
+
shm_size: 2gb
|
33
|
+
depends_on:
|
34
|
+
- selenium-hub
|
35
|
+
environment:
|
36
|
+
- SE_EVENT_BUS_HOST=selenium-hub
|
37
|
+
- SE_EVENT_BUS_PUBLISH_PORT=4442
|
38
|
+
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
|
39
|
+
- SE_NODE_MAX_SESSIONS=4
|
40
|
+
- SE_NODE_OVERRIDE_MAX_SESSIONS=true
|
41
|
+
|
42
|
+
selenium-hub:
|
43
|
+
image: selenium/hub:4.1.2-20220217
|
44
|
+
container_name: selenium-hub
|
45
|
+
ports:
|
46
|
+
- "4442:4442"
|
47
|
+
- "4443:4443"
|
48
|
+
- "4444:4444"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Feature: Basic HTML Test Page using CSS locators
|
2
|
+
In order to xxx
|
3
|
+
As a xxxx
|
4
|
+
I expect to xxxx
|
5
|
+
|
6
|
+
|
7
|
+
Background:
|
8
|
+
Given I am on the Basic CSS Test page
|
9
|
+
|
10
|
+
|
11
|
+
Scenario: xxxxx
|
12
|
+
Then I expect the Basic CSS Test page to be correctly displayed
|
13
|
+
|
14
|
+
|
15
|
+
@!mobile
|
16
|
+
Scenario: xxxxx
|
17
|
+
Then I expect the tab order to be correct
|
18
|
+
|
19
|
+
|
20
|
+
Scenario: xxxxx
|
21
|
+
When I populate the form fields
|
22
|
+
Then I expect the form fields to be correctly populated
|
23
|
+
When I cancel my changes
|
24
|
+
Then I expect the Basic CSS Test page to be correctly displayed
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Feature: Basic HTML Test Page using Xpath locators
|
2
|
+
In order to xxx
|
3
|
+
As a xxxx
|
4
|
+
I expect to xxxx
|
5
|
+
|
6
|
+
|
7
|
+
Background:
|
8
|
+
Given I am on the Basic Xpath Test page
|
9
|
+
|
10
|
+
|
11
|
+
Scenario: xxxxx
|
12
|
+
Then I expect the Basic Xpath Test page to be correctly displayed
|
13
|
+
|
14
|
+
|
15
|
+
@!mobile
|
16
|
+
Scenario: xxxxx
|
17
|
+
Then I expect the tab order to be correct
|
18
|
+
|
19
|
+
|
20
|
+
Scenario: xxxxx
|
21
|
+
When I populate the form fields
|
22
|
+
Then I expect the form fields to be correctly populated
|
23
|
+
When I cancel my changes
|
24
|
+
Then I expect the Basic Xpath Test page to be correctly displayed
|
@@ -0,0 +1,37 @@
|
|
1
|
+
include TestCentricity
|
2
|
+
|
3
|
+
|
4
|
+
Given(/^I am (?:on|viewing) the (.*) page$/) do |page_name|
|
5
|
+
# find and load the specified target page
|
6
|
+
target_page = PageManager.find_page(page_name)
|
7
|
+
target_page.load_page
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
Then(/^I expect the (.*) page to be correctly displayed$/) do |page_name|
|
12
|
+
# find and verify that the specified target page is loaded
|
13
|
+
target_page = PageManager.find_page(page_name)
|
14
|
+
target_page.verify_page_exists
|
15
|
+
# verify that target page is correctly displayed
|
16
|
+
target_page.verify_page_ui
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
When(/^I populate the form fields$/) do
|
21
|
+
PageManager.current_page.populate_form
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
Then(/^I expect the form fields to be correctly populated$/) do
|
26
|
+
PageManager.current_page.verify_form_data
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
When(/^I (.*) my changes$/) do | action|
|
31
|
+
PageManager.current_page.perform_action(action.downcase.to_sym)
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
Then(/^I expect the tab order to be correct$/) do
|
36
|
+
PageManager.current_page.verify_tab_order
|
37
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'capybara/cucumber'
|
2
|
+
require 'parallel_tests'
|
3
|
+
require 'appium_capybara'
|
4
|
+
require 'require_all'
|
5
|
+
require 'simplecov'
|
6
|
+
require 'testcentricity_web'
|
7
|
+
|
8
|
+
SimpleCov.command_name "features #{ENV['WEB_BROWSER']}" + (ENV['TEST_ENV_NUMBER'] || '')
|
9
|
+
|
10
|
+
# require_relative 'world_data'
|
11
|
+
require_relative 'world_pages'
|
12
|
+
|
13
|
+
# require_rel 'data'
|
14
|
+
# require_rel 'sections'
|
15
|
+
require_rel 'pages'
|
16
|
+
|
17
|
+
$LOAD_PATH << './lib'
|
18
|
+
|
19
|
+
# set Capybara's default max wait time to 20 seconds
|
20
|
+
Capybara.default_max_wait_time = 20
|
21
|
+
|
22
|
+
# set the default locale and auto load all translations from config/locales/*.rb,yml.
|
23
|
+
ENV['LOCALE'] = 'en-US' unless ENV['LOCALE']
|
24
|
+
I18n.load_path += Dir['config/locales/*.{rb,yml}']
|
25
|
+
I18n.default_locale = ENV['LOCALE']
|
26
|
+
I18n.locale = ENV['LOCALE']
|
27
|
+
Faker::Config.locale = ENV['LOCALE']
|
28
|
+
|
29
|
+
# instantiate all data objects and target test environment
|
30
|
+
# include WorldData
|
31
|
+
# environs.find_environ(ENV['TEST_ENVIRONMENT'], :yaml)
|
32
|
+
# WorldData.instantiate_data_objects
|
33
|
+
|
34
|
+
# instantiate all page objects
|
35
|
+
include WorldPages
|
36
|
+
WorldPages.instantiate_page_objects
|
37
|
+
|
38
|
+
# establish connection to WebDriver and target web browser
|
39
|
+
Webdrivers.cache_time = 86_400
|
40
|
+
|
41
|
+
options = { app_host: "file://#{File.dirname(__FILE__)}/../../test_site" }
|
42
|
+
options = { app_host: "http://192.168.1.129"}
|
43
|
+
TestCentricity::WebDriverConnect.initialize_web_driver(options)
|
@@ -0,0 +1,245 @@
|
|
1
|
+
|
2
|
+
BeforeAll do
|
3
|
+
# start Appium Server if command line option was specified and target browser is mobile simulator or device
|
4
|
+
if ENV['APPIUM_SERVER'] == 'run' && Environ.driver == :appium
|
5
|
+
$server = TestCentricity::AppiumServer.new
|
6
|
+
$server.start
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
AfterAll do
|
12
|
+
# terminate Appium Server if command line option was specified and target browser is mobile simulator or device
|
13
|
+
if ENV['APPIUM_SERVER'] == 'run' && Environ.driver == :appium && $server.running?
|
14
|
+
$server.stop
|
15
|
+
end
|
16
|
+
# close driver
|
17
|
+
terminate_session
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
Before do |scenario|
|
22
|
+
# if executing tests in parallel concurrent threads, print thread number with scenario name
|
23
|
+
message = Environ.parallel ? "Thread ##{Environ.process_num} | Scenario: #{scenario.name}" : "Scenario: #{scenario.name}"
|
24
|
+
log message
|
25
|
+
$initialized ||= false
|
26
|
+
unless $initialized
|
27
|
+
$initialized = true
|
28
|
+
$test_start_time = Time.now
|
29
|
+
# HTML report header information if reporting is enabled
|
30
|
+
log Environ.report_header if ENV['REPORTING']
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
After do |scenario|
|
36
|
+
# process and embed any screenshots recorded during execution of scenario
|
37
|
+
process_embed_screenshots(scenario)
|
38
|
+
# clear out any queued screenshots
|
39
|
+
Environ.reset_contexts
|
40
|
+
# close any external pages that may have been opened
|
41
|
+
if Environ.external_page
|
42
|
+
Browsers.close_current_browser_instance
|
43
|
+
begin
|
44
|
+
page.driver.browser.switch_to.alert.accept
|
45
|
+
Browsers.switch_to_new_browser_instance
|
46
|
+
rescue
|
47
|
+
end
|
48
|
+
Environ.set_external_page(false)
|
49
|
+
end
|
50
|
+
# block any JavaScript modals that may appear as a result of ending the session
|
51
|
+
Browsers.suppress_js_leave_page_modal
|
52
|
+
# close Capybara Appium driver if it was opened
|
53
|
+
Capybara.page.driver.quit if Capybara.default_driver == :appium
|
54
|
+
|
55
|
+
if ENV['QUIT_DRIVER']
|
56
|
+
terminate_session
|
57
|
+
elsif Environ.grid == :browserstack
|
58
|
+
# restart BrowserStack test sessions if test duration exceeds 110 minutes to avoid the 2 hour test limit
|
59
|
+
test_elapsed_time = Time.now - $test_start_time
|
60
|
+
if test_elapsed_time > 6600
|
61
|
+
terminate_session
|
62
|
+
log 'Restarting BrowserStack test session'
|
63
|
+
$test_start_time = Time.now
|
64
|
+
else
|
65
|
+
Capybara.reset_sessions!
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# exclusionary Around hooks to prevent running feature/scenario on unsupported browsers, devices, or
|
72
|
+
# cloud remote browser hosting platforms. Use the following tags to block test execution:
|
73
|
+
# desktop web browsers: @!safari, @!ie, @!firefox, @!chrome, @!edge
|
74
|
+
# mobile devices: @!ipad, @!iphone
|
75
|
+
# remotely hosted browsers: @!browserstack, @!saucelabs
|
76
|
+
|
77
|
+
# block feature/scenario execution if running against Safari browser
|
78
|
+
Around('@!safari') do |scenario, block|
|
79
|
+
qualify_browser(:safari, 'Safari', scenario, block)
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# block feature/scenario execution if running against Internet Explorer browser
|
84
|
+
Around('@!ie') do |scenario, block|
|
85
|
+
qualify_browser(:ie, 'Internet Explorer', scenario, block)
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
# block feature/scenario execution if running against Microsoft Edge browser
|
90
|
+
Around('@!edge') do |scenario, block|
|
91
|
+
qualify_browser(:edge, 'Edge', scenario, block)
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# block feature/scenario execution if running against Chrome browser
|
96
|
+
Around('@!chrome') do |scenario, block|
|
97
|
+
qualify_browser(:chrome, 'Chrome', scenario, block)
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# block feature/scenario execution if running against Firefox browser
|
102
|
+
Around('@!firefox') do |scenario, block|
|
103
|
+
qualify_browser(:firefox, 'Firefox', scenario, block)
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# block feature/scenario execution if running against iPad mobile browser
|
108
|
+
Around('@!ipad') do |scenario, block|
|
109
|
+
qualify_device('ipad', scenario, block)
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# block feature/scenario execution if running against iPhone mobile browser
|
114
|
+
Around('@!iphone') do |scenario, block|
|
115
|
+
qualify_device('iphone', scenario, block)
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
# block feature/scenario execution if running on Selenium Grid or cloud-hosted services
|
120
|
+
Around('@!grid') do |scenario, block|
|
121
|
+
if !Environ.grid
|
122
|
+
block.call
|
123
|
+
else
|
124
|
+
log "Scenario '#{scenario.name}' cannot be executed on Selenium Grid or cloud-hosted services."
|
125
|
+
skip_this_scenario
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# block feature/scenario execution if running against Browserstack cloud-hosted service
|
131
|
+
Around('@!browserstack') do |scenario, block|
|
132
|
+
if Environ.grid != :browserstack
|
133
|
+
block.call
|
134
|
+
else
|
135
|
+
log "Scenario '#{scenario.name}' cannot be executed on the BrowserStack service."
|
136
|
+
skip_this_scenario
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
# block feature/scenario execution if running against Sauce Labs cloud-hosted service
|
142
|
+
Around('@!saucelabs') do |scenario, block|
|
143
|
+
if Environ.grid != :saucelabs
|
144
|
+
block.call
|
145
|
+
else
|
146
|
+
log "Scenario '#{scenario.name}' cannot be executed on the SauceLabs service."
|
147
|
+
skip_this_scenario
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
# block feature/scenario execution if running against a physical or emulated mobile device
|
153
|
+
Around('@!device') do |scenario, block|
|
154
|
+
if Environ.is_device?
|
155
|
+
log "Scenario '#{scenario.name}' cannot be executed on physical or emulated devices."
|
156
|
+
skip_this_scenario
|
157
|
+
else
|
158
|
+
block.call
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
Around('@!ios') do |scenario, block|
|
164
|
+
if Environ.device_os == :android
|
165
|
+
block.call
|
166
|
+
else
|
167
|
+
log "Scenario '#{scenario.name}' can not be executed on iOS devices."
|
168
|
+
skip_this_scenario
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
Around('@!android') do |scenario, block|
|
174
|
+
if Environ.device_os == :ios
|
175
|
+
block.call
|
176
|
+
else
|
177
|
+
log "Scenario '#{scenario.name}' can not be executed on Android devices."
|
178
|
+
skip_this_scenario
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
Around('@!mobile') do |scenario, block|
|
184
|
+
if Environ.platform == :mobile
|
185
|
+
log "Scenario '#{scenario.name}' can not be executed on mobile devices or simulators."
|
186
|
+
skip_this_scenario
|
187
|
+
else
|
188
|
+
block.call
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
# supporting methods
|
194
|
+
|
195
|
+
def qualify_browser(browser_type, browser_name, scenario, block)
|
196
|
+
if Environ.browser != browser_type && ENV['HOST_BROWSER'] != browser_name.downcase
|
197
|
+
block.call
|
198
|
+
else
|
199
|
+
log "Scenario '#{scenario.name}' cannot be executed with the #{browser_name} browser."
|
200
|
+
skip_this_scenario
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def qualify_device(device, scenario, block)
|
205
|
+
if Environ.is_device?
|
206
|
+
if Environ.device_type.include? device
|
207
|
+
log "Scenario '#{scenario.name}' cannot be executed on #{device} devices."
|
208
|
+
skip_this_scenario
|
209
|
+
else
|
210
|
+
block.call
|
211
|
+
end
|
212
|
+
else
|
213
|
+
block.call
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def terminate_session
|
218
|
+
Capybara.page.driver.quit
|
219
|
+
Capybara.reset_sessions!
|
220
|
+
Environ.session_state = :quit
|
221
|
+
$driver_scenario_count = 0
|
222
|
+
end
|
223
|
+
|
224
|
+
def screen_shot_and_save_page(scenario)
|
225
|
+
timestamp = Time.now.strftime('%Y%m%d%H%M%S%L')
|
226
|
+
filename = scenario.nil? ? "Screenshot-#{timestamp}.png" : "Screenshot-#{scenario.__id__}-#{timestamp}.png"
|
227
|
+
path = File.join Dir.pwd, 'reports/screenshots/', filename
|
228
|
+
save_screenshot path
|
229
|
+
log "Screenshot saved at #{path}"
|
230
|
+
screen_shot = { path: path, filename: filename }
|
231
|
+
Environ.save_screen_shot(screen_shot)
|
232
|
+
attach(path, 'image/png') unless scenario.nil?
|
233
|
+
end
|
234
|
+
|
235
|
+
def process_embed_screenshots(scenario)
|
236
|
+
screen_shots = Environ.get_screen_shots
|
237
|
+
if screen_shots.count > 0
|
238
|
+
screen_shots.each do |row|
|
239
|
+
path = row[:path]
|
240
|
+
attach(path, 'image/png')
|
241
|
+
end
|
242
|
+
else
|
243
|
+
screen_shot_and_save_page(scenario) if scenario.failed?
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# Page Object class definition for Basic HTML Test page with CSS locators
|
2
|
+
|
3
|
+
class BasicCSSTestPage < BasicTestPage
|
4
|
+
trait(:page_name) { 'Basic CSS Test' }
|
5
|
+
trait(:page_locator) { 'form#HTMLFormElements' }
|
6
|
+
|
7
|
+
# Basic HTML Test page UI elements
|
8
|
+
textfields username_field: 'input#username',
|
9
|
+
password_field: 'input#password',
|
10
|
+
max_length_field: 'input#maxlength',
|
11
|
+
read_only_field: 'input#readonly',
|
12
|
+
number_field: 'input#number-field',
|
13
|
+
color_picker: 'input#color-picker',
|
14
|
+
comments_field: 'textarea#comments'
|
15
|
+
range :slider, 'input#slider'
|
16
|
+
filefield :upload_file, 'input#filename'
|
17
|
+
checkboxes check_1: 'input#check1',
|
18
|
+
check_2: 'input#check2',
|
19
|
+
check_3: 'input#check3',
|
20
|
+
check_4: 'input#check4'
|
21
|
+
radios radio_1: 'input#radio1',
|
22
|
+
radio_2: 'input#radio2',
|
23
|
+
radio_3: 'input#radio3',
|
24
|
+
radio_4: 'input#radio4'
|
25
|
+
selectlists multi_select: 'select#multipleselect',
|
26
|
+
drop_down_select: 'select#dropdown'
|
27
|
+
table :static_table, 'table#table'
|
28
|
+
images image_1: 'img#image1',
|
29
|
+
image_2: 'img#image2',
|
30
|
+
image_3: 'img#image3'
|
31
|
+
buttons cancel_button: 'input#cancel',
|
32
|
+
submit_button: 'input#submit'
|
33
|
+
labels header_label: 'h1',
|
34
|
+
username_label: "label[for='username']",
|
35
|
+
password_label: "label[for='password']",
|
36
|
+
max_length_label: "label[for='maxlength']",
|
37
|
+
read_only_label: "label[for='readonly']",
|
38
|
+
number_label: "label[for='number-field']",
|
39
|
+
color_label: "label[for='color-picker']",
|
40
|
+
slider_label: "label[for='slider']",
|
41
|
+
comments_label: "label[for='comments']",
|
42
|
+
filename_label: "label[for='filename']",
|
43
|
+
checkboxes_label: 'label#checkboxes',
|
44
|
+
radios_label: 'label#radios',
|
45
|
+
multiselect_label: "label[for='multipleselect']",
|
46
|
+
dropdown_label: "label[for='dropdown']",
|
47
|
+
table_label: "label[for='table']",
|
48
|
+
images_label: 'label#images'
|
49
|
+
end
|