
tdd
Test-Driven Development workflow for ALL Prowler components (UI, SDK, API). Trigger: ALWAYS when implementing features, fixing bugs, or refactoring - regardless of component. This is a MANDATORY workflow, not optional.
- Installs
- 58
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/prowler-cloud/prowler --skill tdd- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads tdd automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
TDD Cycle (MANDATORY)
+-----------------------------------------+
| RED -> GREEN -> REFACTOR |
| ^ | |
| +------------------------+ |
+-----------------------------------------+
The question is NOT "should I write tests?" but "what tests do I need?"
The Three Laws of TDD
- No production code until you have a failing test
- No more test than necessary to fail
- No more code than necessary to pass
Detect Your Stack
Before starting, identify which component you're working on:
| Working in | Stack | Runner | Test pattern | Details |
|---|---|---|---|---|
ui/ | TypeScript / React | Vitest + RTL | *.test.{ts,tsx} (co-located) | See vitest skill |
prowler/ | Python | pytest + moto | *_test.py (suffix) in tests/ | See prowler-test-sdk skill |
api/ | Python / Django | pytest + django | test_*.py (prefix) in api/src/backend/**/tests/ | See prowler-test-api skill |
Phase 0: Assessment (ALWAYS FIRST)
Before writing ANY code:
UI (ui/)
# 1. Find existing tests
fd "*.test.tsx" ui/components/feature/
# 2. Check coverage
pnpm test:coverage -- components/feature/
# 3. Read existing tests
SDK (prowler/)
# 1. Find existing tests
fd "*_test.py" tests/providers/aws/services/ec2/
# 2. Run specific test
uv run pytest tests/providers/aws/services/ec2/ec2_ami_public/ -v
# 3. Read existing tests
API (api/)
# 1. Find existing tests
fd "test_*.py" api/src/backend/api/tests/
# 2. Run specific test
uv run pytest api/src/backend/api/tests/test_models.py -v
# 3. Read existing tests
Decision Tree (All Stacks)
+------------------------------------------+
| Does test file exist for this code? |
+----------+-----------------------+-------+
| NO | YES
v v
+------------------+ +------------------+
| CREATE test file | | Check coverage |
| -> Phase 1: RED | | for your change |
+------------------+ +--------+---------+
|
+--------+--------+
| Missing cases? |
+---+---------+---+
| YES | NO
v v
+-----------+ +-----------+
| ADD tests | | Proceed |
| Phase 1 | | Phase 2 |
+-----------+ +-----------+
Phase 1: RED - Write Failing Tests
For NEW Functionality
UI (Vitest)
describe("PriceCalculator", () => {
it("should return 0 for quantities below threshold", () => {
// Given
const quantity = 3;
// When
const result = calculateDiscount(quantity);
// Then
expect(result).toBe(0);
});
});
SDK (pytest)
class Test_ec2_ami_public:
@mock_aws
def test_no_public_amis(self):
# Given - No AMIs exist
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch("prowler...ec2_service", new=EC2(aws_provider)):
from prowler...ec2_ami_public import ec2_ami_public
# When
check = ec2_ami_public()
result = check.execute()
# Then
assert len(result) == 0
API (pytest-django)
@pytest.mark.django_db
class TestResourceModel:
def test_create_resource_with_tags(self, aws_provider):
# Given
provider = aws_provider
tenant_id = provider.tenant_id
# When
resource = Resource.objects.create(
tenant_id=tenant_id, provider=provider,
uid="arn:aws:ec2:us-east-1:123456789:instance/i-1234",
name="test", region="us-east-1", service="ec2", type="instance",
)
# Then
assert resource.uid == "arn:aws:ec2:us-east-1:123456789:instance/i-1234"
Run -> MUST fail: Test references code that doesn't exist yet.
For BUG FIXES
Write a test that reproduces the bug first:
UI: expect(() => render(<DatePicker value={null} />)).not.toThrow();
SDK: assert result[0].status == "FAIL" # Currently returns PASS incorrectly
API: assert response.status_code == 403 # Currently returns 200
Run -> Should FAIL (reproducing the bug).
For REFACTORING
Capture ALL current behavior BEFORE refactoring:
# Any stack: run ALL existing tests, they should PASS
# This is your safety net - if any fail after refactoring, you broke something
Run -> All should PASS (baseline).
Phase 2: GREEN - Minimum Code
Write the MINIMUM code to make the test pass. Hardcoding is valid for the first test.
UI:
// Test expects calculateDiscount(100, 10) === 10
function calculateDiscount() {
return 10; // FAKE IT - hardcoded is valid for first test
}
Python (SDK/API):
# Test expects check.execute() returns 0 results
def execute(self):
return [] # FAKE IT - hardcoded is valid for first test
This passes. But we're not done...
Phase 3: Triangulation (CRITICAL)
One test allows faking. Multiple tests FORCE real logic.
Add tests with different inputs that break the hardcoded value:
| Scenario | Required? |
|---|---|
| Happy path | YES |
| Zero/empty values | YES |
| Boundary values | YES |
| Different valid inputs | YES (breaks fake) |
| Error conditions | YES |
UI:
it("should calculate 10% discount", () => {
expect(calculateDiscount(100, 10)).toBe(10);
});
// ADD - breaks the fake:
it("should calculate 15% on 200", () => {
expect(calculateDiscount(200, 15)).toBe(30);
});
it("should return 0 for 0% rate", () => {
expect(calculateDiscount(100, 0)).toBe(0);
});
Python:
def test_single_public_ami(self):
# Different input -> breaks hardcoded empty list
assert len(result) == 1
assert result[0].status == "FAIL"
def test_private_ami(self):
assert result[0].status == "PASS"
Now fake BREAKS -> Real implementation required.
Phase 4: REFACTOR
Tests GREEN -> Improve code quality WITHOUT changing behavior.
- Extract functions/methods
- Improve naming
- Add types/validation
- Reduce duplication
Run tests after EACH change -> Must stay GREEN.
Quick Reference
+------------------------------------------------+
| TDD WORKFLOW |
+------------------------------------------------+
| 0. ASSESS: What tests exist? What's missing? |
| |
| 1. RED: Write ONE failing test |
| +-- Run -> Must fail with clear error |
| |
| 2. GREEN: Write MINIMUM code to pass |
| +-- Fake It is valid for first test |
| |
| 3. TRIANGULATE: Add tests that break the fake |
| +-- Different inputs, edge cases |
| |
| 4. REFACTOR: Improve with confidence |
| +-- Tests stay green throughout |
| |
| 5. REPEAT: Next behavior/requirement |
+------------------------------------------------+
Anti-Patterns (NEVER DO)
# ANY language:
# 1. Code first, tests after
def new_feature(): ... # Then writing tests = USELESS
# 2. Skip triangulation
# Single test allows faking forever
# 3. Test implementation details
assert component.state.is_loading == True # BAD - test behavior, not internals
assert mock_service.call_count == 3 # BAD - brittle coupling
# 4. All tests at once before any code
# Write ONE test, make it pass, THEN write the next
# 5. Giant test methods
# Each test should verify ONE behavior
Commands by Stack
UI (ui/)
pnpm test # Watch mode
pnpm test:run # Single run (CI)
pnpm test:coverage # Coverage report
pnpm test ComponentName # Filter by name
SDK (prowler/)
uv run pytest tests/path/ -v # Run specific tests
uv run pytest tests/path/ -v -k "test_name" # Filter by name
uv run pytest -n auto tests/ # Parallel run
uv run pytest --cov=./prowler tests/ # Coverage
API (api/)
uv run pytest -x --tb=short # Run all (stop on first fail)
uv run pytest api/src/backend/api/tests/test_file.py # Specific file
uv run pytest -k "test_name" -v # Filter by name
FAQ
What does the tdd skill do?
Test-Driven Development workflow for ALL Prowler components (UI, SDK, API). Trigger: ALWAYS when implementing features, fixing bugs, or refactoring - regardless of component. This is a MANDATORY workflow, not optional.
How do I install tdd?
Run npx skills add https://github.com/prowler-cloud/prowler --skill tdd in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/tdd/ (personal) or .claude/skills/tdd/ (project).
Which AI agents can use tdd?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is tdd safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains tdd?
It is published by prowler-cloud in prowler-cloud/prowler. It has 58 recorded installs.
More from prowler-cloud/prowler
zod-4
prowler-cloud/prowler
Zod 4 schema validation patterns. Trigger: When creating or updating Zod v4 schemas for validation/parsing (forms, request payloads, adapters), including v3 - v4 migration patterns.
zustand-5
prowler-cloud/prowler
Zustand 5 state management patterns. Trigger: When implementing client-side state with Zustand (stores, selectors, persist middleware, slices).
react-19
prowler-cloud/prowler
React 19 patterns with React Compiler. Trigger: When writing React 19 components/hooks in .tsx (React Compiler rules, hook patterns, refs as props). If using Next.js App Router/Server Actions, also use nextjs-16.
tailwind-4
prowler-cloud/prowler
Tailwind CSS 4 patterns and best practices. Trigger: When styling with Tailwind (className, variants, cn()), especially when dynamic styling or CSS variables are involved (no var() in className).
django-drf
prowler-cloud/prowler
Django REST Framework patterns. Trigger: When implementing generic DRF APIs (ViewSets, serializers, routers, permissions, filtersets). For Prowler API specifics (RLS/RBAC/Providers), also use prowler-api.
typescript
prowler-cloud/prowler
Open the skill to read its SKILL.md instructions.
Popular testing & qa skills
tdd
mattpocock/skills
Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
grilling
mattpocock/skills
Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases.
migrate-to-shoehorn
mattpocock/skills
Migrate test files from as type assertions to @total-typescript/shoehorn. Use when user mentions shoehorn, wants to replace as in tests, or needs partial test data.
run-train
lllllllama/rigorpilot-skills
Rigor Train skill for deep learning research repositories. Use when a documented or selected training command should be run conservatively for startup verification, short-run verification, full kickoff, or resume, with command, config, seed, log, checkpoint, status, and metric evidence written to standardized trainoutputs/. Do not use for environment setup, exploratory sweeps, speculative idea implementation, or end-to-end orchestration.
test-driven-development
obra/superpowers
Use when implementing any feature or bugfix, before writing implementation code
finishing-a-development-branch
obra/superpowers
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work