cucumber-rest-bdd 0.4.4 → 0.5.1.pre.140

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bdfd0c715aefc7a24bde96d6c3c6b99e3f740a25
4
- data.tar.gz: b888b7f6187cff2d5d5c1bff03656a79b33905b7
3
+ metadata.gz: cb1d9233bd18d88c3a16492812de62b582ad2dae
4
+ data.tar.gz: e874e9bd715a41facadd47f02ed6be5f7f75d442
5
5
  SHA512:
6
- metadata.gz: b7bdd8148100ed05bd005ddd5aafccf564fdcb24edd69e22e68abe6100e36d6d1530279f3703548a9054080c313452a6fc391b6568c42dd3393b1d128cfc80cd
7
- data.tar.gz: 79ad4ad6c2116dcdc21b2172cb14993397d89b70b5d89ebaafb606c907cf2938759b89fd1469d2c1f85ca10094b4d2b44a489a24fc3001203ad0a73fcca81fbc
6
+ metadata.gz: 57f0046b7719f6f35c1f6de7f9fc8f825d9fa8ba913699abf47bbd4cadef25e1819e8e0d0929b2eb2e31b368ed733b68ce7b1810463bf57ad2ce8c21a57ca4aa
7
+ data.tar.gz: 9cfa198f99325aa0dc96d648eb9f7c44df37735b083c2e63b43d898d3983e55cb93a1e5f01f3e111d29d2048aad4868af0a8c8db65453bd2f5aaa6104f95db90
data/Dockerfile CHANGED
@@ -1,7 +1,7 @@
1
1
  FROM ruby
2
2
 
3
3
  MAINTAINER "Harry Bragg <harry.bragg@graze.com>"
4
- LABEL version="0.4.4" \
4
+ LABEL version="0.5.1" \
5
5
  license="MIT"
6
6
 
7
7
  COPY . /usr/local/cucumber-rest-bdd
@@ -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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2016 graze.com
3
+ Copyright (c) 2017 graze.com
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
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
@@ -35,6 +35,7 @@ The following environment variables modify how this will operate:
35
35
 
36
36
  - `endpoint` - (string) the base url to call for each request
37
37
  - `data_key` - (string) the root data key (if applicable) (for example: `"data"` if all responses have a `{"data":{}}` field)
38
+ - `error_key` - (string) this will ignore the `data_key` when checking for errors
38
39
  - `field_separator` - (string) the separator used between words by the api
39
40
  - `field_camel` - (bool [`true`|`false`]) does this endpoint use camelCase for fields (default: `false`)
40
41
  - `resource_single` - (bool [`true`|`false`]) if each resource should be singularized or not (default: `false`)
@@ -154,6 +155,31 @@ Then more than 10 posts have five comments
154
155
  Then less than 200 posts have five comments
155
156
  ```
156
157
 
158
+ #### Errors
159
+
160
+ If the `error_key` environment variable is set, if that key is used as the initial step it will ignore any `data_key`
161
+ setting.
162
+
163
+ Example: `error_key=error`, `data_key=data`
164
+
165
+ ```gherkin
166
+ Then the response has a list of posts | {"data":[{"id": 12}]}
167
+
168
+ Then the response has one error | {"errors":[{"message": "Error"}]}
169
+
170
+ Then the response has an error | {"error": {"message": "Error}}
171
+ ```
172
+
173
+ Example: `error_key=`, `data_key=data`
174
+
175
+ ```gherkin
176
+ Then the response has a list of posts | {"data":[{"id": 12}]}
177
+
178
+ Then the response has one error | {"data": {"errors":[{"message": "Error"}]}}
179
+
180
+ Then the response has an error | {"data": {"error": {"message": "Error}}}
181
+ ```
182
+
157
183
  ### Creation
158
184
 
159
185
  ```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"
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'cucumber-rest-bdd'
3
- s.version = '0.4.4'
3
+ s.version = '0.5.1'
4
4
  s.version = "#{s.version}-#{ENV['TRAVIS_BUILD_NUMBER']}" if ENV['TRAVIS'] && ENV['TRAVIS_TAG'] == ''
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.date = '2017-01-10'
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
4
+ version: 0.5.1.pre.140
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:
@@ -104,12 +106,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
106
  version: '0'
105
107
  required_rubygems_version: !ruby/object:Gem::Requirement
106
108
  requirements:
107
- - - ">="
109
+ - - ">"
108
110
  - !ruby/object:Gem::Version
109
- version: '0'
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