cucumber_helper 0.0.8

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f844c72971f2cf2c1095ddb3e4832538029a17971c1283c4f5f64085f7ebf668
4
+ data.tar.gz: bfabd6968becfe9f9096c7593d6a472ee7d6a4b3bd69982458905d64f81e208d
5
+ SHA512:
6
+ metadata.gz: 25d7b57fc18b09958236863b3e0737afa0b6c77929199b7b684d4e12aa04b1a9f49a018925e01c5c43b4c3d00a9a4ce233bd373ada72b19640293bff5ae19711
7
+ data.tar.gz: b5f903e1827ca9aafe681393570a85279c554578cff7d5474eab86ee1095d0a0cd4af57b05f53ad3968c4dcb7ad50427ca10dcba3a6d8f7c890d44ea9e74eec2
data/README.md ADDED
@@ -0,0 +1,320 @@
1
+ **Cucumber Helper for Automation**
2
+
3
+ You can install this gem locally directly by clone this repo or using bundle.
4
+ by using this we don't need to handle per-repo if there is code changes/update, instead we only update this gem.
5
+
6
+ ## Local Installation
7
+
8
+ ### Build Gem from repo
9
+
10
+ 1. Clone this repository
11
+
12
+ ```sh
13
+ git clone https://bitbucket.org/mid-kelola-indonesia/cucumber-helper.git
14
+
15
+ # or using ssh
16
+ git clone git@bitbucket.org:mid-kelola-indonesia/cucumber-helper.git
17
+ ```
18
+
19
+ 2. Go to the repo root folder and build and install the gem
20
+
21
+ ```sh
22
+ cd cucumber-helper
23
+ gem build cucumber_helper.gemspec
24
+ gem install ./cucumber_helper-0.0.1.gem # cucumber_helper-0.0.1.gem should be written as in File output in gem build
25
+ ```
26
+
27
+ ### Using specific_install gem
28
+
29
+ ```sh
30
+ gem install specific_install
31
+ gem specific_install https://bitbucket.org/mid-kelola-indonesia/cucumber-helper.git
32
+ ```
33
+
34
+ ## Integrate with Your Automation Repo
35
+
36
+ 1. Go to your test automation Repo and open the Gemfile (eg: Nemo) using you file editor and add this line:
37
+
38
+ ```ruby
39
+ # Gemfile
40
+
41
+ gem 'cucumber_helper', git: 'https://bitbucket.org/mid-kelola-indonesia/cucumber-helper.git'
42
+ # or by tag/branch
43
+ gem 'cucumber_helper', git: 'https://bitbucket.org/mid-kelola-indonesia/cucumber-helper.git', tag: '0.0.3'
44
+ gem 'cucumber_helper', git: 'https://bitbucket.org/mid-kelola-indonesia/cucumber-helper.git', branch: 'update-dalt'
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ 2. Import the library in env.rb
50
+
51
+ ```ruby
52
+ # env.rb
53
+
54
+ # for API
55
+ require 'cucumber_helper/api'
56
+ # or for WEB
57
+ require 'cucumber_helper/web'
58
+
59
+ # if you want to add general code for setup env like setup browser
60
+ # you need to add this
61
+ require 'cucumber_helper/support'
62
+ .....
63
+ # setup browser using cucumber_helper support module, put after set SHORT_TIMEOUT and DEFAULT_TIMEOUT
64
+ path = create_report_path
65
+ create_browser path
66
+ config_rspec
67
+ .....
68
+ ```
69
+
70
+ 3. Add helper function in hooks.rb
71
+
72
+ ```ruby
73
+ # hooks.rb
74
+ Before do |scenario|
75
+ ....
76
+ @tags = scn_tags(scenario)
77
+ ....
78
+ end
79
+
80
+ After do |scenario|
81
+ .....
82
+ capture_screenshot(scenario)
83
+ handle_continue(scenario)
84
+ delete_downloaded_file
85
+ .....
86
+ end
87
+ ```
88
+
89
+ 4. If using docker make sure using the latest version by using bundle update command after bundle install
90
+
91
+ ```sh
92
+ # docker.sh
93
+
94
+ ....
95
+ bundle install
96
+ bundle update cucumber_helper
97
+ ....
98
+
99
+ ```
100
+
101
+ ### Hooks Helper
102
+
103
+ - **scn_tags(scenario)** : get the scenario tags into array of tags
104
+ - **capture_screenshot(scenario)** : capture screenshot if the scenario failed
105
+ - **handle_continue(scenario)** : make scenario with @continue tag didn't delete its cookies/cache data
106
+ - **delete_downloaded_file** : delete all downloaded file at ./features/data/downloaded
107
+
108
+ ```ruby
109
+ # hooks.rb
110
+ Before do |scenario|
111
+ @tags = scn_tags(scenario)
112
+ end
113
+
114
+ After do |scenario|
115
+ # .... Your Automation Script .....
116
+ capture_screenshot(scenario)
117
+ handle_continue(scenario)
118
+ delete_downloaded_file
119
+ end
120
+
121
+ ```
122
+
123
+ ## Common Helper
124
+
125
+ This Repo contains many function that generally help to setup automation:
126
+
127
+ - **save_variable(name, value)**
128
+
129
+ This to save the variable to _instance variable_ or _global variable_.
130
+
131
+ _Instance Variable_ is variable that can used in 1 scenario but different step.
132
+
133
+ _Global Variable_ is variable that can used in different scenario and/or different step.
134
+
135
+ to save as global variable you need to add `$` in front of variable name, ex: (`save_variable('$test', 1234)` -> result in $test = 1234)
136
+ For instance variable no need to add `@` but the result will have `@` front of its name, ex: (`save_variable('test', 1234)` -> result in @test = 1234)
137
+
138
+ example:
139
+
140
+ ```ruby
141
+ # your_step.rb
142
+ When('user save the data variable to {string}') do |name|
143
+ save_variable(name, @data)
144
+ end
145
+
146
+ # your_feature.feature
147
+ Scenario: Scenario 1
148
+ .....
149
+
150
+ # to save as Global Variable
151
+ When user save the data variable to "$test"
152
+ # it will save as instance variable
153
+ When user save the data variable to "test"
154
+ .....
155
+ Then user validate "test" data
156
+
157
+ Scenario: Scenario 2
158
+ .....
159
+ # the $test is variable from Scenario 1
160
+ Then user validate "$test" data
161
+ ....
162
+
163
+
164
+ ```
165
+
166
+ - **production?**
167
+
168
+ basically it check for @production tag and the base_url contains mekari.com
169
+
170
+ ```ruby
171
+ # your_step.rb
172
+ if production?
173
+ # do something...
174
+ else
175
+ # do something else ...
176
+ end
177
+
178
+ ```
179
+
180
+ - **TestDataHelper** class
181
+
182
+ It help you load your data in yml format if you have different data in staging or production.
183
+ e.g you have different note id in staging and production to test.
184
+ by default, this helper will load file: features/data/test/test_data.yml in variable @test_data
185
+
186
+ ```ruby
187
+ # test_data.yaml file:
188
+ note_id:
189
+ staging: 11
190
+ production: 5
191
+
192
+ # your_step.rb
193
+ When('User open note of employee') do
194
+ # if need to declare @enviroment to 'staging' or 'production'
195
+ # in this case, if it run on staging, @test_data['note_id'] = 11,
196
+ # if it run in production @test_data['note_id'] = 5
197
+ @pages.employee_page.notes_id.find { |x| x.text == @test_data['note_id'] }.click
198
+ waiting_for_page_ready
199
+ end
200
+
201
+ ```
202
+
203
+ - **DataHelper** class
204
+
205
+ used for load email / password, generally it used to handle stored credentials
206
+
207
+ ```ruby
208
+ When(/^user login using "(.*)" account$/) do |credential_type|
209
+ @data_login = DataHelper.new(@user_yml_data).prepare_credentials(credential_type)
210
+ @pages.login_page.input_email.set @data_login['email']
211
+ @pages.login_page.input_password.set @data_login['password']
212
+ # .....
213
+
214
+ end
215
+ ```
216
+
217
+ ## API Automation Helper
218
+
219
+ - **pretty_json(response)**
220
+
221
+ log your json pretty format
222
+
223
+ ```ruby
224
+ log pretty_json(@response)
225
+ # >> will write in log file:
226
+ # {
227
+ # "message" : "message .....",
228
+ # }
229
+ # instead : { "message" : "message ...." }
230
+
231
+ ```
232
+ ## WEB Automation Helper
233
+
234
+ Many general function are included in this gem
235
+
236
+ ```ruby
237
+ # you can open file in ./lib/cucumber_helper/web/helpers.rb
238
+ # this include:
239
+ waiting_for_page_ready
240
+ short_wait
241
+ wait_for_download
242
+ waiting_for_xhr_complete
243
+ adjust_comma_number
244
+ parse_rp
245
+ # and many more ...
246
+
247
+ ```
248
+ - **TableSection** class helper
249
+
250
+
251
+ This is to help automation of table in an page
252
+ example your page have table:
253
+
254
+ | name | Description | Package |
255
+ | -------------|-------------|-----------|
256
+ | Benefit A | HR Dept | Package A |
257
+ | Benefit B | Quality | Package B |
258
+
259
+ the functions are:
260
+
261
+ ```ruby
262
+ click_header(name)
263
+ # argument:
264
+ # - name: Header name in column, example: name, Description, Package
265
+ # - exact_text: true or false
266
+ # - sort_arrow: true or false
267
+ # - sort_path: css path of the element
268
+ # example: @pages.employee_page.employee_table.click_header('Employee name')
269
+ # @pages.employee_page.employee_table.click_header('Employee name', sort_arrow: true) # if using sort arrow to sort table
270
+
271
+ data_column(name)
272
+ # argument:
273
+ # - name: Header name in column, example: name, Description, Package
274
+ # - exact_text: true or false
275
+
276
+ data_row_as_text(row_number)
277
+ # argument:
278
+ # - row_number: row number
279
+
280
+ data_column_as_text(name)
281
+ # argument:
282
+ # - name: Header name in column, example: name, Description, Package
283
+ # - exact_text: true or false
284
+
285
+ data_column(name)
286
+ # argument:
287
+ # - name: Header name in column, example: name, Description, Package
288
+ # - exact_text: true or false
289
+
290
+ click_data_column(col_name, text)
291
+ # argument:
292
+ # - col_name: Header name in column, example: name, Description, Package
293
+ # - text: Cell text in table example: Quality, Package A
294
+ # - exact_text: true or false
295
+ ```
296
+
297
+ ```ruby
298
+ # your_page_class.rb
299
+ class BenefitPage < SitePrism::Page
300
+ .....
301
+ # TableSection is in our Gem, so no need to declare it in our repo
302
+ # do rather than defining each column, we only need to define the table once
303
+ # if you want to add more like button or something you can do:
304
+ # section :table_benefit, TableSection, '#benefitTable' do
305
+ # elements :btn_action, '#actionButton'
306
+ # end
307
+ section :table_benefit, TableSection, '#benefitTable'
308
+ .....
309
+ end
310
+
311
+ # your_step.rb
312
+ ....
313
+
314
+ Then(/^user successfully sort column "(.*)" benefit group table$/) do |column|
315
+ @pages.benefit_page.table_benefit.click_header(column)
316
+ waiting_for_page_ready
317
+ data = @pages.benefit_page.table_benefit.data_column_as_text(column)
318
+ expect(data).to eq data.sort
319
+ end
320
+ ```
@@ -0,0 +1,32 @@
1
+ module CucumberHelper
2
+ module Api
3
+ module Helpers
4
+ def pretty_json(response)
5
+ begin
6
+ l = JSON.pretty_generate(JSON.parse(response))[..2000]
7
+ rescue TypeError
8
+ l = ''
9
+ rescue JSON::ParserError
10
+ l = response.body if response.respond_to? 'body'
11
+ l = response unless response.respond_to? 'body'
12
+ end
13
+ l += '....' if l.size > 2000
14
+ l
15
+ end
16
+
17
+ def resolve(url)
18
+ url.gsub!(/\{([a-zA-Z0-9_]+)\}/) do |s|
19
+ s.gsub!(/[{}]/, '')
20
+ if instance_variable_defined?("@#{s}") # rubocop:disable Style/GuardClause
21
+ CGI.escape instance_variable_get("@#{s}").to_s
22
+ else
23
+ raise "Did you forget to \"grab\" #{s}?"
24
+ end
25
+ end
26
+ url
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ World(CucumberHelper::Api::Helpers)
@@ -0,0 +1,3 @@
1
+ After do |scenario|
2
+ test_rail_integration(ENV['TESTRAIL_RUN'], scenario_id, scenario.status.to_s) if ENV['is_testrail_update'].eql?('true') && !(ENV['TESTRAIL_RUN'].empty? || ENV['TESTRAIL_RUN'].nil?)
3
+ end
@@ -0,0 +1,155 @@
1
+ # Extension of {RestClient::Response} with support for JSON path traversal and validation
2
+ # original code from https://github.com/hidroh/cucumber-api/blob/master/lib/cucumber-api/response.rb
3
+ module Response
4
+ # Create a Response with JSON path support
5
+ # @param response [RestClient::Response] original response
6
+ # @return [Response] self
7
+ def self.create(response)
8
+ result = response
9
+ result.extend Response
10
+ result
11
+ end
12
+
13
+ def valid_json?(json)
14
+ JSON.parse(json)
15
+ true
16
+ rescue JSON::ParserError
17
+ false
18
+ end
19
+
20
+ # Check if given JSON path exists
21
+ # @param json_path [String] a valid JSON path expression
22
+ # @param json [String] optional JSON from which to check JSON path, default to response body
23
+ # @return [true, false] true if JSON path is valid and exists, false otherwise
24
+ def has(json_path, json = nil)
25
+ json = JSON.parse body if json.nil?
26
+ !JsonPath.new(json_path, { allow_send: false }).on(json).empty?
27
+ end
28
+
29
+ # Retrieve value of the first JSON element with given JSON path
30
+ # @param json_path [String] a valid JSON path expression
31
+ # @param json [String] optional JSON from which to apply JSON path, default to response body
32
+ # @return [Object] value of first retrieved JSON element in form of Ruby object
33
+ # @raise [Exception] if JSON path is invalid or no matching JSON element found
34
+ def get(json_path, json = nil)
35
+ json = JSON.parse body if json.nil?
36
+ results = if Gem.loaded_specs['jsonpath'].version < Gem::Version.create('1.1.2')
37
+ JsonPath.new(json_path).on(json)
38
+ else
39
+ JsonPath.new(json_path, { allow_send: false }).on(json)
40
+ end
41
+ results.empty? ? nil : results.first
42
+ end
43
+
44
+ # Retrieve value of the first JSON element with given JSON path as given type
45
+ # @param json_path [String] a valid JSON path expression
46
+ # @param type [String] required type, possible values are 'numeric', 'array', 'string', 'boolean', 'numeric_string'
47
+ # or 'object'
48
+ # @param json [String] optional JSON from which to apply JSON path, default to response body
49
+ # @return [Object] value of first retrieved JSON element in form of given type
50
+ # @raise [Exception] if JSON path is invalid or no matching JSON element found or matching element does not match
51
+ # required type
52
+ def get_as_type(json_path, type, json = nil)
53
+ value = get(json_path, json)
54
+ case type
55
+ when 'numeric'
56
+ valid = value.is_a? Numeric
57
+ when 'array'
58
+ valid = value.is_a? Array
59
+ when 'string'
60
+ valid = value.is_a? String
61
+ when 'boolean'
62
+ valid = [true, false].include? value
63
+ when 'numeric_string'
64
+ (valid = value.is_a?(Numeric)) || value.is_a?(String)
65
+ when 'object'
66
+ valid = value.is_a? Hash
67
+ when 'null'
68
+ valid = value.is_a? NilClass
69
+ else
70
+ raise %(Invalid expected type '#{type}')
71
+ end
72
+
73
+ raise %(Expect '#{json_path}' as a '#{type}' but was '#{value.class}'\n#{to_json_s}) unless valid
74
+
75
+ value
76
+ end
77
+
78
+ # Retrieve value of the first JSON element with given JSON path as given type, with nil value allowed
79
+ # @param json_path [String] a valid JSON path expression
80
+ # @param type [String] required type, possible values are 'numeric', 'array', 'string', 'boolean', 'numeric_string'
81
+ # or 'object'
82
+ # @param json [String] optional JSON from which to apply JSON path, default to response body
83
+ # @return [Object] value of first retrieved JSON element in form of given type or nil
84
+ # @raise [Exception] if JSON path is invalid or no matching JSON element found or matching element does not match
85
+ # required type
86
+ def get_as_type_or_null(json_path, type, json = nil)
87
+ value = get json_path, json
88
+ value.nil? ? value : get_as_type(json_path, type, json)
89
+ end
90
+
91
+ # Retrieve value of the first JSON element with given JSON path as given type, and check for a given value
92
+ # @param json_path [String] a valid JSON path expression
93
+ # @param type [String] required type, possible values are 'numeric', 'string', 'boolean', or 'numeric_string'
94
+ # @param value [String] value to check for
95
+ # @param json [String] optional JSON from which to apply JSON path, default to response body
96
+ # @return [Object] value of first retrieved JSON element in form of given type or nil
97
+ # @raise [Exception] if JSON path is invalid or no matching JSON element found or matching element does not match
98
+ # required type or value
99
+ def get_as_type_and_check_value(json_path, type, comparison_type, value, json = nil)
100
+ v = get_as_type(json_path, type, json)
101
+
102
+ case comparison_type
103
+ when 'equal'
104
+ raise %(Expect '#{json_path}' to be '#{value}' but was '#{v}'\n#{to_json_s}) if value != v.to_s
105
+
106
+ v.to_s == value
107
+ when 'not equal'
108
+ raise %(Expect '#{json_path}' not to be '#{value}' but was '#{v}'\n#{to_json_s}) if value == v.to_s
109
+
110
+ v.to_s != value
111
+ when 'include'
112
+ raise %(Expect '#{json_path}' should include '#{value}' but was '#{v}'\n#{to_json_s}) unless v.include?(value)
113
+
114
+ v.include?(value)
115
+ when 'between'
116
+ # define vstart and vend first
117
+ range = (vstart..vend)
118
+ raise %(Expect '#{json_path}' should between '#{vstart}' and '#{vend}' but was '#{v}'\n#{to_json_s}) unless range.include?(value)
119
+
120
+ range.include?(value)
121
+ end
122
+ end
123
+
124
+ # Retrieve pretty JSON response for logging
125
+ # @return [String] pretty JSON response if verbose setting is true, empty string otherwise
126
+ def to_json_s
127
+ if ENV['cucumber_api_verbose'] == 'true'
128
+ JSON.pretty_generate(JSON.parse(to_s))
129
+ else
130
+ ''
131
+ end
132
+ end
133
+
134
+ def response_include_text(text, response)
135
+ response = JSON.parse response if valid_json?(response)
136
+ raise "no text #{text} inside #{response}" if (response.to_s.include? text).eql? false
137
+ end
138
+
139
+ # Retrieve pretty JSON response for logging
140
+ # @return [String] pretty JSON response if verbose setting is true, empty string otherwise
141
+ def parser
142
+ JSON.pretty_generate(JSON.parse(to_s))
143
+ rescue JSON::ParserError, NoMethodError
144
+ to_s
145
+ end
146
+
147
+ def pretty_json
148
+ if parser.size > 2000
149
+ "#{parser[..2000]}......"
150
+ else
151
+ parser
152
+ end
153
+ end
154
+ RestClient::Response.send(:include, self)
155
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cucumber_helper/commons'
4
+
5
+ require 'cucumber_helper/api/hooks'
6
+ require 'cucumber_helper/api/helpers'
7
+ require 'cucumber_helper/api/response'
8
+
9
+ require 'cucumber_helper/testrail/testrail'
10
+ require 'cucumber_helper/testrail/test_rail_integration'
11
+
12
+ require 'rest-client'
13
+ require 'json-schema'
14
+ require 'json'
15
+ require 'jsonpath'
16
+
17
+ include CucumberHelper::Api::Helpers
@@ -0,0 +1,28 @@
1
+ module CucumberHelper
2
+ module Commons
3
+ module Commands
4
+ alias old_dup dup
5
+
6
+ # save variable to instance variable or global variable if prefix is '$'
7
+ def save_variable(name, value)
8
+ if name.start_with? '$'
9
+ create_global = "#{name} = '#{value}'"
10
+ Module.module_eval create_global
11
+ else
12
+ instance_variable_set("@#{name}", value)
13
+ end
14
+ end
15
+
16
+ def production?
17
+ @tags.include?('@production') && ENV['BASE_URL'].include?('mekari.com')
18
+ end
19
+
20
+ def dup
21
+ Marshal.load(Marshal.dump(self))
22
+ rescue Exception
23
+ old_dup
24
+ end
25
+ end
26
+ end
27
+ end
28
+ World(CucumberHelper::Commons::Commands)
@@ -0,0 +1,27 @@
1
+ module CucumberHelper
2
+ module Commons
3
+ # This class help when you have test data for specific environment:
4
+ # the YAML can be like:
5
+ # sample.yaml
6
+ #
7
+ # sample_note_id:
8
+ # staging: 15
9
+ # production: 21
10
+ #
11
+ # then you can call with:
12
+ # testdata = TestDataHelper.new(sample.yml, environment)
13
+ # note_id = testdata['sample_note_id']
14
+ class TestDataHelper
15
+ attr_reader :env
16
+
17
+ def initialize(yml, environment)
18
+ @db = YAML.load_file yml
19
+ @env = environment
20
+ end
21
+
22
+ def [](key)
23
+ @db[key][@env]
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ module CucumberHelper
2
+ module Commons
3
+ # use to get credential email and pass, used mostly on WEB automation
4
+ class DataHelper
5
+ def initialize(path)
6
+ @db = YAML.load_file "features/config/#{path}.yml"
7
+ end
8
+
9
+ def prepare_credentials(user_details)
10
+ { 'email' => @db['credentials'][user_details]['email'],
11
+ 'password' => @db['credentials'][user_details]['password'] }
12
+ end
13
+
14
+ def user_information(user_details, key)
15
+ @db['credentials'][user_details][key]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ require_relative './commons/command_helpers'
2
+ require_relative './commons/test_data_helper'
3
+ require_relative './commons/user_data_helper'
4
+
5
+ include CucumberHelper::Commons
6
+ include CucumberHelper::Commons::Commands