Helpers for a host's own test suite, over plain Ring maps and rendered
bodies. Nothing here needs ring-mock or any other library, so it ships in
the jar. The shapes parsed are the base's own — the cookies Ring's session
middleware sets, the CSRF token the shell and security/csrf-field emit —
which is why the base owns these readers rather than every host's tests.
Helpers for a host's own test suite, over plain Ring maps and rendered bodies. Nothing here needs ring-mock or any other library, so it ships in the jar. The shapes parsed are the base's own — the cookies Ring's session middleware sets, the CSRF token the shell and `security/csrf-field` emit — which is why the base owns these readers rather than every host's tests.
(browser handler)A browser over handler, as a value: an empty cookie jar, no CSRF token yet, no
page. visit answers the browser after a request; nothing is mutated, so a test can
keep two tabs of one person by holding two values.
Why the base ships it: every host's suite wrote the same one, and the first lost an afternoon to the one trap it has — a jar chained from the last response alone drops the session cookie at the first page that sets none, so every request after the login looks signed out. This one accumulates.
A browser over `handler`, as a value: an empty cookie jar, no CSRF token yet, no page. `visit` answers the browser after a request; nothing is mutated, so a test can keep two tabs of one person by holding two values. Why the base ships it: every host's suite wrote the same one, and the first lost an afternoon to the one trap it has — a jar chained from the last response alone drops the session cookie at the first page that sets none, so every request after the login looks signed out. This one accumulates.
(call handler method path)(call handler
method
path
{:keys [headers body content-type chunked? remote-addr]})One request to handler as a program sends it — no jar, no CSRF token, no redirect
followed — for an API mounted under :sessionless, which visit, a browser, cannot
drive (since 0.17.0). path may carry a query string, sent as written, malformed
escapes included; an absolute URL is taken for its path and query, the host being
always localhost. opts:
:headers — a map, names lower-cased as Ring has them; host, content-type and
content-length are call's own and refused, and so is a name given twice in
different cases;:body — a string, sent as UTF-8, or bytes; with it :content-type defaults to
application/json;:content-type — the body's type;:chunked? true — no declared length, as a chunked body arrives;:remote-addr — the source address.:content-type or :chunked? without a body, or a body that is neither a string nor
bytes, is refused: a test would otherwise assert about a request that was never sent.
Answers the handler's response as it is; reading a JSON body is the host's codec.
One request to `handler` as a program sends it — no jar, no CSRF token, no redirect followed — for an API mounted under `:sessionless`, which `visit`, a browser, cannot drive (since 0.17.0). `path` may carry a query string, sent as written, malformed escapes included; an absolute URL is taken for its path and query, the host being always `localhost`. `opts`: - `:headers` — a map, names lower-cased as Ring has them; `host`, `content-type` and `content-length` are `call`'s own and refused, and so is a name given twice in different cases; - `:body` — a string, sent as UTF-8, or bytes; with it `:content-type` defaults to `application/json`; - `:content-type` — the body's type; - `:chunked? true` — no declared length, as a chunked body arrives; - `:remote-addr` — the source address. `:content-type` or `:chunked?` without a body, or a body that is neither a string nor bytes, is refused: a test would otherwise assert about a request that was never sent. Answers the handler's response as it is; reading a JSON body is the host's codec.
(cookies response)Every cookie response sets, name to value, the way a browser keeps
them: a deletion (Max-Age of zero or less) is nil, a cookie to forget.
Every cookie `response` sets, name to value, the way a browser keeps them: a deletion (`Max-Age` of zero or less) is nil, a cookie to forget.
(csrf-token response)The CSRF token a rendered response carries, from the hidden field of a
classic form or from the shell's <body> attribute; nil when the body is
not a string or holds neither.
The CSRF token a rendered `response` carries, from the hidden field of a classic form or from the shell's `<body>` attribute; nil when the body is not a string or holds neither.
(fragment request)request as htmx sends it for a swap, so the base renders a fragment —
even a request already marked as a whole-document one.
`request` as htmx sends it for a swap, so the base renders a fragment — even a request already marked as a whole-document one.
(gate-refusal? response login-path)Whether response is the gate's refusal of a request with no subject, sent to
login-path: a 303 for a navigation — to login-path itself, or carrying the page it
asked for as next (since 0.10.0) — and a 200 with HX-Redirect to login-path and
no Location for an htmx swap. The refusal's own headers are part of the test,
because they are what tell it from a handler that redirects to the login page by
itself.
Whether `response` is the gate's refusal of a request with no subject, sent to `login-path`: a 303 for a navigation — to `login-path` itself, or carrying the page it asked for as `next` (since 0.10.0) — and a 200 with `HX-Redirect` to `login-path` and no `Location` for an htmx swap. The refusal's own headers are part of the test, because they are what tell it from a handler that redirects to the login page by itself.
(header response name)The one value of header name in a response, whatever the case of its key, or nil —
the first, when Ring holds several (since 0.17.0).
The one value of header `name` in a response, whatever the case of its key, or nil — the first, when Ring holds several (since 0.17.0).
(header-values headers name)The values of header name in headers, whatever the case of the key and
whether Ring holds one string or several — always a vector, empty when absent. Public
for a host's assertions on a response's headers.
The values of header `name` in `headers`, whatever the case of the key and whether Ring holds one string or several — always a vector, empty when absent. Public for a host's assertions on a response's headers.
(location response)The response's Location, whatever the case of the header's key, or nil.
The response's `Location`, whatever the case of the header's key, or nil.
(router routes)routes compiled as the base compiles them — a child's gate composed with its
parent's — for a test that reads which gates guard which endpoint. A composed gate is
identical to none of its parts; its metadata lists them under :wb/gates.
`routes` compiled as the base compiles them — a child's gate composed with its parent's — for a test that reads which gates guard which endpoint. A composed gate is identical to none of its parts; its metadata lists them under `:wb/gates`.
(visit b method path)(visit b method path params)(visit b method path params opts)The browser after sending method (:get, :post, :put, :patch or :delete) to
path with form params, holding the final :response and, as :path, where it
landed — the address bar, with its query string, after every redirect was followed.
params go where a browser puts them: in the query string for a GET, and for a
DELETE, which htmx sends with no body; as a form body for a POST, PUT or PATCH.{:htmx? true}, as the header the
shell makes htmx send, with the headers of a swap. A PUT, PATCH or DELETE without
{:htmx? true} throws, because no browser form can send one. One with no token
known throws: a 403 that looked like the application's fault is the failure it
replaces. After a login the session, and with it the token, is new — GET a page
before the next one.HX-Redirect is left in the response for the test to read, as htmx would act on it
and a server-side test cannot.{:remote-addr "…"} sets the source address, for anything keyed by it.{:headers {"accept-language" "es"}} adds headers to every request, redirects
followed included, as a browser keeps sending its own. Names are lower-cased; one
visit writes itself — host, cookie, content-type, content-length, the CSRF header
or a swap's — throws, because setting it would fake what the test exercises.{:files {"photo" {:filename "a.png" :content-type "image/png" :bytes b}}} sends a
POST, PUT or PATCH as multipart/form-data, with its params and the CSRF field as
parts beside the files — what a form with a file input sends. A vector of pairs,
[["photo" a] ["photo" b]], repeats the field as <input multiple> does. On any
other method it throws, since there is no body to carry them.{:multipart? true} sends a POST, PUT or PATCH as multipart/form-data with no file
(since 0.17.0) — what a form with enctype="multipart/form-data" sends when nothing
was chosen. Without it, a form with no file is sent urlencoded: :params still holds
its fields, but :multipart-params — what a handler of a multipart form reads — is
nil. Sent to a route that declares no :wb/multipart, nothing parses it and its token
is unseen: the 403 of :files there.{:follow? false} sends one request and follows nothing, for a test that asks who
answered: a handler that redirects to a gated page lands on the login page exactly
as the gate would. The jar still takes what the response set.The jar keeps what cookies reads — a cookie set again replaces the old value and a
deletion (Max-Age of zero or less, which is how Ring deletes) forgets it — and
ignores Path, Domain and Expires: one site, every path.
The browser after sending `method` (`:get`, `:post`, `:put`, `:patch` or `:delete`) to
`path` with form `params`, holding the final `:response` and, as `:path`, where it
landed — the address bar, with its query string, after every redirect was followed.
- `params` go where a browser puts them: in the query string for a GET, and for a
DELETE, which htmx sends with no body; as a form body for a POST, PUT or PATCH.
- A POST, PUT, PATCH or DELETE carries the CSRF token of the last page that had one,
as the hidden field a form would send — or, with `{:htmx? true}`, as the header the
shell makes htmx send, with the headers of a swap. A PUT, PATCH or DELETE without
`{:htmx? true}` throws, because no browser form can send one. One with no token
known throws: a 403 that looked like the application's fault is the failure it
replaces. After a login the session, and with it the token, is new — GET a page
before the next one.
- A 301, 302 or 303 is followed as a GET through the same jar, up to ten times; an
`HX-Redirect` is left in the response for the test to read, as htmx would act on it
and a server-side test cannot.
- `{:remote-addr "…"}` sets the source address, for anything keyed by it.
- `{:headers {"accept-language" "es"}}` adds headers to every request, redirects
followed included, as a browser keeps sending its own. Names are lower-cased; one
`visit` writes itself — host, cookie, content-type, content-length, the CSRF header
or a swap's — throws, because setting it would fake what the test exercises.
- `{:files {"photo" {:filename "a.png" :content-type "image/png" :bytes b}}}` sends a
POST, PUT or PATCH as `multipart/form-data`, with its params and the CSRF field as
parts beside the files — what a form with a file input sends. A vector of pairs,
`[["photo" a] ["photo" b]]`, repeats the field as `<input multiple>` does. On any
other method it throws, since there is no body to carry them.
- `{:multipart? true}` sends a POST, PUT or PATCH as `multipart/form-data` with no file
(since 0.17.0) — what a form with `enctype="multipart/form-data"` sends when nothing
was chosen. Without it, a form with no file is sent urlencoded: `:params` still holds
its fields, but `:multipart-params` — what a handler of a multipart form reads — is
nil. Sent to a route that declares no `:wb/multipart`, nothing parses it and its token
is unseen: the 403 of `:files` there.
- `{:follow? false}` sends one request and follows nothing, for a test that asks who
answered: a handler that redirects to a gated page lands on the login page exactly
as the gate would. The jar still takes what the response set.
The jar keeps what `cookies` reads — a cookie set again replaces the old value and a
deletion (`Max-Age` of zero or less, which is how Ring deletes) forgets it — and
ignores `Path`, `Domain` and `Expires`: one site, every path.(with-cookies request response)request carrying the cookies it already had and every one response
set, the way a browser follows a redirect: a cookie set again replaces the
old value, a deletion forgets it. The second request of a login test, the
swap after a page. Unchanged when the jar does not change.
`request` carrying the cookies it already had and every one `response` set, the way a browser follows a redirect: a cookie set again replaces the old value, a deletion forgets it. The second request of a login test, the swap after a page. Unchanged when the jar does not change.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |