One of Inertia.js's quieter advantages is testability. Because routing, validation and authorization stay in Laravel, the most valuable tests look exactly like classic Laravel feature tests — they just assert page components and props instead of HTML. Add a focused layer of React component tests, and an Inertia app ends up better covered than most SPAs, for less effort.
New to the architecture?
Inertia.js with Laravel and React — SPA without a separate API.
- ## Feature tests: assert the contract
The Inertia testing helper turns a controller call into assertions about the page
use Inertia\Testing\AssertableInertia as Assert;
it('lists only the current team orders', function () {
$team = Team::factory()->create();
Order::factory()->count(3)->for($team)->create();
Order::factory()->count(5)->for(Team::factory())->create();
$this->actingAs($team->owner)
->get('/orders')
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('Orders/Index')
->has('orders.data', 3)
->where('orders.data.0.status', 'new')
);
});
This single test verifies authorization, query scoping, resource shape and the component name — the whole server-side contract of the page. Deferred props get their own assertions: send the follow-up request and assert the prop arrives.
Validation and auth flows
Forms are where bugs hurt most, and they are the easiest to test — the rules live in FormRequests
it('rejects an order without a customer', function () {
$this->actingAs(User::factory()->create())
->post('/orders', ['note' => 'missing customer'])
->assertSessionHasErrors('customer_id');
});
it('redirects guests to login', function () {
$this->get('/orders')->assertRedirect('/login');
});
Because the frontend renders errors from props, testing the rules in Laravel covers the visible behaviour. The React side only needs a component test that errors render when present.
Tip: Test the seam, not the pixels.
assertInertiachecks what the server promises the frontend; component tests check how the frontend renders it. Neither needs a browser.
Component tests on the React side
Vitest + React Testing Library, focused on logic
- A table component sorts and paginates the props it receives.
- A form component renders
errorsunder the right fields. - Permission-based UI hides actions when the prop says so.
Keep them shallow — no Inertia router mocking beyond what the component touches. If a component needs half the framework to test, it is doing too much; split it.
- ## End-to-end: a small, protected set
Browser tests are slow and flaky; use them where only a real browser proves the point: login → navigate → create an order → see it in the list. With Playwright, one such journey per critical module. Everything else stays in the two layers above.
What the pyramid looks like in practice
In our Inertia projects roughly: 70% Laravel feature tests (contract, rules, auth), 20% component tests (rendering logic), 10% Playwright journeys. The suite runs in CI on every push, and deploys are boring — which is the point. The same philosophy applies to the rest of the stack in testing Laravel apps and shows up in how we scope projects at Laravel development services.
FAQ
How do I assert the Inertia page and props in a Laravel test?
Use assertInertia with the AssertableInertia trait — assert component name and prop structure in one call against the real controller.
Do I need end-to-end browser tests?
Only for critical journeys. Feature tests with assertInertia cover the data contract much cheaper; Playwright protects the glue.
What is worth testing on the React side?
- Components with logic: sorting tables, forms rendering errors, permission-based rendering. Vitest + React Testing Library, kept shallow.
👉 Want a test suite that makes deploys boring? Check our Laravel development services or hire a Laravel developer.
📖 Read more: Inertia.js with Laravel and React, forms and validation in Inertia.js and Inertia.js with TypeScript.