tester/SKILL.md
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.
npx skillsauth add tim-hub/role-based-skills testerInstall 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.
Write unit tests that uphold these principles:
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
Before writing any test:
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 |
Before writing mocks from scratch, search the project for existing resources:
test-utils, conftest.py, TestCase base classes, setUp files__mockData__/, fixtures/, factories/, conftest.py, *Factory.phpsetupTests.js, conftest.py, TestCase::setUp(), phpunit.xml__mocks__/, unittest.mock, Mockery, test doublesReuse existing mock data and test utilities. Only create new mocks when no suitable ones exist.
Follow these conventions:
// 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);
});
});
Follow the existing convention with comment headers:
// Multivariate Dependencies
// Components
// Utils
// Types
describe block: Component/function nameit block: Start with "should" — describe the expected behaviorit.each for parameterized tests over multiple similar casesjest.mock() for module-level mocks (at file top, outside describe).jest.spyOn() for spying on specific functions while preserving others.jest.fn() for callback/handler props.jest.clearAllMocks() in beforeEach.mockReturnValue / mockResolvedValue for default mocks; use mockReturnValueOnce / mockResolvedValueOnce for per-test overrides.@testing-library/jest-dom matchers: toBeVisible(), toBeInTheDocument(), toHaveTextContent().screen.getByRole() over getByTestId() — query by accessibility role first.screen.queryBy*() to assert absence (returns null).toStrictEqual() for deep object comparison.expect.objectContaining() for partial matching.toHaveBeenCalledWith() to verify mock call arguments.Use existing test utilities from src/records/components/test-utils.js:
renderWithMuiWrapper — MUI ThemeProviderrenderWithReduxWrapper — Redux Provider with mock storerenderWithMuiAndReduxProvider — Both providersUse redux-saga-test-plan:
expectSaga for integration-style tests (with .withState(), .dispatch(), .put())testSaga for step-by-step unit tests (.next(), .select(), .put(), .isDone())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 making code changes (not explicitly asked for tests), proactively suggest test coverage by:
Do not auto-generate tests without the user's consent unless they explicitly asked for tests.
snapshot tests for new tests unless explicitly requested.enzyme — use @testing-library/react for React.setTimeout/setInterval in tests — use fake timers if timing logic needs testing.sleep() or real delays — use deterministic assertions.Read only the file relevant to the current project's stack:
testing
Use when creating new skills, editing existing skills, or verifying skills work before deployment - applies TDD to process documentation by testing with subagents before writing, iterating until bulletproof against rationalization
development
Use when design is complete and you need detailed implementation tasks for engineers with zero codebase context - creates comprehensive implementation plans with exact file paths, complete code examples, and verification steps assuming engineer has minimal domain knowledge
data-ai
Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always
tools
Use when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees with smart directory selection and safety verification