Loading...
Loading...
Testing Inertia Rails responses with RSpec and Minitest: component assertions, prop matching, flash verification, deferred props, and partial reload helpers. Use when writing controller specs, request specs, or integration tests for Inertia pages. ALWAYS use matchers (render_component, have_props, have_flash), NOT direct access (inertia.component, inertia.props). CRITICAL: after POST/PATCH/DELETE with redirect, MUST call follow_redirect! before asserting flash or props — without it you're asserting against the 302, not the Inertia page. Setup: require 'inertia_rails/rspec'.
npx skill4agent add inertia-rails/skills inertia-rails-testingrender_component('users/index')have_props(users: satisfy { ... })have_no_prop(:secret)follow_redirect!have_flash(notice: '...')have_deferred_props(:analytics)follow_redirect!# spec/rails_helper.rb
require 'inertia_rails/rspec'| Matcher | Purpose |
|---|---|
| Verify response is Inertia format |
| Check rendered component name |
| Partial props match |
| Exact props match |
| Assert prop absent |
| Partial flash match |
| Exact flash match |
| Assert flash absent |
| Check deferred props exist |
| Partial view_data match |
render_componenthave_propshave_flashinertia.componentinertia.props[:key]# BAD — direct property access:
# expect(inertia.component).to eq('users/index')
# expect(inertia.props[:users].length).to eq(3)
# GOOD — use matchers:
expect(inertia).to render_component('users/index')
expect(inertia).to have_props(users: satisfy { |u| u.length == 3 })# Key pattern: follow_redirect! after POST/PATCH/DELETE before asserting
it 'redirects with flash on success' do
post users_path, params: { user: valid_params }
expect(response).to redirect_to(users_path)
follow_redirect!
expect(inertia).to have_flash(notice: 'User created!')
end
it 'returns validation errors on failure' do
post users_path, params: { user: { name: '' } }
follow_redirect!
expect(inertia).to have_props(errors: hash_including('name' => anything))
endinertia_shareinertia.propsinertiatype: :requestinertia_rails/rspecit 'includes shared auth data' do
sign_in(user)
get dashboard_path
expect(inertia).to have_props(
auth: hash_including(user: hash_including(id: user.id))
)
endit 'excludes auth data for unauthenticated users' do
get dashboard_path
expect(inertia).to have_props(auth: hash_including(user: nil))
endit 'defers expensive analytics data' do
get dashboard_path
expect(inertia).to have_deferred_props(:analytics, :statistics)
expect(inertia).to have_deferred_props(:slow_data, group: :slow)
endit 'supports partial reload' do
get users_path
# Simulate partial reload — only fetch specific props
inertia_reload_only(:users, :pagination)
# Or exclude specific props
inertia_reload_except(:expensive_stats)
# Load deferred props
inertia_load_deferred_props(:default)
inertia_load_deferred_props # loads all groups
endit 'redirects to Stripe via inertia_location' do
post checkout_path
# inertia_location returns 409 with X-Inertia-Location header
expect(response).to have_http_status(:conflict)
expect(response.headers['X-Inertia-Location']).to match(/stripe\.com/)
end<Form>router.visithave_props(users: satisfy { ... })follow_redirect!follow_redirect!nilhave_deferred_props(:key)inertia_load_deferred_propstype: :requesttype: :controllerassignsinertia.component # => 'users/index'
inertia.props # => { users: [...] }
inertia.props[:users] # direct prop access
inertia.flash # => { notice: 'Created!' }
inertia.deferred_props # => { default: [:analytics], slow: [:report] }inertia-rails-controllersinertia-rails-formsinertia-rails-pagesreferences/minitest.mdminitest.md