diff --git a/README.md b/README.md index a2b8b811e38..171ec372cc0 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,7 @@ Table of Contents * [HTTP Headers](#http-headers) * [Query Params](#query-params) * [Basic Authentication](#basic-authentication) + * [Passing Data between Requests ](#passing-data-between-requests) * [Sending Data](#sending-data) * [Sending HTML Form Data](#sending-html-form-data) * [Sending Multipart Form Data](#sending-multipart-form-data) @@ -191,12 +192,19 @@ Table of Contents * [Templating a XML Body](#templating-a-xml-body) * [Using GraphQL Query](#using-graphql-query) * [Testing Response](#testing-response) + * [Testing Status Code](#testing-status-code) * [Testing Response Headers](#testing-response-headers) * [Testing REST APIs](#testing-rest-apis) * [Testing HTML Response](#testing-html-response) * [Testing Set-Cookie Attributes](#testing-set-cookie-attributes) * [Testing Bytes Content](#testing-bytes-content) * [SSL Certificate](#ssl-certificate) + * [Checking Full Body](#checking-full-body) + * [Reports](#reports) + * [HTML Report](#html-report) + * [JUnit Report](#junit-report) + * [TAP Report](#tap-report) + * [JSON Output](#json-output) * [Others](#others) * [HTTP Version](#http-version) * [Polling and Retry](#polling-and-retry) @@ -267,6 +275,18 @@ oriented output, you can use [`--test` option]: $ hurl --test sample.hurl ``` +A particular response can be saved with [`[Options] section`][option]: + +```hurl +GET https://example.ord/cats/123 +[Options] +output: cat123.txt # use - to output to stdout +HTTP 200 + +GET https://example.ord/dogs/567 +HTTP 200 +``` + You can check [Hurl tests suite] for more samples. @@ -278,6 +298,15 @@ A simple GET: GET https://example.org ``` +Requests can be chained: + +```hurl +GET https://example.org/a +GET https://example.org/b +HEAD https://example.org/c +GET https://example.org/c +``` + [Doc](https://hurl.dev/docs/request.html#method) ### HTTP Headers @@ -311,6 +340,8 @@ Or: GET https://example.org/news?order=newest&search=something%20to%20search&count=100 ``` +> With `[QueryStringParams]` section, params don't need to be URL escaped. + [Doc](https://hurl.dev/docs/request.html#query-parameters) ### Basic Authentication @@ -331,9 +362,42 @@ GET https://example.org/protected Authorization: Basic Ym9iOnNlY3JldA== ``` -Basic authentication allows per request authentication. -If you want to add basic authentication to all the requests of a Hurl file -you could use [`-u/--user` option]. +Basic authentication section allows per request authentication. If you want to add basic authentication to all the +requests of a Hurl file you could use [`-u/--user` option]: + +```shell +$ hurl --user bob=secret login.hurl +``` + +[`--user`] option can also be set per request: + +```hurl +GET https://example.org/login +[Options] +user: bob:secret +HTTP 200 + +GET https://example.org/login +[Options] +user: alice:secret +HTTP 200 +``` + +### Passing Data between Requests + +[Captures] can be used to pass data from one request to another: + +```hurl +POST https://sample.org/orders +HTTP 201 +[Captures] +order_id: jsonpath "$.order.id" + +GET https://sample.org/orders/{{order_id}} +HTTP 200 +``` + +[Doc](https://hurl.dev/docs/capturing-response.html) ## Sending Data @@ -514,6 +578,44 @@ GraphQL queries can also use [Hurl templates]. ## Testing Response +Responses are optional, everything after `HTTP` is part of the response asserts. + +```hurl +# A request with (almost) no check: +GET https://foo.com + +# A status code check: +GET https://foo.com +HTTP 200 + +# A test on response body +GET https://foo.com +HTTP 200 +[Asserts] +jsonpath "$.state" == "running" +``` + +### Testing Status Code + +```hurl +GET https://example.org/order/435 +HTTP 200 +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#version-status) + +```hurl +GET https://example.org/order/435 +# Testing status code is in a 200-300 range +HTTP * +[Asserts] +status >= 200 +status < 300 +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#status-assert) + + ### Testing Response Headers Use implicit response asserts to test header values: @@ -539,6 +641,16 @@ header "Location" contains "www.example.net" [Doc](https://hurl.dev/docs/asserting-response.html#header-assert) +Implicit and explicit asserts can be combined: + +```hurl +GET https://example.org/index.html +HTTP 200 +Set-Cookie: theme=light +Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT +[Asserts] +header "Location" contains "www.example.net" +``` ### Testing REST APIs @@ -563,27 +675,6 @@ jsonpath "$.created" isIsoDate [Doc](https://hurl.dev/docs/asserting-response.html#jsonpath-assert) -Testing status code: - -```hurl -GET https://example.org/order/435 -HTTP 200 -``` - -[Doc](https://hurl.dev/docs/asserting-response.html#version-status) - -```hurl -GET https://example.org/order/435 -# Testing status code is in a 200-300 range -HTTP * -[Asserts] -status >= 200 -status < 300 -``` - -[Doc](https://hurl.dev/docs/asserting-response.html#status-assert) - - ### Testing HTML Response ```hurl @@ -646,16 +737,141 @@ certificate "Serial-Number" matches /[\da-f]+/ [Doc](https://hurl.dev/docs/asserting-response.html#ssl-certificate-assert) +### Checking Full Body + +Use implicit body to test an exact JSON body match: + +```hurl +GET https://example.org/api/cats/123 +HTTP 200 +{ + "name" : "Purrsloud", + "species" : "Cat", + "favFoods" : ["wet food", "dry food", "any food"], + "birthYear" : 2016, + "photo" : "https://learnwebcode.github.io/json-example/images/cat-2.jpg" +} +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#json-body) + +Or an explicit assert file: + +```hurl +GET https://example.org/index.html +HTTP 200 +[Asserts] +body == file,cat.json; +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#body-assert) + +Implicit asserts supports XML body: + +```hurl +GET https://example.org/api/catalog +HTTP 200 + + + + Gambardella, Matthew + XML Developer's Guide + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications with XML. + + +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#xml-body) + +Plain text: + +~~~hurl +GET https://example.org/models +HTTP 200 +``` +Year,Make,Model,Description,Price +1997,Ford,E350,"ac, abs, moon",3000.00 +1999,Chevy,"Venture ""Extended Edition""","",4900.00 +1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00 +1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00 +``` +~~~ + +[Doc](https://hurl.dev/docs/asserting-response.html#multiline-string-body) + + +One line: + +```hurl +POST https://example.org/helloworld +HTTP 200 +`Hello world!` +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#oneline-string-body) + +File: + +```hurl +GET https://example.org +HTTP 200 +file,data.bin; +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#file-body) + + +## Reports + +### HTML Report + +```shell +$ hurl --test --report-html build/report/ *.hurl +``` + +[Doc](https://hurl.dev/docs/running-tests.html#generating-report) + +### JUnit Report + +```shell +$ hurl --test --report-junit build/report.xml *.hurl +``` + +[Doc](https://hurl.dev/docs/running-tests.html#generating-report) + +### TAP Report + +```shell +$ hurl --test --report-tap build/report.txt *.hurl +``` + +[Doc](https://hurl.dev/docs/running-tests.html#generating-report) + +### JSON Output + +A structured output of running Hurl files can be obtained with [`--json` option]. Each file will produce a JSON export of the run. + + +```shell +$ hurl --json *.hurl +``` + ## Others ### HTTP Version -Testing HTTP version (1.0, 1.1, 2 or 3): +Testing HTTP version (HTTP/1.0, HTTP/1.1, HTTP/2 or HTTP/3): ```hurl -GET https://example.org/order/435 +GET https://foo.com HTTP/3 200 + +GET https://bar.com +HTTP/2 200 ``` [Doc](https://hurl.dev/docs/asserting-response.html#version-status) @@ -706,7 +922,7 @@ HTTP 200 ### Skipping Requests ```hurl -# a, b, d are runner, c is skipped +# a, c, d are run, b is skipped GET https://example.org/a GET https://example.org/b @@ -792,7 +1008,17 @@ Action: GetCallerIdentity Version: 2011-06-15 ``` -The Access Key is given per [`--user`]. +The Access Key is given per [`--user`], either with command line option or within the [`[Options]`][option] section: + +```hurl +POST https://sts.eu-central-1.amazonaws.com/ +[Options] +aws-sigv4: aws:amz:eu-central-1:sts +user: bob=secret +[FormParams] +Action: GetCallerIdentity +Version: 2011-06-15 +``` [Doc](https://hurl.dev/docs/manual.html#aws-sigv4) @@ -1252,6 +1478,9 @@ Please follow the [contrib on Windows section]. [`--user`]: https://hurl.dev/docs/manual.html#user [Hurl templates]: https://hurl.dev/docs/templates.html [AWS Signature Version 4]: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html +[Captures]: https://hurl.dev/docs/capturing-response.html +[option]: https://hurl.dev/docs/request.html#options +[`--json` option]: https://hurl.dev/docs/manual.html#json [GitHub]: https://github.com/Orange-OpenSource/hurl [Hurl latest GitHub release]: https://github.com/Orange-OpenSource/hurl/releases/latest [AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository diff --git a/docs/frequently-asked-questions.md b/docs/frequently-asked-questions.md index 984695f6fc3..aa0df200743 100644 --- a/docs/frequently-asked-questions.md +++ b/docs/frequently-asked-questions.md @@ -182,10 +182,9 @@ For example, the Hurl file ```hurl GET https://example.org/api/users/1 User-Agent: Custom - -HTTP/1.1 200 +HTTP 200 [Asserts] -jsonpath "$.name" equals "Bob" +jsonpath "$.name" == "Bob" ``` will be converted to JSON with the following command: @@ -206,7 +205,7 @@ $ hurlfmt test.hurl --out json | jq ] }, "response": { - "version": "HTTP/1.1", + "version": "HTTP", "status": 200, "asserts": [ { @@ -215,7 +214,7 @@ $ hurlfmt test.hurl --out json | jq "expr": "$.name" }, "predicate": { - "type": "equal", + "type": "==", "value": "Bob" } } diff --git a/docs/manual/hurl.1 b/docs/manual/hurl.1 index 99a6a381555..edc9b4b0132 100644 --- a/docs/manual/hurl.1 +++ b/docs/manual/hurl.1 @@ -1,4 +1,4 @@ -.TH hurl 1 "01 Apr 2024" "hurl 4.3.0-SNAPSHOT" " Hurl Manual" +.TH hurl 1 "04 Apr 2024" "hurl 4.3.0-SNAPSHOT" " Hurl Manual" .SH NAME hurl - run and test HTTP requests. diff --git a/docs/manual/hurlfmt.1 b/docs/manual/hurlfmt.1 index e9f528efb5e..80c4e7d6c7a 100644 --- a/docs/manual/hurlfmt.1 +++ b/docs/manual/hurlfmt.1 @@ -1,4 +1,4 @@ -.TH hurl 1 "01 Apr 2024" "hurl 4.3.0-SNAPSHOT" " Hurl Manual" +.TH hurl 1 "04 Apr 2024" "hurl 4.3.0-SNAPSHOT" " Hurl Manual" .SH NAME hurlfmt - format Hurl files diff --git a/docs/request.md b/docs/request.md index 506eed603df..ca99557e3ce 100644 --- a/docs/request.md +++ b/docs/request.md @@ -650,6 +650,7 @@ output: out.html # dump the response to this file path-as-is: true # do not handle sequences of /../ or /./ in URL path skip: false # skip this request unix-socket: sock # use Unix socket for transfer +user: bob=secret # use basic authentication variable: country=Italy # define variable country variable: planet=Earth # define variable planet verbose: true # allow verbose output diff --git a/docs/samples.md b/docs/samples.md index 83476374418..717e388b769 100644 --- a/docs/samples.md +++ b/docs/samples.md @@ -17,6 +17,18 @@ oriented output, you can use [`--test` option]: $ hurl --test sample.hurl ``` +A particular response can be saved with [`[Options] section`][option]: + +```hurl +GET https://example.ord/cats/123 +[Options] +output: cat123.txt # use - to output to stdout +HTTP 200 + +GET https://example.ord/dogs/567 +HTTP 200 +``` + You can check [Hurl tests suite] for more samples. @@ -28,6 +40,15 @@ A simple GET: GET https://example.org ``` +Requests can be chained: + +```hurl +GET https://example.org/a +GET https://example.org/b +HEAD https://example.org/c +GET https://example.org/c +``` + [Doc](/docs/request.md#method) ### HTTP Headers @@ -61,6 +82,8 @@ Or: GET https://example.org/news?order=newest&search=something%20to%20search&count=100 ``` +> With `[QueryStringParams]` section, params don't need to be URL escaped. + [Doc](/docs/request.md#query-parameters) ### Basic Authentication @@ -81,9 +104,42 @@ GET https://example.org/protected Authorization: Basic Ym9iOnNlY3JldA== ``` -Basic authentication allows per request authentication. -If you want to add basic authentication to all the requests of a Hurl file -you could use [`-u/--user` option]. +Basic authentication section allows per request authentication. If you want to add basic authentication to all the +requests of a Hurl file you could use [`-u/--user` option]: + +```shell +$ hurl --user bob=secret login.hurl +``` + +[`--user`] option can also be set per request: + +```hurl +GET https://example.org/login +[Options] +user: bob:secret +HTTP 200 + +GET https://example.org/login +[Options] +user: alice:secret +HTTP 200 +``` + +### Passing Data between Requests + +[Captures] can be used to pass data from one request to another: + +```hurl +POST https://sample.org/orders +HTTP 201 +[Captures] +order_id: jsonpath "$.order.id" + +GET https://sample.org/orders/{{order_id}} +HTTP 200 +``` + +[Doc](/docs/capturing-response.md) ## Sending Data @@ -264,6 +320,44 @@ GraphQL queries can also use [Hurl templates]. ## Testing Response +Responses are optional, everything after `HTTP` is part of the response asserts. + +```hurl +# A request with (almost) no check: +GET https://foo.com + +# A status code check: +GET https://foo.com +HTTP 200 + +# A test on response body +GET https://foo.com +HTTP 200 +[Asserts] +jsonpath "$.state" == "running" +``` + +### Testing Status Code + +```hurl +GET https://example.org/order/435 +HTTP 200 +``` + +[Doc](/docs/asserting-response.md#version-status) + +```hurl +GET https://example.org/order/435 +# Testing status code is in a 200-300 range +HTTP * +[Asserts] +status >= 200 +status < 300 +``` + +[Doc](/docs/asserting-response.md#status-assert) + + ### Testing Response Headers Use implicit response asserts to test header values: @@ -289,6 +383,16 @@ header "Location" contains "www.example.net" [Doc](/docs/asserting-response.md#header-assert) +Implicit and explicit asserts can be combined: + +```hurl +GET https://example.org/index.html +HTTP 200 +Set-Cookie: theme=light +Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT +[Asserts] +header "Location" contains "www.example.net" +``` ### Testing REST APIs @@ -313,27 +417,6 @@ jsonpath "$.created" isIsoDate [Doc](/docs/asserting-response.md#jsonpath-assert) -Testing status code: - -```hurl -GET https://example.org/order/435 -HTTP 200 -``` - -[Doc](/docs/asserting-response.md#version-status) - -```hurl -GET https://example.org/order/435 -# Testing status code is in a 200-300 range -HTTP * -[Asserts] -status >= 200 -status < 300 -``` - -[Doc](/docs/asserting-response.md#status-assert) - - ### Testing HTML Response ```hurl @@ -396,16 +479,141 @@ certificate "Serial-Number" matches /[\da-f]+/ [Doc](/docs/asserting-response.md#ssl-certificate-assert) +### Checking Full Body + +Use implicit body to test an exact JSON body match: + +```hurl +GET https://example.org/api/cats/123 +HTTP 200 +{ + "name" : "Purrsloud", + "species" : "Cat", + "favFoods" : ["wet food", "dry food", "any food"], + "birthYear" : 2016, + "photo" : "https://learnwebcode.github.io/json-example/images/cat-2.jpg" +} +``` + +[Doc](/docs/asserting-response.md#json-body) + +Or an explicit assert file: + +```hurl +GET https://example.org/index.html +HTTP 200 +[Asserts] +body == file,cat.json; +``` + +[Doc](/docs/asserting-response.md#body-assert) + +Implicit asserts supports XML body: + +```hurl +GET https://example.org/api/catalog +HTTP 200 + + + + Gambardella, Matthew + XML Developer's Guide + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications with XML. + + +``` + +[Doc](/docs/asserting-response.md#xml-body) + +Plain text: + +~~~hurl +GET https://example.org/models +HTTP 200 +``` +Year,Make,Model,Description,Price +1997,Ford,E350,"ac, abs, moon",3000.00 +1999,Chevy,"Venture ""Extended Edition""","",4900.00 +1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00 +1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00 +``` +~~~ + +[Doc](/docs/asserting-response.md#multiline-string-body) + + +One line: + +```hurl +POST https://example.org/helloworld +HTTP 200 +`Hello world!` +``` + +[Doc](/docs/asserting-response.md#oneline-string-body) + +File: + +```hurl +GET https://example.org +HTTP 200 +file,data.bin; +``` + +[Doc](/docs/asserting-response.md#file-body) + + +## Reports + +### HTML Report + +```shell +$ hurl --test --report-html build/report/ *.hurl +``` + +[Doc](/docs/running-tests.md#generating-report) + +### JUnit Report + +```shell +$ hurl --test --report-junit build/report.xml *.hurl +``` + +[Doc](/docs/running-tests.md#generating-report) + +### TAP Report + +```shell +$ hurl --test --report-tap build/report.txt *.hurl +``` + +[Doc](/docs/running-tests.md#generating-report) + +### JSON Output + +A structured output of running Hurl files can be obtained with [`--json` option]. Each file will produce a JSON export of the run. + + +```shell +$ hurl --json *.hurl +``` + ## Others ### HTTP Version -Testing HTTP version (1.0, 1.1, 2 or 3): +Testing HTTP version (HTTP/1.0, HTTP/1.1, HTTP/2 or HTTP/3): ```hurl -GET https://example.org/order/435 +GET https://foo.com HTTP/3 200 + +GET https://bar.com +HTTP/2 200 ``` [Doc](/docs/asserting-response.md#version-status) @@ -456,7 +664,7 @@ HTTP 200 ### Skipping Requests ```hurl -# a, b, d are runner, c is skipped +# a, c, d are run, b is skipped GET https://example.org/a GET https://example.org/b @@ -542,7 +750,17 @@ Action: GetCallerIdentity Version: 2011-06-15 ``` -The Access Key is given per [`--user`]. +The Access Key is given per [`--user`], either with command line option or within the [`[Options]`][option] section: + +```hurl +POST https://sts.eu-central-1.amazonaws.com/ +[Options] +aws-sigv4: aws:amz:eu-central-1:sts +user: bob=secret +[FormParams] +Action: GetCallerIdentity +Version: 2011-06-15 +``` [Doc](/docs/manual.md#aws-sigv4) @@ -564,3 +782,6 @@ The Access Key is given per [`--user`]. [`--user`]: /docs/manual.md#user [Hurl templates]: /docs/templates.md [AWS Signature Version 4]: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html +[Captures]: /docs/capturing-response.md +[option]: /docs/request.md#options +[`--json` option]: /docs/manual.md#json diff --git a/docs/tutorial/debug-tips.md b/docs/tutorial/debug-tips.md index f293e5bd06d..6957c9ae7ca 100644 --- a/docs/tutorial/debug-tips.md +++ b/docs/tutorial/debug-tips.md @@ -77,6 +77,16 @@ $ hurl --verbose --no-output basic.hurl Lines beginning with `*` are debug info, lines that begin with `>` are HTTP request headers and lines that begin with `<` are HTTP response headers. +In each run request, we can also see a curl command line to replay this particular request: + +```shell +... +* Request can be run with the following curl command: +* curl --cookie 'x-session-id=s%3AEE3wsnrgUPSyAkgJZGa3jMWk7xmOtv4E.kXQpkmNBXnFOqmeSssqXnecF4qqv1D7bKu3rpbEJxmQ' 'http://localhost:3000/not-found' +... +``` + + In verbose mode, HTTP request and response bodies are not displayed in the debug logs. If you need to inspect the request or response body, you can display more logs with [`--very-verbose`] option: diff --git a/packages/hurl/README.md b/packages/hurl/README.md index 4b9d5d89276..b9d0205c877 100644 --- a/packages/hurl/README.md +++ b/packages/hurl/README.md @@ -175,6 +175,7 @@ Table of Contents * [HTTP Headers](#http-headers) * [Query Params](#query-params) * [Basic Authentication](#basic-authentication) + * [Passing Data between Requests ](#passing-data-between-requests) * [Sending Data](#sending-data) * [Sending HTML Form Data](#sending-html-form-data) * [Sending Multipart Form Data](#sending-multipart-form-data) @@ -183,12 +184,19 @@ Table of Contents * [Templating a XML Body](#templating-a-xml-body) * [Using GraphQL Query](#using-graphql-query) * [Testing Response](#testing-response) + * [Testing Status Code](#testing-status-code) * [Testing Response Headers](#testing-response-headers) * [Testing REST APIs](#testing-rest-apis) * [Testing HTML Response](#testing-html-response) * [Testing Set-Cookie Attributes](#testing-set-cookie-attributes) * [Testing Bytes Content](#testing-bytes-content) * [SSL Certificate](#ssl-certificate) + * [Checking Full Body](#checking-full-body) + * [Reports](#reports) + * [HTML Report](#html-report) + * [JUnit Report](#junit-report) + * [TAP Report](#tap-report) + * [JSON Output](#json-output) * [Others](#others) * [HTTP Version](#http-version) * [Polling and Retry](#polling-and-retry) @@ -259,6 +267,18 @@ oriented output, you can use [`--test` option]: $ hurl --test sample.hurl ``` +A particular response can be saved with [`[Options] section`][option]: + +```hurl +GET https://example.ord/cats/123 +[Options] +output: cat123.txt # use - to output to stdout +HTTP 200 + +GET https://example.ord/dogs/567 +HTTP 200 +``` + You can check [Hurl tests suite] for more samples. @@ -270,6 +290,15 @@ A simple GET: GET https://example.org ``` +Requests can be chained: + +```hurl +GET https://example.org/a +GET https://example.org/b +HEAD https://example.org/c +GET https://example.org/c +``` + [Doc](https://hurl.dev/docs/request.html#method) ### HTTP Headers @@ -303,6 +332,8 @@ Or: GET https://example.org/news?order=newest&search=something%20to%20search&count=100 ``` +> With `[QueryStringParams]` section, params don't need to be URL escaped. + [Doc](https://hurl.dev/docs/request.html#query-parameters) ### Basic Authentication @@ -323,9 +354,42 @@ GET https://example.org/protected Authorization: Basic Ym9iOnNlY3JldA== ``` -Basic authentication allows per request authentication. -If you want to add basic authentication to all the requests of a Hurl file -you could use [`-u/--user` option]. +Basic authentication section allows per request authentication. If you want to add basic authentication to all the +requests of a Hurl file you could use [`-u/--user` option]: + +```shell +$ hurl --user bob=secret login.hurl +``` + +[`--user`] option can also be set per request: + +```hurl +GET https://example.org/login +[Options] +user: bob:secret +HTTP 200 + +GET https://example.org/login +[Options] +user: alice:secret +HTTP 200 +``` + +### Passing Data between Requests + +[Captures] can be used to pass data from one request to another: + +```hurl +POST https://sample.org/orders +HTTP 201 +[Captures] +order_id: jsonpath "$.order.id" + +GET https://sample.org/orders/{{order_id}} +HTTP 200 +``` + +[Doc](https://hurl.dev/docs/capturing-response.html) ## Sending Data @@ -506,6 +570,44 @@ GraphQL queries can also use [Hurl templates]. ## Testing Response +Responses are optional, everything after `HTTP` is part of the response asserts. + +```hurl +# A request with (almost) no check: +GET https://foo.com + +# A status code check: +GET https://foo.com +HTTP 200 + +# A test on response body +GET https://foo.com +HTTP 200 +[Asserts] +jsonpath "$.state" == "running" +``` + +### Testing Status Code + +```hurl +GET https://example.org/order/435 +HTTP 200 +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#version-status) + +```hurl +GET https://example.org/order/435 +# Testing status code is in a 200-300 range +HTTP * +[Asserts] +status >= 200 +status < 300 +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#status-assert) + + ### Testing Response Headers Use implicit response asserts to test header values: @@ -531,6 +633,16 @@ header "Location" contains "www.example.net" [Doc](https://hurl.dev/docs/asserting-response.html#header-assert) +Implicit and explicit asserts can be combined: + +```hurl +GET https://example.org/index.html +HTTP 200 +Set-Cookie: theme=light +Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT +[Asserts] +header "Location" contains "www.example.net" +``` ### Testing REST APIs @@ -555,27 +667,6 @@ jsonpath "$.created" isIsoDate [Doc](https://hurl.dev/docs/asserting-response.html#jsonpath-assert) -Testing status code: - -```hurl -GET https://example.org/order/435 -HTTP 200 -``` - -[Doc](https://hurl.dev/docs/asserting-response.html#version-status) - -```hurl -GET https://example.org/order/435 -# Testing status code is in a 200-300 range -HTTP * -[Asserts] -status >= 200 -status < 300 -``` - -[Doc](https://hurl.dev/docs/asserting-response.html#status-assert) - - ### Testing HTML Response ```hurl @@ -638,16 +729,141 @@ certificate "Serial-Number" matches /[\da-f]+/ [Doc](https://hurl.dev/docs/asserting-response.html#ssl-certificate-assert) +### Checking Full Body + +Use implicit body to test an exact JSON body match: + +```hurl +GET https://example.org/api/cats/123 +HTTP 200 +{ + "name" : "Purrsloud", + "species" : "Cat", + "favFoods" : ["wet food", "dry food", "any food"], + "birthYear" : 2016, + "photo" : "https://learnwebcode.github.io/json-example/images/cat-2.jpg" +} +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#json-body) + +Or an explicit assert file: + +```hurl +GET https://example.org/index.html +HTTP 200 +[Asserts] +body == file,cat.json; +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#body-assert) + +Implicit asserts supports XML body: + +```hurl +GET https://example.org/api/catalog +HTTP 200 + + + + Gambardella, Matthew + XML Developer's Guide + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications with XML. + + +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#xml-body) + +Plain text: + +~~~hurl +GET https://example.org/models +HTTP 200 +``` +Year,Make,Model,Description,Price +1997,Ford,E350,"ac, abs, moon",3000.00 +1999,Chevy,"Venture ""Extended Edition""","",4900.00 +1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00 +1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00 +``` +~~~ + +[Doc](https://hurl.dev/docs/asserting-response.html#multiline-string-body) + + +One line: + +```hurl +POST https://example.org/helloworld +HTTP 200 +`Hello world!` +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#oneline-string-body) + +File: + +```hurl +GET https://example.org +HTTP 200 +file,data.bin; +``` + +[Doc](https://hurl.dev/docs/asserting-response.html#file-body) + + +## Reports + +### HTML Report + +```shell +$ hurl --test --report-html build/report/ *.hurl +``` + +[Doc](https://hurl.dev/docs/running-tests.html#generating-report) + +### JUnit Report + +```shell +$ hurl --test --report-junit build/report.xml *.hurl +``` + +[Doc](https://hurl.dev/docs/running-tests.html#generating-report) + +### TAP Report + +```shell +$ hurl --test --report-tap build/report.txt *.hurl +``` + +[Doc](https://hurl.dev/docs/running-tests.html#generating-report) + +### JSON Output + +A structured output of running Hurl files can be obtained with [`--json` option]. Each file will produce a JSON export of the run. + + +```shell +$ hurl --json *.hurl +``` + ## Others ### HTTP Version -Testing HTTP version (1.0, 1.1, 2 or 3): +Testing HTTP version (HTTP/1.0, HTTP/1.1, HTTP/2 or HTTP/3): ```hurl -GET https://example.org/order/435 +GET https://foo.com HTTP/3 200 + +GET https://bar.com +HTTP/2 200 ``` [Doc](https://hurl.dev/docs/asserting-response.html#version-status) @@ -698,7 +914,7 @@ HTTP 200 ### Skipping Requests ```hurl -# a, b, d are runner, c is skipped +# a, c, d are run, b is skipped GET https://example.org/a GET https://example.org/b @@ -784,7 +1000,17 @@ Action: GetCallerIdentity Version: 2011-06-15 ``` -The Access Key is given per [`--user`]. +The Access Key is given per [`--user`], either with command line option or within the [`[Options]`][option] section: + +```hurl +POST https://sts.eu-central-1.amazonaws.com/ +[Options] +aws-sigv4: aws:amz:eu-central-1:sts +user: bob=secret +[FormParams] +Action: GetCallerIdentity +Version: 2011-06-15 +``` [Doc](https://hurl.dev/docs/manual.html#aws-sigv4) @@ -1244,6 +1470,9 @@ Please follow the [contrib on Windows section]. [`--user`]: https://hurl.dev/docs/manual.html#user [Hurl templates]: https://hurl.dev/docs/templates.html [AWS Signature Version 4]: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html +[Captures]: https://hurl.dev/docs/capturing-response.html +[option]: https://hurl.dev/docs/request.html#options +[`--json` option]: https://hurl.dev/docs/manual.html#json [GitHub]: https://github.com/Orange-OpenSource/hurl [Hurl latest GitHub release]: https://github.com/Orange-OpenSource/hurl/releases/latest [AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository