---
name: ui-test-utils
description: "Use when writing or updating Anomalib Studio UI component or hook tests that need the shared render/renderHook helpers, React Router paths or parameters, React Query, theme, URL-query, stream, suspense, or toast providers."
---
# Anomalib Studio UI Test Utilities
Use this skill when working on tests in `application/ui/` that render React components or hooks. The shared utilities are defined in `application/ui/tests/utils.ts`.
## Purpose
Import `render` and `renderHook` from the shared test utilities rather than directly from `@testing-library/react` when the unit under test depends on application context. The utilities build a memory router and mount these providers:
- `QueryClientProvider` with an isolated `QueryClient` by default.
- `ThemeProvider` for `@geti-ui/ui` components.
- `NuqsAdapter` for URL query-state hooks.
- `StreamConnectionProvider` for stream-dependent UI.
- `Suspense` with `IntelBrandedLoading` fallback for lazy components.
- `Toast` for toast assertions and feedback behavior.
The default route is `/projects/project-123/inspect`, matched by the default path `/projects/:projectId/inspect`.
## When To Use Each Helper
Use `render` for a component, dialog, or view that renders DOM output. Use `renderHook` for a React hook that reads provider state, route parameters, search parameters, or React Query state.
Keep direct Testing Library rendering only for genuinely provider-free units. Do not duplicate the provider stack in individual tests.
## Advantages
- Tests exercise the component in the same context expected by the Studio application.
- The memory router makes route and route-parameter behavior deterministic without browser navigation.
- A fresh query client prevents React Query cache state leaking between tests by default.
- Shared provider setup keeps tests short and ensures new tests follow the established application test environment.
- Toast, stream, theme, URL-query, and suspense dependencies are available without per-test boilerplate.
## Component Tests
Import the helper using the relative path from the test file to `application/ui/tests/utils.ts`:
```tsx
import { screen } from "@testing-library/react";
import { render } from "../../../../../tests/utils";
import { ProjectPanel } from "./project-panel.component";
it("shows the selected project", () => {
render(, { route: "/projects/project-456/inspect" });
expect(screen.getByText("Project details")).toBeVisible();
});
```
Pass `route` when the component needs a specific location or `projectId`. The supplied route must match the selected `path`.
```tsx
render(, {
path: "/projects/:projectId/settings",
route: "/projects/project-456/settings",
});
```
Use Testing Library's accessible queries and async helpers after rendering. For server-backed behavior, configure the existing MSW `server` handler before calling `render`.
```tsx
server.use(
http.get("/api/projects/{project_id}", () => HttpResponse.json(project)),
);
render(, { route: "/projects/project-456/inspect" });
expect(
await screen.findByRole("heading", { name: project.name }),
).toBeVisible();
```
## Hook Tests
Use the wrapper-enabled helper rather than creating a custom provider wrapper in the test.
```tsx
import { waitFor } from "@testing-library/react";
import { renderHook } from "../../../../../tests/utils";
import { useActivePipelineStatus } from "./use-active-pipeline-status.hook";
it("reports an active project", async () => {
server.use(
http.get("/api/active-pipeline", () =>
HttpResponse.json({ project_id: "project-456" }),
),
);
const { result } = renderHook(() => useActivePipelineStatus("project-123"));
await waitFor(() => {
expect(result.current.hasActiveProject).toBe(true);
});
});
```
The helper accepts the same `route`, `path`, and `queryClient` options as `render`, together with normal Testing Library hook options such as `initialProps`.
```tsx
const queryClient = new QueryClient();
const { result, rerender } = renderHook(
({ projectId }) => useActivePipelineStatus(projectId),
{
initialProps: { projectId: "project-123" },
queryClient,
route: "/projects/project-123/inspect",
},
);
rerender({ projectId: "project-456" });
```
Provide `queryClient` only when the test must seed, inspect, or deliberately share cache state. Otherwise, use the default isolated client.
## Test Hygiene
- Configure MSW responses with `server.use(...)` for API behavior; do not perform real network requests.
- Wait for asynchronous query or mutation results with `findBy...` or `waitFor`.
- Keep routes explicit when behavior depends on project identifiers or URL state.
- Clear any externally imported, shared query client in `beforeEach` when the code under test uses one instead of the client supplied by this helper.
- Do not add application providers around `render` or `renderHook`; the utility already owns that setup.