Skip to main content
edited title
Link
DarkBee
  • 14.5k
  • 9
  • 83
  • 132

ReferenceError: route is not defined when testing Inertia.js component with Vitest + Ziggy

Source Link
desh
  • 699
  • 2
  • 8
  • 33

ReferenceError: route is not defined when testing Inertia.js component with Vitest + Ziggy

I'm trying to test a simple Inertia.js + React component using Vitest and React Testing Library. The component uses useForm() from @inertiajs/react and the route() helper function from Ziggy (Laravel).

Here’s a simplified version of the component(Login.tsx):

import { useForm } from '@inertiajs/react';

export default function Login() {
  const { data, setData, post } = useForm({
    email: '',
    password: '',
  });

  const submit = (e: React.FormEvent) => {
    e.preventDefault();
    post(route('login')); // ❌ This line causes ReferenceError
  };

  return (
    <form onSubmit={submit}>
      <input
        name="email"
        value={data.email}
        onChange={(e) => setData('email', e.target.value)}
      />
      <button type="submit">Login</button>
    </form>
  );
}

Problem: When running the test:

I got this error: ReferenceError: route is not defined

What I tried

globalThis.route = vi.fn((name: string) => `/${name}`);

Adding this to top of the login.test.tsx file

What is the correct and type-safe way to mock Ziggy’s route() function in Vitest, so that I can test Inertia components that call route('login'), route('password.request'), etc.?

Do I need to mock Ziggy or install anything specific for tests?

This is my Login.test.tsx

import { fireEvent, render, screen } from '@testing-library/react';
import Login from '../../Pages/Auth/Login';

// Mock the Inertia route function

const post = vi.fn();
const setData = vi.fn();

vi.mock('@inertiajs/react', async () => {
    const actual = await vi.importActual('@inertiajs/react');

    return {
        ...actual,
        __esModule: true,

        useForm: vi.fn(() => ({
            data: { email: '', password: '', remember: false },
            setData,
            post,
            processing: false,
            errors: {},
            reset: vi.fn(),
        })),
    };
});

describe('LoginPage', () => {
    beforeEach(() => {
        vi.clearAllMocks();
    });

    it('renders login form fields and button', () => {
        render(<Login canResetPassword={true} />);

        expect(screen.getByLabelText(/email/i)).toBeInTheDocument();
        expect(screen.getByLabelText(/password/i)).toBeInTheDocument();
        expect(
            screen.getByRole('button', { name: /log in/i }),
        ).toBeInTheDocument();
        expect(screen.getByText(/forgot your password/i)).toBeInTheDocument();
    });

    it.skip('allows input and submits form', () => {
        render(<Login canResetPassword={true} />);

        const emailInput = screen.getByLabelText(/email/i) as HTMLInputElement;
        const passwordInput = screen.getByLabelText(
            /password/i,
        ) as HTMLInputElement;
        const submitButton = screen.getByRole('button', { name: /log in/i });

        fireEvent.change(emailInput, { target: { value: '[email protected]' } });
        fireEvent.change(passwordInput, { target: { value: 'secret123' } });

        expect(setData).toHaveBeenCalledWith('email', '[email protected]');
        expect(setData).toHaveBeenCalledWith('password', 'secret123');

        fireEvent.click(submitButton);

        expect(post).toHaveBeenCalledWith(
            'login',
            expect.objectContaining({
                onFinish: expect.any(Function),
            }),
        );
    });
});