~ 5 min read
Automate HTTP Testing with hurl: Generate HTML and JUnit reports via GitLab CI
Written by Brie Carranza
I read about hurl.dev on HN and was quite taken with the description:
Hurl is a command line tool that runs HTTP requests defined in a simple plain text format.
That sounds super useful for monitoring my various sites and projects around the Web. The tool even purports to be designed with CI/CD integration in mind.
I set it up to test the httpcat.us site I wrote about in my last post. In this post, I:
- Describe a super-simple
.hurl
file - Improve the
.hurl
file to check for content with asserts - Generate HTML and a JUnit Report from
hurl
- Run
hurl
via GitLab CI
TL;DR - 🔗 The code for this project is stored at gitlab.com/brie/hurl.
A super simple .hurl
file
The simplest .hurl
file looks something like this:
GET https://httpcat.us
That can be built on a bit:
GET https://httpcat.us
HTTP/* 200
With that content in a file like hello.hurl
, run hurl --test hello.hurl
and you’ll get something like this:
hello.hurl: Running [1/1]
hello.hurl: Success (1 request(s) in 103 ms)
--------------------------------------------------------------------------------
Executed files: 1
Succeeded files: 1 (100.0%)
Failed files: 0 (0.0%)
Duration: 108 ms
In order to ensure the site is served via HTTP/2
, the hello.hurl
file would look like this instead:
GET https://httpcat.us
HTTP/2 200
The syntax so far is pretty intuitive:
- We’re checking that we can
GET
https://httpcat.us
. - We can check for a specific version of
HTTP
and confirm that the response code is200
.
Let’s keep going. Let’s add a test for a page that should 404
. To do that, the hello.hurl
file gets updated to look like this:
GET https://httpcat.us
HTTP/2 200
GET https://httpcat.us/lolno
HTTP/2 404
Improve the .hurl
file to check for content with asserts
So far, we are checking that the site is reachable, is serving the expected version of HTTP and the desired HTTP response status code. That’s great but I want to test that the images on httpcat.us are present. We can do this by giving the appropriate XPath to hurl
.
You can use Chrome Developer Tools to identify, evaluate and validate XPath values. The linked article has more but in short:
- Open Developer Tools
- In the Console tab, navigate to the desired element
- Right-click > Copy > Copy XPath
Here’s how the hello.hurl
file we have been building looks with some Asserts
:
GET https://httpcat.us
HTTP/* 200
[Asserts]
xpath "string(//head/title)" == "HTTP Status Codes -- with cats"
xpath "string(//body/div/div/div[2]/div/p[2]/text()[1])" contains "👋"
xpath "//img" count == 6
I’ll summarize the purpose of each xpath
statement:
xpath “string(//head/title)” == “HTTP Status Codes — with cats”
This checks to make sure that the <title>
tag is exactly HTTP Status Codes -- with cats
.
xpath “string(//body/div/div/div[2]/div/p[2]/text()[1])” contains ”👋“
This checks to make sure that the selected text contains the 👋 emoji.
xpath “//img” count == 6
This checks that there are six <img>
tags on the front page. I want to make sure that each of the six cats on the home page is present. 🐱
The [Asserts]
section can also check response headers. These two lines can be added to the [Asserts]
section:
header "Content-Type" == "text/html; charset=utf-8"
header "Server" == "Google Frontend"
Let’s add in the tests for the headers and a few more tests for the 404
page:
GET https://httpcat.us
HTTP/* 200
[Asserts]
xpath "string(//head/title)" == "HTTP Status Codes -- with cats"
xpath "//img" count == 6
xpath "string(//body/div/div/div[2]/div/p[2]/text()[1])" contains "👋"
header "Content-Type" == "text/html; charset=utf-8"
header "Server" == "Google Frontend"
GET https://httpcat.us/not-found
HTTP/* 404
[Asserts]
header "Content-Type" == "text/html; charset=utf-8"
xpath "string(//h1)" == "MEOW?"
xpath "string(//h2)" == "What were you looking for?"
Awesome! The hello.hurl
file is complete. Let’s do more with it than hurl --test hello.hurl
.
Generating HTML and JUnit Reports with hurl
The manual documents a range of options. The ones we are interested in for this section are:
--report-html
--report-junit
To put the HTML report in a directory called public/
and the JUnit report file in a file called http.xml
, we’ll adjust our hurl
command to:
hurl --test --report-html public --report-junit http.xml hello.hurl
The hurl
tutorial and manual have more information on extending the content of the .hurl
file and the options when we run hurl
. Let’s put what we have in a pipeline. 💚
Running hurl
via GitLab CI
With the .hurl
file and the desired options ready, it’s time to put this all in a CI pipeline. The .gitlab-ci.yml
below will:
- Run the
.hurl
file - Serve the HTML report via GitLab Pages
- show the unit test reports in GitLab
pages:
image:
name: orangeopensource/hurl
entrypoint: [""]
script:
- hurl --test --report-html public --report-junit http.xml *.hurl
artifacts:
paths:
- http.xml
- public/
reports:
junit: http.xml
The HTML report generated by the hello.hurl
we have been building is at brie.gitlab.io/hurl.
🚀 Get started!
You can 🍴 fork the brie/hurl project to get up and running with hurl
in a CI pipeline.
In the linked project, the .gitlab-ci.yml
job is expanded to use the services
keyword. The services
keyword is used to start a Web server that the hurl
test are run against. This is useful if you don’t have a Web server to be tested ready just yet.
The .gitlab-ci.yml
from that project looks like this:
pages:
services:
- name: kennethreitz/httpbin
alias: httpbin
allow_failure: true
image:
name: orangeopensource/hurl
entrypoint: [""]
script:
- hurl --test --report-html public --report-junit http.xml *.hurl
artifacts:
paths:
- http.xml
- public/
reports:
junit: http.xml
The kennethreitz/httpbin
image spins up an instance of the very wonderful httpbin, a simple HTTP request and response service.
✨
The image atop this post was generated via Midjourney with the prompt:
giant sunset featuring lemon slice sun