taft 0.1.0 → 0.2.4
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/README.md +9 -3
- data/examples/ruby/rs/framework/red_sky.rb +11 -0
- data/examples/ruby/rs/framework/red_sky/api_helpers/general.rb +140 -0
- data/examples/ruby/rs/framework/red_sky/api_helpers/rest.rb +249 -0
- data/examples/ruby/rs/framework/red_sky/ui_helpers/ui_general.rb +36 -0
- data/examples/ruby/rs/framework/red_sky/watir/custom/all.rb +4 -0
- data/examples/ruby/rs/framework/red_sky/watir/custom/rs_custom.rb +32 -0
- data/examples/ruby/rs/framework/red_sky/watir/pages/page_objects.rb +166 -0
- data/examples/ruby/rs/framework/red_sky/watir/pages/rs_pages.rb +68 -0
- data/examples/ruby/rs/lib/config/red_sky_config.rb +27 -0
- data/examples/ruby/rs/lib/config/runtime_constants.rb +20 -0
- data/examples/ruby/rs/lib/red_sky_test_case.rb +218 -0
- data/examples/ruby/rs/tests/v1/tc_r001_01_an_example_test.rb +112 -0
- data/examples/ruby/rs/tests/v1/tc_r001_01_google_search.rb +64 -0
- data/lib/taft.rb +2 -0
- data/lib/taft_files/framework/zznamezz.rb +3 -0
- data/lib/taft_files/framework/zznamezz/api_helpers/general.rb +13 -13
- data/lib/taft_files/framework/zznamezz/ui_helpers/ui_general.rb +26 -0
- data/lib/taft_files/framework/zznamezz/watir/custom/all.rb +4 -0
- data/lib/taft_files/framework/zznamezz/watir/custom/xxabbrevxx_custom.rb +32 -0
- data/lib/taft_files/framework/zznamezz/watir/pages/page_objects.rb +166 -0
- data/lib/taft_files/framework/zznamezz/watir/pages/xxabbrevxx_pages.rb +101 -0
- data/lib/taft_files/lib/config/runtime_constants.rb +5 -1
- data/lib/taft_files/lib/config/zznamezz_config.rb +7 -2
- data/lib/taft_files/lib/zznamezz_test_case.rb +43 -42
- data/lib/taft_files/tests/v1/tc_r001_01_an_example_test.rb +1 -1
- data/taft.gemspec +5 -5
- metadata +23 -6
@@ -0,0 +1,112 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
2
|
+
|
3
|
+
require "red_sky_test_case"
|
4
|
+
|
5
|
+
class TC_R001_01_AN_EXAMPLE_TEST < Test::Unit::TestCase
|
6
|
+
include RedSkyTestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
# specify setup parameters
|
10
|
+
@certificate = :regular # this is the default user for this test
|
11
|
+
@initialBrowser = :none # if you want this test to navigate to your webapp automatically as part of setup, change this value to the value referring to your webapp
|
12
|
+
|
13
|
+
super # must call super so that the common setup method in RedSkyTestCase is called
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_r001_01_an_example_test
|
17
|
+
|
18
|
+
############################################################################################
|
19
|
+
# PURPOSE :
|
20
|
+
# Verify that <description of your test's intent>
|
21
|
+
#
|
22
|
+
# PRECONDITIONS :
|
23
|
+
# <list your preconditions>
|
24
|
+
############################################################################################
|
25
|
+
|
26
|
+
filename = "data_for_example_test.csv" # file must be in the data/ directory
|
27
|
+
data = @help.read_csv_test_data(filename)
|
28
|
+
header = data.shift
|
29
|
+
|
30
|
+
# Step 1 :
|
31
|
+
# Send a request to the RED SKY API Options method
|
32
|
+
|
33
|
+
random_row = data.random
|
34
|
+
search_term = random_row[0]
|
35
|
+
expected_result_count = random_row[1]
|
36
|
+
|
37
|
+
# This is too raw - it would be better to bundle these lines into a separate "search_options" method,
|
38
|
+
# with additional validation (e.g. to throw a clean error if the request failed)
|
39
|
+
@client = @help.get_rest_client(:options, @certificate, search_term)
|
40
|
+
json = client.get
|
41
|
+
response = JSON.pretty_unparse(json)
|
42
|
+
|
43
|
+
# Expected Result :
|
44
|
+
# The request has succeeded & returned the expected results
|
45
|
+
|
46
|
+
# This is quite brittle
|
47
|
+
# A better approach is to create a new class which would parse the response & convert
|
48
|
+
# it into a bespoke Object, so that the various values could be accessed in a better OO-fashion.
|
49
|
+
# E.g. response.number_of_results. The object could also have extra methods,
|
50
|
+
# e.g. response.check_results_are_valid, and so on.
|
51
|
+
assert_equal(expected_result_count, response["number_of_results"], "The search request did not return the expected number of results")
|
52
|
+
|
53
|
+
|
54
|
+
# Step 2 :
|
55
|
+
# Log in to RED SKY
|
56
|
+
|
57
|
+
rs_login
|
58
|
+
|
59
|
+
# Expected Result :
|
60
|
+
# The RED SKY homepage is displayed
|
61
|
+
|
62
|
+
assert(rsHomepage.displayed?, "The RED SKY homepage is not displayed")
|
63
|
+
|
64
|
+
|
65
|
+
# Step 3 :
|
66
|
+
# Enter in a search term and click the Search button.
|
67
|
+
|
68
|
+
data.each do |row|
|
69
|
+
search_term = row[0]
|
70
|
+
expected_result_text = row[2]
|
71
|
+
puts "Will now search for '#{term}'; expect to see '#{expected_result_text}'"
|
72
|
+
|
73
|
+
rsHomepage.term = search_term
|
74
|
+
rsHomepage.click_search
|
75
|
+
|
76
|
+
|
77
|
+
# Expected Result :
|
78
|
+
# Results are displayed
|
79
|
+
|
80
|
+
assert(rsSearchResults.displayed?, "The RED SKY search results page is not displayed")
|
81
|
+
assert_equal(expected_result_text, rsSearchResults.result, "The RED SKY search results page did not display the expected result")
|
82
|
+
|
83
|
+
|
84
|
+
# Step 4 :
|
85
|
+
# Return to the previous page
|
86
|
+
|
87
|
+
browser.back
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
# Expected Result :
|
92
|
+
# The RED SKY homepage is displayed
|
93
|
+
|
94
|
+
assert(rsHomepage.displayed?, "The RED SKY homepage is not displayed")
|
95
|
+
|
96
|
+
|
97
|
+
# Step 5 :
|
98
|
+
# Repeat steps 3 and 4 for a few more search terms
|
99
|
+
|
100
|
+
# Actions performed in above steps
|
101
|
+
|
102
|
+
|
103
|
+
# Expected Result :
|
104
|
+
# Results are displayed for each term
|
105
|
+
|
106
|
+
# Assertions performed in above steps
|
107
|
+
|
108
|
+
end # end .each
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
$LOAD_PATH.unshift("#{File.expand_path(File.dirname(__FILE__))}/../../lib")
|
2
|
+
|
3
|
+
require "red_sky_test_case"
|
4
|
+
|
5
|
+
class TC_R001_01_GOOGLE_SEARCH < Test::Unit::TestCase
|
6
|
+
include RedSkyTestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
# specify setup parameters
|
10
|
+
@certificate = :regular # this is the default user for this test
|
11
|
+
@initialBrowser = :none # if you want this test to navigate to your webapp automatically as part of setup, change this value to the value referring to your webapp
|
12
|
+
|
13
|
+
super # must call super so that the common setup method in RedSkyTestCase is called
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_r001_01_google_search
|
17
|
+
|
18
|
+
############################################################################################
|
19
|
+
# PURPOSE :
|
20
|
+
# Verify that Google searches can be made
|
21
|
+
#
|
22
|
+
# PRECONDITIONS :
|
23
|
+
# None
|
24
|
+
############################################################################################
|
25
|
+
|
26
|
+
@help.ui_helper_test
|
27
|
+
|
28
|
+
# Step 1 :
|
29
|
+
# Open the Google Search page
|
30
|
+
|
31
|
+
google_login
|
32
|
+
|
33
|
+
# Expected Result :
|
34
|
+
# The RED SKY homepage is displayed
|
35
|
+
|
36
|
+
assert(googleSearch.displayed?, "The Google search page is not displayed")
|
37
|
+
|
38
|
+
|
39
|
+
# Step 3 :
|
40
|
+
# Enter in a search term and click the Search button.
|
41
|
+
|
42
|
+
term = "Ruby"
|
43
|
+
|
44
|
+
puts "Will now search for '#{term}'"
|
45
|
+
|
46
|
+
#googleSearch.search_term = term
|
47
|
+
@help.enter_google_term(term) # use @help to set the field, demonstrating that this can be done outside the test
|
48
|
+
googleSearch.click_search_button
|
49
|
+
|
50
|
+
|
51
|
+
# Expected Result :
|
52
|
+
# Results are displayed
|
53
|
+
|
54
|
+
assert(googleSearchResults.displayed?, "The Google search results page is not displayed")
|
55
|
+
|
56
|
+
puts googleSearchResults.result_stats
|
57
|
+
|
58
|
+
assert_not_nil(googleSearchResults.result_stats, "The Google search results page did not display any result-stats")
|
59
|
+
assert_not_empty(googleSearchResults.result_stats, "The Google search results page did not display any result-stats")
|
60
|
+
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
data/lib/taft.rb
CHANGED
@@ -199,6 +199,8 @@ class Taft
|
|
199
199
|
entries = Dir.entries(dest_base_folder)
|
200
200
|
entries.delete(".")
|
201
201
|
entries.delete("..")
|
202
|
+
entries.delete(".git")
|
203
|
+
entries.delete(".gitignore")
|
202
204
|
entries.each do |f|
|
203
205
|
f = File.expand_path(f)
|
204
206
|
pd "Now looking at #{f}; is dir? #{Dir.exists?(f)}"
|
@@ -5,22 +5,22 @@ require "avro"
|
|
5
5
|
require "csv"
|
6
6
|
require "net/ssh"
|
7
7
|
require "net/sftp"
|
8
|
+
require "more_ruby"
|
8
9
|
|
9
10
|
|
10
11
|
class XXabbrevupperxxHelper
|
11
12
|
include Test::Unit::Assertions
|
12
|
-
include FrameworkHelpers
|
13
13
|
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
case
|
22
|
-
when /^xxabbrevxx/
|
23
|
-
|
14
|
+
# E.g. calling homepage.displayed? from a test script :
|
15
|
+
# Test cannot see homepage so its call is routed through method_missing
|
16
|
+
# If method_missing returns an instance of the class, .displayed? can be called on it (seamlessly)
|
17
|
+
# At present this will happen for every call to a page from a test script
|
18
|
+
def method_missing(name, *args, &block)
|
19
|
+
#puts "XXabbrevupperxxHelper method_missing called; name = #{name.inspect}; #{name.class}"
|
20
|
+
|
21
|
+
case name.to_s
|
22
|
+
when /^xxabbrevxx/i
|
23
|
+
RSPages.find(name.to_s) # return the page so that the helper can use it
|
24
24
|
else
|
25
25
|
super
|
26
26
|
end
|
@@ -28,7 +28,7 @@ class XXabbrevupperxxHelper
|
|
28
28
|
|
29
29
|
# Reads in a file of CSV test data, e.g for use in data-driven tests
|
30
30
|
def read_csv_test_data(filename)
|
31
|
-
path = File.join(File.dirname(File.expand_path(__FILE__)) + "
|
31
|
+
path = File.join(File.dirname(File.expand_path(__FILE__)) + "/../../../tests/data", filename)
|
32
32
|
read_csv_data_from_file(path)
|
33
33
|
end
|
34
34
|
|
@@ -43,7 +43,7 @@ class XXabbrevupperxxHelper
|
|
43
43
|
|
44
44
|
# Reads in a JSON schema
|
45
45
|
def read_json_schema(schema_filename)
|
46
|
-
path = File.join(File.dirname(File.expand_path(__FILE__)) + "
|
46
|
+
path = File.join(File.dirname(File.expand_path(__FILE__)) + "/../../../tests/data", schema_filename)
|
47
47
|
data = []
|
48
48
|
File.open(path, "r") do |f|
|
49
49
|
data = f.readlines
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
class XXabbrevupperxxHelper
|
3
|
+
|
4
|
+
def new_browser_at_url(url)
|
5
|
+
puts "New browser at #{url}"
|
6
|
+
case ZZnamezzConfig::BROWSER
|
7
|
+
when :chrome
|
8
|
+
# Set detach to true so the browser remains open once the test finishes
|
9
|
+
options = Selenium::WebDriver::Chrome::Options.new
|
10
|
+
options.add_option(:detach, true)
|
11
|
+
b = Watir::Browser.new :chrome, :options => options
|
12
|
+
|
13
|
+
when :firefox
|
14
|
+
b = Watir::Browser.new :firefox
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
b.goto url
|
19
|
+
|
20
|
+
# Store the new browser in the global list
|
21
|
+
$browsers << b
|
22
|
+
|
23
|
+
b # return the browser
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
# All methods in this module will be added to those classes. If methods with the
|
3
|
+
# same names exist, these methods will overwrite the pre-existing ones.
|
4
|
+
|
5
|
+
module ZZnamezzCustom
|
6
|
+
|
7
|
+
# Example code :
|
8
|
+
#
|
9
|
+
# class XXabbrevupperxxPage
|
10
|
+
#
|
11
|
+
# # All page titles exist in the same-named element
|
12
|
+
# def title_field
|
13
|
+
# browser.h1(:id => "page_title")
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# def title
|
17
|
+
# title_field.value
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# class XXabbrevupperxxHomepage
|
23
|
+
#
|
24
|
+
# def displayed?
|
25
|
+
# puts "In #{__method__}"
|
26
|
+
# title == "Welcome to ZZnamezz"
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# Base class that every defined page will inherit from
|
2
|
+
class Page
|
3
|
+
|
4
|
+
attr_accessor :name, :displayed_field, :displayed_value
|
5
|
+
attr_accessor :browser
|
6
|
+
attr_accessor :field_parameters_array # stores parameters of each field added to the page
|
7
|
+
|
8
|
+
# Name : the name of this page, e.g. rsHomepage
|
9
|
+
# Field : the field used to determine if the page is displayed. More precisely,
|
10
|
+
# the name of the method that accesses the field. E.g. if the page has a field called 'page_title'
|
11
|
+
# defined, then its accessor method 'page_title_field' will have been generated .
|
12
|
+
# If the displayed? check is against an expected value, specify the field name corresponding to
|
13
|
+
# the read-method (e.g. page_title), and specify the value (String or Regexp).
|
14
|
+
# If the displayed? check is for a field to exist, specify the field's accessor method name
|
15
|
+
# (e.g. page_title_field), and keep value nil.
|
16
|
+
def initialize(name, field, value = nil)
|
17
|
+
@name = name
|
18
|
+
@displayed_field = field
|
19
|
+
@displayed_value = value
|
20
|
+
@field_parameters_array = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def displayed?(wait = true)
|
24
|
+
displayed = false
|
25
|
+
puts "in displayed? for page #{@name}"
|
26
|
+
if wait
|
27
|
+
puts "will wait for page to be loaded"
|
28
|
+
wait_until_displayed
|
29
|
+
end
|
30
|
+
|
31
|
+
puts "about to send to #{@displayed_field.to_sym.inspect}"
|
32
|
+
begin
|
33
|
+
field_or_value = self.send(@displayed_field.to_sym)
|
34
|
+
rescue Watir::Exception::UnknownObjectException
|
35
|
+
# cannot find the field on the page
|
36
|
+
# do nothing, displayed will stay false
|
37
|
+
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
38
|
+
# TODO : fix! wait then call displayed? again?
|
39
|
+
puts "hit StaleElementReferenceError for page #{@name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
puts "field_or_value retrieved is of class #{field_or_value.class}"
|
43
|
+
p field_or_value
|
44
|
+
if @displayed_value == nil
|
45
|
+
displayed = true if field_or_value.exists?
|
46
|
+
else
|
47
|
+
if @displayed_value.class == Regexp
|
48
|
+
displayed = true if field_or_value =~ @displayed_value
|
49
|
+
else
|
50
|
+
displayed = true if field_or_value == @displayed_value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
displayed
|
54
|
+
end
|
55
|
+
|
56
|
+
# Method to wait for the page to be displayed, up to <timeout> seconds
|
57
|
+
# Returns displayed status (true/false)
|
58
|
+
def wait_until_displayed(timeout = 5)
|
59
|
+
max = timeout * 10
|
60
|
+
count = 0
|
61
|
+
displayed = false
|
62
|
+
while count < max
|
63
|
+
displayed = displayed?(false)
|
64
|
+
break if displayed
|
65
|
+
sleep 0.2
|
66
|
+
count += 2
|
67
|
+
end
|
68
|
+
displayed
|
69
|
+
end
|
70
|
+
|
71
|
+
# Defines methods to access the field of specified type, by specified key & value
|
72
|
+
def add_field(name, type, key, value)
|
73
|
+
field_parameters_array << [name, type, key, value]
|
74
|
+
add_field_using_constructor_class(name, type, key, value)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Add to self all fields that were defined on page_object
|
78
|
+
# E.g. the supplied page_object represents part of a panel/page that is common to several pages
|
79
|
+
def add_page(page_object)
|
80
|
+
page_object.field_parameters_array.each do |field_parameters|
|
81
|
+
add_field(field_parameters[0], field_parameters[1], field_parameters[2], field_parameters[3])
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Defines methods to access the field of specified type, by specified key & value
|
86
|
+
def add_field_using_constructor_class(name, type, key, value)
|
87
|
+
PageFieldConstructor.add_fields(self, name, type, key, value)
|
88
|
+
end
|
89
|
+
|
90
|
+
end # end Page
|
91
|
+
|
92
|
+
class PageFieldConstructor
|
93
|
+
|
94
|
+
# Defines methods to access the field of specified type, by specified key & value
|
95
|
+
def PageFieldConstructor.add_fields(page_object, name, type, key, value)
|
96
|
+
|
97
|
+
# Fields cannot have the following names : name
|
98
|
+
raise "Field on page #{page_object.name} with name of #{name} is not allowed" if ZZnamezzConfig::DISALLOWED_FIELD_NAMES.include?(name)
|
99
|
+
|
100
|
+
case type
|
101
|
+
when :button
|
102
|
+
real_type = :input
|
103
|
+
else
|
104
|
+
real_type = type
|
105
|
+
end
|
106
|
+
|
107
|
+
# add accessor to field
|
108
|
+
s = <<-METHOD
|
109
|
+
def page_object.#{name}_field
|
110
|
+
# puts "in #{name} method"
|
111
|
+
@browser.#{real_type}(#{key.inspect} => "#{value}")
|
112
|
+
end
|
113
|
+
METHOD
|
114
|
+
# page_object.class.module_eval(s) # do not do this - want to add methods (field) to the object, not the class!
|
115
|
+
eval(s)
|
116
|
+
|
117
|
+
case type
|
118
|
+
when :text_field
|
119
|
+
add_read_method(page_object, name)
|
120
|
+
add_write_method(page_object, name)
|
121
|
+
when :button
|
122
|
+
add_click_method(page_object, name)
|
123
|
+
when :link
|
124
|
+
add_read_method(page_object, name)
|
125
|
+
add_click_method(page_object, name)
|
126
|
+
else
|
127
|
+
add_read_method(page_object, name)
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
def PageFieldConstructor.add_read_method(page_object, name)
|
133
|
+
s = <<-READ
|
134
|
+
def page_object.#{name}
|
135
|
+
# puts "in #{name} read method"
|
136
|
+
#{name}_field.text # value
|
137
|
+
end
|
138
|
+
READ
|
139
|
+
# page_object.class.module_eval(s) # do not do this - want to add methods (field) to the object, not the class!
|
140
|
+
eval(s)
|
141
|
+
end
|
142
|
+
|
143
|
+
def PageFieldConstructor.add_write_method(page_object, name)
|
144
|
+
s = <<-WRITE
|
145
|
+
def page_object.#{name}=(v)
|
146
|
+
# puts "in #{name} write method"
|
147
|
+
#{name}_field.set(v)
|
148
|
+
end
|
149
|
+
WRITE
|
150
|
+
# page_object.class.module_eval(s) # do not do this - want to add methods (field) to the object, not the class!
|
151
|
+
eval(s)
|
152
|
+
end
|
153
|
+
|
154
|
+
def PageFieldConstructor.add_click_method(page_object, name)
|
155
|
+
s = <<-CLICK
|
156
|
+
def page_object.click_#{name}
|
157
|
+
# puts "in #{name} click method"
|
158
|
+
#{name}_field.click
|
159
|
+
end
|
160
|
+
CLICK
|
161
|
+
# page_object.class.module_eval(s) # do not do this - want to add methods (field) to the object, not the class!
|
162
|
+
eval(s)
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|