Skip to content

Admin Dashboard Testing

The admin dashboard uses Vitest with Testing Library for component testing.

Setup

cd frontend/admin
npm run test        # Run all tests
npm run test -- --watch  # Watch mode

Tests run in a jsdom environment via Vitest.

Test Utilities

Two helper functions in test-utils.tsx simplify testing react-admin components.

renderWithAdmin(ui, options?)

Wraps a component in react-admin's AdminContext with mock providers:

import { renderWithAdmin } from "@/test-utils";

test("renders borrower list", () => {
  renderWithAdmin(<BorrowerList />);
  // Component has access to dataProvider, authProvider, i18nProvider, store
});

Default providers:

  • dataProvider: testDataProvider() from react-admin (mock CRUD operations)
  • authProvider: No-op login/logout, permissions default to wildcard ({ action: "*", resource: "*" })
  • i18nProvider: Full i18n provider with English/Spanish
  • store: In-memory store

renderWithRecord(ui, record, options?)

Wraps a component in AdminContext + RecordContextProvider, making a record available via useRecordContext():

import { renderWithRecord } from "@/test-utils";

test("renders money field", () => {
  renderWithRecord(
    <MoneyField source="amount" />,
    { id: 1, amount: { amount: "1000.00", currency: "USD" } },
  );
  expect(screen.getByText("$1,000.00")).toBeInTheDocument();
});

Use this for testing field components (MoneyField, StatusField, PercentField) that read from record context.

Writing Tests

Field Component Tests

import { screen } from "@testing-library/react";
import { renderWithRecord } from "@/test-utils";
import StatusField from "@/components/StatusField";

test("displays humanized status", () => {
  renderWithRecord(
    <StatusField source="status" />,
    { id: 1, status: "paid_off" },
  );
  expect(screen.getByText("Paid Off")).toBeInTheDocument();
});

Resource Screen Tests

import { screen } from "@testing-library/react";
import { renderWithAdmin } from "@/test-utils";
import { BorrowerList } from "@/admin/borrowers";

test("renders borrower list view", () => {
  renderWithAdmin(<BorrowerList />);
  expect(screen.getByText("Borrowers")).toBeInTheDocument();
});

Testing with Permissions

Override the default wildcard permissions to test permission-gated UI:

// The default authProvider grants all permissions.
// To test restricted access, provide a custom authProvider:
const restrictedAuth = {
  ...defaultAuthProvider,
  getPermissions: () =>
    Promise.resolve([
      { action: "list", resource: "borrowers" },
      { action: "show", resource: "borrowers" },
      // No "create" permission
    ]),
};

Test Organization

Tests live alongside their components in __tests__/ directories:

admin/{resource}/__tests__/
├── {Resource}List.test.tsx
├── {Resource}Show.test.tsx
└── {Resource}Create.test.tsx

Shared component tests:

components/__tests__/
├── MoneyField.test.tsx
├── StatusField.test.tsx
└── ActionButton.test.tsx

See Also