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

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: 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