Principle:MarketSquare Robotframework browser Response Formatting and Validation
Response Formatting and Validation
Transforming raw HTTP response data into structured, queryable objects in Robot Framework Browser.
Overview
When the Robot Framework Browser library receives HTTP responses (from the HTTP keyword or from intercepted network traffic via Wait For Response), the raw data must be transformed from wire-format strings into structured Python objects that Robot Framework tests can easily query and assert against. This transformation process involves JSON auto-parsing, header dictionary conversion, and DotDict wrapping to enable Robot Framework's dot-notation variable access.
Core Concept
HTTP responses travel through multiple layers before reaching the test:
- The browser's JavaScript
fetch()API or Playwright's response listener captures the raw response. - The Node.js Playwright wrapper serializes the response data as JSON, including stringified headers and a text body.
- The data crosses the gRPC boundary as a JSON string.
- The Python side deserializes the JSON and applies formatting transformations.
The formatting step is critical because the raw gRPC payload contains headers as a JSON-encoded string (not a dictionary) and response bodies as raw text (not parsed JSON). Without formatting, tests would need to manually parse these values in every assertion.
JSON Auto-Parsing
The library automatically detects JSON response bodies and parses them into Python dictionaries. This detection is based on the Content-Type header:
- The response headers are examined (case-insensitively) for a
Content-Typeheader. - If the Content-Type contains
application/json, the body is parsed viajson.loads(). - If parsing succeeds, the body is replaced with the resulting Python dictionary.
- If parsing fails (malformed JSON), the body is left as a plain string.
This auto-parsing applies to both:
- The response body (the
bodykey in the response dictionary). - The request postData (the
postDatakey in the nestedrequestdictionary, when present inWait For Responseresults).
Header String-to-Dict Conversion
Headers arrive from the Node side as a JSON-encoded string (e.g., '{"content-type": "application/json", "x-request-id": "abc"}'). The formatting process parses this string into a Python dictionary, making individual header values accessible.
This conversion applies at two levels:
- The response headers are converted from string to dictionary.
- The request headers (within the nested
requestsub-dictionary) are also converted.
DotDict Wrapping
After formatting, the response dictionary is wrapped in Robot Framework's DotDict (from robot.utils). This enables dot-notation access in Robot Framework variables, which is substantially more readable than dictionary bracket syntax:
# With DotDict wrapping (clean):
Should Be Equal As Integers ${response.status} 200
Should Be Equal ${response.body.user.name} John
# Without DotDict (verbose):
${status}= Get From Dictionary ${response} status
Should Be Equal As Integers ${status} 200
${body}= Get From Dictionary ${response} body
${user}= Get From Dictionary ${body} user
${name}= Get From Dictionary ${user} name
Should Be Equal ${name} John
The DotDict wrapping enables nested access through dot notation, so ${response.body.user.name} traverses through the response body's user object to the name field. This works because when the body is JSON-parsed, nested dictionaries are also accessible via dot notation through DotDict's recursive attribute access.
Transformation Pipeline
The complete transformation pipeline for an HTTP response is:
- Raw gRPC response: JSON string containing stringified headers and text body.
- JSON deserialization:
json.loads(response.json)produces a Python dictionary with string-valued headers and body. - Response formatting (
_format_response):- Headers are parsed from JSON string to dictionary.
- Body is conditionally parsed from JSON string to dictionary (if Content-Type is
application/json). - If a
requestsub-dictionary exists, its headers and postData receive the same treatment.
- DotDict wrapping: The formatted dictionary is wrapped in
DotDictfor dot-notation access. - Fallback: If DotDict wrapping fails (e.g., the response is not a standard dictionary), the raw formatted value is returned.
Error Handling
The formatting process is designed to be fault-tolerant:
- JSON parsing errors during body auto-parsing are suppressed (via
contextlib.suppress). If the body looks like it should be JSON (based on Content-Type) but cannot be parsed, it remains as a string. - Header parsing errors default to an empty dictionary (
json.loads(data.get("headers", "{}"))). - DotDict wrapping errors are caught, and the raw dictionary is returned with a debug log message.