Unit testing loaders and actions helps you check that your data fetching and form handling work correctly before running your app. It catches mistakes early and keeps your app reliable.
0
0
Unit testing loaders and actions in Remix
Introduction
You want to verify that your loader returns the right data for a page.
You need to test that your action processes form submissions correctly.
You want to catch errors in data fetching or form handling logic.
You want to ensure your API responses have the expected shape.
You want to run tests without starting the full Remix server.
Syntax
Remix
import { loader, action } from './yourRouteFile'; // Call loader or action with a mock request const mockRequest = new Request('http://localhost/data'); const response = await loader({ request: mockRequest }); const data = await response.json();
Loaders and actions are async functions that receive a request object.
You can create mock requests to simulate different inputs.
Examples
Testing a loader by calling it with a simple GET request and logging the returned data.
Remix
import { loader } from './route'; const mockRequest = new Request('http://localhost/data'); const response = await loader({ request: mockRequest }); const data = await response.json(); console.log(data);
Testing an action by sending form data in a POST request and checking the JSON response.
Remix
import { action } from './route'; const formData = new FormData(); formData.append('name', 'Alice'); const mockRequest = new Request('http://localhost/form', { method: 'POST', body: formData }); const response = await action({ request: mockRequest }); const result = await response.json(); console.log(result);
Sample Program
This example shows how to unit test a Remix loader and action by calling them with mock requests. It tests both success and error cases and logs the results.
Remix
import { json } from '@remix-run/node'; // Example loader that returns user info export async function loader({ request }) { const url = new URL(request.url); const userId = url.searchParams.get('userId'); if (!userId) { return json({ error: 'Missing userId' }, { status: 400 }); } return json({ userId, name: 'Test User' }); } // Example action that echoes posted name export async function action({ request }) { const form = await request.formData(); const name = form.get('name'); if (!name) { return json({ error: 'Name is required' }, { status: 400 }); } return json({ message: `Hello, ${name}!` }); } // Unit test simulation async function test() { // Test loader with userId const loaderRequest = new Request('http://localhost/?userId=123'); const loaderResponse = await loader({ request: loaderRequest }); const loaderData = await loaderResponse.json(); // Test loader missing userId const badLoaderRequest = new Request('http://localhost/'); const badLoaderResponse = await loader({ request: badLoaderRequest }); const badLoaderData = await badLoaderResponse.json(); // Test action with name const formData = new FormData(); formData.append('name', 'Alice'); const actionRequest = new Request('http://localhost/', { method: 'POST', body: formData }); const actionResponse = await action({ request: actionRequest }); const actionData = await actionResponse.json(); // Test action missing name const badFormData = new FormData(); const badActionRequest = new Request('http://localhost/', { method: 'POST', body: badFormData }); const badActionResponse = await action({ request: badActionRequest }); const badActionData = await badActionResponse.json(); console.log('Loader with userId:', loaderData); console.log('Loader missing userId:', badLoaderData); console.log('Action with name:', actionData); console.log('Action missing name:', badActionData); } test();
OutputSuccess
Important Notes
Use Request objects to simulate HTTP requests in tests.
Check both success and error responses to cover all cases.
Remember loaders and actions return Response objects, so use response.json() to get data.
Summary
Unit testing loaders and actions helps catch bugs early in data fetching and form handling.
Use mock Request objects to simulate different inputs.
Test both success and error scenarios for full coverage.