name: tester description: Write unit tests for code changes across multiple stacks including JavaScript/TypeScript (Jest, Vitest), React (Testing Library), PHP (PHPUnit), Python (pytest), Django (TestCase), Hono.js, Express.js, and Flutter (Dart). Use when the user asks to write tests, add test coverage, create unit tests, or when making code changes that need test coverage. Automatically suggests tests for new or modified code.
Unit Test Writer
Write unit tests that uphold these principles:
- Fast feedback - Tests run quickly and give immediate confidence.
- Safety net - Prove the code works as intended.
- Reduce cost - Catch issues early, minimize rework.
- Regression coverage - Prevent fixed bugs from resurfacing.
- Automation-ready - Deterministic, runnable in CI.
- Maintenance-friendly - Future changes are easy to verify.
- Isolated - Mock all external dependencies; never rely on remote services.
Workflow
Task Progress:
- [ ] Step 1: Analyze the code under test
- [ ] Step 2: Identify the test location and type
- [ ] Step 3: Discover existing test utilities and mock data
- [ ] Step 4: Write the test
- [ ] Step 5: Run and verify the test passes
Step 1: Analyze the code under test
Before writing any test:
- Read the source file thoroughly.
- Identify all code paths: happy path, edge cases, error handling.
- List external dependencies that need mocking.
- Check what the function/component receives (props, args) and returns/renders.
Step 2: Identify test location and type
File placement - Always check for a nearby tests/ or __tests__/ folder first and follow the same convention. If no existing pattern, use the stack default:
| Stack | Convention |
|---|---|
| JS/TS (Jest/Vitest) | __tests__/Foo.test.ts or tests/Foo.test.ts next to source |
| PHP (PHPUnit) | tests/Unit/, tests/Feature/ mirroring src/ or app/ structure |
| Python (pytest) | tests/ directory mirroring source, prefixed test_*.py |
| Django | tests/ inside each app, or app/tests/test_*.py |
| Hono.js | src/**/*.test.ts or tests/*.test.ts (Vitest) |
| Express.js | __tests__/ or tests/ with *.test.js / *.spec.js |
| Flutter (Dart) | test/ directory mirroring lib/, suffixed _test.dart |
Test type decision by stack:
| What you're testing | Framework / Tool |
|---|---|
| React component | @testing-library/react + userEvent |
| JS/TS utility function | Direct calls with Jest/Vitest assertions |
| Redux saga | redux-saga-test-plan (expectSaga / testSaga) |
| React hook | @testing-library/react-hooks (renderHook) |
| Express route/middleware | supertest + Jest |
| Hono route/middleware | app.request() or @hono/node-server + Vitest |
| PHP class/service | PHPUnit TestCase with setUp() / tearDown() |
| Python function/class | pytest with fixtures and unittest.mock |
| Django view/model | django.test.TestCase with Client |
| Flutter widget | flutter_test with testWidgets, WidgetTester, find |
| Dart class/function | test package with group, test, expect |
| Flutter Bloc/Cubit | bloc_test with blocTest |
Step 3: Discover existing utilities and mock data
Before writing mocks from scratch, search the project for existing resources:
- Test helpers/utilities: Look for
test-utils,conftest.py,TestCasebase classes,setUpfiles - Mock data / fixtures: Look for
__mockData__/,fixtures/,factories/,conftest.py,*Factory.php - Setup files:
setupTests.js,conftest.py,TestCase::setUp(),phpunit.xml - Existing mocks:
__mocks__/,unittest.mock, Mockery, test doubles
Reuse existing mock data and test utilities. Only create new mocks when no suitable ones exist.
Step 4: Write the test
Follow these conventions:
Structure
// Multivariate Dependencies
import React from 'react';
// Components
import { MyComponent } from '../MyComponent';
// Utils
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
// Types
import { SomeType } from '../../types/SomeType';
describe('MyComponent', () => {
// Setup mocks at describe scope
const mockHandler = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
});
// Optional: helper render function for repeated setup
const renderComponent = (overrides = {}) => {
const defaultProps = { onSubmit: mockHandler, ...overrides };
return render(<MyComponent {...defaultProps} />);
};
it('should render the submit button', () => {
renderComponent();
expect(screen.getByRole('button', { name: 'Submit' })).toBeVisible();
});
it('should call onSubmit when clicked', () => {
renderComponent();
userEvent.click(screen.getByRole('button', { name: 'Submit' }));
expect(mockHandler).toHaveBeenCalledTimes(1);
});
});
Import grouping
Follow the existing convention with comment headers:
// Multivariate Dependencies
// Components
// Utils
// Types
Naming conventions
describeblock: Component/function nameitblock: Start with "should" — describe the expected behavior- Use
it.eachfor parameterized tests over multiple similar cases
Mocking rules
- Use
jest.mock()for module-level mocks (at file top, outside describe). - Use
jest.spyOn()for spying on specific functions while preserving others. - Use
jest.fn()for callback/handler props. - Call
jest.clearAllMocks()inbeforeEach. - Use
mockReturnValue/mockResolvedValuefor default mocks; usemockReturnValueOnce/mockResolvedValueOncefor per-test overrides.
Assertions
- Prefer
@testing-library/jest-dommatchers:toBeVisible(),toBeInTheDocument(),toHaveTextContent(). - Use
screen.getByRole()overgetByTestId()— query by accessibility role first. - Use
screen.queryBy*()to assert absence (returnsnull). - Use
toStrictEqual()for deep object comparison. - Use
expect.objectContaining()for partial matching. - Use
toHaveBeenCalledWith()to verify mock call arguments.
Components requiring providers
Use existing test utilities from src/records/components/test-utils.js:
renderWithMuiWrapper— MUI ThemeProviderrenderWithReduxWrapper— Redux Provider with mock storerenderWithMuiAndReduxProvider— Both providers
Redux saga tests
Use redux-saga-test-plan:
expectSagafor integration-style tests (with.withState(),.dispatch(),.put())testSagafor step-by-step unit tests (.next(),.select(),.put(),.isDone())
Step 5: Run and verify
Run the test to confirm it passes. Use the appropriate command for the stack:
# JS/TS (Jest)
npx jest --testPathPattern="path/to/test" --no-coverage
# JS/TS (Vitest)
npx vitest run path/to/test
# PHP (PHPUnit)
./vendor/bin/phpunit --filter=TestClassName tests/Unit/path/to/Test.php
# Python (pytest)
python -m pytest tests/path/to/test_file.py -v
# Django
python manage.py test app.tests.test_module.TestClassName -v 2
# Flutter (Dart)
flutter test test/path/to/file_test.dart
If tests fail, read the error output, fix the issue, and rerun. Do not leave failing tests.
When suggesting tests for code changes
When making code changes (not explicitly asked for tests), proactively suggest test coverage by:
- Noting which functions/components were added or modified.
- Briefly listing what should be tested (happy path, edge cases, error handling).
- Offering to write the tests.
Do not auto-generate tests without the user's consent unless they explicitly asked for tests.
Anti-patterns to avoid
- Never test implementation details (internal state, private methods).
- Never use
snapshottests for new tests unless explicitly requested. - Never import from
enzyme— use@testing-library/reactfor React. - Never hardcode magic strings — import constants/enums from source.
- Never write tests that depend on test execution order.
- Never make real network requests — mock all API calls and external services.
- Never use
setTimeout/setIntervalin tests — use fake timers if timing logic needs testing. - Never use the real database in unit tests — use mocks, fakes, or in-memory SQLite.
- Never use
sleep()or real delays — use deterministic assertions.
Examples by stack
Read only the file relevant to the current project's stack:
- examples-react-jest.md — React, Jest, Redux Saga, Testing Library
- examples-php.md — PHP, PHPUnit
- examples-python.md — Python, pytest, async
- examples-django.md — Django models, views, API
- examples-hono.md — Hono.js, Vitest
- examples-express.md — Express.js, Supertest, Jest
- examples-flutter.md — Flutter, Dart, widget tests, Bloc