AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Api Test Generate

skill-manastalukdar-ai-devstudio-api-test-generate · by manastalukdar

Auto-generate comprehensive API tests for REST and GraphQL endpoints with request/response validation

No reviews yet
0 installs
19 views
0.0% view→install

Install

$ agentstack add skill-manastalukdar-ai-devstudio-api-test-generate

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-manastalukdar-ai-devstudio-api-test-generate)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Api Test Generate? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

API Test Generation

I'll generate comprehensive API tests for your REST or GraphQL endpoints with proper validation and assertions.

Features:

  • Auto-detect API framework (Express, FastAPI, Next.js API routes)
  • Generate request/response tests
  • Schema validation
  • Error handling tests
  • Authentication tests

Phase 1: API Framework Detection

# Detect API framework efficiently
detect_api_framework() {
    if [ -f "package.json" ]; then
        if grep -q "\"express\"" package.json; then
            echo "express"
        elif grep -q "\"fastify\"" package.json; then
            echo "fastify"
        elif grep -q "\"next\"" package.json; then
            echo "nextjs"
        elif grep -q "\"@apollo/server\"" package.json; then
            echo "apollo"
        fi
    elif [ -f "requirements.txt" ]; then
        if grep -q "fastapi" requirements.txt; then
            echo "fastapi"
        elif grep -q "flask" requirements.txt; then
            echo "flask"
        elif grep -q "django" requirements.txt; then
            echo "django"
        fi
    elif [ -f "go.mod" ]; then
        if grep -q "gin-gonic" go.mod; then
            echo "gin"
        elif grep -q "fiber" go.mod; then
            echo "fiber"
        fi
    fi
}

FRAMEWORK=$(detect_api_framework)

if [ -z "$FRAMEWORK" ]; then
    echo "❌ No API framework detected"
    echo "Supported frameworks:"
    echo "  Node: Express, Fastify, Next.js API routes, Apollo"
    echo "  Python: FastAPI, Flask, Django"
    echo "  Go: Gin, Fiber"
    exit 1
fi

echo "✓ API Framework: $FRAMEWORK"

Phase 2: Endpoint Discovery

echo ""
echo "Discovering API endpoints..."

# Use Grep to find endpoints efficiently
case $FRAMEWORK in
    express|fastify)
        ENDPOINTS=$(grep -r "\.get\(\\|\.post\(\\|\.put\(\\|\.delete\(\\|\.patch\(" \
                         --include="*.js" --include="*.ts" \
                         --exclude-dir=node_modules \
                         . | head -20)
        ;;
    nextjs)
        # Next.js API routes are file-based
        ENDPOINTS=$(find pages/api app/api -name "*.ts" -o -name "*.js" 2>/dev/null | head -20)
        ;;
    apollo)
        # GraphQL resolvers
        ENDPOINTS=$(grep -r "Query\\|Mutation" --include="*.ts" --include="*.js" \
                         --exclude-dir=node_modules . | head -20)
        ;;
    fastapi)
        ENDPOINTS=$(grep -r "@app\.\(get\|post\|put\|delete\|patch\)" --include="*.py" . | head -20)
        ;;
    flask)
        ENDPOINTS=$(grep -r "@app\.route" --include="*.py" . | head -20)
        ;;
    django)
        ENDPOINTS=$(find . -name "urls.py" -o -name "views.py" | head -20)
        ;;
esac

if [ -z "$ENDPOINTS" ]; then
    echo "⚠️ No API endpoints found"
    exit 1
fi

ENDPOINT_COUNT=$(echo "$ENDPOINTS" | wc -l)
echo "✓ Found $ENDPOINT_COUNT endpoints"
echo ""
echo "Sample endpoints:"
echo "$ENDPOINTS" | head -5 | sed 's/^/  /'

Phase 3: Test Framework Setup

echo ""
echo "Setting up test framework..."

# Detect or install test framework
if [ "$FRAMEWORK" = "express" ] || [ "$FRAMEWORK" = "fastify" ] || [ "$FRAMEWORK" = "nextjs" ]; then
    # Node.js - use supertest + jest
    if ! grep -q "\"supertest\"" package.json; then
        echo "Installing supertest for API testing..."
        npm install --save-dev supertest @types/supertest
    fi

    if ! grep -q "\"jest\"" package.json; then
        echo "Installing Jest..."
        npm install --save-dev jest ts-jest @types/jest
    fi

    echo "✓ Test framework ready: Jest + Supertest"

elif [ "$FRAMEWORK" = "fastapi" ] || [ "$FRAMEWORK" = "flask" ]; then
    # Python - use pytest + requests
    if ! grep -q "pytest" requirements.txt 2>/dev/null; then
        echo "Add to requirements.txt: pytest requests"
    fi

    echo "✓ Test framework: Pytest"
fi

Phase 4: Generate Test Files

echo ""
echo "Generating test files..."

mkdir -p tests/api

# Generate test file based on framework
case $FRAMEWORK in
    express|fastapi)
        cat > tests/api/endpoints.test.ts  {
  describe('GET /api/health', () => {
    it('should return 200 OK', async () => {
      const response = await request(app)
        .get('/api/health')
        .expect(200);

      expect(response.body).toHaveProperty('status');
      expect(response.body.status).toBe('ok');
    });
  });

  describe('GET /api/users', () => {
    it('should return list of users', async () => {
      const response = await request(app)
        .get('/api/users')
        .expect(200);

      expect(Array.isArray(response.body)).toBe(true);
      if (response.body.length > 0) {
        expect(response.body[0]).toHaveProperty('id');
        expect(response.body[0]).toHaveProperty('name');
        expect(response.body[0]).toHaveProperty('email');
      }
    });

    it('should handle query parameters', async () => {
      const response = await request(app)
        .get('/api/users?limit=10&offset=0')
        .expect(200);

      expect(response.body.length).toBeLessThanOrEqual(10);
    });
  });

  describe('POST /api/users', () => {
    it('should create new user', async () => {
      const newUser = {
        name: 'Test User',
        email: 'test@example.com'
      };

      const response = await request(app)
        .post('/api/users')
        .send(newUser)
        .expect(201);

      expect(response.body).toHaveProperty('id');
      expect(response.body.name).toBe(newUser.name);
      expect(response.body.email).toBe(newUser.email);
    });

    it('should validate required fields', async () => {
      const invalidUser = {
        name: 'Test User'
        // Missing email
      };

      await request(app)
        .post('/api/users')
        .send(invalidUser)
        .expect(400);
    });

    it('should reject invalid email format', async () => {
      const invalidUser = {
        name: 'Test User',
        email: 'invalid-email'
      };

      await request(app)
        .post('/api/users')
        .send(invalidUser)
        .expect(400);
    });
  });

  describe('GET /api/users/:id', () => {
    it('should return user by ID', async () => {
      const response = await request(app)
        .get('/api/users/1')
        .expect(200);

      expect(response.body).toHaveProperty('id');
      expect(response.body.id).toBe(1);
    });

    it('should return 404 for non-existent user', async () => {
      await request(app)
        .get('/api/users/99999')
        .expect(404);
    });
  });

  describe('PUT /api/users/:id', () => {
    it('should update existing user', async () => {
      const updates = {
        name: 'Updated Name'
      };

      const response = await request(app)
        .put('/api/users/1')
        .send(updates)
        .expect(200);

      expect(response.body.name).toBe(updates.name);
    });
  });

  describe('DELETE /api/users/:id', () => {
    it('should delete user', async () => {
      await request(app)
        .delete('/api/users/1')
        .expect(204);
    });

    it('should return 404 for non-existent user', async () => {
      await request(app)
        .delete('/api/users/99999')
        .expect(404);
    });
  });

  describe('Authentication', () => {
    it('should reject requests without auth token', async () => {
      await request(app)
        .get('/api/protected')
        .expect(401);
    });

    it('should accept requests with valid token', async () => {
      const token = 'valid-token'; // Get from login or fixture

      await request(app)
        .get('/api/protected')
        .set('Authorization', `Bearer ${token}`)
        .expect(200);
    });

    it('should reject invalid tokens', async () => {
      await request(app)
        .get('/api/protected')
        .set('Authorization', 'Bearer invalid-token')
        .expect(401);
    });
  });

  describe('Error Handling', () => {
    it('should handle server errors gracefully', async () => {
      // Test endpoint that might throw an error
      const response = await request(app)
        .get('/api/error-test')
        .expect(500);

      expect(response.body).toHaveProperty('error');
    });

    it('should return proper error messages', async () => {
      const response = await request(app)
        .post('/api/users')
        .send({}) // Invalid payload
        .expect(400);

      expect(response.body).toHaveProperty('message');
      expect(typeof response.body.message).toBe('string');
    });
  });
});
EOF

        echo "✓ Created tests/api/endpoints.test.ts"
        ;;

    apollo)
        cat > tests/api/graphql.test.ts  {
  let server: ApolloServer;

  beforeAll(() => {
    server = new ApolloServer({
      typeDefs,
      resolvers,
    });
  });

  describe('Queries', () => {
    it('should query users', async () => {
      const response = await server.executeOperation({
        query: `
          query {
            users {
              id
              name
              email
            }
          }
        `,
      });

      expect(response.body.kind).toBe('single');
      if (response.body.kind === 'single') {
        expect(response.body.singleResult.data?.users).toBeDefined();
      }
    });

    it('should query user by ID', async () => {
      const response = await server.executeOperation({
        query: `
          query GetUser($id: ID!) {
            user(id: $id) {
              id
              name
              email
            }
          }
        `,
        variables: { id: '1' },
      });

      expect(response.body.kind).toBe('single');
      if (response.body.kind === 'single') {
        expect(response.body.singleResult.data?.user).toHaveProperty('id');
      }
    });
  });

  describe('Mutations', () => {
    it('should create user', async () => {
      const response = await server.executeOperation({
        query: `
          mutation CreateUser($input: CreateUserInput!) {
            createUser(input: $input) {
              id
              name
              email
            }
          }
        `,
        variables: {
          input: {
            name: 'Test User',
            email: 'test@example.com',
          },
        },
      });

      expect(response.body.kind).toBe('single');
      if (response.body.kind === 'single') {
        expect(response.body.singleResult.data?.createUser).toHaveProperty('id');
      }
    });
  });
});
EOF

        echo "✓ Created tests/api/graphql.test.ts"
        ;;
esac

# Generate test helpers
cat > tests/api/helpers.ts  {
  // Generate test auth token
  return `test-token-${userId}`;
};

export const wait = (ms: number): Promise => {
  return new Promise(resolve => setTimeout(resolve, ms));
};
EOF

echo "✓ Created tests/api/helpers.ts"

Phase 5: Configuration

# Add test scripts to package.json
echo ""
echo "Add these scripts to package.json:"
cat << 'EOF'

  "scripts": {
    "test:api": "jest tests/api",
    "test:api:watch": "jest tests/api --watch",
    "test:api:coverage": "jest tests/api --coverage"
  }
EOF

Summary

echo ""
echo "=== API Test Generation Complete! ==="
echo ""
echo "✓ Framework: $FRAMEWORK"
echo "✓ Endpoints discovered: $ENDPOINT_COUNT"
echo "✓ Test files created"
echo ""
echo "📁 Generated files:"
echo "  - tests/api/endpoints.test.ts (or graphql.test.ts)"
echo "  - tests/api/helpers.ts"
echo ""
echo "🚀 Run tests:"
echo "  npm run test:api              # Run API tests"
echo "  npm run test:api:watch        # Watch mode"
echo "  npm run test:api:coverage     # With coverage"
echo ""
echo "📝 Next steps:"
echo "  1. Update test file with actual endpoint paths"
echo "  2. Customize assertions for your data models"
echo "  3. Add authentication setup if needed"
echo "  4. Run tests: npm run test:api"
echo "  5. Add to CI pipeline with /ci-setup"

Best Practices

API Testing Tips:

  • Test happy paths and error cases
  • Validate request/response schemas
  • Test authentication and authorization
  • Test rate limiting and pagination
  • Mock external dependencies

Integration Points:

  • /api-validate - Validate API contracts
  • /ci-setup - Add to CI pipeline
  • /test - Run alongside unit tests

Credits: API testing patterns based on Supertest documentation, FastAPI testing guide, and industry best practices.

Token Optimization

Expected range: 1,200–2,500 tokens (initial), 300–500 tokens (cache hit)

Caching: Caches API endpoint inventory in .claude/cache/api/endpoints.json for 7 days. Invalidated when route files change.

Early exit: Returns immediately if no API routes found in changed files.

Patterns used: Grep-before-Read, early exit, git diff scope default, template-based generation, caching

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.