.agents/skills/frontend-testing/SKILL.md
Guidelines and strict rules for testing React components and hooks using Jest and React Testing Library.
npx skillsauth add filippovskii09/quize-audit Frontend Testing StandardsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Enforcement levels: MUST = mandatory · SHOULD = expected default · MAY = optional.
Example: assert "button not shown" → user clicks → "button appears".
screenscreen for all queries — do not destructure query methods from the render return value.rerender, unmount may be destructured from render.// ❌
const { getByRole } = render(<Example />)
getByRole('alert')
// ✅
render(<Example />)
screen.getByRole('alert')
| Priority | Query |
|---|---|
| 1 ✅ | getByRole / findByRole |
| 2 | getByLabelText, getByPlaceholderText, getByText, getByDisplayValue |
| 3 | getByAltText, getByTitle |
| 4 ⚠️ last resort | getByTestId |
container.querySelector for primary assertions.within(container) when multiple similar elements exist.role or aria-* attributes that duplicate implicit HTML semantics.// ❌ — redundant, <button> already has role="button"
<button role="button">Click me</button>
// ✅
<button>Click me</button>
@testing-library/user-event for user interactions (not fireEvent).findBy* for async appearance.waitFor only with a concrete assertion inside.waitFor.queryBy* only for non-existence assertions.ResizeObserver) in tests/setup.ts — not in individual test files.jest-dom semantic matchers@testing-library/jest-dom matchers instead of raw DOM property checks:| Instead of | Use |
|---|---|
| .disabled === true | .toBeDisabled() |
| .textContent === 'foo' | .toHaveTextContent('foo') |
| getComputedStyle(el).display !== 'none' | .toBeVisible() |
| el !== null | .toBeInTheDocument() |
// ✅
APP_MODE.IDLE
// ❌
'idle'
defaultMessage when UI text is message-driven:// ✅
import messages from '../messages';
expect(el).toHaveTextContent(messages.submitBtn.defaultMessage);
// ❌
expect(el).toHaveTextContent('Start Audit');
mock.calls[0][1].toEqual, toMatchObject) for payload checks.within() when multiple similar elements exist.act Usagerender or standard userEvent flows in manual act.act for explicit timer advancement:// ✅ correct use of act
act(() => {
jest.advanceTimersByTime(500);
});
Before writing assertions, MUST run a constants/messages discovery step:
constants.ts, messages.ts, __mocks__/.describe blocks shallow (max 2 levels deep).it / test names that match the test body behavior.setupFilesAfterEnach).// ❌ tests implementation detail
container.querySelector('.my-3')
// ✅ tests behavior
screen.getByRole('alert')
.closest(), .parentElement) in assertions.Test files follow a proximity rule — keep specs close to source:
Place directly alongside the source file (in the same folder):
src/components/ui/Button/
index.tsx
types.ts
index.spec.tsx ← ✅ single spec, stays in component root
When a folder has two or more spec files, MUST move all into __tests__/:
src/hooks/
useLocalStorage.ts
usePagination.ts
__tests__/
useLocalStorage.spec.ts ← ✅ multiple specs → __tests__/
usePagination.spec.ts
This rule applies everywhere:
src/components/**,src/hooks/,src/utils/, etc.
renderHook only when the hook has many independent edge cases, or is a published shared hook.renderHook rulesresult.current.act().waitFor for async hooks.@testing-library/react (React 18):import { renderHook, act } from '@testing-library/react';
rerender (from renderHook return) to test prop changes.unmount to test useEffect teardown.wrapper to renderHook when the hook requires context.useState, useEffect, etc.).src/test-utils.tsxrender from @src/test-utils — it wraps all required providers automatically.@testing-library/react exports from test-utils so tests have a single import source.// ✅
import { render, screen } from '@src/test-utils';
// ❌
import { screen } from '@testing-library/react';
import { renderWithProviders } from '@src/test-utils';
Only providers needed by the majority of components:
I18nProvider (project uses react-intl)Providers needed by only one or two tests MUST NOT be added to the global wrapper.
development
Domain skill for React internationalization setup with react-intl, locale switching, and typed i18n context. Use when adding new translations or extending locale behavior.
development
Domain skill for reusable typed React hooks used in business logic. Use when extending or validating shared hooks like local storage and pagination.
development
Reusable Prettier formatting recipe for TypeScript and frontend repositories. Use when enforcing consistent code style and integrating format checks in hooks.
tools
Declarative pre-commit framework recipe for polyglot repositories with stage-aware hooks (pre-commit and pre-push). Use when repositories need non-Node quality gates or mixed toolchains.