cucumber-rest-bdd 0.3.4.pre.alpha.pre.86
Sign up to get free protection for your applications and to get access to all the features.
- 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
|