refrakt/testing
Test helpers for Refrakt applications.
Build test requests without a running HTTP server.
Example
import refrakt/testing
pub fn index_returns_200_test() {
let req = testing.get("/posts")
let resp = post_handler.index(req, test_ctx())
resp.status |> should.equal(200)
}
Tests against a real database
with_database runs a test body against a database that is set up
for it and torn down after it, also when an assertion fails. It knows
nothing about any database driver: generated apps call it from
test/<app>/support/test_db.gleam, which opens the database with the
app’s own pog or sqlight dependency, applies the migrations and
keeps every test’s writes from reaching the next test.
Values
pub fn assert_header(
resp: response.Response(String),
name: String,
expected: String,
) -> Bool
Check that a response has a specific header value.
pub fn assert_status(
resp: response.Response(String),
expected: Int,
) -> Bool
Check that a response has a specific status code.
pub fn cross_site(
req: request.Request(body),
from origin: String,
) -> request.Request(body)
Mark a test request as sent by a page on another site, such as
"https://evil.example". refrakt/csrf.protect rejects it with 403
unless the method is safe.
pub fn delete(path: String) -> request.Request(String)
Create a DELETE request for testing.
pub fn json_request(
method: http.Method,
path: String,
body: String,
) -> request.Request(wisp.Connection)
Create a request with a JSON body, ready to pass straight to a handler.
Unlike the builders above, this returns a wisp.Request, the type
handlers take. The body is a string so tests can send malformed JSON
too; build valid bodies with gleam/json. The content-type header
is application/json, as wisp.require_json expects.
let body = json.object([#("title", json.string("Hello"))])
testing.json_request(http.Post, "/api/posts", json.to_string(body))
|> post_handler.create(ctx)
pub fn request(
method: http.Method,
path: String,
) -> request.Request(String)
Create a request with a specific method and path.
pub fn same_origin(
req: request.Request(body),
) -> request.Request(body)
Mark a test request as sent by a page of this app, the way a browser
submits a form: sets the host header (from the request’s host, if
it is missing) and a matching origin header. Unsafe requests need
these to get past refrakt/csrf.protect with their cookies.
pub fn with_body(
req: request.Request(String),
body: String,
) -> request.Request(String)
Set the body of a test request.
pub fn with_database(
open open: fn() -> Result(db, String),
close close: fn(db) -> Nil,
run body: fn(db) -> a,
) -> a
Run body with a database opened by open, then close it with
close. close always runs: also when body panics, as a failing
should assertion does, so one failing test cannot leave its data
behind for the next.
When open fails, the test fails with a panic that shows its error,
so explain there how to make the database reachable.
pub fn with_db(body: fn(sqlight.Connection) -> a) -> a {
testing.with_database(
open: fn() {
sqlight.open("file:test?mode=memory&cache=shared")
|> result.map_error(fn(error) { error.message })
},
close: fn(conn) {
let _ = sqlight.close(conn)
Nil
},
run: body,
)
}
pub fn with_header(
req: request.Request(String),
name: String,
value: String,
) -> request.Request(String)
Add a header to a test request.