cucumber-rest-bdd 0.3.4.pre.alpha.pre.86
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 +7 -0
- data/.gitignore +50 -0
- data/.travis.yml +15 -0
- data/Dockerfile +17 -0
- data/Dockerfile.dev +22 -0
- data/LICENSE +21 -0
- data/Makefile +15 -0
- data/README.md +267 -0
- data/STEPS.md +199 -0
- data/cucumber-rest-bdd.gemspec +19 -0
- data/docker-compose.yml +22 -0
- data/features/functional.feature +21 -0
- data/features/grabs.feature +21 -0
- data/features/headers.feature +16 -0
- data/features/methods.feature +101 -0
- data/features/response.feature +103 -0
- data/features/status.feature +18 -0
- data/features/support/env.rb +2 -0
- data/features/types.feature +48 -0
- data/lib/cucumber-rest-bdd/hash.rb +9 -0
- data/lib/cucumber-rest-bdd/steps/functional.rb +25 -0
- data/lib/cucumber-rest-bdd/steps/resource.rb +127 -0
- data/lib/cucumber-rest-bdd/steps/response.rb +156 -0
- data/lib/cucumber-rest-bdd/steps/status.rb +59 -0
- data/lib/cucumber-rest-bdd/steps.rb +4 -0
- data/lib/cucumber-rest-bdd/types.rb +138 -0
- data/lib/cucumber-rest-bdd/url.rb +4 -0
- data/lib/cucumber-rest-bdd.rb +1 -0
- data/server/db.json +41044 -0
- metadata +114 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
Feature: Performing different rest methods
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I am a client
|
5
|
+
|
6
|
+
Scenario: Count the number of elements
|
7
|
+
When I request a list of posts with:
|
8
|
+
| User Id | 8 |
|
9
|
+
Then the request is successful
|
10
|
+
And the JSON response should have "$." of type array with 10 entries
|
11
|
+
|
12
|
+
Scenario: Check for null type
|
13
|
+
When I request to create a post with:
|
14
|
+
| attribute | type | value |
|
15
|
+
| title | string | foo |
|
16
|
+
| body | text | bar |
|
17
|
+
| null | null | |
|
18
|
+
| nil | nil | |
|
19
|
+
Then the JSON response should have "null" of type null
|
20
|
+
Then the JSON response should have "nil" of type nil
|
21
|
+
Then the JSON response should have "nil" of type nill
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Feature: Using the response from a previous request
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I am a client
|
5
|
+
|
6
|
+
Scenario: Get an id from creation and use in get
|
7
|
+
When I request to create a post with:
|
8
|
+
| attribute | type | value |
|
9
|
+
| Title | string | foo |
|
10
|
+
| Body | string | bar |
|
11
|
+
| User Id | integer | 12 |
|
12
|
+
Then the request is successful
|
13
|
+
When I save "id"
|
14
|
+
And I request the post "{id}"
|
15
|
+
Then the request is successful
|
16
|
+
And the response has the following attributes:
|
17
|
+
| attribute | type | value |
|
18
|
+
| Title | string | foo |
|
19
|
+
| Body | string | bar |
|
20
|
+
| User Id | numeric | 12 |
|
21
|
+
| Id | numeric | {id} |
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Feature: We can inspect the headers of the response
|
2
|
+
|
3
|
+
Scenario: Parse a single result
|
4
|
+
When I request the post "1"
|
5
|
+
Then the request was successful
|
6
|
+
And the response has the header "Content Type" with value "application/json; charset=utf-8"
|
7
|
+
|
8
|
+
Scenario Outline: Can check for multiple headers
|
9
|
+
When I request the post "1"
|
10
|
+
Then the request was successful
|
11
|
+
And the response has the header "<header>" with the value "<value>"
|
12
|
+
|
13
|
+
Examples:
|
14
|
+
| header | value |
|
15
|
+
| Content Type | application/json; charset=utf-8 |
|
16
|
+
| Cache Control | no-cache |
|
@@ -0,0 +1,101 @@
|
|
1
|
+
Feature: Performing different rest methods
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I am a client
|
5
|
+
|
6
|
+
Scenario: Retrieve a single item
|
7
|
+
When I request the post "1"
|
8
|
+
Then the request was successful
|
9
|
+
And the response has the following attributes:
|
10
|
+
| attribute | type | value |
|
11
|
+
| User Id | numeric | 1 |
|
12
|
+
| Id | numeric | 1 |
|
13
|
+
| Title | string | sunt aut facere repellat provident occaecati excepturi optio reprehenderit |
|
14
|
+
| Body | string | quia et suscipit\\nsuscipit recusandae consequuntur expedita et cum\\nreprehenderit molestiae ut ut quas totam\\nnostrum rerum est autem sunt rem eveniet architecto |
|
15
|
+
|
16
|
+
Scenario: Retrieve multiple items
|
17
|
+
When I request a list of posts
|
18
|
+
Then the request was successful
|
19
|
+
And the response is a list of at least 2 posts
|
20
|
+
And one post has the following attributes:
|
21
|
+
| attribute | type | value |
|
22
|
+
| User Id | numeric | 1 |
|
23
|
+
| Id | numeric | 1 |
|
24
|
+
| Title | string | sunt aut facere repellat provident occaecati excepturi optio reprehenderit |
|
25
|
+
| Body | string | quia et suscipit\\nsuscipit recusandae consequuntur expedita et cum\\nreprehenderit molestiae ut ut quas totam\\nnostrum rerum est autem sunt rem eveniet architecto |
|
26
|
+
And one post has the following attributes:
|
27
|
+
| attribute | type | value |
|
28
|
+
| User Id | numeric | 1 |
|
29
|
+
| Id | numeric | 2 |
|
30
|
+
| Title | string | qui est esse |
|
31
|
+
| Body | string | est rerum tempore vitae\\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\\nqui aperiam non debitis possimus qui neque nisi nulla |
|
32
|
+
And ten posts have the following attributes:
|
33
|
+
| attribute | type | value |
|
34
|
+
| User Id | numeric | 5 |
|
35
|
+
And at most 20 posts have the following attributes:
|
36
|
+
| attribute | type | value |
|
37
|
+
| User Id | numeric | 5 |
|
38
|
+
|
39
|
+
Scenario: Retrieve multiple items with filter
|
40
|
+
When I request a list of posts with:
|
41
|
+
| User Id | 2 |
|
42
|
+
Then the request is successful
|
43
|
+
And the response is a list of at least 2 posts
|
44
|
+
And the response is a list of fewer than 100 posts
|
45
|
+
And one post has the following attributes:
|
46
|
+
| attribute | type | value |
|
47
|
+
| User Id | numeric | 2 |
|
48
|
+
| Id | numeric | 11 |
|
49
|
+
| Title | string | et ea vero quia laudantium autem |
|
50
|
+
| Body | string | delectus reiciendis molestiae occaecati non minima eveniet qui voluptatibus\\naccusamus in eum beatae sit\\nvel qui neque voluptates ut commodi qui incidunt\nut animi commodi |
|
51
|
+
And one post has the following attributes:
|
52
|
+
| attribute | type | value |
|
53
|
+
| User Id | numeric | 2 |
|
54
|
+
| Id | numeric | 12 |
|
55
|
+
| Title | string | in quibusdam tempore odit est dolorem |
|
56
|
+
| Body | string | itaque id aut magnam\\npraesentium quia et ea odit et ea voluptas et\\nsapiente quia nihil amet occaecati quia id voluptatem\\nincidunt ea est distinctio odio |
|
57
|
+
And more than two posts has the following attributes:
|
58
|
+
| attribute | type | value |
|
59
|
+
| User Id | numeric | 2 |
|
60
|
+
|
61
|
+
Scenario: Create an item
|
62
|
+
When I request to create a post with:
|
63
|
+
| attribute | type | value |
|
64
|
+
| Title | string | foo |
|
65
|
+
| Body | string | bar |
|
66
|
+
| User Id | numeric | 1 |
|
67
|
+
Then the request is successful and a post was created
|
68
|
+
And the response has the following attributes:
|
69
|
+
| attribute | type | value |
|
70
|
+
| User Id | numeric | 1 |
|
71
|
+
| Title | string | foo |
|
72
|
+
| Body | string | bar |
|
73
|
+
|
74
|
+
Scenario: Remove an item
|
75
|
+
When I request to remove the post "20"
|
76
|
+
Then the request is successful
|
77
|
+
|
78
|
+
Scenario: Modify an item
|
79
|
+
When I request to modify the post "21" with:
|
80
|
+
| attribute | type | value |
|
81
|
+
| Title | string | foo |
|
82
|
+
Then the request is successful
|
83
|
+
And the response has the following attributes:
|
84
|
+
| attribute | type | value |
|
85
|
+
| User Id | numeric | 3 |
|
86
|
+
| Title | string | foo |
|
87
|
+
| Body | string | repellat aliquid praesentium dolorem quo\\nsed totam minus non itaque\\nnihil labore molestiae sunt dolor eveniet hic recusandae veniam\\ntempora et tenetur expedita sunt |
|
88
|
+
|
89
|
+
Scenario: Update an item with Id
|
90
|
+
When I request to create a post "22" with:
|
91
|
+
| attribute | type | value |
|
92
|
+
| Title | string | foo |
|
93
|
+
| Body | string | bar |
|
94
|
+
| User Id | numeric | 1 |
|
95
|
+
Then the request is successful
|
96
|
+
And the response has the following attributes:
|
97
|
+
| attribute | type | value |
|
98
|
+
| User Id | numeric | 1 |
|
99
|
+
| Id | numeric | 22 |
|
100
|
+
| Title | string | foo |
|
101
|
+
| Body | string | bar |
|
@@ -0,0 +1,103 @@
|
|
1
|
+
Feature: Dealing with sub objects
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I am a client
|
5
|
+
|
6
|
+
Scenario: Create and read an item with child objects
|
7
|
+
When I request to create a post with:
|
8
|
+
| attribute | type | value |
|
9
|
+
| Title | string | foo |
|
10
|
+
| Body | string | bar |
|
11
|
+
| User : Id | numeric | 1 |
|
12
|
+
| User : name | string | name |
|
13
|
+
Then the request is successful and a post was created
|
14
|
+
And the response has the following attributes:
|
15
|
+
| attribute | type | value |
|
16
|
+
| Title | string | foo |
|
17
|
+
| Body | string | bar |
|
18
|
+
| User : Id | numeric | 1 |
|
19
|
+
| User : name | string | name |
|
20
|
+
|
21
|
+
Scenario: Request a single item with child objects
|
22
|
+
When I request the comment "1" with:
|
23
|
+
| `_expand` | post |
|
24
|
+
Then the response has the following attributes:
|
25
|
+
| attribute | type | value |
|
26
|
+
| name | string | id labore ex et quam laborum |
|
27
|
+
| email | string | Eliseo@gardner.biz |
|
28
|
+
| body | string | laudantium enim quasi est quidem magnam voluptate ipsam eos\\ntempora quo necessitatibus\\ndolor quam autem quasi\\nreiciendis et nam sapiente accusantium |
|
29
|
+
| post : title | string | sunt aut facere repellat provident occaecati excepturi optio reprehenderit |
|
30
|
+
| post : body | string | quia et suscipit\\nsuscipit recusandae consequuntur expedita et cum\\nreprehenderit molestiae ut ut quas totam\\nnostrum rerum est autem sunt rem eveniet architecto |
|
31
|
+
|
32
|
+
Scenario: Request an item within a list of items
|
33
|
+
When I request a list of comments with:
|
34
|
+
| `_expand` | post |
|
35
|
+
| Post ID | 1 |
|
36
|
+
Then the response is a list of more than 1 comment
|
37
|
+
And one comment has the following attributes:
|
38
|
+
| attribute | type | value |
|
39
|
+
| name | string | id labore ex et quam laborum |
|
40
|
+
| email | string | Eliseo@gardner.biz |
|
41
|
+
| body | string | laudantium enim quasi est quidem magnam voluptate ipsam eos\\ntempora quo necessitatibus\\ndolor quam autem quasi\\nreiciendis et nam sapiente accusantium |
|
42
|
+
| post : title | string | sunt aut facere repellat provident occaecati excepturi optio reprehenderit |
|
43
|
+
| post : body | string | quia et suscipit\\nsuscipit recusandae consequuntur expedita et cum\\nreprehenderit molestiae ut ut quas totam\\nnostrum rerum est autem sunt rem eveniet architecto |
|
44
|
+
|
45
|
+
Scenario: Match an item with a list of items
|
46
|
+
When I request the post "1" with:
|
47
|
+
| `_embed` | comments |
|
48
|
+
Then the response has the following attributes:
|
49
|
+
| attribute | type | value |
|
50
|
+
| title | string | sunt aut facere repellat provident occaecati excepturi optio reprehenderit |
|
51
|
+
| body | string | quia et suscipit\\nsuscipit recusandae consequuntur expedita et cum\\nreprehenderit molestiae ut ut quas totam\\nnostrum rerum est autem sunt rem eveniet architecto |
|
52
|
+
And the response has one comment with attributes:
|
53
|
+
| attribute | type | value |
|
54
|
+
| name | string | id labore ex et quam laborum |
|
55
|
+
| email | string | Eliseo@gardner.biz |
|
56
|
+
| body | string | laudantium enim quasi est quidem magnam voluptate ipsam eos\\ntempora quo necessitatibus\\ndolor quam autem quasi\\nreiciendis et nam sapiente accusantium |
|
57
|
+
And the response has five comments with attributes:
|
58
|
+
| attribute | type | value |
|
59
|
+
| Post Id | integer | 1 |
|
60
|
+
And the response has at least five comments
|
61
|
+
|
62
|
+
Scenario: Multiple levels
|
63
|
+
When I set JSON request body to:
|
64
|
+
"""
|
65
|
+
{"title":"test","body":"multiple",
|
66
|
+
"comments":[
|
67
|
+
{"common":1,"id":1,"title":"fish","body":"cake","image":{"href":"some_url"}},
|
68
|
+
{"common":1,"id":2,"title":"foo","body":"bar","image":{"href":"some_url"}}
|
69
|
+
]}
|
70
|
+
"""
|
71
|
+
And I send a POST request to "http://test-server/posts"
|
72
|
+
Then the response has the attributes:
|
73
|
+
| attribute | type | value |
|
74
|
+
| title | string | test |
|
75
|
+
| body | string | multiple |
|
76
|
+
And the response has a list of comments
|
77
|
+
And the response has a list of 2 comments
|
78
|
+
And the response has two comments with attributes:
|
79
|
+
| attribute | type | value |
|
80
|
+
| common | integer | 1 |
|
81
|
+
And the response has two comments with an image with attributes:
|
82
|
+
| attribute | type | value |
|
83
|
+
| href | string | some_url |
|
84
|
+
And the response has one comment with attributes:
|
85
|
+
| attribute | type | value |
|
86
|
+
| Id | integer | 1 |
|
87
|
+
| Title | string | fish |
|
88
|
+
| Body | string | cake |
|
89
|
+
And the response has one comment with attributes:
|
90
|
+
| attribute | type | value |
|
91
|
+
| Id | integer | 2 |
|
92
|
+
| Title | string | foo |
|
93
|
+
| Body | string | bar |
|
94
|
+
|
95
|
+
Scenario: Multiple levels in array
|
96
|
+
When I request a list of posts with:
|
97
|
+
| `_embed` | comments |
|
98
|
+
Then the request is successful
|
99
|
+
And one post has one comment with attributes:
|
100
|
+
| attribute | type | value |
|
101
|
+
| Id | integer | 1 |
|
102
|
+
And at least ten posts contain a list of five comments
|
103
|
+
And more than 95 posts contain more than four comments
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: I can handle different response codes
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I am a client
|
5
|
+
|
6
|
+
Scenario: Successful response
|
7
|
+
When I request the post "1"
|
8
|
+
Then the request is successful
|
9
|
+
|
10
|
+
Scenario: Key not found
|
11
|
+
When I request the post "not-found"
|
12
|
+
Then the request fails
|
13
|
+
And it fails because the post was not found
|
14
|
+
|
15
|
+
Scenario: Resource not found
|
16
|
+
When I request the Not Found "5"
|
17
|
+
Then the request fails
|
18
|
+
And it fails because the not found was not found
|
@@ -0,0 +1,48 @@
|
|
1
|
+
Feature: Dealing with sub objects
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given I am a client
|
5
|
+
|
6
|
+
Scenario: Handle null values
|
7
|
+
When I request to create a post with:
|
8
|
+
| attribute | type | value |
|
9
|
+
| title | string | foo |
|
10
|
+
| body | string | bar |
|
11
|
+
| extra | null | |
|
12
|
+
Then the request was successful
|
13
|
+
And the response has the following attributes:
|
14
|
+
| attribute | type | value |
|
15
|
+
| title | string | foo |
|
16
|
+
| body | string | bar |
|
17
|
+
| extra | nil | |
|
18
|
+
|
19
|
+
Scenario: Handle types
|
20
|
+
When I request to create a post with:
|
21
|
+
| attribute | type | value |
|
22
|
+
| title | string | foo |
|
23
|
+
| body | text | bar |
|
24
|
+
| int | int | 1 |
|
25
|
+
| long | long | 1347289473247823749 |
|
26
|
+
| float | float | 1.2 |
|
27
|
+
| double | double | 1.4 |
|
28
|
+
| number | number | 12 |
|
29
|
+
| numeric | numeric | 15 |
|
30
|
+
| bool | bool | true |
|
31
|
+
| boolean | boolean | false |
|
32
|
+
| null | null | |
|
33
|
+
| nil | nil | |
|
34
|
+
Then the request was successful
|
35
|
+
And the response has the following attributes:
|
36
|
+
| attribute | type | value |
|
37
|
+
| title | string | foo |
|
38
|
+
| body | text | bar |
|
39
|
+
| int | int | 1 |
|
40
|
+
| long | long | 1347289473247824000 |
|
41
|
+
| float | float | 1.2 |
|
42
|
+
| double | double | 1.4 |
|
43
|
+
| number | number | 12 |
|
44
|
+
| numeric | numeric | 15 |
|
45
|
+
| bool | bool | true |
|
46
|
+
| boolean | boolean | false |
|
47
|
+
| null | null | |
|
48
|
+
| nil | nil | |
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'cucumber-api/response'
|
2
|
+
require 'cucumber-api/steps'
|
3
|
+
|
4
|
+
Then(/^the response (?:should have|has a|has the) header "([^"]*)" with (?:a |the )?value "([^"]*)"$/) do |header, value|
|
5
|
+
p_value = resolve(value)
|
6
|
+
p_header = header.parameterize
|
7
|
+
raise %/Required header: #{header} not found\n#{@response.raw_headers.inspect}/ if !@response.raw_headers.key?(p_header)
|
8
|
+
exists = @response.raw_headers[p_header].include? p_value
|
9
|
+
raise %/Expect #{p_value} in #{header} (#{p_header})\n#{@response.raw_headers.inspect}/ if !exists
|
10
|
+
end
|
11
|
+
|
12
|
+
Then(/^the JSON response should have "([^"]*)" of type array with (\d+) entr(?:y|ies)$/) do |json_path, number|
|
13
|
+
list = @response.get_as_type json_path, 'array'
|
14
|
+
raise %/Expected #{number} items in array for path '#{json_path}', found: #{list.count}\n#{@response.to_json_s}/ if list.count != number.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
Then(/^the JSON response should have "([^"]*)" of type (.+) that matches "(.+)"$/) do |json_path, type, regex|
|
18
|
+
value = @response.get_as_type json_path, type
|
19
|
+
raise %/Expected #{json_path} value '#{value}' to match regex: #{regex}\n#{@response.to_json_s}/ if (Regexp.new(regex) =~ value).nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
Then(/^the JSON response should have "([^"]*)" of type (?:nill|null|nil)$/) do |json_path|
|
23
|
+
value = @response.get_as_type_or_null json_path, 'string'
|
24
|
+
raise %/Expected #{json_path} to be nil, was: #{value.class}\n#{@response.to_json_s}/ if !value.nil?
|
25
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'cucumber-api/response'
|
2
|
+
require 'cucumber-api/steps'
|
3
|
+
require 'active_support/inflector'
|
4
|
+
require 'cucumber-rest-bdd/url'
|
5
|
+
require 'cucumber-rest-bdd/types'
|
6
|
+
require 'cucumber-rest-bdd/hash'
|
7
|
+
require 'easy_diff'
|
8
|
+
|
9
|
+
Given(/^I am a client$/) do
|
10
|
+
steps %Q{
|
11
|
+
Given I send "application/json" and accept JSON
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
# GET
|
16
|
+
|
17
|
+
When(/^I request (?:an?|the) (.+?)(?: with (?:key|id))? "([^"]*)"$/) do |resource, token|
|
18
|
+
resource_name = get_resource(resource)
|
19
|
+
url = get_url("#{resource_name}/#{token}")
|
20
|
+
steps %Q{When I send a GET request to "#{url}"}
|
21
|
+
end
|
22
|
+
|
23
|
+
When(/^I request (?:an?|the) (.+?)(?: with (?:key|id))? "([^"]*)" with:$/) do |resource, token, params|
|
24
|
+
resource_name = get_resource(resource)
|
25
|
+
url = get_url("#{resource_name}/#{token}")
|
26
|
+
unless params.raw.empty?
|
27
|
+
query = params.raw.map{|key, value| %/#{get_parameter(key)}=#{resolve(value)}/}.join("&")
|
28
|
+
url = "#{url}?#{query}"
|
29
|
+
end
|
30
|
+
steps %Q{When I send a GET request to "#{url}"}
|
31
|
+
end
|
32
|
+
|
33
|
+
When(/^I request a list of ([^:]+)$/) do |resource|
|
34
|
+
resource_name = get_resource(resource)
|
35
|
+
url = get_url("#{resource_name}")
|
36
|
+
steps %Q{When I send a GET request to "#{url}"}
|
37
|
+
end
|
38
|
+
|
39
|
+
When(/^I request a list of (.+) with:$/) do |resource, params|
|
40
|
+
resource_name = get_resource(resource)
|
41
|
+
url = get_url("#{resource_name}")
|
42
|
+
unless params.raw.empty?
|
43
|
+
query = params.raw.map{|key, value| %/#{get_parameter(key)}=#{resolve(value)}/}.join("&")
|
44
|
+
url = "#{url}?#{query}"
|
45
|
+
end
|
46
|
+
steps %Q{When I send a GET request to "#{url}"}
|
47
|
+
end
|
48
|
+
|
49
|
+
# DELETE
|
50
|
+
|
51
|
+
When(/^I request to (?:delete|remove) the (.+) "([^"]*)"$/) do |resource, token|
|
52
|
+
resource_name = get_resource(resource)
|
53
|
+
url = get_url("#{resource_name}/#{token}")
|
54
|
+
steps %Q{When I send a DELETE request to "#{url}"}
|
55
|
+
end
|
56
|
+
|
57
|
+
# POST
|
58
|
+
|
59
|
+
When(/^I request to create an? ([^:]+?)$/) do |resource|
|
60
|
+
resource_name = get_resource(resource)
|
61
|
+
url = get_url("#{resource_name}")
|
62
|
+
steps %Q{When I send a POST request to "#{url}"}
|
63
|
+
end
|
64
|
+
|
65
|
+
When(/^I request to create an? ([^"]+?) with:$/) do |resource, params|
|
66
|
+
resource_name = get_resource(resource)
|
67
|
+
request_hash = get_attributes(params.hashes)
|
68
|
+
json = MultiJson.dump(request_hash)
|
69
|
+
url = get_url("#{resource_name}")
|
70
|
+
steps %Q{
|
71
|
+
When I set JSON request body to:
|
72
|
+
"""
|
73
|
+
#{json}
|
74
|
+
"""
|
75
|
+
And I send a POST request to "#{url}"
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
# PUT
|
80
|
+
|
81
|
+
When(/^I request to (?:create|replace) (?:an?|the) ([^"]+?)(?: with (?:key|id))? "([^"]+)"$/) do |resource, id|
|
82
|
+
resource_name = get_resource(resource)
|
83
|
+
url = get_url("#{resource_name}/#{id}")
|
84
|
+
steps %Q{
|
85
|
+
When I send a PUT request to "#{url}"
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
When(/^I request to (?:create|replace) (?:an?|the) ([^"]+?)(?: with (?:key|id))? "([^"]+)" with:$/) do |resource, id, params|
|
90
|
+
resource_name = get_resource(resource)
|
91
|
+
request_hash = get_attributes(params.hashes)
|
92
|
+
json = MultiJson.dump(request_hash)
|
93
|
+
url = get_url("#{resource_name}/#{id}")
|
94
|
+
steps %Q{
|
95
|
+
When I set JSON request body to:
|
96
|
+
"""
|
97
|
+
#{json}
|
98
|
+
"""
|
99
|
+
And I send a PUT request to "#{url}"
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
# PATCH
|
104
|
+
|
105
|
+
When(/^I request to modify the (.+?)(?: with (?:key|id))? "([^"]+)" with:$/) do |resource, id, params|
|
106
|
+
resource_name = get_resource(resource)
|
107
|
+
request_hash = get_attributes(params.hashes)
|
108
|
+
json = MultiJson.dump(request_hash)
|
109
|
+
url = get_url("#{resource_name}/#{id}")
|
110
|
+
steps %Q{
|
111
|
+
When I set JSON request body to:
|
112
|
+
"""
|
113
|
+
#{json}
|
114
|
+
"""
|
115
|
+
And I send a PATCH request to "#{url}"
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
# value capture
|
120
|
+
|
121
|
+
When(/^I save (?:attribute )?"([^"]+)"$/) do |attribute|
|
122
|
+
steps %Q{When I grab "#{get_json_path(attribute)}"}
|
123
|
+
end
|
124
|
+
|
125
|
+
When(/^I save (?:attribute )?"([^"]+)" to "([^"]+)"$/) do |attribute, ref|
|
126
|
+
steps %Q{When I grab "#{get_json_path(attribute)}" as "#{ref}"}
|
127
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'cucumber-rest-bdd/steps/resource'
|
2
|
+
require 'cucumber-rest-bdd/types'
|
3
|
+
|
4
|
+
# response interrogation
|
5
|
+
|
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#{@repsponse.to_json_s}/ if !num_compare(count_mod, list.count, count.to_i)
|
9
|
+
end
|
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|
|
12
|
+
expected = get_attributes(attributes.hashes)
|
13
|
+
groups = nesting
|
14
|
+
grouping = get_grouping(groups)
|
15
|
+
grouping.push({
|
16
|
+
root: true,
|
17
|
+
type: 'single'
|
18
|
+
})
|
19
|
+
data = @response.get get_root_json_path()
|
20
|
+
raise %/Could not find a match for: #{nesting}\n#{@response.to_json_s}/ if !nest_match(data, grouping, expected)
|
21
|
+
end
|
22
|
+
|
23
|
+
Then(/^the response ((?:#{HAVE_SYNONYM} (?:a|an|(?:(?:#{FEWER_MORE_THAN})?\s*#{CAPTURE_INT}|\d+)) (?:\w+)\s?)+)$/) do |nesting|
|
24
|
+
groups = nesting
|
25
|
+
grouping = get_grouping(groups)
|
26
|
+
grouping.push({
|
27
|
+
root: true,
|
28
|
+
type: 'single'
|
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, {})
|
32
|
+
end
|
33
|
+
|
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|
|
35
|
+
expected = get_attributes(attributes.hashes)
|
36
|
+
groups = nesting
|
37
|
+
grouping = get_grouping(groups)
|
38
|
+
grouping.push({
|
39
|
+
root: true,
|
40
|
+
type: 'multiple',
|
41
|
+
count: count.to_i,
|
42
|
+
count_mod: count_mod
|
43
|
+
})
|
44
|
+
data = @response.get get_root_json_path()
|
45
|
+
raise %/Expected #{compare_to_string(count_mod)}#{count} items in array with attributes for: #{nesting}\n#{@response.to_json_s}/ if !nest_match(data, grouping, expected)
|
46
|
+
end
|
47
|
+
|
48
|
+
Then(/^(#{FEWER_MORE_THAN})?\s*(#{CAPTURE_INT}|\d+) (?:.*?) ((?:#{HAVE_SYNONYM} (?:a|an|(?:(?:#{FEWER_MORE_THAN})?\s*#{CAPTURE_INT}|\d+)) (?:\w+)\s?)+)$/) do |count_mod, count, nesting|
|
49
|
+
groups = nesting
|
50
|
+
grouping = get_grouping(groups)
|
51
|
+
grouping.push({
|
52
|
+
root: true,
|
53
|
+
type: 'multiple',
|
54
|
+
count: count.to_i,
|
55
|
+
count_mod: count_mod
|
56
|
+
})
|
57
|
+
data = @response.get get_root_json_path()
|
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
|
+
end
|
60
|
+
|
61
|
+
Then(/^the response ((?:#{HAVE_SYNONYM} (?:a|an|(?:(?:#{FEWER_MORE_THAN})?\s*#{CAPTURE_INT}|\d+)) (?:\w+) )*)#{HAVE_SYNONYM} a list of (#{FEWER_MORE_THAN})?\s*(#{CAPTURE_INT} |\d+ )?(\w+)$/) do |nesting, num_mod, num, item|
|
62
|
+
groups = nesting
|
63
|
+
list = {
|
64
|
+
type: 'list',
|
65
|
+
key: get_resource(item)
|
66
|
+
}
|
67
|
+
if (num) then
|
68
|
+
list[:count] = num.to_i
|
69
|
+
list[:count_mod] = num_mod
|
70
|
+
end
|
71
|
+
grouping = [list]
|
72
|
+
grouping.concat(get_grouping(groups))
|
73
|
+
grouping.push({
|
74
|
+
root: true,
|
75
|
+
type: 'single'
|
76
|
+
})
|
77
|
+
data = @response.get get_root_json_path()
|
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
|
+
end
|
80
|
+
|
81
|
+
Then(/^(#{FEWER_MORE_THAN})?\s*(#{CAPTURE_INT}|\d+) (?:.*?) ((?:#{HAVE_SYNONYM} (?:a|an|(?:(?:#{FEWER_MORE_THAN})?\s*#{CAPTURE_INT}|\d+)) (?:\w+) )*)#{HAVE_SYNONYM} a list of (#{FEWER_MORE_THAN})?\s*(?:(#{CAPTURE_INT}|\d+) )?(\w+)$/) do |count_mod, count, nesting, num_mod, num, item|
|
82
|
+
groups = nesting
|
83
|
+
list = {
|
84
|
+
type: 'list',
|
85
|
+
key: get_resource(item)
|
86
|
+
}
|
87
|
+
if (num) then
|
88
|
+
list[:count] = num.to_i
|
89
|
+
list[:count_mod] = num_mod
|
90
|
+
end
|
91
|
+
grouping = [list]
|
92
|
+
grouping.concat(get_grouping(groups))
|
93
|
+
grouping.push({
|
94
|
+
root: true,
|
95
|
+
type: 'multiple',
|
96
|
+
count: count.to_i,
|
97
|
+
count_mod: count_mod
|
98
|
+
})
|
99
|
+
data = @response.get get_root_json_path()
|
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
|
+
end
|
102
|
+
|
103
|
+
# gets an array in the nesting format that nest_match understands to interrogate nested object and array data
|
104
|
+
def get_grouping(nesting)
|
105
|
+
grouping = []
|
106
|
+
while matches = /^#{HAVE_SYNONYM} (?:a|an|(?:(#{FEWER_MORE_THAN})?\s*(#{CAPTURE_INT}|\d+))) (\w+)\s?+/.match(nesting)
|
107
|
+
nesting = nesting[matches[0].length, nesting.length]
|
108
|
+
if matches[2].nil? then
|
109
|
+
level = {
|
110
|
+
type: 'single',
|
111
|
+
key: get_parameter(matches[3]),
|
112
|
+
root: false
|
113
|
+
}
|
114
|
+
else
|
115
|
+
level = {
|
116
|
+
type: 'multiple',
|
117
|
+
key: get_parameter(matches[3]),
|
118
|
+
count: to_num(matches[2]),
|
119
|
+
root: false,
|
120
|
+
count_mod: to_compare(matches[1])
|
121
|
+
}
|
122
|
+
end
|
123
|
+
grouping.push(level)
|
124
|
+
end
|
125
|
+
grouping.reverse
|
126
|
+
end
|
127
|
+
|
128
|
+
# top level has 2 children with an item containing at most three fish with attributes:
|
129
|
+
#
|
130
|
+
# nesting = [{key=fish,count=3,count_mod='<=',type=multiple},{key=item,type=single},{key=children,type=multiple,count=2,count_mod='='},{root=true,type=single}]
|
131
|
+
#
|
132
|
+
# returns true if the expected data is contained within the data based on the nesting information
|
133
|
+
def nest_match(data, nesting, expected)
|
134
|
+
return data.deep_include?(expected) if nesting.size == 0
|
135
|
+
|
136
|
+
local_nesting = nesting.dup
|
137
|
+
level = local_nesting.pop
|
138
|
+
case level[:type]
|
139
|
+
when 'single' then
|
140
|
+
child_data = level[:root] ? data.dup : data[get_parameter(level[:key])]
|
141
|
+
return nest_match(child_data, local_nesting, expected)
|
142
|
+
when 'multiple' then
|
143
|
+
child_data = level[:root] ? data.dup : data[get_resource(level[:key])]
|
144
|
+
matched = child_data.select { |item| nest_match(item, local_nesting, expected) }
|
145
|
+
return num_compare(level[:count_mod], matched.count, level[:count])
|
146
|
+
when 'list' then
|
147
|
+
child_data = level[:root] ? data.dup : data[get_resource(level[:key])]
|
148
|
+
return false if !child_data.is_a?(Array)
|
149
|
+
if level.has_key?(:count) then
|
150
|
+
return num_compare(level[:count_mod], child_data.count, level[:count])
|
151
|
+
end
|
152
|
+
return true
|
153
|
+
else
|
154
|
+
raise %/Unknown nested data type: #{level[:type]}/
|
155
|
+
end
|
156
|
+
end
|