cucumber-rest-bdd 0.4.4.pre.124 → 0.4.4.pre.136

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eb615fea4da2428d0bb99748c5095c18f7d6b11f
4
- data.tar.gz: d94194a9a2f89a51ce610d206e2c801152b98261
3
+ metadata.gz: f9bb4e19befe54674236ada928775cc8f6a4d6a1
4
+ data.tar.gz: 0cfc7671388549be92b15f8e7e927600c00ad06a
5
5
  SHA512:
6
- metadata.gz: bb7b8b2539ce1d5fc8907c667376a49f62e795552cf5fde3ba469f1e0ba3ccdb19dd77e0ee150176c60499554e6837a96f53b8c83a0f4b9fb86a5a3622cb077c
7
- data.tar.gz: 39309d24870a52c17a13306fb49ad64190cc0887f349934c21f6a2181f362e77c974bd28fa6d508ff8fa4988ce86a85d15a35d3f3a1d1b2f3b57c88bdcc52b73
6
+ metadata.gz: 1de33c7788797ee55173764bf15997c43d965e292006582c0d5b4fdcda13c92babd02be5f692c6b6de597ad1d7de2f2dbd456beb0ba8744bc802e653756c53b1
7
+ data.tar.gz: b6c62f44e4bd80219a74a8f5f6ea9ff40075c4e2acbd7e70ebe429f5e7432d2066af37186cacaa327043394115477ce946f236c812e4cb388bf96ea6510b95a3
data/Dockerfile CHANGED
@@ -18,6 +18,7 @@ ENV field_camel=false
18
18
  ENV resource_single=false
19
19
  ENV cucumber_api_verbose=false
20
20
  ENV data_key=
21
+ ENV error_key=error
21
22
  ENV set_parent_id=false
22
23
 
23
24
  CMD ["cucumber"]
data/Makefile CHANGED
@@ -5,7 +5,7 @@ build:
5
5
  docker-compose build runner
6
6
 
7
7
  test: start-test-server
8
- docker-compose run --rm runner cucumber --order random
8
+ docker-compose run --rm runner cucumber --order random --format progress
9
9
  make stop-test-server > /dev/null 2>&1 &
10
10
 
11
11
  start-test-server: stop-test-server
data/README.md CHANGED
@@ -154,6 +154,31 @@ Then more than 10 posts have five comments
154
154
  Then less than 200 posts have five comments
155
155
  ```
156
156
 
157
+ #### Errors
158
+
159
+ If the `error_key` environment variable is set, if that key is used as the initial step it will ignore any `data_key`
160
+ setting.
161
+
162
+ Example: `error_key=error`, `data_key=data`
163
+
164
+ ```gherkin
165
+ Then the response has a list of posts | {"data":[{"id": 12}]}
166
+
167
+ Then the response has one error | {"errors":[{"message": "Error"}]}
168
+
169
+ Then the response has an error | {"error": {"message": "Error}}
170
+ ```
171
+
172
+ Example: `error_key=`, `data_key=data`
173
+
174
+ ```gherkin
175
+ Then the response has a list of posts | {"data":[{"id": 12}]}
176
+
177
+ Then the response has one error | {"data": {"errors":[{"message": "Error"}]}}
178
+
179
+ Then the response has an error | {"data": {"error": {"message": "Error}}}
180
+ ```
181
+
157
182
  ### Creation
158
183
 
159
184
  ```gherkin
data/STEPS.md CHANGED
@@ -139,6 +139,37 @@ Then more than two items have have the following <N/A>
139
139
  "application/json"
140
140
  ```
141
141
 
142
+ ### Error Handling
143
+
144
+ Using the environment variable: `error_key` to represent the error resource
145
+
146
+ ```
147
+ Behavioural Functional
148
+ --------------------------------------------------- --------------------------------------------------------------
149
+ Then the response has one error: Then the JSON response should have "errors[0].code" of type
150
+ | attribute | type | value | string with value "ERR-BLA"
151
+ | code | string | ERR-BLA |
152
+
153
+ Then the response has one error with attributes: Then the JSON response should have "errors[0].code" of type
154
+ | attribute | type | value | string with value "ERR-BLA"
155
+ | code | string | ERR-BLA |
156
+
157
+ Then the response has at least one error Then the JSON response should have "errors" of type array
158
+ with at least 1 entry
159
+
160
+ Then the response has an error Then the JSON response should have required key "error" of
161
+ Then the response contains an error type object
162
+
163
+ Then the response has two errors with:
164
+ | attribute | type | value |
165
+ | message | string | super error |
166
+
167
+ Then the response has three errors with two links <N/A>
168
+ with:
169
+ | attribute | type | value |
170
+ | href | string | http://oops |
171
+ ```
172
+
142
173
  ### Attribute saving and re-use
143
174
 
144
175
  ```
@@ -155,7 +186,7 @@ Behavioural Functional
155
186
  --------------------------------------------------- --------------------------------------------------------------
156
187
  When I request a list of comments for post "1" When I send a GET request to "http://url/posts/1/comments"
157
188
 
158
- When I request the comment "2" for post "3" When I send a GET request to "http://url/posts/2/comments/3"
189
+ When I request the comment "2" for post "3" When I send a GET request to "http://url/posts/3/comments/2"
159
190
 
160
191
  When I request the photo "3" in album "4" for user When I send a GET request to
161
192
  "5" "http://url/users/5/albums/4/photos/3"
data/docker-compose.yml CHANGED
@@ -2,7 +2,7 @@ version: '2'
2
2
  services:
3
3
  test-server:
4
4
  image: clue/json-server
5
- command: --routes /data/routes.json
5
+ command: --routes /data/routes.json --middlewares /data/error.js
6
6
  volumes:
7
7
  - ./server:/data:ro
8
8
 
@@ -19,4 +19,5 @@ services:
19
19
  - field_camel=true
20
20
  - resource_single=false
21
21
  - data_key=
22
+ - error_key=error
22
23
  - set_parent_id=true
@@ -0,0 +1,22 @@
1
+ Feature: Handling error responses
2
+
3
+ Background:
4
+ Given I am a client
5
+
6
+ Scenario: Handle errors as a list
7
+ When I request the error "list"
8
+ Then the request fails because the post was not found
9
+ And the response contains at least one errors
10
+ And the response has one error
11
+ And the response has one error with the attributes:
12
+ | attribute | type | value |
13
+ | Message | string | Not Found |
14
+
15
+ Scenario: Handle error as a single item
16
+ When I request the error "single"
17
+ Then the request fails because it was invalid
18
+ And the response contains an error
19
+ And the response has an error
20
+ And the response has an error with the attributes:
21
+ | attribute | type | value |
22
+ | Message | string | Bad Request |
@@ -4,11 +4,11 @@ require 'cucumber-rest-bdd/types'
4
4
  # response interrogation
5
5
 
6
6
  Then(/^the response is a list (?:of|containing) (#{FEWER_MORE_THAN})?\s*(#{CAPTURE_INT}|\d+) .*?$/) do |count_mod, count|
7
- list = @response.get_as_type get_root_json_path(), 'array'
8
- raise %/Expected at least #{count} items in array for path '#{get_root_json_path()}', found: #{list.count}\n#{@response.to_json_s}/ if !num_compare(count_mod, list.count, count.to_i)
7
+ list = @response.get_as_type get_root_data_key(), 'array'
8
+ raise %/Expected at least #{count} items in array for path '#{get_root_data_key()}', found: #{list.count}\n#{@response.to_json_s}/ if !num_compare(count_mod, list.count, count.to_i)
9
9
  end
10
10
 
11
- Then(/^the response ((?:#{HAVE_SYNONYM} (?:a|an|(?:(?:#{FEWER_MORE_THAN})?\s*#{CAPTURE_INT}|\d+)) (?:\w+) )*)#{HAVE_SYNONYM} (?:the )?(?:following )?(?:data )?attributes:$/) do |nesting, attributes|
11
+ Then(/^the response ((?:#{HAVE_SYNONYM} (?:a|an|(?:(?:#{FEWER_MORE_THAN})?\s*#{CAPTURE_INT}|\d+)) (?:\w+) )*)#{HAVE_SYNONYM} (?:the )?(?:following )?(?:data|error )?attributes:$/) do |nesting, attributes|
12
12
  expected = get_attributes(attributes.hashes)
13
13
  groups = nesting
14
14
  grouping = get_grouping(groups)
@@ -16,8 +16,8 @@ Then(/^the response ((?:#{HAVE_SYNONYM} (?:a|an|(?:(?:#{FEWER_MORE_THAN})?\s*#{C
16
16
  root: true,
17
17
  type: 'single'
18
18
  })
19
- data = @response.get get_root_json_path()
20
- raise %/Could not find a match for: #{nesting}\n#{expected.inspect}\n#{@response.to_json_s}/ if !nest_match(data, grouping, expected)
19
+ data = @response.get get_key(grouping)
20
+ raise %/Could not find a match for: #{nesting}\n#{expected.inspect}\n#{@response.to_json_s}/ if data.empty? || !nest_match(data, grouping, expected)
21
21
  end
22
22
 
23
23
  Then(/^the response ((?:#{HAVE_SYNONYM} (?:a|an|(?:(?:#{FEWER_MORE_THAN})?\s*#{CAPTURE_INT}|\d+)) (?:\w+)\s?)+)$/) do |nesting|
@@ -27,8 +27,8 @@ Then(/^the response ((?:#{HAVE_SYNONYM} (?:a|an|(?:(?:#{FEWER_MORE_THAN})?\s*#{C
27
27
  root: true,
28
28
  type: 'single'
29
29
  })
30
- data = @response.get get_root_json_path()
31
- raise %/Could not find a match for: #{nesting}\n#{@response.to_json_s}/ if !nest_match(data, grouping, {})
30
+ data = @response.get get_key(grouping)
31
+ raise %/Could not find a match for: #{nesting}\n#{@response.to_json_s}/ if data.empty? || !nest_match(data, grouping, {})
32
32
  end
33
33
 
34
34
  Then(/^(#{FEWER_MORE_THAN})?\s*(#{CAPTURE_INT}|\d+) (?:.*?) ((?:#{HAVE_SYNONYM} (?:a|an|(?:(?:#{FEWER_MORE_THAN})?\s*#{CAPTURE_INT}|\d+)) (?:\w+) )*)#{HAVE_SYNONYM} (?:the )?(?:following )?(?:data )?attributes:$/) do |count_mod, count, nesting, attributes|
@@ -41,7 +41,7 @@ Then(/^(#{FEWER_MORE_THAN})?\s*(#{CAPTURE_INT}|\d+) (?:.*?) ((?:#{HAVE_SYNONYM}
41
41
  count: count.to_i,
42
42
  count_mod: count_mod
43
43
  })
44
- data = @response.get get_root_json_path()
44
+ data = @response.get get_key(grouping)
45
45
  raise %/Expected #{compare_to_string(count_mod)}#{count} items in array with attributes for: #{nesting}\n#{expected.inspect}\n#{@response.to_json_s}/ if !nest_match(data, grouping, expected)
46
46
  end
47
47
 
@@ -54,7 +54,7 @@ Then(/^(#{FEWER_MORE_THAN})?\s*(#{CAPTURE_INT}|\d+) (?:.*?) ((?:#{HAVE_SYNONYM}
54
54
  count: count.to_i,
55
55
  count_mod: count_mod
56
56
  })
57
- data = @response.get get_root_json_path()
57
+ data = @response.get get_key(grouping)
58
58
  raise %/Expected #{compare_to_string(count_mod)}#{count} items in array with: #{nesting}\n#{@response.to_json_s}/ if !nest_match(data, grouping, {})
59
59
  end
60
60
 
@@ -74,7 +74,7 @@ Then(/^the response ((?:#{HAVE_SYNONYM} (?:a|an|(?:(?:#{FEWER_MORE_THAN})?\s*#{C
74
74
  root: true,
75
75
  type: 'single'
76
76
  })
77
- data = @response.get get_root_json_path()
77
+ data = @response.get get_key(grouping)
78
78
  raise %/Could not find a match for #{nesting}#{compare_to_string(num_mod)}#{num} #{item}\n#{@response.to_json_s}/ if !nest_match(data, grouping, {})
79
79
  end
80
80
 
@@ -96,10 +96,19 @@ Then(/^(#{FEWER_MORE_THAN})?\s*(#{CAPTURE_INT}|\d+) (?:.*?) ((?:#{HAVE_SYNONYM}
96
96
  count: count.to_i,
97
97
  count_mod: count_mod
98
98
  })
99
- data = @response.get get_root_json_path()
99
+ data = @response.get get_key(grouping)
100
100
  raise %/Expected #{compare_to_string(count_mod)}#{count} items with #{nesting}#{compare_to_string(num_mod)}#{num}#{item}\n#{@response.to_json_s}/ if !nest_match(data, grouping, {})
101
101
  end
102
102
 
103
+ # gets the relevant key for the response based on the first key element
104
+ def get_key(grouping)
105
+ if ENV['error_key'] && !ENV['error_key'].empty? && grouping.count > 1 && grouping[-2][:key] == ENV['error_key'] then
106
+ get_root_error_key()
107
+ else
108
+ get_root_data_key()
109
+ end
110
+ end
111
+
103
112
  # gets an array in the nesting format that nest_match understands to interrogate nested object and array data
104
113
  def get_grouping(nesting)
105
114
  grouping = []
@@ -131,6 +140,7 @@ end
131
140
  #
132
141
  # returns true if the expected data is contained within the data based on the nesting information
133
142
  def nest_match(data, nesting, expected)
143
+ return false if !data
134
144
  return data.deep_include?(expected) if nesting.size == 0
135
145
 
136
146
  local_nesting = nesting.dup
@@ -102,12 +102,16 @@ def get_resource(name)
102
102
  resource = (ENV.has_key?('resource_single') && ENV['resource_single'] == 'true') ? resource.singularize : resource.pluralize
103
103
  end
104
104
 
105
- def get_root_json_path()
105
+ def get_root_data_key()
106
106
  return ENV.has_key?('data_key') && !ENV['data_key'].empty? ? "$.#{ENV['data_key']}." : "$."
107
107
  end
108
108
 
109
+ def get_root_error_key()
110
+ return "$."
111
+ end
112
+
109
113
  def get_json_path(names)
110
- return "#{get_root_json_path()}#{get_parameters(names).join('.')}"
114
+ return "#{get_root_data_key()}#{get_parameters(names).join('.')}"
111
115
  end
112
116
 
113
117
  def get_parameters(names)
@@ -119,7 +123,7 @@ def get_parameter(name)
119
123
  name = name[1..-2]
120
124
  else
121
125
  separator = ENV.has_key?('field_separator') ? ENV['field_separator'] : '_'
122
- name = name.parameterize(separator: separator)
126
+ name = name.singularize.parameterize(separator: separator)
123
127
  name = name.camelize(:lower) if (ENV.has_key?('field_camel') && ENV['field_camel'] == 'true')
124
128
  end
125
129
  name
data/server/error.js ADDED
@@ -0,0 +1,14 @@
1
+ module.exports = (req, res, next) => {
2
+ if (req.path == '/errors/list') {
3
+ res.status(404)
4
+ res.locals.data = {
5
+ errors: [{ message: 'Not Found' }]
6
+ }
7
+ } else if (req.path == '/errors/single') {
8
+ res.status(400)
9
+ res.locals.data = {
10
+ error: { message: 'Bad Request' }
11
+ }
12
+ }
13
+ next()
14
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cucumber-rest-bdd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4.pre.124
4
+ version: 0.4.4.pre.136
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harry Bragg
@@ -68,6 +68,7 @@ files:
68
68
  - STEPS.md
69
69
  - cucumber-rest-bdd.gemspec
70
70
  - docker-compose.yml
71
+ - features/errors.feature
71
72
  - features/functional.feature
72
73
  - features/grabs.feature
73
74
  - features/headers.feature
@@ -88,6 +89,7 @@ files:
88
89
  - lib/cucumber-rest-bdd/types.rb
89
90
  - lib/cucumber-rest-bdd/url.rb
90
91
  - server/db.json
92
+ - server/error.js
91
93
  - server/routes.json
92
94
  homepage: http://github.com/graze/cucumber-rest-bdd
93
95
  licenses:
@@ -109,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
111
  version: 1.3.1
110
112
  requirements: []
111
113
  rubyforge_project:
112
- rubygems_version: 2.4.8
114
+ rubygems_version: 2.6.8
113
115
  signing_key:
114
116
  specification_version: 4
115
117
  summary: BDD Rest API specifics for cucumber