SimpliTest 0.0.1
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 +7 -0
- data/README.md +22 -0
- data/SimpliTest.gemspec +42 -0
- data/bin/SimpliTest +22 -0
- data/lib/SimpliTest.rb +2 -0
- data/lib/SimpliTest/cli/main.rb +305 -0
- data/lib/SimpliTest/config/configuration.rb +107 -0
- data/lib/SimpliTest/config/directory_paths.rb +36 -0
- data/lib/SimpliTest/config/environment.rb +67 -0
- data/lib/SimpliTest/config/local_environment.rb +20 -0
- data/lib/SimpliTest/config/profiles/chrome.rb +18 -0
- data/lib/SimpliTest/config/profiles/firefox.rb +14 -0
- data/lib/SimpliTest/config/profiles/internet_explorer.rb +12 -0
- data/lib/SimpliTest/config/profiles/phantom.rb +9 -0
- data/lib/SimpliTest/config/profiles/phantom_debug.rb +12 -0
- data/lib/SimpliTest/config/profiles/selenium.rb +13 -0
- data/lib/SimpliTest/config/screen_size.rb +25 -0
- data/lib/SimpliTest/config/steps.rb +8 -0
- data/lib/SimpliTest/helpers/data_validation.rb +60 -0
- data/lib/SimpliTest/helpers/file.rb +38 -0
- data/lib/SimpliTest/helpers/project_setup.rb +186 -0
- data/lib/SimpliTest/helpers/step_helpers/custom_chrome_helpers.rb +14 -0
- data/lib/SimpliTest/helpers/step_helpers/custom_date_helpers.rb +64 -0
- data/lib/SimpliTest/helpers/step_helpers/custom_form_helpers.rb +66 -0
- data/lib/SimpliTest/helpers/step_helpers/custom_phantomjs_helpers.rb +49 -0
- data/lib/SimpliTest/helpers/step_helpers/custom_selenium_helpers.rb +41 -0
- data/lib/SimpliTest/helpers/step_helpers/html_selectors_helpers.rb +154 -0
- data/lib/SimpliTest/helpers/step_helpers/navigation_helpers.rb +196 -0
- data/lib/SimpliTest/helpers/step_helpers/tolerance_for_sync_issues.rb +38 -0
- data/lib/SimpliTest/helpers/step_helpers/within_helpers.rb +6 -0
- data/lib/SimpliTest/helpers/windows_ui.rb +52 -0
- data/lib/SimpliTest/steps/debugging_steps.rb +19 -0
- data/lib/SimpliTest/steps/form_steps.rb +352 -0
- data/lib/SimpliTest/steps/form_verification_steps.rb +190 -0
- data/lib/SimpliTest/steps/navigation_steps.rb +47 -0
- data/lib/SimpliTest/steps/scoper.rb +42 -0
- data/lib/SimpliTest/steps/verification_steps.rb +306 -0
- data/lib/SimpliTest/tasks/document.rb +169 -0
- data/lib/SimpliTest/tasks/examples.rb +18 -0
- data/lib/SimpliTest/tasks/internal_release.rb +39 -0
- data/lib/SimpliTest/tasks/testinstall.rb +5 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/Readme.txt +5 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/cucumber.yml +26 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/documentation/step_definitions.html +87 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/features/specifications/RegressionTests/HelloWorld.feature +4 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/features/specifications/SmokeTest/HelloWorld.feature +4 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/features/specifications/accessibilityTests/HelloWorld.feature +4 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/features/support/config/environments.yml +11 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/features/support/config/pages.yml +26 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/features/support/config/selectors.yml +44 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/features/support/config/settings.yml +26 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/features/support/env.rb +33 -0
- data/lib/SimpliTest/templates/NewSimpliTestProject/license.txt +30 -0
- data/lib/SimpliTest/templates/document/css/style.css +28 -0
- data/lib/SimpliTest/templates/document/index.html +60 -0
- data/lib/version.rb +3 -0
- metadata +395 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
#The chrome profile loads Selenium Helpers as well. These methods
|
2
|
+
#override the methods available in Selenium Helpers
|
3
|
+
module CustomChromeHelpers
|
4
|
+
def maximize_window
|
5
|
+
page.driver.browser.manage.window.resize_to(MAX_WIDTH,MAX_HEIGHT)
|
6
|
+
end
|
7
|
+
def keydown_on(element)
|
8
|
+
element.native.send_key(:arrow_down)
|
9
|
+
end
|
10
|
+
|
11
|
+
def capture_screenshot(filename)
|
12
|
+
page.driver.browser.save_screenshot(filename)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module CustomDateHelpers
|
2
|
+
def calculated_date_from(date_rule)
|
3
|
+
# Takes strings like "Today's Date", "4 days ago", "5 days since" etc. and
|
4
|
+
# returns a calculated date in the default_date_format
|
5
|
+
potential_date_formats = /[0-9]+\/[0-9]+\/[0-9]+/x
|
6
|
+
first_and_last_regex = /the (nearest|first|last) (.*)/
|
7
|
+
date = case date_rule
|
8
|
+
when potential_date_formats
|
9
|
+
date_rule
|
10
|
+
when /Today's Date/i
|
11
|
+
Date.today
|
12
|
+
when /(\d+) days (ago|since)/i
|
13
|
+
number_of_days = $1.to_i rescue nil
|
14
|
+
time_travel_method = $2.downcase.to_sym
|
15
|
+
raise "Invalid number of days. Please enter a valid number" if number_of_days.nil?
|
16
|
+
number_of_days.send(:days).send(time_travel_method)
|
17
|
+
when first_and_last_regex
|
18
|
+
first_and_last_date_rule(rule)
|
19
|
+
end
|
20
|
+
date.respond_to?(:strftime) ? date.strftime(default_date_format) : date
|
21
|
+
end
|
22
|
+
|
23
|
+
def first_and_last_date_rule(phrase)
|
24
|
+
# Takes a phrase like "the first day of the month" or "last day of the
|
25
|
+
# previous month" and returns a calculated date in the default_date_format
|
26
|
+
case phrase
|
27
|
+
when /the (first|last) day of the month/i
|
28
|
+
Date.today.send(beginning_or_end($1))
|
29
|
+
when /the (first|last) day of next month/i
|
30
|
+
1.month.since.send(beginning_or_end($1))
|
31
|
+
when /the (first|last) day of previous month/i
|
32
|
+
1.month.ago.send(beginning_or_end($1))
|
33
|
+
when /the (first|last) day of (.*)/i
|
34
|
+
date_from_phrase($1, $2)
|
35
|
+
when /the nearest (first|last) day of month/i
|
36
|
+
rule = Date.today.day >= 15 ? "the #{$1} day of next month" : "the #{$1} day of the month"
|
37
|
+
calculated_date_from(rule)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def beginning_or_end(first_or_last)
|
42
|
+
first_or_last == 'first' ? :beginning_of_month : :end_of_month
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_date_format
|
46
|
+
format_for_strftime SimpliTest.config_settings['DEFAULT_DATE_FORMAT']
|
47
|
+
end
|
48
|
+
|
49
|
+
def date_from_phrase(first_or_last, month)
|
50
|
+
month_name = month.downcase.camelize
|
51
|
+
month = Date::MONTHNAMES.index(month_name)
|
52
|
+
if month.nil?
|
53
|
+
raise "Oops you provided an invalid month name. Please use a valid month name from January to December"
|
54
|
+
end
|
55
|
+
date = Date.parse("#{month}/1") #mm/dd in current year
|
56
|
+
date = date.send(:end_of_month) if first_or_last == 'last'
|
57
|
+
end
|
58
|
+
|
59
|
+
def format_for_strftime(string)
|
60
|
+
string.gsub('mm', '%m').gsub('dd', '%d').gsub('yyyy', '%Y').gsub('yy', '%y')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
World(CustomDateHelpers)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module CustomFormHelpers
|
2
|
+
|
3
|
+
def numerize(number_name)
|
4
|
+
case number_name
|
5
|
+
when 'first'; 0
|
6
|
+
when 'last'; -1
|
7
|
+
else number_name.match(/[0-9]/)[1].to_i + 1 rescue 0 #take the first one if you cant figure it out
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def blur(selector_and_xpath)
|
12
|
+
css_selector, xpath = selector_and_xpath
|
13
|
+
selector = xpath ? xpath : css_selector
|
14
|
+
if xpath
|
15
|
+
return
|
16
|
+
else
|
17
|
+
#TODO: Hate how this done...need to come back to this
|
18
|
+
execute_script_for_driver(SimpliTest.config_driver, %Q{ $('#{selector}').blur(); })
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def fill_in_masked_field(css_selector, value)
|
23
|
+
STDOUT.puts "Entering #{value} in Masked Field #{css_selector} now" #TODO: Delete this debugging statement
|
24
|
+
execute_script_for_driver(SimpliTest.config_driver, %Q{ $("#{css_selector}").val("#{value}"); })
|
25
|
+
STDOUT.puts "Blurring the field now" #TODO: Delete this debugging statement
|
26
|
+
execute_script_for_driver(SimpliTest.config_driver, %Q{ $("#{css_selector}").blur(); })
|
27
|
+
#page.driver.debug
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def press_key(key)
|
32
|
+
keycode = keycode_for[key.downcase.gsub(' ','_')]
|
33
|
+
keypress_script = "var e = $.Event('keydown', { keyCode: #{keycode} }); $('body').trigger(e);"
|
34
|
+
execute_js(keypress_script)
|
35
|
+
end
|
36
|
+
|
37
|
+
def tab_on(element)
|
38
|
+
element.native.send_key(:tab)
|
39
|
+
end
|
40
|
+
|
41
|
+
def keypress_on(elem, key, charCode = 0)
|
42
|
+
keyCode = keycode_for[key]
|
43
|
+
elem.base.invoke('keypress', false, false, false, false, keyCode, charCode);
|
44
|
+
end
|
45
|
+
|
46
|
+
def keycode_for
|
47
|
+
{
|
48
|
+
:tab => 9,
|
49
|
+
:enter => 13,
|
50
|
+
:up_arrow => 38,
|
51
|
+
:down_arrow => 40,
|
52
|
+
:left_arrow => 37,
|
53
|
+
:right_arrow => 39,
|
54
|
+
:escape => 27,
|
55
|
+
:spacebar => 32,
|
56
|
+
:ctrl => 17,
|
57
|
+
:alt => 18,
|
58
|
+
:shift => 16,
|
59
|
+
:caps_lock => 20,
|
60
|
+
:backspace => 8,
|
61
|
+
:delete => 46
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
World(CustomFormHelpers)
|
66
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module CustomPhantomjsHelpers
|
2
|
+
def maximize_window
|
3
|
+
page.driver.resize_window(MAX_WIDTH,MAX_HEIGHT)
|
4
|
+
end
|
5
|
+
|
6
|
+
def tab_on(element)
|
7
|
+
element.native.send_key(:Tab)
|
8
|
+
end
|
9
|
+
|
10
|
+
def accept_confirmation
|
11
|
+
#TODO: accept confirmation
|
12
|
+
raise "NotImplementedError"
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute_js(script)
|
16
|
+
page.execute_script(script)
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_text_from(element)
|
20
|
+
element.native.all_text
|
21
|
+
end
|
22
|
+
|
23
|
+
def click_element(element)
|
24
|
+
begin
|
25
|
+
element.click
|
26
|
+
rescue Capybara::Poltergeist::MouseEventFailed
|
27
|
+
element.trigger('click')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def key_in(character, element)
|
32
|
+
element.native.send_key(character)
|
33
|
+
end
|
34
|
+
|
35
|
+
def keydown_on(element)
|
36
|
+
key_in('Down', element)
|
37
|
+
end
|
38
|
+
|
39
|
+
def capture_screenshot(filename)
|
40
|
+
page.save_screenshot(filename)
|
41
|
+
end
|
42
|
+
|
43
|
+
def change_window(first_or_last)
|
44
|
+
raise "Invalid window name #{first_or_last}. You can only use 'first' or 'last'" unless first_or_last =~ /first|last/
|
45
|
+
window_handle = page.driver.browser.window_handles.send(first_or_last.to_sym)
|
46
|
+
page.driver.browser.switch_to_window(window_handle)
|
47
|
+
wait_for(page.driver.browser.window_handles.size, 1)
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module CustomSeleniumHelpers
|
2
|
+
def maximize_window
|
3
|
+
page.driver.browser.manage.window.resize_to(MAX_WIDTH, MAX_HEIGHT)
|
4
|
+
end
|
5
|
+
|
6
|
+
def capture_screenshot(filename)
|
7
|
+
page.driver.browser.save_screenshot(filename)
|
8
|
+
end
|
9
|
+
|
10
|
+
def accept_confirmation
|
11
|
+
page.driver.browser.switch_to.alert.accept
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute_js(script)
|
15
|
+
page.driver.browser.execute_script(script)
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_text_from(element)
|
19
|
+
element.text
|
20
|
+
end
|
21
|
+
|
22
|
+
def click_element(element)
|
23
|
+
element.click
|
24
|
+
end
|
25
|
+
|
26
|
+
def key_in(character, element)
|
27
|
+
element.native.send_key(character)
|
28
|
+
end
|
29
|
+
|
30
|
+
def keydown_on(element)
|
31
|
+
key_in(:arrow_down, element)
|
32
|
+
end
|
33
|
+
|
34
|
+
def change_window(first_or_last)
|
35
|
+
raise "Invalid window name #{first_or_last}. You can only use 'first' or 'last'" unless first_or_last =~ /first|last/
|
36
|
+
window_handle = page.driver.browser.window_handles.send(first_or_last.to_sym)
|
37
|
+
page.driver.browser.switch_to.window(window_handle)
|
38
|
+
wait_for(page.driver.browser.window_handles.size, 1)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module HtmlSelectorsHelpers
|
2
|
+
#TODO: Rewrite without test app for template. The code here effing nuts'...clean this shit
|
3
|
+
@selectors_file = 'features/support/config/selectors.yml'
|
4
|
+
|
5
|
+
def pagination_links_for(page_number)
|
6
|
+
selector = "input[title='Page #{page_number}']"
|
7
|
+
all(:css, selector)
|
8
|
+
end
|
9
|
+
|
10
|
+
def pagination_element_for(index)
|
11
|
+
lookup = {
|
12
|
+
'first' => 'firstButton',
|
13
|
+
'last' => 'lastButton',
|
14
|
+
'previous' => 'prevButton',
|
15
|
+
'next' => 'nextButton'
|
16
|
+
}
|
17
|
+
selector = "##{lookup[index]}"
|
18
|
+
elements = all(:css, selector)
|
19
|
+
elements.first if elements
|
20
|
+
end
|
21
|
+
|
22
|
+
def select_options_for(locator)
|
23
|
+
element = get_element_from(locator)
|
24
|
+
get_text_from(element)
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_element_from(locator, try_field=true, find_button_or_link=false)
|
28
|
+
selector, selector_type = selector_for(locator)
|
29
|
+
element = nil
|
30
|
+
patiently do
|
31
|
+
if selector_type == 'xpath'
|
32
|
+
element = page.find(:xpath, selector)
|
33
|
+
elsif selector_type == 'css'
|
34
|
+
element = page.find(:css, selector)
|
35
|
+
elsif try_field
|
36
|
+
element = page.find_field(selector)
|
37
|
+
elsif find_button_or_link
|
38
|
+
raise "Button or Link Not Found"
|
39
|
+
else
|
40
|
+
element = find(selector)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def get_button_or_link_from(locator)
|
47
|
+
begin
|
48
|
+
get_element_from(locator, false, true)
|
49
|
+
rescue
|
50
|
+
begin
|
51
|
+
page.find_link(locator)
|
52
|
+
rescue
|
53
|
+
page.find_button(locator)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def selector_for(locator)
|
59
|
+
if SimpliTest.config_selectors
|
60
|
+
mapping = mapping_for(locator)
|
61
|
+
mapping ? selector_from(mapping) : default_selector_for(locator)
|
62
|
+
else
|
63
|
+
default_selector_for(locator)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def mapping_for(selector)
|
68
|
+
SimpliTest.config_selectors[unquoted(selector)] || false
|
69
|
+
end
|
70
|
+
|
71
|
+
def selector_from(selector)
|
72
|
+
selector_type = is_xpath?(selector) ? 'xpath' : (is_css?(selector) ? 'css' : 'other')
|
73
|
+
selector = without_identifier(selector)
|
74
|
+
return selector, selector_type
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def is_xpath?(locator)
|
79
|
+
selector_for(locator)[0].match(/xpath:(.*)/)
|
80
|
+
end
|
81
|
+
|
82
|
+
def is_css?(locator)
|
83
|
+
selector_for(locator)[0].match(/css:(.*)/)
|
84
|
+
end
|
85
|
+
|
86
|
+
def without_identifier(locator)
|
87
|
+
if match = (is_xpath?(locator) || is_css?(locator))
|
88
|
+
return match[1]
|
89
|
+
else
|
90
|
+
return locator
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def unquoted(string)
|
96
|
+
#string[0] is the first char
|
97
|
+
#string[-1,1] is the last char
|
98
|
+
is_string_quoted = (string[0] == string[-1, 1]) && (%w[' "].include?(string[0]))
|
99
|
+
is_string_quoted ? string.gsub(/^"|"$/, '') : string
|
100
|
+
end
|
101
|
+
|
102
|
+
def default_selector_for(locator)
|
103
|
+
case locator
|
104
|
+
|
105
|
+
when "the page"
|
106
|
+
with_selector_type "html > body"
|
107
|
+
when "table's header"
|
108
|
+
with_selector_type "table tbody > tr th"
|
109
|
+
when /^paragraphs?$/
|
110
|
+
with_selector_type "p"
|
111
|
+
when "\"table tr\""
|
112
|
+
with_selector_type "table tr"
|
113
|
+
when "\"div.some_class\""
|
114
|
+
with_selector_type "div.some_class"
|
115
|
+
else
|
116
|
+
with_selector_type locator
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def with_selector_type(selector, selector_type='other')
|
121
|
+
[selector, selector_type]
|
122
|
+
end
|
123
|
+
|
124
|
+
def validate_absence_of(text)
|
125
|
+
min_wait_time = SimpliTest.config_settings ? SimpliTest.config_settings['MIN_WAIT_TIME'] : 2
|
126
|
+
using_wait_time min_wait_time do #because we are validating absence we don't need to wait all 5 seconds?
|
127
|
+
begin
|
128
|
+
should_not have_link(text)
|
129
|
+
rescue RSpec::Expectations::ExpectationNotMetError, Capybara::ExpectationNotMet
|
130
|
+
element = get_button_or_link_from(text)
|
131
|
+
element.should_not be_visible if element.respond_to?(:visible?)
|
132
|
+
## deprecating the approach below for performance reasons
|
133
|
+
##xpath = potential_hidden_paths_for(text).join('|')
|
134
|
+
##should have_xpath(xpath)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def selectors_from_section(section)
|
140
|
+
SimpliTest.config_selectors[section].values
|
141
|
+
end
|
142
|
+
|
143
|
+
#def potential_hidden_paths_for(text) #the different ways developers might choose to hide things in the DOM
|
144
|
+
#[
|
145
|
+
#"//*[@class='hidden' and contains(.,'#{text}')]",
|
146
|
+
#"//*[@class='invisible' and contains(.,'#{text}')]",
|
147
|
+
#"//*[@style='display: none;' and contains(.,'#{text}')]"
|
148
|
+
#]
|
149
|
+
|
150
|
+
#end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
World(HtmlSelectorsHelpers)
|
@@ -0,0 +1,196 @@
|
|
1
|
+
module NavigationHelpers
|
2
|
+
# Maps a name to a path. Used by the
|
3
|
+
#
|
4
|
+
# When /^I go to (.+)$/ do |page_name|
|
5
|
+
#
|
6
|
+
#TODO: Rewrite without test app for template
|
7
|
+
def path_to(page_name)
|
8
|
+
if is_url?(page_name)
|
9
|
+
page_name
|
10
|
+
elsif SimpliTest.config_pages
|
11
|
+
matches = SimpliTest.config_pages.select { |p| unquoted(page_name) == p }
|
12
|
+
matches.any? ? url_from(matches, page_name) : default_path_for(page_name)
|
13
|
+
else
|
14
|
+
default_path_for(page_name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# :nocov:
|
18
|
+
def url_from(matches, page_name)
|
19
|
+
if matches.length > 1
|
20
|
+
raise "Oops ambigous page name! More than one matched our search. It seems you have similar page names. \n" +
|
21
|
+
"Now, go and modify #{page_name} to something cooler in config/pages.yml"
|
22
|
+
else
|
23
|
+
path = matches.values.first
|
24
|
+
end
|
25
|
+
url_to(path) if path
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_path_for(page_name)
|
29
|
+
case page_name
|
30
|
+
|
31
|
+
when /^home$/
|
32
|
+
'/'
|
33
|
+
when /^congratulations$/
|
34
|
+
'/congratulations'
|
35
|
+
when /^other$/
|
36
|
+
'/other/page'
|
37
|
+
when /^form$/
|
38
|
+
'/form/page'
|
39
|
+
when /^valid_links$/
|
40
|
+
'/valid-links'
|
41
|
+
when /^invalid_links$/
|
42
|
+
'/invalid-links'
|
43
|
+
# Add more mappings here.
|
44
|
+
# Here is an example that pulls values out of the Regexp:
|
45
|
+
#
|
46
|
+
# when /^(.*)'s profile page$/i
|
47
|
+
# user_profile_path(User.find_by_login($1))
|
48
|
+
|
49
|
+
else
|
50
|
+
begin
|
51
|
+
page_name =~ /^the (.*) page$/
|
52
|
+
path_components = $1.split(/\s+/)
|
53
|
+
self.send(path_components.push('path').join('_').to_sym)
|
54
|
+
rescue NoMethodError, ArgumentError
|
55
|
+
raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
|
56
|
+
"Now, go and add a mapping in #{__FILE__}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
# :nocov:
|
61
|
+
|
62
|
+
def url_to(path)
|
63
|
+
if is_url?(path)
|
64
|
+
path
|
65
|
+
else
|
66
|
+
begin
|
67
|
+
URI.parse(SimpliTest.config_environments[SimpliTest.config_environment] + path).normalize.to_s
|
68
|
+
rescue
|
69
|
+
puts "It seems that the #{SimpliTest.config_environment} enviroment has not been set up. Please add it to features/config/environments.yml"
|
70
|
+
raise "Unidentified Environment Requested!!"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def is_url?(path)
|
76
|
+
uri = URI.parse(path)
|
77
|
+
uri if uri.scheme =~ /^https?$/
|
78
|
+
rescue URI::BadURIError, URI::InvalidURIError
|
79
|
+
false
|
80
|
+
end
|
81
|
+
|
82
|
+
def is_relative?(path)
|
83
|
+
uri = URI.parse(path)
|
84
|
+
uri.relative?
|
85
|
+
end
|
86
|
+
|
87
|
+
def is_valid_url_or_path?(path)
|
88
|
+
is_url?(path) || is_relative?(path)
|
89
|
+
end
|
90
|
+
|
91
|
+
def is_javascript_href?(href)
|
92
|
+
href =~ /^(javascript|#)/
|
93
|
+
end
|
94
|
+
|
95
|
+
def parse_dom_tree(url)
|
96
|
+
Nokogiri::HTML(open(url))
|
97
|
+
end
|
98
|
+
|
99
|
+
def valid_assets_links_from(nokogiri_html_document)
|
100
|
+
doc = nokogiri_html_document
|
101
|
+
links = stylesheet_references_on(doc) + javascript_references_on(doc)
|
102
|
+
links.select{ |l| !is_javascript_href?(l) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def stylesheet_references_on(doc)
|
106
|
+
doc.css('link').collect{|l| l['href'] }.compact
|
107
|
+
end
|
108
|
+
|
109
|
+
def javascript_references_on(doc)
|
110
|
+
doc.css('script').collect{|l| l['src']}.compact
|
111
|
+
end
|
112
|
+
|
113
|
+
def links_on(doc)
|
114
|
+
doc.css('a').collect{|l| l['href']}.compact.select{ |l| !is_javascript_href?(l) }
|
115
|
+
end
|
116
|
+
|
117
|
+
def validate_response_from(page_name, href)
|
118
|
+
begin
|
119
|
+
root_path = path_to(page_name)
|
120
|
+
uri = is_relative?(href) ? (URI.join(root_path, href)) : URI.parse(href)
|
121
|
+
response = get_response_from(uri)
|
122
|
+
valid_status_groups = [Net::HTTPRedirection, Net::HTTPInformation, Net::HTTPSuccess ]
|
123
|
+
valid_status_groups.should include(response.class.superclass)
|
124
|
+
rescue RSpec::Expectations::ExpectationNotMetError
|
125
|
+
message = "Received a #{response.code} #{ response.msg } from #{href} on #{page_name}"
|
126
|
+
fail message
|
127
|
+
rescue
|
128
|
+
message = "Invalid reference: #{href} found on #{page_name} page"
|
129
|
+
fail message
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
#this returns a hash with a response code and the url to help provide good fail detail
|
134
|
+
def get_response_from(uri)
|
135
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
136
|
+
http.read_timeout = http.open_timeout = SimpliTest.config[:settings]["HTTP_TIMEOUT"] || 3
|
137
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
138
|
+
if uri.scheme == 'https'
|
139
|
+
http.use_ssl = true
|
140
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
141
|
+
end
|
142
|
+
http.request(request)
|
143
|
+
end
|
144
|
+
|
145
|
+
#FIXME: Code not used. Should be deleted
|
146
|
+
def url_in_new_window
|
147
|
+
if handles = page.driver.browser.window_handles rescue nil
|
148
|
+
new_window = handles.last
|
149
|
+
page.within_window(new_window) do
|
150
|
+
return without_trailing_slash(current_url)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def without_trailing_slash(url)
|
156
|
+
url.chomp('/')
|
157
|
+
end
|
158
|
+
|
159
|
+
def with_encoded_white_space(string)
|
160
|
+
string.gsub(' ', '%20')
|
161
|
+
end
|
162
|
+
|
163
|
+
def with_unencoded_white_space(string)
|
164
|
+
string.gsub('%20', ' ')
|
165
|
+
end
|
166
|
+
|
167
|
+
def normalize(url)
|
168
|
+
normalized_uri = URI.parse(url).normalize
|
169
|
+
url = normalized_uri.to_s
|
170
|
+
encoded_url = URI::encode(url)
|
171
|
+
without_trailing_slash(encoded_url)
|
172
|
+
end
|
173
|
+
|
174
|
+
def normalize_path(path)
|
175
|
+
if path = is_url?(path)
|
176
|
+
path = path.path
|
177
|
+
end
|
178
|
+
with_encoded_white_space(without_trailing_slash(path))
|
179
|
+
end
|
180
|
+
|
181
|
+
def wait_for(left_argument, right_argument)
|
182
|
+
called_at = Time.now
|
183
|
+
until left_argument > right_argument do
|
184
|
+
past_wait_time = called_at < Time.now - SimpliTest.config['HTTP_TIMEOUT']
|
185
|
+
return if past_wait_time
|
186
|
+
sleep 1
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def comparable_urls_for(target_url, source_url)
|
191
|
+
is_url?(target_url) ? [target_url, source_url].map{|u| normalize(u)} : [target_url, URI.parse(source_url).path]
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
World(NavigationHelpers)
|