Skip to content
Security
Skill

/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.

From plugin
prowler
15k39 skills1 MCP

Claude Code

$ npx -y skills add prowler-cloud/prowler --skill tdd --agent claude-code

SKILL.md

tdd.SKILL.md
name: tdd
description: >
  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.
license: Apache-2.0
metadata:
  author: prowler-cloud
  version: "2.1"
  scope: [root, ui, api, sdk]
  auto_invoke:
    - "Implementing feature"
    - "Fixing bug"
    - "Refactoring code"
    - "Working on task"
    - "Modifying component"
allowed-tools: Read, Edit, Write, Glob, Grep, Bash, Task

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

1. **No production code** until you have a failing test 2. **No more test** than necessary to fail 3. **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 for AWS, MagicMock elsewhere) | `*_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
find ui/components/feature -name "*.test.ts*"

# 2. Check coverage
cd ui && pnpm test:coverage components/feature/

# 3. Read existing tests

SDK (`prowler/`)

# 1. Find existing tests
find tests/providers/aws/services/ec2 -name "*_test.py"

# 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
find api/src/backend -path "*/tests/*" -name "test_*.py"

# 2. Run specific test (API commands run from api/)
cd api && uv run pytest 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_amis(self):
        # Given - No AMIs exist
        from prowler.providers.aws.services.ec2.ec2_service import EC2

        aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])

        with (
            mock.patch(
                "prowler.providers.common.provider.Provider.get_global_provider",
                return_value=aws_provider,
            ),
            mock.patch(
                "prowler.providers.aws.services.ec2.ec2_ami_public.ec2_ami_public.ec2_client",
                new=EC2(aws_provider),
            ),
        ):
            from prowler.providers.aws.services.ec2.ec2_ami_public.ec2_ami_public import (
                ec2_ami_public,
            )

            # When
            result = ec2_ami_public().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 calc
Read more
@prowler-cloud
Ships withprowler

Prowler is the world’s most widely used Open-Source Cloud Security Platform that automates security and compliance across any cloud environment.

15k39 skills1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
15.2k
Star history of prowler-cloud/prowler on GitHub, a chart by star-history.com

Other skills on prowler.

ai-sdk-5

ai-sdk-5

Vercel AI SDK patterns for the installed major (ui/package.json: `ai` 6.x, `@ai-sdk/react` 3.x). The skill name is historical;…

django-drf

django-drf

Django REST Framework patterns. Trigger: When implementing generic DRF APIs (ViewSets, serializers, routers, permissions,…

gh-aw

gh-aw

Create and maintain GitHub Agentic Workflows (gh-aw) for Prowler. Trigger: When creating agentic workflows, modifying gh-aw…

jsonapi

jsonapi

Strict JSON:API v1.1 specification compliance. Trigger: When creating or modifying API endpoints, reviewing API responses, or…

More skills from other plugins.

api-security

api-security

Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…

@zhaoxuya520@zhaoxuya520Install Skill
nemoclaw-user-guide

nemoclaw-user-guide

Find official NemoClaw documentation for installation, configuration, operation, or troubleshooting. Also handles requested docs…

nemoclaw10d23k
@nvidia@nvidiaInstall Skill

Questions about tdd.

Which coding agents can use tdd?
tdd installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.