taft 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bd9ae23e1324c24c5a99e25a21858ea93ade0f8f1993379501fdfaf76c67ea19
4
+ data.tar.gz: 5efce5a842f8a21f3b9c75a3a8edce0211aab23ac006f683fb7a562f1193ab31
5
+ SHA512:
6
+ metadata.gz: b4cc3d8926584f3b14c60f99475c85c5ecdb9265a1d2258c4b9e827037b8bdb25f640ab944fd309bfbb7c40f84da3c4a9237424ce8e390f540b324b18f07c37b
7
+ data.tar.gz: cf13e673c7f5d6abb4594e42ab55006a3adad34492b3b7bae2f9e9e1bae6f1be702c97e446e6f47820de837fcfa803bff83cf4c4c974b245f8e72879bdeac6b1
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Richard Morrisby
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,17 @@
1
+ ### Test Automation Framework Template
2
+
3
+ This gem will deploy/install a skeleton code framework for the automated testing of applications with APIs and/or web-UIs.
4
+
5
+ Languages : Ruby
6
+
7
+ ## How to use
8
+
9
+ Command line : `ruby -e "require 'taft'; Taft.install"`
10
+
11
+
12
+
13
+
14
+ ## TODO
15
+
16
+ * More languages : Java
17
+ * Ruby installation will also install some gems (bundled within TAFT)
@@ -0,0 +1,51 @@
1
+ # Simple build script
2
+ # Deletes the existing gem file (if present)
3
+ # Uninstalls the gem
4
+ # Builds the gem
5
+ # Installs the new gem
6
+
7
+ # Note : when calling system (or backticks, etc.) th enew process starts at the system default, not the current working directory.
8
+ # Therefore we need to use a syntax of : system "cd #{gem_dir} && #{i_cmd}"
9
+
10
+ # Run from this directory!
11
+
12
+ gem_dir = Dir.getwd
13
+
14
+ # Delete existing .gem files in the dir
15
+
16
+ gemfiles = Dir.entries(gem_dir).collect {|q| q if q =~ /.gem$/}.compact
17
+
18
+ gemfiles.each do |q|
19
+ File.delete q
20
+ puts "Deleted #{q}"
21
+ end
22
+
23
+ gemfiles = Dir.entries(gem_dir).collect {|q| q if q =~ /.gem$/}.compact
24
+ raise "Gem has not been deleted" unless gemfiles.size == 0
25
+
26
+ # Uninstall, build, install
27
+ gemspecs = Dir.entries(gem_dir).collect {|q| q if q =~ /.gemspec$/}.compact
28
+
29
+ raise "Did not find a .gemspec in #{gem_dir}" if gemspecs.size < 1
30
+ raise "Found more than one .gemspec in #{gem_dir}" if gemspecs.size > 1
31
+
32
+ gemspec = gemspecs[0]
33
+
34
+ gemname = File.basename(gemspec, File.extname(gemspec))
35
+
36
+ u_cmd = "gem uninstall #{gemname}"
37
+ system u_cmd
38
+
39
+ b_cmd = "gem build #{gemspec}"
40
+ system "cd #{gem_dir} && #{b_cmd}"
41
+
42
+ gemfiles = Dir.entries(gem_dir).collect {|q| q if q =~ /.gem$/}.compact
43
+ raise "Gem was not built" unless gemfiles.size == 1
44
+
45
+ gemfile = gemfiles[0]
46
+ raise "Gem file is not for the expected gem, expected a #{gemname} gem but found #{gemfile}" unless gemfile =~ /^#{gemname}/
47
+
48
+ i_cmd = "gem install #{gemfile}"
49
+ system "cd #{gem_dir} && #{i_cmd}"
50
+
51
+ puts "Gem #{gemname} built & installed"
@@ -0,0 +1,286 @@
1
+ require 'fileutils'
2
+ require 'pathname'
3
+ require 'more_ruby'
4
+
5
+ def pd(s)
6
+ puts s if $TAFT_DEBUGGING
7
+ end
8
+
9
+ class Taft
10
+ TEMPLATE_PROJECT_NAME_REGEX = /(zznamezz)/ # e.g. redsky if one word, red_sky if two # regex to use when matching a template file name
11
+ TEMPLATE_PROJECT_NAME_UPPERCASE_REGEX = /(ZZnamezz)/ # e.g. Redsky if one word, RedSky if two # regex to use when matching a template file name
12
+ TEMPLATE_PROJECT_ABBREV_REGEX = /(xxabbrevxx)/ # e.g. bs # regex to use when matching a template file name
13
+ TEMPLATE_PROJECT_ABBREV_UPPERCASE_REGEX = /(xxabbrevupperxx)/i # e.g. BS # regex to use when matching some template text
14
+ TEMPLATE_PROJECT_RAW_NAME_REGEX = /(yyrawnameyy)/i # e.g. RED SKY # regex to use when matching some template text
15
+
16
+ NAMES_AND_ABBREVS_REGEXES = [TEMPLATE_PROJECT_ABBREV_REGEX, TEMPLATE_PROJECT_ABBREV_UPPERCASE_REGEX, TEMPLATE_PROJECT_NAME_REGEX, TEMPLATE_PROJECT_NAME_UPPERCASE_REGEX]
17
+ TEMPLATE_GEM_NAME_REGEX = /-\d+.\d+.\d+.gem/
18
+
19
+ LANGUAGES = [:ruby]#, :java] # Java not yet supported
20
+
21
+ @project_name_part = nil
22
+ @project_name_uppercase_part = nil
23
+ @project_abbrev_part = nil
24
+ @project_abbrev_uppercase_part = nil
25
+
26
+ def self.install_ruby(debugging = false, dest = "", overwrite_ok = false, project_name = "", project_abbrev = "")
27
+ install(:ruby, debugging, dest, overwrite_ok, project_name, project_abbrev)
28
+ end
29
+
30
+ def self.install_java(debugging = false, dest = "", overwrite_ok = false, project_name = "", project_abbrev = "")
31
+ install(:java, debugging, dest, overwrite_ok, project_name, project_abbrev)
32
+ end
33
+
34
+ def self.install(lang = nil, debugging = false, dest = "", overwrite_ok = false, project_name = "", project_abbrev = "")
35
+ $TAFT_DEBUGGING = true if debugging
36
+
37
+ unless dest.empty?
38
+ puts "Taft.install has been called with the following parameters :"
39
+ puts "Language : #{lang}"
40
+ puts "Project name : #{project_name}"
41
+ puts "Project abbreviation : #{project_abbrev}"
42
+ puts "Destination folder (relative to #{Dir.getwd} if a relative path) : #{dest}"
43
+ puts "Press Enter to continue..."
44
+ gets
45
+ end
46
+
47
+ base_wd = Dir.getwd
48
+ dest_base_folder = ""
49
+
50
+ if lang == nil
51
+ puts "\nPlease enter the language of this project : #{LANGUAGES.join(", ")}"
52
+ lang = gets.chomp.downcase.to_sym
53
+ raise "TAFT cannot install a new project in that language" unless LANGUAGES.include?(lang)
54
+ end
55
+
56
+ if dest.empty?
57
+ puts "\nPlease enter the path of the base folder that TAFT should create, up to and including the name of the base folder"
58
+ puts "TAFT will create this folder if it does not exist"
59
+ puts "If a relative path is entered, it will be taken as being relative to path : #{Dir.getwd}"
60
+ dest = gets.chomp
61
+ raise "The base folder path entered was empty" if dest.empty?
62
+
63
+ puts "Does this folder already exist? Entering Y will grant TAFT permission to write into that folder, overwriting any files with matching names that are aready present."
64
+ folder_exists = gets.chomp
65
+
66
+ overwrite_ok = (folder_exists == "Y")
67
+ end
68
+ # if dest has been specified in the call, then overwrite_ok has as well
69
+
70
+ case lang
71
+ when :ruby
72
+ raw_file_path = "#{File.expand_path(File.dirname(__FILE__))}/taft_files"
73
+ # TODO determine list of gems & put in folder
74
+ # Might be better to output a list of gem install commands instead? What if people are using earlier/later versions of Ruby?
75
+ # bundled_gem_path = "#{File.expand_path(File.dirname(__FILE__))}/bundled_gems"
76
+ # install_gems(bundled_gem_path)
77
+ when :java
78
+ raw_file_path = "#{File.expand_path(File.dirname(__FILE__))}/java_taft_files"
79
+ end
80
+
81
+ # TODO does this handle dests like "~/foo" ?
82
+ if (Pathname.new dest).absolute?
83
+ dest_base_folder = dest
84
+ else
85
+ dest_base_folder = File.join(Dir.getwd, dest)
86
+ end
87
+ dest_base_folder = File.expand_path(dest_base_folder)
88
+ puts "TAFT will install to #{dest_base_folder}"
89
+
90
+ raise "Folder #{dest_base_folder} already exists, and you did not grant TAFT permission to write into the folder" if Dir.exists?(dest_base_folder) && !overwrite_ok
91
+
92
+ # Create the base folder
93
+ begin
94
+ Dir.mkdir(dest_base_folder) unless Dir.exists?(dest_base_folder)
95
+ ensure
96
+ raise "The base folder '#{dest_base_folder}' did not exist" if folder_exists && !Dir.exists?(dest_base_folder)
97
+ raise "The base folder '#{dest_base_folder}' could not be created" unless Dir.exists?(dest_base_folder)
98
+ end
99
+
100
+ # Copy the raw files into the base folder, preserving the structure
101
+ FileUtils.copy_entry(raw_file_path, dest_base_folder, false, false, true)
102
+
103
+ puts "\nFiles have been copied"
104
+ if project_name.empty?
105
+ puts "\nPlease enter the name of your project (e.g. RED SKY) :"
106
+ project_name = gets.chomp
107
+ raise "The project name entered was empty" if project_name.empty?
108
+ end
109
+
110
+ if project_abbrev.empty?
111
+ puts "\nPlease enter the abbreviation of your project (e.g. RS) :"
112
+ project_abbrev = gets.chomp
113
+ raise "The project abbreviation entered was empty" if project_abbrev.empty?
114
+ end
115
+
116
+
117
+ @project_name_part = project_name.gsub(/[\s-]+/, "_").downcase # TODO use .snakecase ?
118
+ @project_name_uppercase_part = @project_name_part.upcase
119
+ @project_abbrev_part = project_abbrev.gsub(/[\s-]+/, "_").delete("_").downcase # TODO use .snakecase ?
120
+ @project_abbrev_uppercase_part = @project_abbrev_part.upcase
121
+
122
+ # Now sweep over the copied files, adjusting the names accordingly
123
+ Taft.adjust_file_names(dest_base_folder, project_name, project_abbrev)
124
+
125
+ # Now sweep over the copied files, adjusting the contents accordingly
126
+ Taft.adjust_file_contents(dest_base_folder, project_name, project_abbrev)
127
+
128
+ puts "\nFiles have been tailored to your project."
129
+
130
+ puts "\nTAFT has installed a tailored copy of the #{lang.capitalize} Automation Framework to #{dest_base_folder}"
131
+ puts "Installation complete."
132
+ end
133
+
134
+ # Looks at the names of each file & folder within dest_base_folder and renames them, applying the project_name or project_abbrev as appropriate
135
+ def self.adjust_file_names(dest_base_folder, project_name, project_abbrev)
136
+ pd "Now in #{__method__}; #{dest_base_folder}; #{project_name}; #{project_abbrev}"
137
+ project_file_name_part = project_name.gsub(/[\s-]+/, "_").downcase # TODO use .snakecase ?
138
+ project_file_abbrev_part = project_abbrev.gsub(/[\s-]+/, "_").delete("_").downcase # TODO use .snakecase ?
139
+
140
+ pd "project_file_name_part : #{project_file_name_part}" # snakecase
141
+ pd "project_file_abbrev_part : #{project_file_abbrev_part}" # lowercase
142
+ Dir.chdir(dest_base_folder) do
143
+ entries = Dir.entries(dest_base_folder)
144
+ entries.delete(".")
145
+ entries.delete("..")
146
+ entries.each do |f|
147
+ f = File.expand_path(f)
148
+ pd "Now looking at #{f}; is dir? #{Dir.exists?(f)}"
149
+ if Dir.exists?(f) # if this is a dir, call recursively
150
+ Taft.adjust_file_names(f, project_name, project_abbrev)
151
+ end
152
+
153
+ # After processing the contents of the directory, rename it
154
+ # Or if the entry was actually a file, rename it
155
+ basename = File.basename(f, ".*")
156
+ NAMES_AND_ABBREVS_REGEXES.each do |regex|
157
+ if basename =~ regex
158
+ ext = File.extname(f)
159
+ dir = File.split(f)[0]
160
+
161
+ # For the given regex, work out what the replacement text should be
162
+ case regex.inspect
163
+ when TEMPLATE_PROJECT_NAME_REGEX
164
+ replacement = @project_name_part
165
+ when TEMPLATE_PROJECT_NAME_UPPERCASE_REGEX
166
+ replacement = @project_name_uppercase_part
167
+ when TEMPLATE_PROJECT_ABBREV_REGEX
168
+ replacement = @project_abbrev_part
169
+ when TEMPLATE_PROJECT_ABBREV_UPPERCASE_REGEX
170
+ replacement = @project_abbrev_uppercase_part
171
+ end
172
+
173
+ new_f = basename.gsub(regex, replacement)
174
+ new_f += ext # must add the extension back on
175
+ new_f = File.join(dir, new_f) # this is the full path
176
+ pd "Will rename #{f}\n to #{new_f}"
177
+ Taft.delete_file(new_f)
178
+ File.rename(f, new_f)
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+
186
+ # Looks at the contents of each file within dest_base_folder and edits their contents, applying the project_name or project_abbrev as appropriate
187
+ def self.adjust_file_contents(dest_base_folder, project_name, project_abbrev)
188
+ pd "Now in #{__method__}; #{dest_base_folder}; #{project_name}; #{project_abbrev}"
189
+ raw_name = project_name # should have been entered in form like RED SKY
190
+ project_class_name_part = project_name.gsub(/[\s-]+/, "_").downcase # TODO use .snakecase ?
191
+ project_class_name_uppercase_part = project_name.pascalcase
192
+ project_class_abbrev_part = project_abbrev.gsub(/[\s-]+/, "_").delete("_").downcase # TODO use .snakecase ?
193
+
194
+ pd "project_class_name_part : #{project_class_name_part}" # snakecase
195
+ pd "project_class_name_uppercase_part : #{project_class_name_uppercase_part}" # pascalcase
196
+ pd "project_class_abbrev_part : #{project_class_abbrev_part}" # lowercase
197
+
198
+ Dir.chdir(dest_base_folder) do
199
+ entries = Dir.entries(dest_base_folder)
200
+ entries.delete(".")
201
+ entries.delete("..")
202
+ entries.each do |f|
203
+ f = File.expand_path(f)
204
+ pd "Now looking at #{f}; is dir? #{Dir.exists?(f)}"
205
+ if Dir.exists?(f) # if this is a dir, call recursively
206
+ Taft.adjust_file_contents(f, project_name, project_abbrev)
207
+ next
208
+ end
209
+
210
+ lines = []
211
+ File.open(f, "r") do |file_obj|
212
+ lines = file_obj.readlines
213
+ end
214
+
215
+
216
+ # Each line may match more than one regex
217
+ # Hence each line should be passed through all of the regexes, not stopping after the first one it matches
218
+ # i.e. separate if-ends, not one big case-when or if-elsif routine
219
+ lines.each do |line|
220
+ if line =~ TEMPLATE_PROJECT_NAME_REGEX
221
+ line.gsub!(TEMPLATE_PROJECT_NAME_REGEX, project_class_name_part)
222
+ end
223
+ if line =~ TEMPLATE_PROJECT_NAME_UPPERCASE_REGEX
224
+ line.gsub!(TEMPLATE_PROJECT_NAME_UPPERCASE_REGEX, project_class_name_uppercase_part)
225
+ end
226
+ if line =~ TEMPLATE_PROJECT_ABBREV_REGEX
227
+ line.gsub!(TEMPLATE_PROJECT_ABBREV_REGEX, project_class_abbrev_part)
228
+ end
229
+ if line =~ TEMPLATE_PROJECT_ABBREV_UPPERCASE_REGEX
230
+ line.gsub!(TEMPLATE_PROJECT_ABBREV_UPPERCASE_REGEX, project_class_abbrev_part.upcase)
231
+ end
232
+ if line =~ TEMPLATE_PROJECT_RAW_NAME_REGEX
233
+ line.gsub!(TEMPLATE_PROJECT_RAW_NAME_REGEX, raw_name)
234
+ end
235
+ end
236
+
237
+ File.open(f, "w") do |file_obj|
238
+ file_obj.puts lines
239
+ end
240
+ end
241
+ end
242
+ end
243
+
244
+ def self.delete_file(abs_file_path)
245
+ if Dir.exists?(abs_file_path)
246
+ FileUtils.remove_dir(abs_file_path)
247
+ elsif File.exists?(abs_file_path)
248
+ File.delete(abs_file_path)
249
+ end
250
+ end
251
+
252
+ def self.install_gems(bundled_gem_path)
253
+ puts "\nWill first install all gems bundled in with the TAFT gem."
254
+
255
+ gem_list = Dir.entries(bundled_gem_path)
256
+ gem_list.delete(".")
257
+ gem_list.delete("..")
258
+ gems_to_install = []
259
+ gem_list.each do |gem_name|
260
+ # For each gem, try to require it. Only install those that couldn't be required.
261
+ begin
262
+ gem_base_name = gem_name.gsub(TEMPLATE_GEM_NAME_REGEX, "")
263
+ require gem_base_name
264
+ rescue LoadError
265
+ puts "#{gem_base_name} could not be required; will install #{gem_name}"
266
+ gems_to_install << gem_name
267
+ end
268
+ end
269
+
270
+ if gems_to_install.empty?
271
+ puts "All required gems are already installed"
272
+ else
273
+ puts "Will install the following gems :"
274
+ gems_to_install.each {|gem_name| puts gem_name }
275
+
276
+ Dir.chdir(bundled_gem_path) # set this to be the working directory while installing the gems
277
+ gems_to_install.each do |gem_name|
278
+ puts "\nNow installing #{gem_name}..."
279
+ system("gem install #{gem_name}")
280
+ puts "Gem installed."
281
+ end
282
+ Dir.chdir(base_wd) # reset the working directory
283
+ end
284
+ end
285
+
286
+ end
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+
3
+ # Add a require line for every file within framework/zznamezz
4
+
5
+ require "zznamezz/api_helpers/general"
6
+ require "zznamezz/api_helpers/rest"
7
+
8
+ require "zznamezz/ui_helpers/ui_general"
@@ -0,0 +1,140 @@
1
+ require "test/unit/assertions" # required for the assert_ methods
2
+
3
+ require "json-schema"
4
+ require "avro"
5
+ require "csv"
6
+ require "net/ssh"
7
+ require "net/sftp"
8
+
9
+
10
+ class XXabbrevupperxxHelper
11
+ include Test::Unit::Assertions
12
+ include FrameworkHelpers
13
+
14
+ # initialize and method_missing are necessary for for allowing this class to access outside methods
15
+ attr_accessor :xxabbrevxx_context
16
+ def initialize(xxabbrevxx_context)
17
+ @xxabbrevxx_context = xxabbrevxx_context
18
+ end
19
+
20
+ def method_missing(meth, *args)
21
+ case meth.to_s
22
+ when /^xxabbrevxx/
23
+ @xxabbrevxx_context.send(meth, *args)
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ # Reads in a file of CSV test data, e.g for use in data-driven tests
30
+ def read_csv_test_data(filename)
31
+ path = File.join(File.dirname(File.expand_path(__FILE__)) + "/../../../../tests/data", filename)
32
+ read_csv_data_from_file(path)
33
+ end
34
+
35
+ # Reads in a CSV
36
+ def read_csv_data_from_file(full_file_path)
37
+ data = []
38
+ CSV.open(full_file_path, "r") do |csv|
39
+ data = csv.readlines
40
+ end
41
+ data
42
+ end
43
+
44
+ # Reads in a JSON schema
45
+ def read_json_schema(schema_filename)
46
+ path = File.join(File.dirname(File.expand_path(__FILE__)) + "/../../../../tests/data", schema_filename)
47
+ data = []
48
+ File.open(path, "r") do |f|
49
+ data = f.readlines
50
+ end
51
+ schema = JSON.parse(data.chomp) # there may be trailing whitespace
52
+ schema
53
+ end
54
+
55
+ # Reads in a serialised AVRO file
56
+ # Returns an array of the deserialised data rows
57
+ def read_avro_file(filename)
58
+ lines = []
59
+ File.open(path, "rb") do |f|
60
+ reader = Avro::IO::DatumReader.new
61
+ dr = Avro::DataFile::Reader.new(f, reader)
62
+ dr.each do |record|
63
+ lines << record
64
+ end
65
+ end
66
+ lines
67
+ end
68
+
69
+ # Validates the supplied hash against the JSON schema
70
+ def validate_hash_against_json_schema(hash, schema_filename)
71
+ raise "Must supply a hash to #{__method__}" unless hash.class == Hash
72
+
73
+ schema = read_json_schema(schema_filename)
74
+ errors = JSON::Validator.fully_validate(schema, hash)
75
+ errors
76
+ end
77
+
78
+ # Calls the build_number REST method
79
+ # This is an example of how to use get_rest_client
80
+ def get_version_number_from_api(cert_symbol = :regular)
81
+ client = get_rest_client(:build_number, cert_symbol)
82
+ json = client.get # {"message":"1.8.0"}
83
+ parsed = JSON.parse(json)
84
+ parsed["message"]
85
+ end
86
+
87
+ # Forms a .tar.gz archive from the specified source file
88
+ # Creates the file in the working directory
89
+ # Creates the .tar.gz via a call to system
90
+ def create_tar_gz_file(gz_base_file_name, source_file)
91
+ gz_name = "#{gz_base_file_name}.tar.gz"
92
+ cmd = "tar -czf #{gz_name} #{source_file}"
93
+ system(cmd)
94
+ gz_name
95
+ end
96
+
97
+ # Renames the specified file on the Linux server
98
+ # Needs the full path
99
+ def rename_linux_file(old_file, new_file, cert_symbol = :regular)
100
+ # Derive the FTP host & path from the URL in config
101
+ host = ZZnamezzConfig::SERVER[:zznamezz_url].split("//")[1].split(":")[0]
102
+ host_short_form = host.split(".")[0]
103
+ user = get_user_id(cert_symbol)
104
+ pass = get_user_cert_pw(cert_symbol)
105
+
106
+ Net::SFTP.start(host, user, :password => pass) do |sftp|
107
+ puts "Renaming file : #{old_file} -> #{new_file}"
108
+ sftp.rename(old_file, new_file)
109
+ end
110
+ end
111
+
112
+ # Sets 777 permissions to the Linux server file
113
+ # Need the file name & dir
114
+ def chmod_linux_file(host, user, pass, path, file_name)
115
+ Net::SSH.start(host, user, :password => pass) do |ssh|
116
+ ssh.exec!("cd #{path}; chmod 777 #{file_name}")
117
+ end
118
+ end
119
+
120
+ # Executes the supplied curl command on the server
121
+ def submit_curl_command(cmd, cert_symbol = :regular)
122
+ # Derive the FTP host & path from the URL in config
123
+ host = ZZnamezzConfig::SERVER[:zznamezz_url].split("//")[1].split(":")[0]
124
+ host_short_form = host.split(".")[0]
125
+ user = get_user_id(cert_symbol)
126
+ pass = get_user_cert_pw(cert_symbol)
127
+
128
+ output = ""
129
+ Net::SSH.start(host, user, :password => pass) do |ssh|
130
+ output = ssh.exec!(cmd)
131
+ end
132
+
133
+ # We expect a JSON response from the server
134
+ # The recorded output will contain this inside curl's own SDTOUT, so we need to extract the JSON
135
+ output = output[output.index("{") .. output.index("}")]
136
+ JSON.parse(output)
137
+ end
138
+
139
+
140
+ end
@@ -0,0 +1,249 @@
1
+ require "rest_client"
2
+ require "uri"
3
+ require "openssl"
4
+ require "json"
5
+
6
+ # File contains methods conductive to the execution of tests and scripts that call REST interfaces
7
+
8
+
9
+ class XXabbrevupperxxHelper
10
+
11
+ # Returns a RestClient::Resource object pointing to the URL of the requested service
12
+ def get_rest_client(service, cert_symbol = :regular, parameter_array_or_hash = [], base_url = ZZnamezzConfig::SERVER[:zznamezz_url], version = nil, timeout = 150)
13
+
14
+ separator = "/"
15
+ api_version_string = separator + ZZnamezzConfig::API_VERSION.to_s # as the version parameter can be entirely absent, let's build the separator into the term
16
+ api_version_string = "" if ZZnamezzConfig::API_VERSION == :none # special case
17
+
18
+ api_version_string = separator + version if version # override always wins
19
+
20
+ parameter_array_or_hash = [parameter_array_or_hash] if parameter_array_or_hash.class != Array && parameter_array_or_hash.class != Hash # convert to array if a non-array/hash was supplied
21
+
22
+ # If common headers are needed
23
+ # headers = {"foo" => bar}
24
+
25
+ # Build up the path-string, then append it to the base URL
26
+ s = "" # initialise before manipulating it
27
+
28
+ if service.class == String
29
+ s = service
30
+ else
31
+ case service
32
+ when :options
33
+ s = "options#{api_version_string}"
34
+ s += "/#{parameter_array_or_hash[0]}"
35
+ when :build_number
36
+ s = "query/info#{api_version_string}/buildnumber"
37
+ else
38
+ raise "Unknown service #{service} supplied to #{__method__}"
39
+ end
40
+ end
41
+
42
+ encoded = encode_uri(s).to_s # Generates a URI::Generic object; we want a string
43
+ url = base_url + encoded
44
+
45
+ puts url
46
+
47
+ #######################################################
48
+ # Get certificate and other parameters needed for valid credentials
49
+ #######################################################
50
+
51
+ OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:ssl_version] = "SSLv3" # this may or may not be needed
52
+
53
+ cert_path = File.expand_path(ZZnamezzConfig::CERTIFICATE_DIR) # this must be an absolute filepath
54
+ cert_extension = get_user_cert_ext(cert_symbol).to_s
55
+
56
+ cert_name = get_user_p12_cert_name(cert_symbol)
57
+ cert_pw = get_user_cert_pw(cert_symbol)
58
+
59
+ # ca_file = ZZnamezzConfig::CA_CERTIFICATE_FILE # needed for VERIFY_PEER mode # VERIFY_PEER mode currently disabled
60
+
61
+ if cert_extension.to_sym == :pem
62
+ # If PEM, the credentials are in two parts - the certs.pem file and the key.pem file
63
+ # Need to read in the two separate files & construct OpenSSL::X509::Certificate & OpenSSL::PKey::RSA objects
64
+ cert_key_name = get_user_pem_cert_key_name(cert_symbol)
65
+ cert_key_pw = get_user_cert_key_pw(cert_symbol)
66
+ pem = File.read(File.join(cert_path, cert_name))
67
+ key_pem = File.read(File.join(cert_path, cert_key_name))
68
+
69
+ cert = OpenSSL::X509::Certificate.new(pem)
70
+
71
+ begin
72
+ key = OpenSSL::PKey::RSA.new(key_pem, cert_key_pw)
73
+ rescue
74
+ raise "Could not form OpenSSL::PKey::RSA object for the corresponding key.pem file. Does it have the right password?"
75
+ end
76
+ return RestClient::Resource.new(url, {:ssl_client_cert => cert, :ssl_client_key => key, :verify_ssl => OpenSSL::SSL::VERIFY_NONE, :timeout => timeout})
77
+ else
78
+ # If P12 or PFX, only need to construct the one object - the certificate and key are both stored within it
79
+ begin
80
+ p12 = OpenSSL::PKCS12.new(File.read(File.join(cert_path, cert_name), :binmode => true), cert_pw)
81
+ rescue OpenSSL::PKCS12::PKCS12Error => e
82
+ if e.to_s.include?("mac verify failure")
83
+ raise "Could not create PKCS12 object from certificate #{cert_name}; please specify a password for the certificate"
84
+ else
85
+ raise e
86
+ end
87
+ end
88
+
89
+ # Use if performing SSL Peer verification - needs a ca certificate
90
+ return RestClient::Resource.new(url, {:ssl_client_cert => p12.certificate, :ssl_client_key => p12.key, :ssl_ca_file => ca_file, :verify_ssl => OpenSSL::SSL::VERIFY_PEER, :headers => headers, :timeout => timeout})
91
+
92
+ # Use if not performing SSL Peer verification - does not need a ca certificate
93
+ return RestClient::Resource.new(url, {:ssl_client_cert => p12.certificate, :ssl_client_key => p12.key, :verify_ssl => OpenSSL::SSL::VERIFY_NONE, :timeout => timeout})
94
+ end
95
+
96
+ end
97
+
98
+ # Method to encode the URI
99
+ # Takes a string or an array of path fragments. If an array, the contents will be joined using / characters
100
+ def encode_uri(uri)
101
+ uri = uri.join("/") if uri.class == Array
102
+ additional_encoding(URI.parse(URI.encode(uri)).to_s)
103
+ end
104
+
105
+
106
+ # Method to perform additional encoding
107
+ # URI.encode does not convert the following chars: : +
108
+ def additional_encoding(s)
109
+ encoding_hash = {":" => "%3A", "+" => "%2B"}
110
+ encoding_hash.each_pair do |k, v|
111
+ s.gsub!(k, v)
112
+ end
113
+ s
114
+ end
115
+
116
+ # Converts a string or int representing the number of microseconds since the Time epoch (1970/01/01) into a DateTime object
117
+ def read_epoch_time(microseconds_since_epoch)
118
+ Time.at(microseconds_since_epoch.to_i/1000)
119
+ end
120
+
121
+ # Converts the body of the response object from JSON to Ruby, and sets the defaults for the main hash and all sub-hashes
122
+ def get_response_body(response)
123
+ raise "REST response was nil" if response == nil
124
+ raise "REST response had no attached body" if response.body == nil
125
+ begin
126
+ body = JSON.parse(response.body, {:max_nesting => 100})
127
+ set_all_defaults(body)
128
+ rescue JSON::ParserError => e
129
+ puts "rescued : ParserError"
130
+ puts e
131
+ body = response.body
132
+ end
133
+ body
134
+ end
135
+
136
+
137
+ # Converts the header of the response object from JSON to Ruby, and sets the defaults for the main hash and all sub-hashes
138
+ def get_response_header(response)
139
+ raise "REST response was nil" if response == nil
140
+ raise "REST response had no attached header" if response.headers == nil
141
+ begin
142
+ header = response.headers # already in Ruby Hash format
143
+ set_all_defaults(body)
144
+ rescue JSON::ParserError => e
145
+ puts "rescued : ParserError"
146
+ puts e
147
+ header = response.headers
148
+ end
149
+ header
150
+ end
151
+
152
+ # Takes a hash a recursively sets the default of the hash and all sub-hashes
153
+ def set_all_defaults(hash, default = nil)
154
+ return unless hash.class == Hash
155
+ hash.default = default
156
+ hash.each_pair do |k, v|
157
+ set_all_defaults(v) if v.class == Hash
158
+ if v.class == Array
159
+ v.each {|z| set_all_defaults(z) if z.class == Hash}
160
+ end
161
+ end
162
+ end
163
+
164
+ # Method to perform a POST request. Requires the RESTClient Resource client and a hash of the information to be sent in the POST body. This hash is converted to JSON for the POST.
165
+ # Optionally also takes an additional hash which contains desired headers for the POST request.
166
+ # Returns a RESTClient::Response object
167
+ def post_request(client, post_information_hash, additional_hash = nil)
168
+ new_hash = {:content_type => "application/json"}
169
+ additional_hash ||= {}
170
+ new_hash.merge!(additional_hash)
171
+
172
+ begin
173
+ client.post(JSON.generate(post_information_hash, {:max_nesting => 100}), new_hash)
174
+ rescue OpenSSL::SSL::SSLError => e
175
+ raise "SSLError occurred when calling REST service; #{e}"
176
+ rescue RestClient::Exception => e # if the request failed, RestClient will throw an error. We want to retrieve that error and the response within
177
+ puts "RestClient::Exception hit when calling REST service"
178
+ puts e
179
+ puts e.response
180
+ return e.response
181
+ rescue => e
182
+ raise "Unexpected error occurred when calling REST service; #{e}"
183
+ end
184
+ end
185
+
186
+ # Method to perform a POST request that sends a file. Requires the RESTClient Resource client and a hash of the information to be sent in the POST body.
187
+ # Assumes that all file information (including the File object itself) is included in the supplied hash
188
+ # Optionally also takes an additional hash which contains desired headers for the POST request.
189
+ # Returns a RESTClient::Response object
190
+ def post_file_request(client, post_information_hash, additional_hash = nil)
191
+ new_hash = {}
192
+ additional_hash ||= {}
193
+ new_hash.merge!(additional_hash)
194
+
195
+ begin
196
+ client.post(post_information_hash, new_hash)
197
+ rescue OpenSSL::SSL::SSLError => e
198
+ raise "SSLError occurred when calling REST service; #{e}"
199
+ rescue RestClient::Exception => e # if the request failed, RestClient will throw an error. We want to retrieve that error and the response within
200
+ puts "RestClient::Exception hit when calling REST service"
201
+ puts e
202
+ puts e.response
203
+ return e.response
204
+ rescue => e
205
+ raise "Unexpected error occurred when calling REST service; #{e}"
206
+ end
207
+ end
208
+
209
+
210
+ # Method to perform a PUT request. Requires the RESTClient Resource client and a hash of the information to be sent in the PUT body. This hash is converted to JSON for the PUT.
211
+ # Optionally also takes an additional hash which contains desired headers for the PUT request, e.g. {:content_type => "application/json"}
212
+ # Returns a RESTClient::Response object
213
+ def put_request(client, put_information_hash, additional_hash = nil)
214
+ new_hash = {:content_type => "application/json"}
215
+ additional_hash ||= {}
216
+ new_hash.merge!(additional_hash)
217
+
218
+ begin
219
+ client.put(JSON.generate(put_information_hash, {:max_nesting => 100}), new_hash)
220
+ rescue OpenSSL::SSL::SSLError => e
221
+ raise "SSLError occurred when calling REST service; #{e}"
222
+ rescue RestClient::Exception => e # if the request failed, RestClient will throw an error. We want to retrieve that error and the response within
223
+ puts "RestClient::Exception hit when calling REST service"
224
+ puts e
225
+ puts e.response
226
+ return e.response
227
+ rescue => e
228
+ raise "Unexpected error occurred when calling REST service; #{e}"
229
+ end
230
+ end
231
+
232
+
233
+ # Method to perform a DELETE request. Requires the RESTClient Resource client.
234
+ # Returns a RESTClient::Response object
235
+ def delete_request(client)
236
+ begin
237
+ client.delete
238
+ rescue OpenSSL::SSL::SSLError => e
239
+ raise "SSLError occurred when calling REST service; #{e}"
240
+ rescue RestClient::Exception => e # if the request failed, RestClient will throw an error. We want to retrieve that error and the response within
241
+ puts "RestClient::Exception hit when calling REST service"
242
+ puts e
243
+ puts e.response
244
+ return e.response
245
+ rescue => e
246
+ raise "Unexpected error occurred when calling REST service; #{e}"
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,16 @@
1
+
2
+ # This class holds parameters that may frequently change between test runs, e.g the test environment
3
+ class RuntimeConstants
4
+
5
+ $TEST_ENV = :test_1
6
+
7
+ CLOSE_BROWSER_AFTER_TEST = true # close the browser if the test passed?
8
+ FORCE_CLOSE_BROWSER_AFTER_TEST = false # always close the browser?
9
+
10
+ MAKE_ERROR_SCREENSHOTS = true
11
+ ERROR_SCREENSHOT_LOCATION = "screenshots"
12
+
13
+ RESULTS_CSV = "results.csv"
14
+
15
+ end
16
+
@@ -0,0 +1,22 @@
1
+ # Holds system configuration parameters
2
+
3
+ require_relative 'runtime_constants.rb'
4
+
5
+ class ZZnamezzConfig
6
+ include RuntimeConstants
7
+
8
+ CERTIFICATE_DIR = "certs"
9
+
10
+ API_VERSION = "latest"
11
+
12
+ SERVERS = {
13
+ :test_1 => {:zznamezz_url = "https://"},
14
+ :ref_1 => {:zznamezz_url = "https://"},
15
+ }
16
+
17
+ SERVER = SERVERS[$TEST_ENV]
18
+
19
+
20
+ PASSED = "Passed"
21
+ FAILED = "Failed"
22
+ end
@@ -0,0 +1,212 @@
1
+
2
+ # This file defines a module to be included in all test cases for the testing of yyrawnameyy.
3
+ # This module contains a general setup and teardown method that each test should run.
4
+ # If tests wish to perform their own specific seup and/or teardown routines, they
5
+ # should implement their own methods and call super within them to trigger these common
6
+ # setup/teardown methods at the right time.
7
+
8
+ $LOAD_PATH.unshift File.dirname(__FILE__) + "/..")
9
+
10
+ gem 'test-unit'
11
+ require 'test/unit'
12
+ require 'tmpdir'
13
+ require 'time'
14
+ require 'fileutils'
15
+ require 'timeout'
16
+
17
+ # Config
18
+ require 'config/zznamezz_config'
19
+
20
+ # Helpers
21
+ require 'framework/zznamezz.rb'
22
+
23
+
24
+
25
+ STDOUT.sync = true
26
+
27
+ if ZZnamezzConfig::WRITE_CI_REPORTS
28
+ require 'ci/reporter/rake/test_unit_loader'
29
+
30
+ ENV["CI_REPORTS"] = $CI_REPORTS_PATH # supplied in invokation to test
31
+ puts "Will create XML reports in #{ENV["CI_REPORTS"]}"
32
+ end
33
+
34
+ module ZZnamezzTestCase
35
+
36
+ include ZZnamezz
37
+
38
+ attr_accessor :browser_has_been_opened
39
+
40
+ # optional field
41
+ # If the cause of a test's failure is already likely to be known, the contents of this variable
42
+ # will automatically be added to the test result's Notes field, to help with reporting.
43
+ # If there are multiple tests in a file, this variable needs to be set within each test
44
+ # method (if they have any relevent failure notes).
45
+ attr_accessor :failure_notes
46
+
47
+ # By default, unknown methods (e.g. xxabbrevupperxxPage names) are sent to the different contexts
48
+ # for resolution. This allows pages to be accessed as xxabbrevxxHomePage rather than
49
+ # @xxabbrevxx_context.xxabbrevxxHomePage
50
+ def method_missing(meth, *args)
51
+ case meth.to_s
52
+ when /^xxabbrevxx/
53
+ @xxabbrevxx_context.send(meth, *args)
54
+ # when /^some_other_app/
55
+ # @some_other_app_context.send(meth, *args)
56
+ else
57
+ super
58
+ end
59
+ end
60
+
61
+
62
+ if $WRITE_RESULTS # supplied from invokation
63
+ WRITE_RESULTS = true
64
+ else
65
+ WRITE_RESULTS = false
66
+ end
67
+
68
+ # Close the current browser and log in again
69
+ def re_login
70
+ browser.close
71
+
72
+ new_browser_on_login_page
73
+ # Reinitialise the contexd and @help
74
+ reinitialisexxabbrevupperxxContext(browser)
75
+ end
76
+
77
+ # Connect to yyrawnameyy and reinitialise the context, etc.
78
+ def xxabbrevxx_login(url = ZZnamezzConfig::SERVER[:zznamezz_url])
79
+ puts url
80
+ new_browser_on_login_page(url)
81
+ reinitialisexxabbrevupperxxContext(browser)
82
+ end
83
+
84
+ # Reinitialise xxabbrevupperxx context only
85
+ def reinitialisexxabbrevupperxxContext(new_browser)
86
+ @xxabbrevxx_context = ZZnamezz::Context.new(new_browser)
87
+ @help = xxabbrevupperxxHelper.new(@xxabbrevxx_context)
88
+ end
89
+
90
+ # Return to the previous xxabbrevupperxx session
91
+ def return_to_xxabbrevxx
92
+ self.browser = @xxabbrevxx_context.browser
93
+ end
94
+
95
+ # Close the current browser
96
+ def close_browser
97
+ self.browser.close
98
+ end
99
+
100
+ def close(browser)
101
+ if browser.exists? && ((ZZnamezzConfig::CLOSE_BROWSER_AFTER_TEST && passed?) || ZZnamezzConfig::FORCE_CLOSE_BROWSER_AFTER_TEST)
102
+ browser.close
103
+ $browsers.delete_at($current_browser_position - 1) # array indexing
104
+ self.browser = $browsers[-1] # set browser to the last one that is still in the array
105
+ end
106
+ end
107
+
108
+ def close_all_browsers
109
+ if (ZZnamezzConfig::CLOSE_BROWSER_AFTER_TEST && passed?) || ZZnamezzConfig::FORCE_CLOSE_BROWSER_AFTER_TEST
110
+ until $browsers.empty?
111
+ self.browser = $browsers.shift
112
+ browser.close
113
+ end
114
+ end
115
+ end
116
+
117
+ # Ensure that every test (that wants one) has a browser that is already logged in to the system
118
+ def setup
119
+
120
+ Watir.always_locate = true # default is true; setting to false speeds up Watir to a degree
121
+
122
+ # Get start time for later output in results
123
+ @test_start_time = Time.now
124
+
125
+ # Get the directory that the specific test lives in, so that it can be included in the results file
126
+ @test_file_dir = @test_file.split(File::SEPARATOR)[-2]
127
+
128
+ # Select default certificate if none is configured
129
+ @certificate ||= :regular
130
+
131
+ @timeout = ZZnamezzConfig::CERTIFICATE_POPUP_TIMEOUT
132
+
133
+ # Open the browser & ensure page contenxt and helper are available
134
+ $browsers = [] # global array containing all browser objects
135
+ # $current_browser_position = nil # global variable to track the position in $browsers of the active browser # TODO used?
136
+ # When that browser is closed, we can ensure that the corresponding browser object is removed from the array
137
+ if @initialBrowser == :xxabbrevxx
138
+ xxabbrevxx_login
139
+ elsif (@initialBrowser == :none || @initialBrowser == nil)
140
+ browser = nil
141
+ reinitialisexxabbrevupperxxContext(browser)
142
+ end
143
+
144
+ end # end setup
145
+
146
+ # Close all browsers and write the result of the test to the results CSV
147
+ def teardown
148
+
149
+ begin
150
+ # Get end time
151
+ @test_end_time = Time.now
152
+ elapsed_time = (@test_end_time - @test_start_time).to_s
153
+ elapsed_time_in_minutes = (elapsed_time.to_i/60.0).to_s
154
+
155
+ test_name = self.to_s.split("(")[0] # self.to_s gives output like test_ABC5_01(TC_ABC5_01)
156
+
157
+ puts "Test has now finished; #{test_name} : #{passed?}"
158
+
159
+ if WRITE_RESULTS
160
+ puts "Will now write results to #{ZZnamezzConfig::RESULTS_BASE_DIR}"
161
+
162
+ notes = ""
163
+ success_text = passed? ? ZZnamezzConfig::PASSED : ZZnamezzConfig::FAILED
164
+
165
+ unless passed?
166
+ begin
167
+ if ZZnamezzConfig::MAKE_ERROR_SCREENSHOTS
168
+ puts "Now taking error screenshots"
169
+ dir_2 = ZZnamezzConfig::ERROR_SCREENSHOT_LOCATION
170
+ Dir.mkdir(dir_2) unless File.exists?(dir_2)
171
+ $browsers.each do |browser|
172
+ browser.screenshot.save(ZZnamezzConfig::ERROR_SCREENSHOT_LOCATION + "/#{test_name}_Time_#{@test_end_time.strftime("%H-%M-%S")}_Browser_#{$browsers.index(browser)}.png")
173
+ end
174
+ end
175
+ rescue
176
+ puts "Failed to make screenshot"
177
+ end
178
+ notes = @failure_notes
179
+ puts "Notes : #{notes}"
180
+ end # end unless passed?
181
+
182
+ close_all_browsers
183
+
184
+ # Write to the results file
185
+ begin
186
+ File.open(ZZnamezzConfig::RESULTS_CSV, "a") do |f|
187
+ row = [@test_file_dir, test_name, success_text, @test_start_time.strftime("%Y-%m-%d %H:%M:%S"), @test_end_time.strftime("%Y-%m-%d %H:%M:%S"), elapsed_time, elapsed_time_in_minutes, notes]
188
+ f.puts row.join(",")
189
+ puts "Result for test #{test_name} written"
190
+ end
191
+ rescue
192
+ puts "Had to rescue from writing results to file #{ZZnamezzConfig::RESULTS_CSV}"
193
+ end
194
+ end # end if WRITE_RESULTS
195
+ rescue Timeout::Error => t_error
196
+ puts "Timeout::Error :"
197
+ puts t_error
198
+ puts "Backtrace :"
199
+ puts t_error.backtrace
200
+ rescue Exception => error
201
+ puts "Error :"
202
+ puts error
203
+ puts "Backtrace :"
204
+ puts error.backtrace
205
+ end # end begin
206
+ end
207
+
208
+
209
+
210
+ end
211
+
212
+
@@ -0,0 +1,112 @@
1
+ $LOAD_PATH.unshift("#{File.expand_path(File.dirname(__FILE__))}/../../lib")
2
+
3
+ require "zznamezz_test_case"
4
+
5
+ class TC_R001_01_AN_EXAMPLE_TEST < Test::Unit::TestCase
6
+ include ZZnamezzTestCase
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 ZZnamezzTestCase 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 yyrawnameyy 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 yyrawnameyy
56
+
57
+ xxabbrevxx_login
58
+
59
+ # Expected Result :
60
+ # The yyrawnameyy homepage is displayed
61
+
62
+ assert(xxabbrevxxHomepage.displayed?, "The yyrawnameyy 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
+ xxabbrevxxHomepage.term = search_term
74
+ xxabbrevxxHomepage.click_search
75
+
76
+
77
+ # Expected Result :
78
+ # Results are displayed
79
+
80
+ assert(xxabbrevxxSearchResults.displayed?, "The yyrawnameyy search results page is not displayed")
81
+ assert_equal(expected_result_text, xxabbrevxxSearchResults.result, "The yyrawnameyy 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 yyrawnameyy homepage is displayed
93
+
94
+ assert(xxabbrevxxHomepage.displayed?, "The yyrawnameyy 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,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'taft'
3
+ s.version = '0.1.0'
4
+ s.licenses = ['MIT']
5
+ s.summary = "Test Automation Framework Template"
6
+ s.description = "This gem will deploy/install a skeleton code framework for the automated testing of applications with APIs and/or web-UIs"
7
+ s.authors = ["Richard Morrisby"]
8
+ s.email = 'rmorrisby@gmail.com'
9
+ s.files = ["lib/taft.rb"]
10
+ s.homepage = 'https://rubygems.org/gems/taft'
11
+ s.required_ruby_version = '>=1.9'
12
+ s.files = Dir['**/**']
13
+ s.test_files = Dir["test/test*.rb"]
14
+ end
@@ -0,0 +1,10 @@
1
+ require "test/unit"
2
+ require_relative "../lib/ex"
3
+
4
+ class TestEx < Test::Unit::TestCase
5
+
6
+ def test_ex
7
+
8
+ end
9
+
10
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: taft
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Richard Morrisby
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-08-25 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: This gem will deploy/install a skeleton code framework for the automated
14
+ testing of applications with APIs and/or web-UIs
15
+ email: rmorrisby@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - LICENCE.txt
21
+ - README.md
22
+ - build.rb
23
+ - lib/taft.rb
24
+ - lib/taft_files/framework/zznamezz.rb
25
+ - lib/taft_files/framework/zznamezz/api_helpers/general.rb
26
+ - lib/taft_files/framework/zznamezz/api_helpers/rest.rb
27
+ - lib/taft_files/framework/zznamezz/ui_helpers/ui_general.rb
28
+ - lib/taft_files/lib/config/runtime_constants.rb
29
+ - lib/taft_files/lib/config/zznamezz_config.rb
30
+ - lib/taft_files/lib/zznamezz_test_case.rb
31
+ - lib/taft_files/tests/v1/tc_r001_01_an_example_test.rb
32
+ - taft.gemspec
33
+ - test/test_example.rb
34
+ homepage: https://rubygems.org/gems/taft
35
+ licenses:
36
+ - MIT
37
+ metadata: {}
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '1.9'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubygems_version: 3.0.3
54
+ signing_key:
55
+ specification_version: 4
56
+ summary: Test Automation Framework Template
57
+ test_files:
58
+ - test/test_example.rb