Testing
If you use end-to-end tools like Capybara or client-side frameworks like Vitest, those work with Inertia out of the box. This page covers endpoint tests — testing the Inertia responses from your Rails backend.
Setup
Inertia Rails provides test helpers for both RSpec and Minitest.
# spec/rails_helper.rb
require 'inertia_rails/rspec'RSpec helpers are automatically available in all request specs. Minitest helpers are automatically included in ActionDispatch::IntegrationTest.
Assertions
Both RSpec and Minitest provide matchers/assertions for testing Inertia responses. In RSpec, negation is done with not_to.
The inertia helper gives you direct access to inertia.props, inertia.component, inertia.view_data, inertia.flash, and inertia.deferred_props.
| Description | RSpec | Minitest |
|---|---|---|
| Inertia response | be_inertia_response | assert_inertia_response / refute_inertia_response |
| Component name | render_component | assert_inertia_component / refute_inertia_component |
| Props (partial match) | have_props | assert_inertia_props / refute_inertia_props |
| Props (exact match) | have_exact_props | assert_inertia_props_equal / refute_inertia_props_equal |
| Prop key absent | have_no_prop | assert_no_inertia_prop |
| View data (partial match) | have_view_data | assert_inertia_view_data / refute_inertia_view_data |
| View data (exact match) | have_exact_view_data | assert_inertia_view_data_equal / refute_inertia_view_data_equal |
| View data key absent | have_no_view_data | assert_no_inertia_view_data |
| Flash (partial match) | have_flash | assert_inertia_flash / refute_inertia_flash |
| Flash (exact match) | have_exact_flash | assert_inertia_flash_equal / refute_inertia_flash_equal |
| Flash key absent | have_no_flash | assert_no_inertia_flash |
| Deferred props | have_deferred_props | assert_inertia_deferred_props / refute_inertia_deferred_props |
# spec/requests/events_spec.rb
RSpec.describe '/events' do
describe '#index' do
let!(:event) { Event.create!(title: 'Rails World', start_date: '2026-09-23', description: 'Annual Ruby on Rails conference') }
it 'renders inertia component' do
get events_path
expect(inertia).to be_inertia_response
expect(inertia).to render_component 'events/index'
expect(inertia).to have_props(title: 'Rails World')
expect(inertia).to have_exact_props(title: 'Rails World', start_date: '2026-09-23', description: 'Annual Ruby on Rails conference')
# Props support both symbol and string keys
expect(inertia.props[:title]).to eq 'Rails World'
expect(inertia.props['title']).to eq 'Rails World'
expect(inertia).to have_view_data(timezone: 'UTC')
expect(inertia).to have_exact_view_data(timezone: 'UTC')
expect(inertia.view_data[:timezone]).to eq 'UTC'
expect(inertia).to have_no_prop(:secret)
end
end
endCommon testing tasks
Test flash messages
Inertia Rails automatically shares flash data with your frontend.
RSpec.describe '/events' do
it 'shows flash message after create' do
post events_path, params: { event: { title: 'New Event' } }
expect(inertia).to have_flash(notice: 'Event created!')
expect(inertia).to have_exact_flash(notice: 'Event created!')
expect(inertia.flash[:notice]).to eq 'Event created!'
expect(inertia).to have_no_flash(:alert)
end
endTest validation errors
Validation errors are shared as props automatically when using redirect_to with inertia_errors. Assert them on the errors key.
RSpec.describe '/events' do
it 'returns validation errors' do
post events_path, params: { event: { title: '' } }
expect(inertia).to render_component 'events/new'
expect(inertia).to have_props(errors: { title: ["can't be blank"] })
end
endTest redirects
After a redirect, use follow_redirect! and assert the resulting Inertia response.
RSpec.describe '/events' do
it 'redirects after create' do
post events_path, params: { event: { title: 'Conference' } }
follow_redirect!
expect(inertia).to render_component 'events/show'
expect(inertia).to have_flash(notice: 'Event created!')
end
endTest deferred props
Deferred props are excluded from the initial page load and fetched in a subsequent request.
RSpec.describe '/events' do
it 'defers expensive data' do
get events_path
expect(inertia).to have_deferred_props
expect(inertia).to have_deferred_props(:analytics)
expect(inertia).to have_deferred_props(:analytics, :statistics)
# Check a specific group
expect(inertia).to have_deferred_props(:other_data, group: :slow)
expect(inertia.deferred_props[:default]).to include('analytics')
expect(inertia.props[:analytics]).to be_nil
end
endTest partial reloads
Use inertia_reload_only, inertia_reload_except, and inertia_load_deferred_props to simulate partial reloads and deferred prop loading.
RSpec.describe '/events' do
it 'supports partial reloads' do
get events_path
inertia_reload_only(:analytics, :statistics)
expect(inertia.props[:analytics]).to be_present
inertia_reload_except(:expensive_data)
# Load deferred props by group
inertia_load_deferred_props(:default)
# Load all deferred props
inertia_load_deferred_props
end
endConfiguration
evaluate_optional_props
By default, optional and deferred props are excluded on first load — just like in production. This means inertia.props[:my_optional] returns nil unless you simulate a partial reload.
To have these props evaluated on first load in tests, enable evaluate_optional_props:
# spec/rails_helper.rb
require 'inertia_rails/rspec'
InertiaRails::Testing.evaluate_optional_props = trueOptional and deferred props are then included in inertia.props on first load:
get events_path
expect(inertia.props[:analytics]).to be_present
expect(inertia.props[:statistics]).to eq({ views: 100 })You can also toggle this setting per-test:
around do |example|
InertiaRails::Testing.evaluate_optional_props = true
example.run
ensure
InertiaRails::Testing.evaluate_optional_props = false
endWARNING
When evaluate_optional_props is enabled, deferred props will appear in inertia.props but will still be listed in inertia.deferred_props. Partial reload behaviour is unaffected — this setting only changes first-load behaviour.