用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Objective-Arts/lens-dist --skill react-test命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | react-test |
| description | React and testing patterns |
Apply Kent C. Dodds' philosophy and patterns for React development and testing.
╱╲
╱ ╲ E2E (few)
╱────╲
╱ ╲ Integration (most)
╱────────╲
╱ ╲ Unit (some)
╱────────────╲
╱ ╲ Static (ESLint, TypeScript)
╱────────────────╲
Key insight: Integration tests give the best confidence-to-effort ratio.
"Write tests. Not too many. Mostly integration."
"The more your tests resemble the way your software is used, the more confidence they can give you."
// BEST: Accessible to everyone
getByRole('button', { name: /submit/i })
getByLabelText('Email')
getByPlaceholderText('Enter email')
getByText('Welcome')
// GOOD: Semantic queries
getByAltText('Profile picture')
getByTitle('Close')
// OK: Test IDs (last resort)
getByTestId('submit-button')
Never use: container.querySelector, DOM structure queries
// WRONG
fireEvent.click(button)
fireEvent.change(input, { target: { value: 'text' } })
// RIGHT
import userEvent from '@testing-library/user-event'
const user = userEvent.setup()
await user.click(button)
await user.type(input, 'text')
// WRONG - tests implementation
expect(component.state.isOpen).toBe(true)
expect(wrapper.find('Modal').props().visible).toBe(true)
// RIGHT - tests behavior
expect(screen.getByRole('dialog')).toBeInTheDocument()
expect(screen.getByText('Modal content')).toBeVisible()
// FINE - multiple assertions for one behavior
test('submitting the form shows success message', async () => {
const user = userEvent.setup()
render(<ContactForm />)
await user.type(screen.getByLabelText(/email/i), 'test@example.com')
await user.type(screen.getByLabelText(/message/i), 'Hello')
await user.click(screen.getByRole('button', { name: /submit/i }))
expect(screen.getByRole('alert')).toHaveTextContent(/success/i)
expect(screen.queryByLabelText(/email/i)).not.toBeInTheDocument()
})
// WRONG - afterEach cleanup can hide issues
afterEach(() => {
jest.clearAllMocks()
cleanup()
})
// RIGHT - let Testing Library auto-cleanup
// It does this automatically between tests
test('shows error when submission fails', async () => {
server.use(
rest.post('/api/contact', (req, res, ctx) => {
return res(ctx.status(500))
})
)
const user = userEvent.setup()
render(<ContactForm />)
await user.click(screen.getByRole('button', { name: /submit/i }))
expect(screen.getByRole('alert')).toHaveTextContent(/error/i)
})
// Instead of prop drilling
<Menu items={items} onSelect={onSelect} renderItem={renderItem} />
// Use compound components
<Menu>
<Menu.Button>Options</Menu.Button>
<Menu.List>
<Menu.Item onSelect={() => {}}>Edit</Menu.Item>
<Menu.Item onSelect={() => {}}>Delete</Menu.Item>
</Menu.List>
</Menu>
function useToggle() {
const [on, setOn] = useState(false)
const toggle = () => setOn(o => !o)
// Prop getter - flexible
const getTogglerProps = (props = {}) => ({
'aria-pressed': on,
onClick: () => {
props.onClick?.()
toggle()
},
...props,
})
return { on, toggle, getTogglerProps }
}
// Usage
const { on, getTogglerProps } = useToggle()
<button {...getTogglerProps({ onClick: customHandler })}>
{on ? 'ON' : 'OFF'}
</button>
function useToggle({ reducer = (state, action) => action.changes } = {}) {
const [{ on }, dispatch] = useReducer(
(state, action) => reducer(state, { ...action, changes: toggleReducer(state, action) }),
{ on: false }
)
const toggle = () => dispatch({ type: 'toggle' })
return { on, toggle }
}
// Consumer can intercept state changes
const { on, toggle } = useToggle({
reducer: (state, action) => {
if (action.type === 'toggle' && clickedTooMany) {
return state // Prevent change
}
return action.changes
}
})
function useToggle({ on: controlledOn, onChange } = {}) {
const [internalOn, setInternalOn] = useState(false)
// Is it controlled?
const isControlled = controlledOn !== undefined
const on = isControlled ? controlledOn : internalOn
const toggle = () => {
if (!isControlled) {
setInternalOn(o => !o)
}
onChange?.(!on)
}
return { on, toggle }
}
// WRONG
<div onClick={handleClick}>Click me</div>
// RIGHT
<button onClick={handleClick}>Click me</button>
// Custom component needs ARIA
<div
role="button"
tabIndex={0}
aria-pressed={isActive}
onClick={handleClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleClick()
}
}}
>
Toggle
</div>
// WRONG
<input placeholder="Email" />
// RIGHT
<label>
Email
<input type="email" />
</label>
// OR
<label htmlFor="email">Email</label>
<input id="email" type="email" />
// OR (visually hidden label)
<label htmlFor="search" className="sr-only">Search</label>
<input id="search" placeholder="Search..." />
function Modal({ isOpen, onClose, children }) {
const closeButtonRef = useRef()
useEffect(() => {
if (isOpen) {
closeButtonRef.current?.focus()
}
}, [isOpen])
// Trap focus inside modal
// Return focus when closed
}
When reviewing React code, check:
| Instead of | Use |
|---|---|
fireEvent.click() | userEvent.click() |
getByTestId() | getByRole() or getByLabelText() |
wrapper.find() | screen.getByRole() |
expect(state) | expect(screen.getBy...) |
<div onClick> | <button onClick> |
| Mock everything | Mock at network boundary |