MarketSquare / MarketSquare/robotframework-browser
Extend `HTTP` keyword with `multipart=` file uploads, `form=`, `params=`, `timeout=` and `fail_on_status_code=`
@Snooz82 is already working on this.
Since Aug 6, 2026.
- Dominant language
- Python
- Stars
- 655
- Forks
- 147
- Avg merge
- 5h 27m
- Merged PRs (30d)
- 59
Description
## Use case
The `HTTP` keyword is the library's way to make API calls that automatically share cookies and session state with the open browser page — the main reason to use it over RequestsLibrary. But today it only supports `url`, `method`, `body` and `headers`, which leaves several very common API-testing needs uncovered:
- **File uploads (the headline of this issue):** there is currently *no way at all* to POST a file (`multipart/form-data`) via the `HTTP` keyword. Avatar upload, document upload and import endpoints are extremely common in real suites, and users are forced to fall back to RequestsLibrary — losing exactly the automatic browser-session cookie sharing they came for.
- **Classic form posts:** endpoints backed by HTML forms (login forms, legacy APIs) expect `application/x-www-form-urlencoded` bodies. Users must hand-build the encoded string and set the `Content-Type` header themselves.
- **Query parameters:** special characters must be URL-encoded manually when concatenating query strings.
- **Timeouts:** every other Browser keyword exposes a `timeout` argument; `HTTP` is an outlier where a hung endpoint can stall a test indefinitely with no keyword-level control.
- **Fail-fast on error status:** asserting `${res.status}` works, but a fail-fast option matching Playwright's `failOnStatusCode` saves a line in every API test and produces a clearer error at the point of failure.
## Proposed keyword / arguments
All new arguments are named-only with `None`/behavior-preserving defaults:
```
HTTP url method=GET body=None headers=None
... *, multipart=None form=None params=None timeout=None fail_on_status_code=False
```
- `multipart` — dict of form fields; each value is either a string or a file spec `{name, mimeType, path}` (or `buffer` instead of `path`), mirroring how `Upload File By Selector` already handles files. Sends the request as `multipart/form-data`.
- `form` — dict, URL-encoded by the library and sent with `Content-Type: application/x-www-form-urlencoded`.
- `params` — dict of query parameters, URL-encoded and merged into the request URL.
- `timeout` — Robot Framework time format (e.g. `10 s`), per-request timeout.
- `fail_on_status_code` — when `True`, the keyword fails if the response status is not in the 200–399 range.
`multipart`, `form` and `body` are mutually exclusive.
```robotframework
*** Test Cases ***
Upload Avatar Via API
&{file}= Create Dictionary name=avatar.png mimeType=image/png path=${CURDIR}/testdata/avatar.png
&{fields}= Create Dictionary description=Profile picture file=${file}
&{res}= HTTP /api/users/me/avatar method=POST multipart=${fields} timeout=10 s
Should Be Equal ${res.status} ${201}
Legacy Form Login
&{creds}= Create Dictionary username=demo password=mode
&{res}= HTTP /login method=POST form=${creds} fail_on_status_code=True
Search With Query Params
&{query}= Create Dictionary q=robot framework page=1
&{res}= HTTP /api/search params=${query}
Should Be Equal ${res.body.results[0].name} robot framework
```
## Playwright API
Maps to the request options of `APIRequestContext.fetch`/`post`/etc.: [`multipart`](https://playwright.dev/docs/api/class-apirequestcontext#api-request-context-fetch-option-multipart), [`form`](https://playwright.dev/docs/api/class-apirequestcontext#api-request-context-fetch-option-form), [`params`](https://playwright.dev/docs/api/class-apirequestcontext#api-request-context-fetch-option-params), [`timeout`](https://playwright.dev/docs/api/class-apirequestcontext#api-request-context-fetch-option-timeout), [`failOnStatusCode`](https://playwright.dev/docs/api/class-apirequestcontext#api-request-context-fetch-option-fail-on-status-code).
Note: the library's `HTTP` keyword is implemented as `fetch()` inside the page (`page.evaluate` in `node/playwright-wrapper/network.ts`), not via a real `APIRequestContext`, so these options are implemented as equivalents, not direct pass-throughs.
## Implementation notes
- `protobuf/playwright.proto`: extend the `HttpRequest` message with the new fields (multipart spec, form dict, params dict, timeout, fail flag).
- `node/playwright-wrapper/network.ts` (`httpRequest`): the **multipart body must be built node-side** — file contents are read from disk in the Node process (large/binary payloads cannot reasonably cross the gRPC/JSON boundary or be constructed as a binary `FormData` inside `page.evaluate` from Python-supplied data), then assembled into the `multipart/form-data` body and handed to the in-page `fetch`. `form`/`params` are simple encoding steps; `timeout` via `AbortController` around the fetch.
- `Browser/keywords/network.py` (`http`): new named-only arguments, validation of mutually exclusive body arguments, docs.
- Stub regeneration (`inv build`), atest coverage against the test app including an upload endpoint.
## Backwards compatibility
Fully additive: all five arguments are new, named-only, and default to values that reproduce the current behavior exactly (`None`/`False`). Existing calls are unaffected.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.