diff --git a/README.MD b/README.MD index 70152b3..1becec0 100644 --- a/README.MD +++ b/README.MD @@ -9,21 +9,21 @@ that implements 🥒[gherkin/cucumber](https://cucumber.io/docs/gherkin/) syntax ## Why ? **No more** long and time-consuming framework setup. This project **cuts initial time** & allows bootstrap e2e test framework with **plenty of -utility methods** (_for testing HTTP(s) API using JSON/YAML_) in just few steps. Just grab it and write tests right away. +utility methods** (_for testing HTTP(s) API using JSON/YAML/XML_) in just few steps. Just grab it and write tests right away. Benefits: * **short time** from **[setup](https://github.com/pawelWritesCode/godog-example-setup/wiki/Set-up#clone-repository) - to writing** actual E2E tests, * [35+ well-documented, coupled in logical groups steps](https://github.com/pawelWritesCode/godog-example-setup/wiki/Steps) useful for testing HTTP(s) API, * support for using templated values as in [text/template](https://pkg.go.dev/text/template) package, -* support for querying JSON/YAML tree with different path engines ([oliveagle - JSON](https://github.com/oliveagle/jsonpath), [qjson - JSON](https://github.com/pawelWritesCode/qjson), [go-yaml - YAML](https://github.com/goccy/go-yaml)), +* support for querying nodes with different path engines ([oliveagle](https://github.com/oliveagle/jsonpath), [qjson](https://github.com/pawelWritesCode/qjson) - JSON, [go-yaml](https://github.com/goccy/go-yaml) - YAML, [antchfx](https://github.com/antchfx/xmlquery) - XML), * support for sending _multipart/form-data_ forms with file in it, * rich debugging possibilities - various ways to debug tests, -* very customisable (ability to [replace](https://github.com/pawelWritesCode/godog-example-setup/blob/main/main_test.go#L58) internal services with your own implementation), -* friendly for custom [steps development](https://github.com/pawelWritesCode/godog-example-setup/wiki/Steps-development) because of [exported utility services](https://github.com/pawelWritesCode/gdutils/blob/master/state.go#L18). +* customisable - ability to [replace](https://github.com/pawelWritesCode/godog-example-setup/blob/main/main_test.go#L58) utility services with your own implementations, +* supports custom [steps development](https://github.com/pawelWritesCode/godog-example-setup/wiki/Steps-development) through [exported utility services](https://github.com/pawelWritesCode/gdutils/blob/master/state.go#L18). ## Example -#### [Click here 👆 to see more tests](https://github.com/pawelWritesCode/godog-example-setup/blob/main/features/) +#### [Click here 👆 to see more tests using JSON/YAML/XML](https://github.com/pawelWritesCode/godog-example-setup/blob/main/features/test_server) ```cucumber Feature: Adding new user @@ -128,5 +128,6 @@ See project ![hand pointing right](assets/gifs/hand-pointing-right.gif) [wiki]( * [Project structure](https://github.com/pawelWritesCode/godog-example-setup/wiki/Project-structure) - describes repository folder structure, * [Setup](https://github.com/pawelWritesCode/godog-example-setup/wiki/Set-up) - guide how to bootstrap repository on your machine, * [Steps](https://github.com/pawelWritesCode/godog-example-setup/wiki/Steps) - describes each available step and how to use it in tests, -* [Steps development](https://github.com/pawelWritesCode/godog-example-setup/wiki/Steps-development) - how to create custom steps using internal services, +* [Steps debugging](https://github.com/pawelWritesCode/godog-example-setup/wiki/Steps-debugging) - how to debug tests, +* [Steps development](https://github.com/pawelWritesCode/godog-example-setup/wiki/Steps-development) - how to create custom steps using utility services, * [Usage](https://github.com/pawelWritesCode/godog-example-setup/wiki/Usage) - how to run tests. \ No newline at end of file diff --git a/assets/test_server/bin/darwin/amd64/user_crud b/assets/test_server/bin/darwin/amd64/user_crud index 485ef3b..1fba4e2 100755 Binary files a/assets/test_server/bin/darwin/amd64/user_crud and b/assets/test_server/bin/darwin/amd64/user_crud differ diff --git a/assets/test_server/bin/linux/amd64/user_crud b/assets/test_server/bin/linux/amd64/user_crud index 90b0ef1..33456f9 100755 Binary files a/assets/test_server/bin/linux/amd64/user_crud and b/assets/test_server/bin/linux/amd64/user_crud differ diff --git a/assets/test_server/bin/windows/amd64/user_crud.exe b/assets/test_server/bin/windows/amd64/user_crud.exe index 6aaf3ab..b7cad57 100755 Binary files a/assets/test_server/bin/windows/amd64/user_crud.exe and b/assets/test_server/bin/windows/amd64/user_crud.exe differ diff --git a/assets/test_server/doc/schema.json b/assets/test_server/doc/schema.json index d63b918..1409e41 100644 --- a/assets/test_server/doc/schema.json +++ b/assets/test_server/doc/schema.json @@ -35,6 +35,17 @@ "user" ], "summary": "Create user", + "parameters": [ + { + "name": "format", + "in": "query", + "description": "response body format", + "required": false, + "schema": { + "enum": ["json", "xml", "yaml"] + } + } + ], "description": "Creation of new user.", "operationId": "create_user", "requestBody": { @@ -52,7 +63,17 @@ "200": { "description": "Successfully created user", "content": { - "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GETUser" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/GETUser" + } + }, + "application/x-yaml": { "schema": { "$ref": "#/components/schemas/GETUser" } @@ -66,6 +87,16 @@ "schema": { "$ref": "#/components/schemas/general_error" } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/general_error_xml" + } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/general_error" + } } } } @@ -77,6 +108,17 @@ ], "summary": "Get user by user name", "operationId": "get_users_list", + "parameters": [ + { + "name": "format", + "in": "query", + "description": "response body format", + "required": false, + "schema": { + "enum": ["json", "xml", "yaml"] + } + } + ], "responses": { "200": { "description": "successful operation", @@ -88,6 +130,26 @@ "$ref": "#/components/schemas/GETUser" } } + }, + "application/xml": { + "schema": { + "type": "array", + "xml": { + "wrapped": true, + "name": "users" + }, + "items": { + "$ref": "#/components/schemas/GETUser" + } + } + }, + "application/x-yaml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GETUser" + } + } } } } @@ -110,6 +172,15 @@ "schema": { "type": "integer" } + }, + { + "name": "format", + "in": "query", + "description": "response body format", + "required": false, + "schema": { + "enum": ["json", "xml", "yaml"] + } } ], "responses": { @@ -120,6 +191,16 @@ "schema": { "$ref": "#/components/schemas/GETUser" } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/GETUser" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/GETUser" + } } } }, @@ -130,6 +211,16 @@ "schema": { "$ref": "#/components/schemas/general_error" } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/general_error" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/general_error_xml" + } } } } @@ -151,6 +242,15 @@ "schema": { "type": "integer" } + }, + { + "name": "format", + "in": "query", + "description": "response body format", + "required": false, + "schema": { + "enum": ["json", "xml", "yaml"] + } } ], "requestBody": { @@ -176,6 +276,16 @@ "schema": { "$ref": "#/components/schemas/general_error" } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/general_error" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/general_error_xml" + } } } } @@ -197,6 +307,15 @@ "schema": { "type": "integer" } + }, + { + "name": "format", + "in": "query", + "description": "response body format", + "required": false, + "schema": { + "enum": ["json", "xml", "yaml"] + } } ], "responses": { @@ -211,6 +330,16 @@ "schema": { "$ref": "#/components/schemas/general_error" } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/general_error" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/general_error_xml" + } } } } @@ -231,6 +360,15 @@ "schema": { "type": "integer" } + }, + { + "name": "format", + "in": "query", + "description": "response body format", + "required": false, + "schema": { + "enum": ["json", "xml", "yaml"] + } } ], "requestBody": { @@ -263,6 +401,16 @@ "schema": { "$ref": "#/components/schemas/general_error" } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/general_error" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/general_error_xml" + } } } }, @@ -273,6 +421,16 @@ "schema": { "$ref": "#/components/schemas/general_error" } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/general_error" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/general_error_xml" + } } } }, @@ -283,6 +441,16 @@ "schema": { "$ref": "#/components/schemas/general_error" } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/general_error" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/general_error_xml" + } } } } @@ -300,6 +468,9 @@ }, "general_error": { "$ref": "./schema/general_error.json" + }, + "general_error_xml": { + "$ref": "./schema/general_error_xml.json" } } } diff --git a/assets/test_server/doc/schema/general_error_xml.json b/assets/test_server/doc/schema/general_error_xml.json new file mode 100644 index 0000000..d130077 --- /dev/null +++ b/assets/test_server/doc/schema/general_error_xml.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "general error", + "description": "general error", + "type": "object", + "properties": {}, + "additionalProperties": false, + "xml": { + "name": "Error" + } +} \ No newline at end of file diff --git a/assets/test_server/doc/schema/user/user.json b/assets/test_server/doc/schema/user/user.json index 17d0d73..7e0955b 100644 --- a/assets/test_server/doc/schema/user/user.json +++ b/assets/test_server/doc/schema/user/user.json @@ -4,6 +4,9 @@ "description": "get user", "type": "object", "additionalProperties": false, + "xml": { + "name": "user" + }, "properties": { "id": { "type": "integer", diff --git a/features/test_server/avatar.feature b/features/test_server/json/avatar.feature similarity index 96% rename from features/test_server/avatar.feature rename to features/test_server/json/avatar.feature index cfe9d19..8fc4fa2 100644 --- a/features/test_server/avatar.feature +++ b/features/test_server/json/avatar.feature @@ -4,6 +4,7 @@ Feature: Send avatar file using multipart/form-data in HTTP(s) request. Background: Given I save "application/json" as "CONTENT_TYPE_JSON" + Given I generate a random word having from "5" to "10" of "russian" characters and save it as "RANDOM_FIRST_NAME" Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" @@ -56,7 +57,7 @@ Feature: Send avatar file using multipart/form-data in HTTP(s) request. #------------------------------------------------------------------------------------------------------------------- # Fetching user, to check whether avatar field appeared and has proper value. - When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}" with body and headers: + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=json" with body and headers: """ { "body": {}, @@ -75,7 +76,7 @@ Feature: Send avatar file using multipart/form-data in HTTP(s) request. #------------------------------------------------------------------------------------------------------------------- # Create new user using data generated in background section above. - When I send "POST" request to "{{.MY_APP_URL}}/users" with body and headers: + When I send "POST" request to "{{.MY_APP_URL}}/users?format=json" with body and headers: """ { "body": { @@ -95,7 +96,7 @@ Feature: Send avatar file using multipart/form-data in HTTP(s) request. And the response body should have format "JSON" And I save from the last response "JSON" node "id" as "USER_ID" - Given I prepare new "POST" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}/avatar" and save it as "AVATAR_REQUEST" + Given I prepare new "POST" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}/avatar?format=json" and save it as "AVATAR_REQUEST" #------------------------------------------------------------------------------------------------------------------- # This form has invalid name property diff --git a/features/test_server/create.feature b/features/test_server/json/create.feature similarity index 97% rename from features/test_server/create.feature rename to features/test_server/json/create.feature index ba05086..a55600b 100644 --- a/features/test_server/create.feature +++ b/features/test_server/json/create.feature @@ -18,6 +18,7 @@ Feature: Adding new user Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" Given I save "application/json" as "CONTENT_TYPE_JSON" + @wip Scenario: Successfully create user v1 As application user I would like to create new account @@ -26,7 +27,7 @@ Feature: Adding new user # We send HTTP(s) request using pre-generated data to create new user. # Accessing saved data from scenario cache is done through template syntax from text/template package. # Docstring may be in YAML or JSON format and should have "body" and "headers" keys. - When I send "POST" request to "{{.MY_APP_URL}}/users" with body and headers: + When I send "POST" request to "{{.MY_APP_URL}}/users?format=json" with body and headers: """ { "body": { @@ -97,7 +98,7 @@ Feature: Adding new user #--------------------------------------------------------------------------------------------------- # At first we prepare new HTTP(s) request and save it scenario cache under key "CREATE_USER" - Given I prepare new "POST" request to "{{.MY_APP_URL}}/users" and save it as "CREATE_USER" + Given I prepare new "POST" request to "{{.MY_APP_URL}}/users?format=json" and save it as "CREATE_USER" #--------------------------------------------------------------------------------------------------- # Secondly, we set Content-Type header for "CREATE_USER" request. @@ -157,7 +158,7 @@ Feature: Adding new user #--------------------------------------------------------------------------------------------------- # Request body's field description have type int instead of string - When I send "POST" request to "{{.MY_APP_URL}}/users" with body and headers: + When I send "POST" request to "{{.MY_APP_URL}}/users?format=json" with body and headers: """ { "body": { diff --git a/features/test_server/delete.feature b/features/test_server/json/delete.feature similarity index 96% rename from features/test_server/delete.feature rename to features/test_server/json/delete.feature index dedfea2..d6fe86c 100644 --- a/features/test_server/delete.feature +++ b/features/test_server/json/delete.feature @@ -15,7 +15,7 @@ Feature: Removing user #--------------------------------------------------------------------------------------------------- # Create new user using generated data from Background section above - When I send "POST" request to "{{.MY_APP_URL}}/users" with body and headers: + When I send "POST" request to "{{.MY_APP_URL}}/users?format=json" with body and headers: """ { "body": { @@ -38,7 +38,7 @@ Feature: Removing user #--------------------------------------------------------------------------------------------------- # We send HTTP(s) request to obtain previously created user - When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}" with body and headers: + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=json" with body and headers: """ { "body": {}, @@ -69,7 +69,7 @@ Feature: Removing user #--------------------------------------------------------------------------------------------------- # We send HTTP(s) request to prove there is no more user of id "USER_ID" - When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}" with body and headers: + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=json" with body and headers: """ { "body": {}, diff --git a/features/test_server/get_many.feature b/features/test_server/json/get_many.feature similarity index 93% rename from features/test_server/get_many.feature rename to features/test_server/json/get_many.feature index 3351258..f865770 100644 --- a/features/test_server/get_many.feature +++ b/features/test_server/json/get_many.feature @@ -16,7 +16,7 @@ Feature: Fetching many users. #--------------------------------------------------------------------------------------------------- # Create new user using generated data from Background section above - When I send "POST" request to "{{.MY_APP_URL}}/users" with body and headers: + When I send "POST" request to "{{.MY_APP_URL}}/users?format=json" with body and headers: """ { "body": { @@ -47,7 +47,7 @@ Feature: Fetching many users. #--------------------------------------------------------------------------------------------------- # We send HTTP(s) request with pre-generated data to create second user - When I send "POST" request to "{{.MY_APP_URL}}/users" with body and headers: + When I send "POST" request to "{{.MY_APP_URL}}/users?format=json" with body and headers: """ { "body": { @@ -70,7 +70,7 @@ Feature: Fetching many users. #--------------------------------------------------------------------------------------------------- # We send HTTP(s) request to fetch all users. - When I send "GET" request to "{{.MY_APP_URL}}/users" with body and headers: + When I send "GET" request to "{{.MY_APP_URL}}/users?format=json" with body and headers: """ { "body": {}, diff --git a/features/test_server/get_one.feature b/features/test_server/json/get_one.feature similarity index 95% rename from features/test_server/get_one.feature rename to features/test_server/json/get_one.feature index 22c4234..9966fde 100644 --- a/features/test_server/get_one.feature +++ b/features/test_server/json/get_one.feature @@ -15,7 +15,7 @@ Feature: Fetching single user. #--------------------------------------------------------------------------------------------------- # Create new user using generated data from Background section above. - When I send "POST" request to "{{.MY_APP_URL}}/users" with body and headers: + When I send "POST" request to "{{.MY_APP_URL}}/users?format=json" with body and headers: """ { "body": { @@ -39,7 +39,7 @@ Feature: Fetching single user. #--------------------------------------------------------------------------------------------------- # We send HTTP(s) request to obtain previously created user. - When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}" with body and headers: + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=json" with body and headers: """ { "body": {}, @@ -68,7 +68,7 @@ Feature: Fetching single user. #--------------------------------------------------------------------------------------------------- # We send HTTP(s) request with invalid userId path param - When I send "GET" request to "{{.MY_APP_URL}}/users/{{.NOT_EXISTING_USER_ID}}" with body and headers: + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.NOT_EXISTING_USER_ID}}?format=json" with body and headers: """ { "body": {}, diff --git a/features/test_server/replace.feature b/features/test_server/json/replace.feature similarity index 97% rename from features/test_server/replace.feature rename to features/test_server/json/replace.feature index 3884b88..b80ff05 100644 --- a/features/test_server/replace.feature +++ b/features/test_server/json/replace.feature @@ -16,7 +16,7 @@ Feature: Replacing single user account. #--------------------------------------------------------------------------------------------------- # Create new user using generated data from Background section above - When I send "POST" request to "{{.MY_APP_URL}}/users" with body and headers: + When I send "POST" request to "{{.MY_APP_URL}}/users?format=json" with body and headers: """ { "body": { @@ -40,7 +40,7 @@ Feature: Replacing single user account. #--------------------------------------------------------------------------------------------------- # We send HTTP(s) request to obtain previously created user - When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}" with body and headers: + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=json" with body and headers: """ { "body": {}, @@ -92,7 +92,7 @@ Feature: Replacing single user account. #--------------------------------------------------------------------------------------------------- # We send HTTP(s) request to obtain replaced user - When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}" with body and headers: + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=json" with body and headers: """ { "body": {}, @@ -118,7 +118,7 @@ Feature: Replacing single user account. #--------------------------------------------------------------------------------------------------- # Create new user using generated data from Background section above - When I send "POST" request to "{{.MY_APP_URL}}/users" with body and headers: + When I send "POST" request to "{{.MY_APP_URL}}/users?format=json" with body and headers: """ { "body": { @@ -169,7 +169,7 @@ Feature: Replacing single user account. #--------------------------------------------------------------------------------------------------- # We send HTTP(s) request to obtain previously created user and prove nothing has changed - When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}" with body and headers: + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=json" with body and headers: """ { "body": {}, diff --git a/features/test_server/xml/avatar.feature b/features/test_server/xml/avatar.feature new file mode 100644 index 0000000..7d16c91 --- /dev/null +++ b/features/test_server/xml/avatar.feature @@ -0,0 +1,111 @@ +Feature: Send avatar file using multipart/form-data in HTTP(s) request. + Server allows to send avatar for user account. + Endpoint: POST /users/:userId/avatar + + Background: + Given I save "application/xml" as "CONTENT_TYPE_XML" + Given I generate a random word having from "5" to "10" of "russian" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate a random sentence having from "2" to "4" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + Given I generate a random word having from "3" to "7" of "english" characters and save it as "RANDOM_AVATAR_NAME" + + Scenario: Successfully send avatar + As Application user + I would like to create new account + which will have avatar attached to it. + + #------------------------------------------------------------------------------------------------------------------- + # Create new user using data generated in background section above. + When I send "POST" request to "{{.MY_APP_URL}}/users?format=xml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "doe-{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "{{.CONTENT_TYPE_XML}}; charset=UTF-8" + And the response body should have format "XML" + And I save from the last response "XML" node "//id" as "USER_ID" + + Given I prepare new "POST" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}/avatar?format=xml" and save it as "AVATAR_REQUEST" + #------------------------------------------------------------------------------------------------------------------- + # Here, we create form which will be send through HTTP(s) request. + # Method automatically set Content-Type: multipart/form-data header with proper boundary. If you want to change + # Content-Type header to application/x-www-form-urlencoded, afterwards use step for setting headers to overwrite it + # To attach any file, use following syntax: file://path/to/file + Given I set following form for prepared request "AVATAR_REQUEST": + """ + { + "name": "{{.RANDOM_AVATAR_NAME}}.gif", + "avatar": "file://{{.CWD}}/assets/gifs/hand-pointing-left.gif" + } + """ + When I send request "AVATAR_REQUEST" + Then the response status code should be 200 + + #------------------------------------------------------------------------------------------------------------------- + # Fetching user, to check whether avatar field appeared and has proper value. + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=xml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + # file is uploaded in OS temporary folder: $TMPDIR/{{.USER_ID}}_{{.RANDOM_AVATAR_NAME}}.gif + And the "XML" node "//avatar" should be "string" of value "{{.RANDOM_AVATAR_NAME}}.gif" + + Scenario: Unsuccessful attempt to add avatar for user account + As application user + I would like to create new account and not be able to add avatar using invalid data + + #------------------------------------------------------------------------------------------------------------------- + # Create new user using data generated in background section above. + When I send "POST" request to "{{.MY_APP_URL}}/users?format=xml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "doe-{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "{{.CONTENT_TYPE_XML}}; charset=UTF-8" + And the response body should have format "XML" + And I save from the last response "XML" node "//id" as "USER_ID" + + Given I prepare new "POST" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}/avatar?format=xml" and save it as "AVATAR_REQUEST" + + #------------------------------------------------------------------------------------------------------------------- + # This form has invalid name property + Given I set following form for prepared request "AVATAR_REQUEST": + """ + { + "name": "", + "avatar": "file://{{.CWD}}/assets/gifs/hand-pointing-left.gif" + } + """ + When I send request "AVATAR_REQUEST" + Then the response status code should be 400 + And the "XML" response should have node "//Error" \ No newline at end of file diff --git a/features/test_server/xml/create.feature b/features/test_server/xml/create.feature new file mode 100644 index 0000000..55d2da2 --- /dev/null +++ b/features/test_server/xml/create.feature @@ -0,0 +1,139 @@ +Feature: Adding new user + User's CRUD API binary and it's documentation can be found in assets/test_server/ dir. It is web server with endpoints + - POST /users - creates new user + - GET /users - retrieve all users + - GET /users/{user_id} - retrieve user by user_id + - PUT /users/{user_id} - replace user by user_id + - DELETE /users/{user_id} - delete user by user_id + - POST /users/{user_id}/avatar - add avatar for user of user_id + + Background: + This section runs before every Scenario. Its main purpose is to generate random user data + and save it under provided key in scenario cache. + + Given I generate a random word having from "5" to "10" of "polish" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "3" to "7" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random sentence having from "3" to "4" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + Given I save "application/json" as "CONTENT_TYPE_JSON" + Given I save "application/xml" as "CONTENT_TYPE_XML" + + Scenario: Successfully create user v1 + As application user + I would like to create new account + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request using pre-generated data to create new user. + # Accessing saved data from scenario cache is done through template syntax from text/template package. + # Docstring may be in YAML or JSON format and should have "body" and "headers" keys. + When I send "POST" request to "{{.MY_APP_URL}}/users?format=xml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "doe-{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "{{.CONTENT_TYPE_JSON}}" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Length" + And the response should have header "Content-Type" of value "{{.CONTENT_TYPE_XML}}; charset=UTF-8" + And the response body should have format "XML" + And time between last request and response should be less than or equal to "2s" + And the "XML" node "//firstName" should be "string" of value "{{.RANDOM_FIRST_NAME}}" + And the "XML" node "//lastName" should be "string" of value "doe-{{.RANDOM_LAST_NAME}}" + And the "XML" node "//lastName" should match regExp "doe-.*" + And the "XML" node "//age" should be "int" of value "{{.RANDOM_AGE}}" + And the "XML" node "//description" should be "string" of value "{{.RANDOM_DESCRIPTION}}" + And the "XML" node "//friendSince" should be "string" of value "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + + Scenario: Successfully create user v2. + As application user + I would like to create new account + + #--------------------------------------------------------------------------------------------------- + # At first we prepare new HTTP(s) request and save it scenario cache under key "CREATE_USER" + Given I prepare new "POST" request to "{{.MY_APP_URL}}/users?format=xml" and save it as "CREATE_USER" + + #--------------------------------------------------------------------------------------------------- + # Secondly, we set Content-Type header for "CREATE_USER" request. + # Docstring may be in YAML or JSON format. + Given I set following headers for prepared request "CREATE_USER": + """ + --- + Content-Type: application/json + """ + + #--------------------------------------------------------------------------------------------------- + # Next, we set csrf_token cookie for "CREATE_USER" request. + # Docstring may be in YAML or JSON format + Given I set following cookies for prepared request "CREATE_USER": + """ + [ + { + "name": "csrf_token", + "value": "this_cookie_is_unnecessary_just_added_for_demonstration" + } + ] + """ + + #--------------------------------------------------------------------------------------------------- + # Lastly, we define request body for "CREATE_USER" request + # Notice, we use pre-generated values(from Background section above) + # using go templates syntax from text/template package. + Given I set following body for prepared request "CREATE_USER": + """ + { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "doe-{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format "2006-01-02T15:04:05Z"}}" + } + """ + #--------------------------------------------------------------------------------------------------- + # Finally, we send prepared request "CREATE_USER". + # Uncommenting lines next to step "I send request "CREATE_USER" will turn on debug mode for a while. + +# Given I start debug mode + When I send request "CREATE_USER" +# Given I stop debug mode + + #--------------------------------------------------------------------------------------------------- + # From now on, we make some assertions against response from "CREATE_USER" request + Then the response status code should be 201 + And the response should have header "Content-Type" of value "{{.CONTENT_TYPE_XML}}; charset=UTF-8" + And the response body should have format "XML" + And time between last request and response should be less than or equal to "2s" + + Scenario: Unsuccessful attempt to create new user due to invalid request body + As application user + I should not be able to create new account using invalid data + + #--------------------------------------------------------------------------------------------------- + # Request body's field description have type int instead of string + When I send "POST" request to "{{.MY_APP_URL}}/users?format=xml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "doe-{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": 2, + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "{{.CONTENT_TYPE_JSON}}" + } + } + """ + Then the response status code should be 400 + And the response body should have format "XML" + And the "XML" response should have node "//Error" \ No newline at end of file diff --git a/features/test_server/xml/delete.feature b/features/test_server/xml/delete.feature new file mode 100644 index 0000000..98a8cd6 --- /dev/null +++ b/features/test_server/xml/delete.feature @@ -0,0 +1,101 @@ +Feature: Removing user + Test from this feature focus on removing user account from app. + + Background: + Given I generate a random word having from "5" to "15" of "ASCII" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate a random sentence having from "5" to "10" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + + Scenario: Successfully remove user + As application user + I would like to create new account + and then I would like to remove it. + + #--------------------------------------------------------------------------------------------------- + # Create new user using generated data from Background section above + When I send "POST" request to "{{.MY_APP_URL}}/users?format=xml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response body should have format "XML" + And time between last request and response should be less than or equal to "2s" + And I save from the last response "XML" node "//id" as "USER_ID" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to obtain previously created user + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=xml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" + And time between last request and response should be less than or equal to "2s" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to delete user of id hold under cache key "USER_ID" + When I send "DELETE" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=xml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + And the response status code should be 204 + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to prove there is no more user of id "USER_ID" + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=xml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response body should have format "XML" + And the response status code should be 404 + + Scenario: Unsuccessful attempt to remove not existing user + As application user + I should not be able to remove not existing account + + Given I save "111122223333" as "NOT_EXISTING_USER_ID" + + #--------------------------------------------------------------------------------------------------- + # Unsuccessful attempt to delete user because of invalid path param userId + When I send "DELETE" request to "{{.MY_APP_URL}}/users/{{.NOT_EXISTING_USER_ID}}?format=xml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + And the response status code should be 400 + Then the response body should have format "XML" + And the "XML" response should have node "//Error" + And the "XML" node "//Error" should match regExp "could not find in database user of id .*" \ No newline at end of file diff --git a/features/test_server/xml/get_many.feature b/features/test_server/xml/get_many.feature new file mode 100644 index 0000000..b5b8642 --- /dev/null +++ b/features/test_server/xml/get_many.feature @@ -0,0 +1,81 @@ +Feature: Fetching many users. + Tests from this feature focus on fetching many users at once. + + Background: + Given I generate a random word having from "5" to "15" of "ASCII" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate a random sentence having from "5" to "10" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + + Scenario: Get users + As application user + I would like to create new account + and then I would like to create another account + and then I would like to fetch those accounts. + + #--------------------------------------------------------------------------------------------------- + # Create new user using generated data from Background section above + When I send "POST" request to "{{.MY_APP_URL}}/users?format=xml" with body and headers: + """ + { + "body": { + "firstName": "a", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" + And time between last request and response should be less than or equal to "2s" + + #--------------------------------------------------------------------------------------------------- + # We generate second user's data + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME2" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE2" + Given I generate a random sentence having from "5" to "10" of "english" words and save it as "RANDOM_DESCRIPTION2" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE2" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request with pre-generated data to create second user + When I send "POST" request to "{{.MY_APP_URL}}/users?format=xml" with body and headers: + """ + { + "body": { + "firstName": "b", + "lastName": "{{.RANDOM_LAST_NAME2}}", + "age": {{.RANDOM_AGE2}}, + "description": "{{.RANDOM_DESCRIPTION2}}", + "friendSince": "{{.MEET_DATE2.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" + And time between last request and response should be less than or equal to "2s" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to fetch all users. + When I send "GET" request to "{{.MY_APP_URL}}/users?format=xml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" \ No newline at end of file diff --git a/features/test_server/xml/get_one.feature b/features/test_server/xml/get_one.feature new file mode 100644 index 0000000..4cd879b --- /dev/null +++ b/features/test_server/xml/get_one.feature @@ -0,0 +1,80 @@ +Feature: Fetching single user. + Tests from this feature focus on fetching given user. + + Background: + Given I generate a random word having from "5" to "15" of "ASCII" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate a random sentence having from "5" to "10" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + + Scenario: Successfully get single user + As application user + I would like to create new account + and then fetch it. + + #--------------------------------------------------------------------------------------------------- + # Create new user using generated data from Background section above. + When I send "POST" request to "{{.MY_APP_URL}}/users?format=xml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" + And time between last request and response should be less than or equal to "2s" + And I save from the last response "XML" node "//id" as "USER_ID" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to obtain previously created user. + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=xml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" + And time between last request and response should be less than or equal to "2s" + And the "XML" node "//firstName" should be "string" of value "{{.RANDOM_FIRST_NAME}}" + And the "XML" node "//lastName" should be "string" of value "{{.RANDOM_LAST_NAME}}" + And the "XML" node "//age" should be "int" of value "{{.RANDOM_AGE}}" + And the "XML" node "//id" should be "int" of value "{{.USER_ID}}" + And the "XML" node "//description" should be "string" of value "{{.RANDOM_DESCRIPTION}}" + And the "XML" node "//friendSince" should be "string" of value "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + + Scenario: Unsuccessful attempt to fetch not existing user + As application user + I should not be able to fetch not existing account + + Given I save "111122223333" as "NOT_EXISTING_USER_ID" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request with invalid userId path param + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.NOT_EXISTING_USER_ID}}?format=xml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 404 + And the response body should have format "XML" + And the "XML" response should have node "//Error" \ No newline at end of file diff --git a/features/test_server/xml/replace.feature b/features/test_server/xml/replace.feature new file mode 100644 index 0000000..fc40c67 --- /dev/null +++ b/features/test_server/xml/replace.feature @@ -0,0 +1,211 @@ +Feature: Replacing single user account. + Tests from this feature focus on replacing existing user account with another. + + Background: + Given I generate a random word having from "5" to "15" of "ASCII" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate a random sentence having from "5" to "10" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + + Scenario: Successfully update user account + As application user + I would like to create new account + and then I would like to update this account + and then I would like to obtain this account to prove successful update. + + #--------------------------------------------------------------------------------------------------- + # Create new user using generated data from Background section above + When I send "POST" request to "{{.MY_APP_URL}}/users?format=xml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" + And time between last request and response should be less than or equal to "2s" + And I save from the last response "XML" node "//id" as "USER_ID" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to obtain previously created user + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=xml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" + And the "XML" node "//firstName" should be "string" of value "{{.RANDOM_FIRST_NAME}}" + And the "XML" node "//lastName" should be "string" of value "{{.RANDOM_LAST_NAME}}" + And the "XML" node "//age" should be "int" of value "{{.RANDOM_AGE}}" + And the "XML" node "//id" should be "int" of value "{{.USER_ID}}" + And the "XML" node "//description" should be "string" of value "{{.RANDOM_DESCRIPTION}}" + And the "XML" node "//friendSince" should be "string" of value "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + + #--------------------------------------------------------------------------------------------------- + # Here, we generate new user data. + Given I generate a random word having from "5" to "15" of "ASCII" characters and save it as "NEW_USER_RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "NEW_USER_RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "NEW_USER_RANDOM_AGE" + Given I generate a random sentence having from "1" to "17" of "english" words and save it as "NEW_USER_RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "340h" in time and save it as "NEW_USER_MEET_DATE" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to replace user + When I send "PUT" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=xml" with body and headers: + """ + { + "body": { + "firstName": "{{.NEW_USER_RANDOM_FIRST_NAME}}", + "lastName": "{{.NEW_USER_RANDOM_LAST_NAME}}", + "age": {{.NEW_USER_RANDOM_AGE}}, + "description": "{{.NEW_USER_RANDOM_DESCRIPTION}}", + "friendSince": "{{.NEW_USER_MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" + And time between last request and response should be less than or equal to "2s" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to obtain replaced user + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=xml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" + And the "XML" node "//firstName" should be "string" of value "{{.NEW_USER_RANDOM_FIRST_NAME}}" + And the "XML" node "//lastName" should be "string" of value "{{.NEW_USER_RANDOM_LAST_NAME}}" + And the "XML" node "//age" should be "int" of value "{{.NEW_USER_RANDOM_AGE}}" + And the "XML" node "//id" should be "int" of value "{{.USER_ID}}" + And the "XML" node "//description" should be "string" of value "{{.NEW_USER_RANDOM_DESCRIPTION}}" + And the "XML" node "//friendSince" should be "string" of value "{{.NEW_USER_MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + + Scenario: Unsuccessful attempt to replace user account with invalid data + As application user + I should not be able to update existing account with invalid data + + #--------------------------------------------------------------------------------------------------- + # Create new user using generated data from Background section above + When I send "POST" request to "{{.MY_APP_URL}}/users?format=xml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" + And time between last request and response should be less than or equal to "2s" + And I save from the last response "XML" node "//id" as "USER_ID" + + #--------------------------------------------------------------------------------------------------- + # Here, we generate new user data. + Given I generate a random "int" in the range from "18" to "48" and save it as "NEW_USER_RANDOM_AGE" + Given I generate current time and travel "backward" "340h" in time and save it as "NEW_USER_MEET_DATE" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to replace user + When I send "PUT" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=xml" with body and headers: + """ + { + "body": { + "firstName": "a", + "lastName": "b", + "age": {{.NEW_USER_RANDOM_AGE}}, + "description": 2, + "friendSince": "{{.NEW_USER_MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 400 + And the response body should have format "XML" + And the "XML" response should have node "//Error" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to obtain previously created user and prove nothing has changed + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=xml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/xml; charset=UTF-8" + And the response body should have format "XML" + And the "XML" node "//firstName" should be "string" of value "{{.RANDOM_FIRST_NAME}}" + And the "XML" node "//lastName" should be "string" of value "{{.RANDOM_LAST_NAME}}" + And the "XML" node "//age" should be "int" of value "{{.RANDOM_AGE}}" + And the "XML" node "//id" should be "int" of value "{{.USER_ID}}" + And the "XML" node "//description" should be "string" of value "{{.RANDOM_DESCRIPTION}}" + And the "XML" node "//friendSince" should be "string" of value "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + + Scenario: Unsuccessful attempt to replace not existing user + As application user + I would like to be not able to modify not existing account + + Given I save "111122223333" as "NOT_EXISTING_USER_ID" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to replace not existing user account + When I send "PUT" request to "{{.MY_APP_URL}}/users/{{.NOT_EXISTING_USER_ID}}?format=xml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 400 + And the response body should have format "XML" + And the "XML" response should have node "//Error" diff --git a/features/test_server/yaml/avatar.feature b/features/test_server/yaml/avatar.feature new file mode 100644 index 0000000..954d0d3 --- /dev/null +++ b/features/test_server/yaml/avatar.feature @@ -0,0 +1,111 @@ +Feature: Send avatar file using multipart/form-data in HTTP(s) request. + Server allows to send avatar for user account. + Endpoint: POST /users/:userId/avatar + + Background: + Given I save "application/x-yaml" as "CONTENT_TYPE_YAML" + Given I generate a random word having from "5" to "10" of "russian" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate a random sentence having from "2" to "4" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + Given I generate a random word having from "3" to "7" of "english" characters and save it as "RANDOM_AVATAR_NAME" + + Scenario: Successfully send avatar + As Application user + I would like to create new account + which will have avatar attached to it. + + #------------------------------------------------------------------------------------------------------------------- + # Create new user using data generated in background section above. + When I send "POST" request to "{{.MY_APP_URL}}/users?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "doe-{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "{{.CONTENT_TYPE_YAML}}" + And the response body should have format "YAML" + And I save from the last response "YAML" node "$.id" as "USER_ID" + + Given I prepare new "POST" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}/avatar" and save it as "AVATAR_REQUEST" + #------------------------------------------------------------------------------------------------------------------- + # Here, we create form which will be send through HTTP(s) request. + # Method automatically set Content-Type: multipart/form-data header with proper boundary. If you want to change + # Content-Type header to application/x-www-form-urlencoded, afterwards use step for setting headers to overwrite it + # To attach any file, use following syntax: file://path/to/file + Given I set following form for prepared request "AVATAR_REQUEST": + """ + { + "name": "{{.RANDOM_AVATAR_NAME}}.gif", + "avatar": "file://{{.CWD}}/assets/gifs/hand-pointing-left.gif" + } + """ + When I send request "AVATAR_REQUEST" + Then the response status code should be 200 + + #------------------------------------------------------------------------------------------------------------------- + # Fetching user, to check whether avatar field appeared and has proper value. + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=yaml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + # file is uploaded in OS temporary folder: $TMPDIR/{{.USER_ID}}_{{.RANDOM_AVATAR_NAME}}.gif + And the "YAML" node "$.avatar" should be "string" of value "{{.RANDOM_AVATAR_NAME}}.gif" + + Scenario: Unsuccessful attempt to add avatar for user account + As application user + I would like to create new account and not be able to add avatar using invalid data + + #------------------------------------------------------------------------------------------------------------------- + # Create new user using data generated in background section above. + When I send "POST" request to "{{.MY_APP_URL}}/users?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "doe-{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "{{.CONTENT_TYPE_YAML}}" + And the response body should have format "YAML" + And I save from the last response "YAML" node "$.id" as "USER_ID" + + Given I prepare new "POST" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}/avatar?format=yaml" and save it as "AVATAR_REQUEST" + + #------------------------------------------------------------------------------------------------------------------- + # This form has invalid name property + Given I set following form for prepared request "AVATAR_REQUEST": + """ + { + "name": "", + "avatar": "file://{{.CWD}}/assets/gifs/hand-pointing-left.gif" + } + """ + When I send request "AVATAR_REQUEST" + Then the response status code should be 400 + And the "YAML" response should have node "$.error" \ No newline at end of file diff --git a/features/test_server/yaml/create.feature b/features/test_server/yaml/create.feature new file mode 100644 index 0000000..fd3681c --- /dev/null +++ b/features/test_server/yaml/create.feature @@ -0,0 +1,139 @@ +Feature: Adding new user + User's CRUD API binary and it's documentation can be found in assets/test_server/ dir. It is web server with endpoints + - POST /users - creates new user + - GET /users - retrieve all users + - GET /users/{user_id} - retrieve user by user_id + - PUT /users/{user_id} - replace user by user_id + - DELETE /users/{user_id} - delete user by user_id + - POST /users/{user_id}/avatar - add avatar for user of user_id + + Background: + This section runs before every Scenario. Its main purpose is to generate random user data + and save it under provided key in scenario cache. + + Given I generate a random word having from "5" to "10" of "polish" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "3" to "7" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random sentence having from "3" to "4" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + Given I save "application/json" as "CONTENT_TYPE_JSON" + Given I save "application/x-yaml" as "CONTENT_TYPE_YAML" + + Scenario: Successfully create user v1 + As application user + I would like to create new account + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request using pre-generated data to create new user. + # Accessing saved data from scenario cache is done through template syntax from text/template package. + # Docstring may be in YAML or JSON format and should have "body" and "headers" keys. + When I send "POST" request to "{{.MY_APP_URL}}/users?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "doe-{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "{{.CONTENT_TYPE_JSON}}" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Length" + And the response should have header "Content-Type" of value "{{.CONTENT_TYPE_YAML}}" + And the response body should have format "YAML" + And time between last request and response should be less than or equal to "2s" + And the "YAML" node "$.firstName" should be "string" of value "{{.RANDOM_FIRST_NAME}}" + And the "YAML" node "$.lastName" should be "string" of value "doe-{{.RANDOM_LAST_NAME}}" + And the "YAML" node "$.lastName" should match regExp "doe-.*" + And the "YAML" node "$.age" should be "int" of value "{{.RANDOM_AGE}}" + And the "YAML" node "$.description" should be "string" of value "{{.RANDOM_DESCRIPTION}}" + And the "YAML" node "$.friendSince" should be "string" of value "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + + Scenario: Successfully create user v2. + As application user + I would like to create new account + + #--------------------------------------------------------------------------------------------------- + # At first we prepare new HTTP(s) request and save it scenario cache under key "CREATE_USER" + Given I prepare new "POST" request to "{{.MY_APP_URL}}/users?format=yaml" and save it as "CREATE_USER" + + #--------------------------------------------------------------------------------------------------- + # Secondly, we set Content-Type header for "CREATE_USER" request. + # Docstring may be in YAML or JSON format. + Given I set following headers for prepared request "CREATE_USER": + """ + --- + Content-Type: application/json + """ + + #--------------------------------------------------------------------------------------------------- + # Next, we set csrf_token cookie for "CREATE_USER" request. + # Docstring may be in YAML or JSON format + Given I set following cookies for prepared request "CREATE_USER": + """ + [ + { + "name": "csrf_token", + "value": "this_cookie_is_unnecessary_just_added_for_demonstration" + } + ] + """ + + #--------------------------------------------------------------------------------------------------- + # Lastly, we define request body for "CREATE_USER" request + # Notice, we use pre-generated values(from Background section above) + # using go templates syntax from text/template package. + Given I set following body for prepared request "CREATE_USER": + """ + { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "doe-{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format "2006-01-02T15:04:05Z"}}" + } + """ + #--------------------------------------------------------------------------------------------------- + # Finally, we send prepared request "CREATE_USER". + # Uncommenting lines next to step "I send request "CREATE_USER" will turn on debug mode for a while. + +# Given I start debug mode + When I send request "CREATE_USER" +# Given I stop debug mode + + #--------------------------------------------------------------------------------------------------- + # From now on, we make some assertions against response from "CREATE_USER" request + Then the response status code should be 201 + And the response should have header "Content-Type" of value "{{.CONTENT_TYPE_YAML}}" + And the response body should have format "YAML" + And time between last request and response should be less than or equal to "2s" + + Scenario: Unsuccessful attempt to create new user due to invalid request body + As application user + I should not be able to create new account using invalid data + + #--------------------------------------------------------------------------------------------------- + # Request body's field description have type int instead of string + When I send "POST" request to "{{.MY_APP_URL}}/users?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "doe-{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": 2, + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "{{.CONTENT_TYPE_JSON}}" + } + } + """ + Then the response status code should be 400 + And the response body should have format "YAML" + And the "YAML" response should have node "$.error" \ No newline at end of file diff --git a/features/test_server/yaml/delete.feature b/features/test_server/yaml/delete.feature new file mode 100644 index 0000000..37eeeeb --- /dev/null +++ b/features/test_server/yaml/delete.feature @@ -0,0 +1,101 @@ +Feature: Removing user + Test from this feature focus on removing user account from app. + + Background: + Given I generate a random word having from "5" to "15" of "ASCII" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate a random sentence having from "5" to "10" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + + Scenario: Successfully remove user + As application user + I would like to create new account + and then I would like to remove it. + + #--------------------------------------------------------------------------------------------------- + # Create new user using generated data from Background section above + When I send "POST" request to "{{.MY_APP_URL}}/users?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response body should have format "YAML" + And time between last request and response should be less than or equal to "2s" + And I save from the last response "YAML" node "$.id" as "USER_ID" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to obtain previously created user + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=yaml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + And time between last request and response should be less than or equal to "2s" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to delete user of id hold under cache key "USER_ID" + When I send "DELETE" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=yaml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + And the response status code should be 204 + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to prove there is no more user of id "USER_ID" + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=yaml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response body should have format "YAML" + And the response status code should be 404 + + Scenario: Unsuccessful attempt to remove not existing user + As application user + I should not be able to remove not existing account + + Given I save "111122223333" as "NOT_EXISTING_USER_ID" + + #--------------------------------------------------------------------------------------------------- + # Unsuccessful attempt to delete user because of invalid path param userId + When I send "DELETE" request to "{{.MY_APP_URL}}/users/{{.NOT_EXISTING_USER_ID}}?format=yaml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + And the response status code should be 400 + Then the response body should have format "YAML" + And the "YAML" response should have node "$.error" + And the "YAML" node "$.error" should match regExp "could not find in database user of id .*" \ No newline at end of file diff --git a/features/test_server/yaml/get_many.feature b/features/test_server/yaml/get_many.feature new file mode 100644 index 0000000..f0b6615 --- /dev/null +++ b/features/test_server/yaml/get_many.feature @@ -0,0 +1,84 @@ +Feature: Fetching many users. + Tests from this feature focus on fetching many users at once. + + Background: + Given I generate a random word having from "5" to "15" of "ASCII" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate a random sentence having from "5" to "10" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + + Scenario: Get users + As application user + I would like to create new account + and then I would like to create another account + and then I would like to fetch those accounts. + + #--------------------------------------------------------------------------------------------------- + # Create new user using generated data from Background section above + When I send "POST" request to "{{.MY_APP_URL}}/users?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + And time between last request and response should be less than or equal to "2s" + + #--------------------------------------------------------------------------------------------------- + # We generate second user's data + Given I generate a random word having from "5" to "15" of "ASCII" characters and save it as "RANDOM_FIRST_NAME2" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME2" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE2" + Given I generate a random sentence having from "5" to "10" of "english" words and save it as "RANDOM_DESCRIPTION2" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE2" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request with pre-generated data to create second user + When I send "POST" request to "{{.MY_APP_URL}}/users?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME2}}", + "lastName": "{{.RANDOM_LAST_NAME2}}", + "age": {{.RANDOM_AGE2}}, + "description": "{{.RANDOM_DESCRIPTION2}}", + "friendSince": "{{.MEET_DATE2.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + And time between last request and response should be less than or equal to "2s" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to fetch all users. + When I send "GET" request to "{{.MY_APP_URL}}/users?format=yaml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + # here we only check only node type, not its exact value + And the "YAML" node "$." should be "slice" \ No newline at end of file diff --git a/features/test_server/yaml/get_one.feature b/features/test_server/yaml/get_one.feature new file mode 100644 index 0000000..b134323 --- /dev/null +++ b/features/test_server/yaml/get_one.feature @@ -0,0 +1,80 @@ +Feature: Fetching single user. + Tests from this feature focus on fetching given user. + + Background: + Given I generate a random word having from "5" to "15" of "ASCII" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate a random sentence having from "5" to "10" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + + Scenario: Successfully get single user + As application user + I would like to create new account + and then fetch it. + + #--------------------------------------------------------------------------------------------------- + # Create new user using generated data from Background section above. + When I send "POST" request to "{{.MY_APP_URL}}/users?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + And time between last request and response should be less than or equal to "2s" + And I save from the last response "YAML" node "$.id" as "USER_ID" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to obtain previously created user. + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=yaml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + And time between last request and response should be less than or equal to "2s" + And the "YAML" node "$.firstName" should be "string" of value "{{.RANDOM_FIRST_NAME}}" + And the "YAML" node "$.lastName" should be "string" of value "{{.RANDOM_LAST_NAME}}" + And the "YAML" node "$.age" should be "int" of value "{{.RANDOM_AGE}}" + And the "YAML" node "$.id" should be "int" of value "{{.USER_ID}}" + And the "YAML" node "$.description" should be "string" of value "{{.RANDOM_DESCRIPTION}}" + And the "YAML" node "$.friendSince" should be "string" of value "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + + Scenario: Unsuccessful attempt to fetch not existing user + As application user + I should not be able to fetch not existing account + + Given I save "111122223333" as "NOT_EXISTING_USER_ID" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request with invalid userId path param + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.NOT_EXISTING_USER_ID}}?format=yaml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 404 + And the response body should have format "YAML" + And the "YAML" response should have node "$.error" \ No newline at end of file diff --git a/features/test_server/yaml/replace.feature b/features/test_server/yaml/replace.feature new file mode 100644 index 0000000..b5635dc --- /dev/null +++ b/features/test_server/yaml/replace.feature @@ -0,0 +1,211 @@ +Feature: Replacing single user account. + Tests from this feature focus on replacing existing user account with another. + + Background: + Given I generate a random word having from "5" to "15" of "ASCII" characters and save it as "RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "RANDOM_AGE" + Given I generate a random sentence having from "5" to "10" of "english" words and save it as "RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "240h" in time and save it as "MEET_DATE" + + Scenario: Successfully update user account + As application user + I would like to create new account + and then I would like to update this account + and then I would like to obtain this account to prove successful update. + + #--------------------------------------------------------------------------------------------------- + # Create new user using generated data from Background section above + When I send "POST" request to "{{.MY_APP_URL}}/users?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + And time between last request and response should be less than or equal to "2s" + And I save from the last response "YAML" node "$.id" as "USER_ID" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to obtain previously created user + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=yaml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + And the "YAML" node "$.firstName" should be "string" of value "{{.RANDOM_FIRST_NAME}}" + And the "YAML" node "$.lastName" should be "string" of value "{{.RANDOM_LAST_NAME}}" + And the "YAML" node "$.age" should be "int" of value "{{.RANDOM_AGE}}" + And the "YAML" node "$.id" should be "int" of value "{{.USER_ID}}" + And the "YAML" node "$.description" should be "string" of value "{{.RANDOM_DESCRIPTION}}" + And the "YAML" node "$.friendSince" should be "string" of value "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + + #--------------------------------------------------------------------------------------------------- + # Here, we generate new user data. + Given I generate a random word having from "5" to "15" of "ASCII" characters and save it as "NEW_USER_RANDOM_FIRST_NAME" + Given I generate a random word having from "5" to "15" of "UNICODE" characters and save it as "NEW_USER_RANDOM_LAST_NAME" + Given I generate a random "int" in the range from "18" to "48" and save it as "NEW_USER_RANDOM_AGE" + Given I generate a random sentence having from "1" to "17" of "english" words and save it as "NEW_USER_RANDOM_DESCRIPTION" + Given I generate current time and travel "backward" "340h" in time and save it as "NEW_USER_MEET_DATE" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to replace user + When I send "PUT" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.NEW_USER_RANDOM_FIRST_NAME}}", + "lastName": "{{.NEW_USER_RANDOM_LAST_NAME}}", + "age": {{.NEW_USER_RANDOM_AGE}}, + "description": "{{.NEW_USER_RANDOM_DESCRIPTION}}", + "friendSince": "{{.NEW_USER_MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + And time between last request and response should be less than or equal to "2s" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to obtain replaced user + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=yaml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + And the "YAML" node "$.firstName" should be "string" of value "{{.NEW_USER_RANDOM_FIRST_NAME}}" + And the "YAML" node "$.lastName" should be "string" of value "{{.NEW_USER_RANDOM_LAST_NAME}}" + And the "YAML" node "$.age" should be "int" of value "{{.NEW_USER_RANDOM_AGE}}" + And the "YAML" node "$.id" should be "int" of value "{{.USER_ID}}" + And the "YAML" node "$.description" should be "string" of value "{{.NEW_USER_RANDOM_DESCRIPTION}}" + And the "YAML" node "$.friendSince" should be "string" of value "{{.NEW_USER_MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + + Scenario: Unsuccessful attempt to replace user account with invalid data + As application user + I should not be able to update existing account with invalid data + + #--------------------------------------------------------------------------------------------------- + # Create new user using generated data from Background section above + When I send "POST" request to "{{.MY_APP_URL}}/users?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 201 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + And time between last request and response should be less than or equal to "2s" + And I save from the last response "YAML" node "$.id" as "USER_ID" + + #--------------------------------------------------------------------------------------------------- + # Here, we generate new user data. + Given I generate a random "int" in the range from "18" to "48" and save it as "NEW_USER_RANDOM_AGE" + Given I generate current time and travel "backward" "340h" in time and save it as "NEW_USER_MEET_DATE" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to replace user + When I send "PUT" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "a", + "lastName": "b", + "age": {{.NEW_USER_RANDOM_AGE}}, + "description": 2, + "friendSince": "{{.NEW_USER_MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 400 + And the response body should have format "YAML" + And the "YAML" response should have node "$.error" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to obtain previously created user and prove nothing has changed + When I send "GET" request to "{{.MY_APP_URL}}/users/{{.USER_ID}}?format=yaml" with body and headers: + """ + { + "body": {}, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 200 + And the response should have header "Content-Type" of value "application/x-yaml" + And the response body should have format "YAML" + And the "YAML" node "$.firstName" should be "string" of value "{{.RANDOM_FIRST_NAME}}" + And the "YAML" node "$.lastName" should be "string" of value "{{.RANDOM_LAST_NAME}}" + And the "YAML" node "$.age" should be "int" of value "{{.RANDOM_AGE}}" + And the "YAML" node "$.id" should be "int" of value "{{.USER_ID}}" + And the "YAML" node "$.description" should be "string" of value "{{.RANDOM_DESCRIPTION}}" + And the "YAML" node "$.friendSince" should be "string" of value "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + + Scenario: Unsuccessful attempt to replace not existing user + As application user + I would like to be not able to modify not existing account + + Given I save "111122223333" as "NOT_EXISTING_USER_ID" + + #--------------------------------------------------------------------------------------------------- + # We send HTTP(s) request to replace not existing user account + When I send "PUT" request to "{{.MY_APP_URL}}/users/{{.NOT_EXISTING_USER_ID}}?format=yaml" with body and headers: + """ + { + "body": { + "firstName": "{{.RANDOM_FIRST_NAME}}", + "lastName": "{{.RANDOM_LAST_NAME}}", + "age": {{.RANDOM_AGE}}, + "description": "{{.RANDOM_DESCRIPTION}}", + "friendSince": "{{.MEET_DATE.Format `2006-01-02T15:04:05Z`}}" + }, + "headers": { + "Content-Type": "application/json" + } + } + """ + Then the response status code should be 400 + And the response body should have format "YAML" + And the "YAML" response should have node "$.error" diff --git a/go.mod b/go.mod index fb0a089..951238f 100644 --- a/go.mod +++ b/go.mod @@ -5,16 +5,19 @@ go 1.17 require ( github.com/cucumber/godog v0.12.4 github.com/joho/godotenv v1.4.0 - github.com/pawelWritesCode/gdutils v0.12.3 + github.com/pawelWritesCode/gdutils v0.13.1 github.com/spf13/pflag v1.0.5 ) require ( + github.com/antchfx/xmlquery v1.3.9 // indirect + github.com/antchfx/xpath v1.2.0 // indirect github.com/cucumber/gherkin-go/v19 v19.0.3 // indirect github.com/cucumber/messages-go/v16 v16.0.1 // indirect github.com/fatih/color v1.13.0 // indirect github.com/goccy/go-yaml v1.9.5 // indirect github.com/gofrs/uuid v4.2.0+incompatible // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-memdb v1.3.2 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect @@ -26,7 +29,9 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect + golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc // indirect golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 // indirect + golang.org/x/text v0.3.2 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index cf0d7b1..ec4d754 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,10 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/antchfx/xmlquery v1.3.9 h1:Y+zyMdiUZ4fasTQTkDb3DflOXP7+obcYEh80SISBmnQ= +github.com/antchfx/xmlquery v1.3.9/go.mod h1:wojC/BxjEkjJt6dPiAqUzoXO5nIMWtxHS8PD8TmN4ks= +github.com/antchfx/xpath v1.2.0 h1:mbwv7co+x0RwgeGAOHdrKy89GvHaGvxxBtPK0uF9Zr8= +github.com/antchfx/xpath v1.2.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -71,6 +75,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -174,8 +180,8 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 h1:Yl0tPBa8QPjGmesFh1D0rDy+q1Twx6FyU7VWHi8wZbI= github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx5Vwu4gd2mmMZvVZsgIqNSaW3xxRThUJ0k/TPk4= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pawelWritesCode/gdutils v0.12.3 h1:N4wYuADDTshRMot1p8eR+LUlzSAhiHPzyyE95X+1P7Y= -github.com/pawelWritesCode/gdutils v0.12.3/go.mod h1:q8YnXFPp3bsNooHG+yOczIlzCuHvkRnNMuFo7L985wk= +github.com/pawelWritesCode/gdutils v0.13.1 h1:03BhM9dLPQtYfZCSlUdGcYdgLWiTQTJQ+DR1JnnN6Mk= +github.com/pawelWritesCode/gdutils v0.13.1/go.mod h1:EN3UFzXecxhUGFEA15KIm+dTL5bBtJ6OMa5RQ+sifjg= github.com/pawelWritesCode/qjson v1.0.1 h1:MreBuXjjQj2XROgrGK5e9rWDiwLzDO4TyMyo8IvYP9M= github.com/pawelWritesCode/qjson v1.0.1/go.mod h1:BBj5FLhYUYGE8lNCKdz+MjJab+2fFcs+s9NFDDFjjnk= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -277,6 +283,8 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -300,12 +308,14 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 h1:BXxu8t6QN0G1uff4bzZzSkpsax8+ALqTGUtz08QrV00= golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/main_test.go b/main_test.go index 48b290d..ef3cbfd 100644 --- a/main_test.go +++ b/main_test.go @@ -71,8 +71,7 @@ func InitializeScenario(ctx *godog.ScenarioContext) { // Here you can define more scenario-scoped values using scenario.State.Cache.Save() method scenario.State.Cache.Save("MY_APP_URL", os.Getenv(envMyAppURL)) - scenario.State.Cache.Save("NOW", time.Now().Format(time.RFC3339)) - scenario.State.Cache.Save("CWD", wd) + scenario.State.Cache.Save("CWD", wd) // current working directory - full OS path to this file return ctx, nil }) @@ -137,7 +136,7 @@ func InitializeScenario(ctx *godog.ScenarioContext) { |---------------------------------------------------------------------------------------------------------------- | | This section contains assertions against last HTTP(s) responses, especially: - | - response body JSON nodes, + | - response body nodes, | - HTTP(s) headers, | - HTTP(s) cookies, | - HTTP(s) status code, @@ -148,6 +147,7 @@ func InitializeScenario(ctx *godog.ScenarioContext) { | https://github.com/pawelWritesCode/qjson (JSON) | https://github.com/oliveagle/jsonpath (JSON) | https://github.com/goccy/go-yaml (YAML) + | https://github.com/antchfx/xmlquery (XML) | | Method "the response should have nodes" accepts list of nodes, | separated with comma ",". For example: "data[0].user, $.data[1].user, data". @@ -169,20 +169,20 @@ func InitializeScenario(ctx *godog.ScenarioContext) { ctx.Step(`^the response status code should be (\d+)$`, scenario.TheResponseStatusCodeShouldBe) - ctx.Step(`^the "(JSON|YAML)" response should have nodes "([^"]*)"$`, scenario.TheResponseShouldHaveNodes) - ctx.Step(`^the "(JSON|YAML)" response should have node "([^"]*)"$`, scenario.TheResponseShouldHaveNode) + ctx.Step(`^the "(JSON|YAML|XML)" response should have nodes "([^"]*)"$`, scenario.TheResponseShouldHaveNodes) + ctx.Step(`^the "(JSON|YAML|XML)" response should have node "([^"]*)"$`, scenario.TheResponseShouldHaveNode) - ctx.Step(`^the "(JSON|YAML)" node "([^"]*)" should be "(string|int|float|bool)" of value "([^"]*)"$`, scenario.TheNodeShouldBeOfValue) - ctx.Step(`^the "(JSON|YAML)" node "([^"]*)" should be slice of length "(\d+)"$`, scenario.TheNodeShouldBeSliceOfLength) + ctx.Step(`^the "(JSON|YAML|XML)" node "([^"]*)" should be "(string|int|float|bool)" of value "([^"]*)"$`, scenario.TheNodeShouldBeOfValue) + ctx.Step(`^the "(JSON|YAML|XML)" node "([^"]*)" should be slice of length "(\d+)"$`, scenario.TheNodeShouldBeSliceOfLength) ctx.Step(`^the "(JSON|YAML)" node "([^"]*)" should be "(nil|string|int|float|bool|map|slice)"$`, scenario.TheNodeShouldBe) ctx.Step(`^the "(JSON|YAML)" node "([^"]*)" should not be "(nil|string|int|float|bool|map|slice)"$`, scenario.TheNodeShouldNotBe) - ctx.Step(`^the "(JSON|YAML)" node "([^"]*)" should match regExp "([^"]*)"$`, scenario.TheNodeShouldMatchRegExp) + ctx.Step(`^the "(JSON|YAML|XML)" node "([^"]*)" should match regExp "([^"]*)"$`, scenario.TheNodeShouldMatchRegExp) ctx.Step(`^the "(JSON|YAML)" node "([^"]*)" should be valid according to schema "([^"]*)"$`, scenario.IValidateNodeWithSchemaReference) ctx.Step(`^the "(JSON|YAML)" node "([^"]*)" should be valid according to schema:$`, scenario.IValidateNodeWithSchemaString) ctx.Step(`^the response body should be valid according to schema "([^"]*)"$`, scenario.IValidateLastResponseBodyWithSchema) ctx.Step(`^the response body should be valid according to schema:$`, scenario.IValidateLastResponseBodyWithFollowingSchema) - ctx.Step(`^the response body should have format "(JSON|YAML|plain text)"$`, scenario.TheResponseBodyShouldHaveFormat) + ctx.Step(`^the response body should have format "(JSON|YAML|XML|plain text)"$`, scenario.TheResponseBodyShouldHaveFormat) ctx.Step(`^time between last request and response should be less than or equal to "([^"]*)"$`, scenario.TimeBetweenLastHTTPRequestResponseShouldBeLessThanOrEqualTo) @@ -198,9 +198,10 @@ func InitializeScenario(ctx *godog.ScenarioContext) { | https://github.com/pawelWritesCode/qjson (JSON) | https://github.com/oliveagle/jsonpath (JSON) | https://github.com/goccy/go-yaml (YAML) + | https://github.com/antchfx/xmlquery (XML) */ ctx.Step(`^I save "([^"]*)" as "([^"]*)"$`, scenario.ISaveAs) - ctx.Step(`^I save from the last response "(JSON|YAML)" node "([^"]*)" as "([^"]*)"$`, scenario.ISaveFromTheLastResponseNodeAs) + ctx.Step(`^I save from the last response "(JSON|YAML|XML)" node "([^"]*)" as "([^"]*)"$`, scenario.ISaveFromTheLastResponseNodeAs) /* |----------------------------------------------------------------------------------------------------------------