Response steps inspect the HTTP response headers behind the page you are looking at. Cache-control directives, security headers like x-frame-options, content types, CDN and session cookies - the things DevOps and Compliance teams verify on every release - become one-line assertions inside the same BDD scenario that exercises the UI.
Under the hood, a scenario-level hook listens to every response in the tab and remembers the headers and status of the most recent main-frame navigation - the document itself, not images, scripts, or AJAX calls. Each assertion reads that captured set. If nothing has been captured yet (for example the page was opened before the listener attached), the step falls back to re-fetching the current URL through Playwright's request API and reads the headers from that response instead.
All header-name comparisons are case-insensitive, matching how HTTP treats them - Content-Type, content-type, and CONTENT-TYPE are the same header. Value checks are substring matches, so you can assert "html" without pinning the exact text/html; charset=utf-8 string.
Quick reference
| Step | What it does |
|---|---|
Then the response should contain the header "content-type" | Assert the most recent navigation response carried a header (case-insensitive). |
Then the response should not contain the header "x-fake-header" | Assert the most recent navigation response did NOT carry a header. |
Then the response header "content-type" should contain the value "html" | Assert a header's value contains a substring. |
Then the response header "content-type" should not contain the value "application/json" | Assert a header's value does NOT contain a substring (or the header is absent). |
Steps in detail
Then the response should contain the header "..."
Passes when the named header is present on the latest main-frame navigation response, regardless of its value. Name matching is case-insensitive. Typical uses: confirming cache-control is set at all, that set-cookie is issued on login, or that security headers such as x-frame-options made it through the CDN.
Given I am on the homepage
Then the response should contain the header "content-type"
And the response should contain the header "cache-control"
Then the response should not contain the header "..."
The inverse: fails if the header exists with any value. This is the standard check for information-disclosure headers that hardening guides say to strip - x-powered-by, server, x-aspnet-version, or framework debug tokens.
Given I am on the homepage
Then the response should not contain the header "x-powered-by"
And the response should not contain the header "x-debug-token"
Then the response header "..." should contain the value "..."
Two assertions in one: the header must be present, and its value must contain the given substring. Substring matching keeps scenarios stable when the full value carries extra directives - "no-cache" matches no-cache, no-store, must-revalidate. The failure message shows the actual header value.
Given I am on the homepage
Then the response header "content-type" should contain the value "html"
And the response header "content-type" should contain the value "charset=utf-8"
Then the response header "..." should not contain the value "..."
Passes when the header is present without the substring - or when the header is missing entirely. That leniency makes it safe for checks like "caching must not be public" across pages that may or may not send cache-control at all. If you need the header to exist too, pair it with the response should contain the header.
Then the response header "cache-control" should not contain the value "public"
And the response header "x-frame-options" should not contain the value "ALLOW"
Complete example
From tests/features/response.feature, running against the bundled example site.
Feature: Response step definitions
Scenario: Inspect response headers from main navigation
Given I am on the homepage
Then the response should contain the header "content-type"
And the response header "content-type" should contain the value "html"
And the response should not contain the header "x-fake-header"
And the response header "content-type" should not contain the value "application/json"
Tips
- These steps look at the document response of the current tab. To assert on headers, status codes, or JSON bodies of API endpoints, use the API steps instead.
- Navigate (or
reload) before asserting - the captured headers always describe the most recent main-frame navigation, so a redirect chain yields the final response. - The fallback re-fetch issues a fresh GET of the current URL; on endpoints that vary per request (rotating cookies, one-time tokens) prefer asserting immediately after a real navigation.
- Status-code assertions such as
Then the response status code should be 200live in the assertion steps group.