Aviary
Guides

Testing

Use expectInertia, InertiaTestingModule, and assertInertia to test NestJS Inertia controllers.

Install

pnpm add -D @dudousxd/nestjs-inertia-testing
npm install --save-dev @dudousxd/nestjs-inertia-testing
yarn add -D @dudousxd/nestjs-inertia-testing

E2E with supertest

Spins up the real HTTP stack. Best for testing the full Inertia response lifecycle.

import * as request from 'supertest';
import { expectInertia } from '@dudousxd/nestjs-inertia-testing';

it('renders Dashboard with user prop', async () => {
  const res = await request(app.getHttpServer())
    .get('/dashboard')
    .set('X-Inertia', 'true');

  expectInertia(res)
    .toRenderComponent('Dashboard')
    .toHaveProp('user.id', 42);
});

expectInertia(res) returns a chainable InertiaAssertion. Every method returns this, so you can chain as many checks as you want.

Unit tests with InertiaTestingModule

For fast tests that skip HTTP entirely.

import { Test } from '@nestjs/testing';
import {
  InertiaTestingModule,
  createFakeInertiaRequest,
  expectInertia,
} from '@dudousxd/nestjs-inertia-testing';

const moduleRef = await Test.createTestingModule({
  imports: [InertiaTestingModule.forTest()],
  controllers: [DashboardController],
  providers: [{ provide: UserService, useValue: mockUsers }],
}).compile();

const controller = moduleRef.get(DashboardController);
const fakeReq = createFakeInertiaRequest({ method: 'GET', url: '/dashboard' });
await controller.show(fakeReq);

InertiaTestingModule.forTest(options?) wraps InertiaModule.forRoot() with a default version: 'test-v1'. Pass any InertiaModuleOptions to override.

assertInertia (raw payloads)

For testing codegen output, JSON fixtures, or any raw Inertia page object.

import { assertInertia } from '@dudousxd/nestjs-inertia-testing';

const payload = { component: 'Dashboard', props: { count: 5 }, url: '/dashboard', version: '1' };

assertInertia(payload)
  .toRenderComponent('Dashboard')
  .toHaveProp('count', 5);

Full assertion API

MethodDescription
.toRenderComponent(name)Component name matches exactly
.toHaveUrl(url)Page URL matches (string or RegExp)
.toHaveVersion(matcher)Asset version matches (string or RegExp)
.toHaveProp(path, value?)Deep prop exists; optionally check value
.toHavePropMatching(path, regex)String prop matches a RegExp
.toMissProp(path)Prop is absent
.toHaveExactProps(props)Full props deep-equality
.toShareProp(path, value?)Alias for toHaveProp (reads better for shared props)
.toHaveDeferredProp(name, group?)Prop listed in deferredProps
.toHaveMergeProp(name, opts?)Prop listed in mergeProps or deepMergeProps
.toHaveAlwaysProp(name)Prop present (always-props resolve on every request)
.toHaveOptionalProp(name)Prop present (optional-props resolve when requested)
.toHaveErrors(errors)Validation errors match (string or RegExp values)
.toHaveErrorBag(bag)Named error bag is an object
.toRedirectTo(url, status?)Location header + optional status (302 or 303)
.toRedirectExternal(url)Status 409 + X-Inertia-Location header
.toRenderFullHtml()Content-Type includes html
.withSsrHead(pattern)SSR head content matches a RegExp
.pageObject()Returns the raw PageObject
.unwrap()Returns { component, props, url, version }

Chained example:

expectInertia(res)
  .toRenderComponent('Dashboard')
  .toHaveUrl('/dashboard')
  .toHaveProp('user.name', 'Alice')
  .toHaveProp('count')
  .toMissProp('hidden')
  .toHaveDeferredProp('activity')
  .toHaveMergeProp('transactions')
  .toHaveErrors({ email: 'required' });

Partial reload testing

Set the partial-reload headers, then assert that only the requested props are present.

const res = await request(app.getHttpServer())
  .get('/dashboard')
  .set('X-Inertia', 'true')
  .set('X-Inertia-Partial-Component', 'Dashboard')
  .set('X-Inertia-Partial-Data', 'stats');

expectInertia(res)
  .toHaveProp('stats')
  .toMissProp('activity');

Framework matchers

Register custom matchers so you can write expect(res).toRenderInertiaComponent('Dashboard') directly.

// vitest.setup.ts
import '@dudousxd/nestjs-inertia-testing/vitest';
// jest.setup.ts
import '@dudousxd/nestjs-inertia-testing/jest';

Available matchers

MatcherEquivalent assertion
toRenderInertiaComponent(name).toRenderComponent(name)
toHaveInertiaProp(path, value?).toHaveProp(path, value?)
toHaveInertiaUrl(url).toHaveUrl(url)
toHaveInertiaVersion(matcher).toHaveVersion(matcher)
toMissInertiaProp(path).toMissProp(path)
toRedirectInertiaExternal(url).toRedirectExternal(url)
// With matchers registered, use native expect syntax:
expect(res).toRenderInertiaComponent('Dashboard');
expect(res).toHaveInertiaProp('user.id', 42);
expect(res).toMissInertiaProp('secret');

On this page