원클릭으로
vitest-testing
Vitest unit and component testing patterns. Use when writing unit tests, component tests, or hook tests.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Vitest unit and component testing patterns. Use when writing unit tests, component tests, or hook tests.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Code review of current PR/commit changes against project coding standards. Use when the user asks for a code review or mentions reviewing changes.
Reference for the Tangle component YAML specification format
Guidelines for building well-structured, maintainable ML pipelines in Tangle
Analyzes merged PRs from the past week, identifies user-facing changes, and opens a draft PR to the TangleML/website docs repo with updated documentation. Use when running the weekly documentation sync, or when the user invokes /docs-update.
React and React Compiler patterns for this project. Use when writing React components, hooks, providers, or working with React Compiler compatibility.
Run validation and testing commands for the project. Use when the user asks to validate, lint, typecheck, or run tests.
| name | vitest-testing |
| description | Vitest unit and component testing patterns. Use when writing unit tests, component tests, or hook tests. |
Focus tests on the component/hook under test. Assume that dependencies (services, hooks, utilities) are independently tested in their own test files. Only mock what's necessary to isolate the unit under test — don't re-test dependency behavior or create elaborate mock setups for services that aren't the focus of the test.
describe, it, expect are globally available (no imports needed)@testing-library/jest-dom is configured in vitest-setup.js@testing-library/react with render, screen, fireEvent, waitForvi.mock() and vi.fn(), not HTTP interceptionTests are co-located next to source files:
src/utils/searchUtils.ts
src/utils/searchUtils.test.ts
src/hooks/useIOSelectionPersistence.ts
src/hooks/useIOSelectionPersistence.test.ts
src/components/shared/SuspenseWrapper.tsx
src/components/shared/SuspenseWrapper.test.tsx
describe("formatDuration", () => {
it("formats seconds correctly", () => {
const start = "2024-01-01T10:00:00.000Z";
const end = "2024-01-01T10:00:30.000Z";
expect(formatDuration(start, end)).toBe("30s");
});
});
Render with providers using a wrapper function:
const renderWithProviders = (component: React.ReactElement) => {
return render(component, {
wrapper: ({ children }) => (
<ComponentSpecProvider spec={mockComponentSpec}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</ComponentSpecProvider>
),
});
};
it("renders the toolbar", async () => {
renderWithProviders(<RunToolbar />);
await waitFor(() => {
expect(screen.getByTestId("inspect-pipeline-button")).toBeInTheDocument();
});
});
Use renderHook with a wrapper for hooks that need providers:
const createWrapper = () => {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
return ({ children }: { children: React.ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
};
it("should hydrate component", async () => {
vi.mocked(hydrateComponentReference).mockResolvedValue(mockHydratedRef);
const { result } = renderHook(
() => useHydrateComponentReference(mockComponent),
{ wrapper: createWrapper() },
);
await waitFor(() => {
expect(result.current).toEqual(mockHydratedRef);
});
});
Use act for state updates in hooks:
act(() => {
result.current.preserveIOSelectionOnSpecChange(initialSpec);
});
expect(mockSetNodes).toHaveBeenCalledWith(expect.any(Function));
vi.mock()vi.mock("@/utils/localforage", () => ({
componentExistsByUrl: vi.fn(),
getComponentByUrl: vi.fn(),
saveComponent: vi.fn(),
}));
// React component mock
vi.mock("@monaco-editor/react", () => ({
default: ({ defaultValue }: { defaultValue: string }) => (
<pre data-testid="monaco-mock">{defaultValue}</pre>
),
}));
// Provider/context mock
vi.mock("@/providers/ComponentSpecProvider", () => ({
useComponentSpec: () => ({
componentSpec: mockSpec,
setComponentSpec: mockSetComponentSpec,
}),
}));
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
// ... test code
expect(consoleSpy).toHaveBeenCalledWith("Error:", expect.any(Error));
const mockFetch = vi.fn();
global.fetch = mockFetch;
mockFetch.mockResolvedValue({
ok: true,
text: () => Promise.resolve(yamlContent),
} as Response);
vi.stubEnv("VITE_GITHUB_CLIENT_ID", "test-client-id");
Create inline helper functions for test data — don't over-abstract:
const createMockNode = (
id: string,
type: "input" | "output" | "task",
label: string,
selected = false,
) => ({
id,
type,
position: { x: 0, y: 0 },
data: { label },
selected,
});
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
cleanup(); // Testing Library cleanup
queryClient.clear(); // Clear query cache if using QueryClient
vi.restoreAllMocks();
});
// DOM assertions
expect(screen.getByTestId("submit")).toBeInTheDocument();
expect(screen.queryByTestId("hidden")).not.toBeInTheDocument();
// Mock assertions
expect(mockFn).toHaveBeenCalledWith(url);
expect(mockFn).toHaveBeenCalledTimes(1);
expect(mockFn).not.toHaveBeenCalled();
// Partial matching
expect(mockSave).toHaveBeenCalledWith({
id: expect.stringMatching(/^component-\w+$/),
createdAt: expect.any(Number),
});
Prefer fireEvent for simple interactions in this project:
const input = screen.getByLabelText("Name") as HTMLInputElement;
fireEvent.change(input, { target: { value: "NewName" } });
fireEvent.blur(input);
expect(mockCallback).toHaveBeenCalled();
// Wait for state updates
await waitFor(() => {
expect(screen.getByTestId("content")).toBeInTheDocument();
});
// Assert on promises
await expect(promise).resolves.toBe(expectedValue);
pnpm test — Run all unit tests oncepnpm run test:coverage — Run with coverage reportpnpm run validate:test — Full validate + unit tests