0

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),
            }),
        );
    });
});

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.