inertia_wisp/testing

Testing utilities for exercising wisp handlers returning inertia responses.

This module augments the wisp/simulate module with helpers to create inertia requests and extract props and metadata from inertia responses.

Example

import inertia_wisp/testing

pub fn test_home_page() {
  let req = testing.inertia_request()
  let response = my_handler(req)

  assert testing.component(response) == Ok("HomePage")
  assert testing.prop(response, "title", decode.string) == Ok("Welcome")
}

Values

pub fn clear_history(
  response: response.Response(wisp.Body),
) -> Result(Bool, json.DecodeError)

Extract the clear_history flag from an Inertia response.

Example

assert testing.clear_history(response) == Ok(True)
pub fn component(
  response: response.Response(wisp.Body),
) -> Result(String, json.DecodeError)

Extract the component name from an Inertia response.

This works for both JSON responses (XHR requests) and HTML responses (initial page loads) by parsing the appropriate format.

Example

let response = my_handler(req)
assert testing.component(response) == Ok("HomePage")
pub fn deep_merge_props(
  response: response.Response(wisp.Body),
  decoder: decode.Decoder(a),
) -> Result(a, json.DecodeError)

Extract deep merge props from an Inertia response.

assert testing.deep_merge_props(response, decode.list(decode.string)) == Ok(["nested", "deep"])
pub fn deferred_props(
  response: response.Response(wisp.Body),
  group: String,
  decoder: decode.Decoder(a),
) -> Result(a, json.DecodeError)

Extract deferred props from an Inertia response.

assert testing.deferred_props(response, "default", decode.list(decode.string)) == Ok(["expensive"])
pub fn encrypt_history(
  response: response.Response(wisp.Body),
) -> Result(Bool, json.DecodeError)

Extract the encrypt_history flag from an Inertia response.

Example

assert testing.encrypt_history(response) == Ok(True)
pub fn inertia_delete(
  path: String,
) -> request.Request(wisp.Connection)

Create a test Inertia DELETE request.

Useful for testing delete endpoints.

pub fn inertia_patch(
  path: String,
  data: json.Json,
) -> request.Request(wisp.Connection)

Create a test Inertia PATCH request with JSON body.

Useful for testing partial update endpoints.

pub fn inertia_post(
  path: String,
  data: json.Json,
) -> request.Request(wisp.Connection)

Create an Inertia JSON POST request for testing form submissions.

This creates a POST request with the necessary headers for Inertia.js form submissions using JSON data (as sent by useForm().post() or router.post()).

The request will include:

  • Content-Type: application/json
  • Accept: application/json
  • X-Inertia: true
  • X-Inertia-Version: 1

Examples

Testing user creation:

let data = json.object([
  #("name", json.string("John Doe")),
  #("email", json.string("john@example.com")),
])
let req = testing.inertia_post("/users", data)
let response = create_user_handler(req, db)
assert testing.component(response) == Error(_) // Should redirect on success

Testing validation errors:

let invalid_data = json.object([
  #("name", json.string("")),  // Invalid: empty name
  #("email", json.string("invalid-email")),  // Invalid: bad format
])
let req = testing.inertia_post("/users", invalid_data)
let response = create_user_handler(req, db)
assert testing.component(response) == Ok("Users/Create") // Should return form with errors
pub fn inertia_put(
  path: String,
  data: json.Json,
) -> request.Request(wisp.Connection)

Create a test Inertia PUT request with JSON body.

Useful for testing update endpoints.

pub fn inertia_request() -> request.Request(wisp.Connection)

Create a mock Inertia XHR request for testing.

This creates a request with the necessary Inertia headers:

  • x-inertia: true to indicate this is an Inertia request
  • x-inertia-version: 1 for version matching
  • accept: application/json for JSON responses

Example

let req = testing.inertia_request()
let response = my_handler(req)
assert testing.component(response) == Ok("HomePage")
pub fn inertia_request_to(
  path: String,
) -> request.Request(wisp.Connection)

Create a mock Inertia XHR request for testing with a custom path.

This creates a request with the necessary Inertia headers:

  • x-inertia: true to indicate this is an Inertia request
  • x-inertia-version: 1 for version matching
  • accept: application/json for JSON responses

Example

let req = testing.inertia_request_to("/users?search=Demo")
let response = my_handler(req)
assert testing.component(response) == Ok("Users/Index")
pub fn match_props_on(
  response: response.Response(wisp.Body),
  decoder: decode.Decoder(a),
) -> Result(a, json.DecodeError)

Extract match props on from an Inertia response.

assert testing.match_props_on(response, decode.list(decode.string)) == Ok(["posts.id", "posts.slug"])
pub fn merge_props(
  response: response.Response(wisp.Body),
  decoder: decode.Decoder(a),
) -> Result(a, json.DecodeError)

Extract merge props from an Inertia response.

assert testing.merge_props(response, decode.list(decode.string)) == Ok(["posts", "comments"])
pub fn partial_component(
  req: request.Request(wisp.Connection),
  component: String,
) -> request.Request(wisp.Connection)

Add partial component header to a request for testing component matching.

This modifies an existing request to include the x-inertia-partial-component header, which specifies which component is expected for partial reloads. If the component doesn’t match, it should be treated as a regular page load.

Example

let req = testing.inertia_request()
  |> testing.partial_data(["posts"])
  |> testing.partial_component("HomePage")
let response = my_handler(req)
// Should only include partial data if component matches "HomePage"
pub fn partial_data(
  req: request.Request(wisp.Connection),
  props: List(String),
) -> request.Request(wisp.Connection)

Add partial data headers to a request for testing partial reloads.

This modifies an existing request to include the x-inertia-partial-data header, which tells Inertia to only return the specified props.

Example

let req = testing.inertia_request()
  |> testing.partial_data(["posts", "comments"])
let response = my_handler(req)
// Only "posts" and "comments" props will be included
pub fn prop(
  resp: response.Response(wisp.Body),
  key: String,
  decoder: decode.Decoder(a),
) -> Result(a, json.DecodeError)

Extract a specific prop value from an Inertia response.

This function allows you to retrieve and decode any prop from the response using Gleam’s dynamic decoders. Works for both JSON and HTML responses.

Example

// Test a string prop
assert testing.prop(response, "title", decode.string) == Ok("My Title")

// Test an integer prop
assert testing.prop(response, "count", decode.int) == Ok(42)

// Test a complex object
assert testing.prop(response, "user", decode.field("name", decode.string)) == Ok("John")
pub fn regular_request() -> request.Request(wisp.Connection)

Create a regular HTTP request for testing initial page loads.

This creates a request WITHOUT Inertia headers, simulating a direct browser visit or page refresh. The response should be HTML with embedded JSON data in the data-page attribute.

Example

let req = testing.regular_request()
let response = my_handler(req)
assert testing.component(response) == Ok("HomePage")
pub fn regular_request_to(
  path: String,
) -> request.Request(wisp.Connection)

Create a regular HTTP request for testing initial page loads with a custom path.

This creates a request WITHOUT Inertia headers, simulating a direct browser visit or page refresh to a specific URL.

Example

let req = testing.regular_request_to("/users/123")
let response = my_handler(req)
assert testing.component(response) == Ok("Users/Show")
pub fn url(
  response: response.Response(wisp.Body),
) -> Result(String, json.DecodeError)

Extract the URL from an Inertia response.

Example

assert testing.url(response) == Ok("/dashboard")
pub fn version(
  response: response.Response(wisp.Body),
) -> Result(String, json.DecodeError)

Extract the version from an Inertia response.

Example

assert testing.version(response) == Ok("1")
Search Document