hitspec has first-class support for GraphQL. Instead of manually constructing JSON bodies, you write queries in a >>>graphql block and variables in a >>>variables block. hitspec handles the rest.
Prerequisites
The Complete Test File
This example tests the Countries GraphQL API , a free public GraphQL endpoint.
Create a file called graphql.http:
@ baseUrl = https://countries.trevorblades.com
### Get a country by code
# @name getCountry
# @tags smoke
POST {{baseUrl}}/
Content-Type : application/json
>>>graphql
query GetCountry ( $code : ID ! ) {
country ( code : $code ) {
name
capital
currency
emoji
languages {
name
code
}
continent {
name
}
}
}
>>> variables
{
"code" : "US"
}
<<<
>>>
expect status 200
expect body . data . country . name == "United States"
expect body . data . country . capital == "Washington D.C."
expect body . data . country . currency contains "USD"
expect body . data . country . emoji exists
expect body . data . country . languages type array
expect body . data . country . languages length > 0
expect body . data . country . languages [0]. name == "English"
expect body . data . country . continent . name == "North America"
<<<
>>> capture
countryName from body . data . country . name
continentName from body . data . country . continent . name
<<<
### List all continents
# @name listContinents
# @tags smoke
POST {{baseUrl}}/
Content-Type : application/json
>>>graphql
query {
continents {
code
name
}
}
<<<
>>>
expect status 200
expect body . data . continents type array
expect body . data . continents length 7
expect body . data . continents [0]. code exists
expect body . data . continents [0]. name exists
<<<
### Get countries in a continent
# @name countriesInContinent
# @tags continent
# @depends getCountry
POST {{baseUrl}}/
Content-Type : application/json
>>>graphql
query GetContinent ( $code : ID ! ) {
continent ( code : $code ) {
name
countries {
name
capital
emoji
}
}
}
>>> variables
{
"code" : "NA"
}
<<<
>>>
expect status 200
expect body . data . continent . name == "North America"
expect body . data . continent . countries type array
expect body . data . continent . countries length > 0
<<<
>>> capture
countryCount from body . data . continent . countries . #
<<<
### Get languages
# @name getLanguages
# @tags language
POST {{baseUrl}}/
Content-Type : application/json
>>>graphql
query GetLanguage ( $code : ID ! ) {
language ( code : $code ) {
name
native
rtl
}
}
>>> variables
{
"code" : "en"
}
<<<
>>>
expect status 200
expect body . data . language . name == "English"
expect body . data . language . native == "English"
expect body . data . language . rtl == false
<<<
### Query with multiple filters
# @name filteredCountries
# @tags filter
POST {{baseUrl}}/
Content-Type : application/json
>>>graphql
query FilterCountries ( $filter : CountryFilterInput ) {
countries ( filter : $filter ) {
name
code
capital
continent {
name
}
}
}
>>> variables
{
"filter" : {
"continent" : {
"eq" : "NA"
}
}
}
<<<
>>>
expect status 200
expect body . data . countries type array
expect body . data . countries length > 0
expect body . data . countries each type object
<<<
Step-by-Step Breakdown
Write a GraphQL query with variables
The >>>graphql block contains the query, and >>>variables provides the variable values as JSON. POST {{baseUrl}}/
Content-Type : application/json
>>>graphql
query GetCountry ( $code : ID ! ) {
country ( code : $code ) {
name
capital
currency
}
}
>>> variables
{
"code" : "US"
}
<<<
hitspec converts this into the standard GraphQL JSON format: {
"query" : "query GetCountry($code: ID!) { country(code: $code) { name capital currency } }" ,
"variables" : { "code" : "US" }
}
You write the query naturally and hitspec handles the serialization.
Assert nested response fields
GraphQL responses have a data wrapper. Use dot notation to reach nested fields. >>>
expect status 200
expect body.data.country.name == "United States"
expect body.data.country.capital == "Washington D.C."
expect body.data.country.currency contains "USD"
expect body.data.country.languages type array
expect body.data.country.languages[ 0 ].name == "English"
expect body.data.country.continent.name == "North America"
<<<
The JSON path syntax supports:
Dot notation: body.data.country.name
Array indexing: body.data.country.languages[0].name
Length via gjson: body.data.country.languages.#
Capture values from GraphQL responses
Captures work the same way as with REST responses. Extract values for use in later requests. >>>capture
countryName from body.data.country.name
continentName from body.data.country.continent.name
<<<
These values are accessible as {{getCountry.countryName}} and {{getCountry.continentName}} in subsequent requests.
Query without variables
For queries with no variables, you can omit the >>>variables block. POST {{baseUrl}}/
Content-Type : application/json
>>>graphql
query {
continents {
code
name
}
}
<<<
Use the each operator for collections
The each operator applies an assertion to every element in an array. >>>
expect status 200
expect body.data.countries type array
expect body.data.countries each type object
<<<
This verifies that every item in the countries array is a JSON object.
Run the GraphQL tests
Run only smoke-tagged queries: hitspec run graphql.http --tags smoke
Expected output: getCountry (312ms)
listContinents (198ms)
countriesInContinent (245ms)
getLanguages (167ms)
filteredCountries (223ms)
5 passed, 0 failed
GraphQL Error Handling
GraphQL APIs return errors in a data.errors array. You can assert on these:
POST {{baseUrl}}/
Content-Type : application/json
>>>graphql
query {
nonExistentField {
id
}
}
<<<
>>>
expect status 200
expect body . errors exists
expect body . errors type array
expect body . errors length > 0
expect body . errors [0]. message exists
<<<
GraphQL APIs typically return HTTP 200 even for query errors. Always check body.errors in addition to the status code.
Next Steps
Multipart and GraphQL Full reference for GraphQL blocks and multipart uploads.
Assertions All 26 assertion operators available in hitspec.