supabase
Handles the full Supabase workflow from schema changes to deployment, with built-in security guardrails that catch common traps like RLS...
integration-test-writer
Generate comprehensive integration tests for component interactions,
Full skill instructions
This skill provides systematic guidance for writing integration tests that verify component interactions, API endpoints, database operations, and end-to-end workflows. Integration tests validate that multiple components work together correctly.
Unit Tests:
Integration Tests:
Map the system:
# Identify components to test together
- API controllers + Services + Database
- Services + External APIs
- Authentication + Authorization + Resources
- Multi-step workflows
Integration test targets:
Deliverable: Integration test plan
Test environment components:
Test Database:
Test Configuration:
Test Fixtures:
Python example (pytest + FastAPI):
# tests/conftest.py
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session
from src.main import app
from src.database import Base, get_db
from src.models import User, Resource
# Test database
TEST_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(TEST_DATABASE_URL, connect_args={"check_same_thread": False})
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
@pytest.fixture(scope="function")
def db() -> Session:
"""
Database fixture with setup and teardown.
Yields:
Database session for testing
Notes:
- Creates all tables before test
- Drops all tables after test
- Each test gets fresh database
"""
Base.metadata.create_all(bind=engine)
db = TestingSessionLocal()
try:
yield db
finally:
db.close()
Base.metadata.drop_all(bind=engine)
@pytest.fixture
def client(db: Session) -> TestClient:
"""
Test client with database dependency override.
Args:
db: Database session fixture
Returns:
FastAPI TestClient configured for testing
"""
def override_get_db():
try:
yield db
finally:
pass
app.dependency_overrides[get_db] = override_get_db
client = TestClient(app)
yield client
app.dependency_overrides.clear()
@pytest.fixture
def test_user(db: Session) -> User:
"""
Create test user in database.
Args:
db: Database session
Returns:
Created user instance
"""
user = User(
name="Test User",
email="[email protected]",
password_hash="hashed_password"
)
db.add(user)
db.commit()
db.refresh(user)
return user
@pytest.fixture
def auth_token(client: TestClient, test_user: User) -> str:
"""
Generate authentication token for test user.
Args:
client: Test client
test_user: Test user fixture
Returns:
JWT authentication token
"""
response = client.post(
"/api/auth/login",
json={"email": test_user.email, "password": "password"}
)
return response.json()["access_token"]
@pytest.fixture
def auth_headers(auth_token: str) -> dict:
"""
Generate authorization headers with token.
Args:
auth_token: JWT token
Returns:
Headers dictionary with Authorization header
"""
return {"Authorization": f"Bearer {auth_token}"}
JavaScript/TypeScript example (Jest + Express):
// tests/setup.ts
import { Express } from 'express';
import request from 'supertest';
import { createApp } from '../src/app';
import { setupTestDatabase, teardownTestDatabase } from './helpers/database';
let app: Express;
beforeAll(async () => {
await setupTestDatabase();
app = createApp();
});
afterAll(async () => {
await teardownTestDatabase();
});
beforeEach(async () => {
// Clean database before each test
await clearDatabase();
});
export const getTestApp = () => app;
// tests/helpers/database.ts
import { DataSource } from 'typeorm';
let testDataSource: DataSource;
export async function setupTestDatabase() {
testDataSource = new DataSource({
type: 'sqlite',
database: ':memory:',
entities: ['src/entities/**/*.ts'],
synchronize: true,
});
await testDataSource.initialize();
}
export async function teardownTestDatabase() {
await testDataSource.destroy();
}
export async function clearDatabase() {
const entities = testDataSource.entityMetadatas;
for (const entity of entities) {
const repository = testDataSource.getRepository(entity.name);
await repository.clear();
}
}
Deliverable: Test environment configured
Test structure for API endpoints:
# tests/integration/test_users_api.py
"""
Integration tests for Users API.
Tests cover:
- CRUD operations
- Authentication and authorization
- Validation and error handling
- Database interactions
"""
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from src.models import User
class TestUsersAPI:
"""Tests for /api/users endpoints."""
def test_get_users_returns_list(self, client: TestClient, db: Session):
"""Test GET /api/users returns list of users."""
# Arrange: Create test users
users = [
User(name=f"User {i}", email=f"user{i}@example.com")
for i in range(3)
]
db.add_all(users)
db.commit()
# Act
response = client.get("/api/users")
# Assert
assert response.status_code == 200
data = response.json()
assert len(data) == 3
assert all("id" in user for user in data)
assert all("name" in user for user in data)
def test_get_user_by_id_returns_user(
self, client: TestClient, test_user: User
):
"""Test GET /api/users/:id returns specific user."""
# Act
response = client.get(f"/api/users/{test_user.id}")
# Assert
assert response.status_code == 200
data = response.json()
assert data["id"] == test_user.id
assert data["name"] == test_user.name
assert data["email"] == test_user.email
def test_get_user_nonexistent_returns_404(self, client: TestClient):
"""Test GET /api/users/:id with invalid ID returns 404."""
# Act
response = client.get("/api/users/99999")
# Assert
assert response.status_code == 404
assert "not found" in response.json()["detail"].lower()
def test_create_user_returns_created(
self, client: TestClient, db: Session
):
"""Test POST /api/users creates new user."""
# Arrange
user_data = {
"name": "New User",
"email": "[email protected]",
"password": "SecurePass123"
}
# Act
response = client.post("/api/users", json=user_data)
# Assert
assert response.status_code == 201
data = response.json()
assert data["name"] == user_data["name"]
assert data["email"] == user_data["email"]
assert "id" in data
assert "password" not in data # Password not returned
# Verify in database
user = db.query(User).filter_by(email=user_data["email"]).first()
assert user is not None
assert user.name == user_data["name"]
def test_create_user_duplicate_email_returns_400(
self, client: TestClient, test_user: User
):
"""Test POST /api/users with duplicate email returns 400."""
# Arrange
duplicate_data = {
"name": "Another User",
"email": test_user.email,
"password": "password"
}
# Act
response = client.post("/api/users", json=duplicate_data)
# Assert
assert response.status_code == 400
assert "email" in response.json()["detail"].lower()
def test_create_user_invalid_email_returns_400(self, client: TestClient):
"""Test POST /api/users with invalid email returns 400."""
# Arrange
invalid_data = {
"name": "User",
"email": "not-an-email",
"password": "password"
}
# Act
response = client.post("/api/users", json=invalid_data)
# Assert
assert response.status_code == 400
def test_update_user_returns_updated(
self, client: TestClient, test_user: User, auth_headers: dict, db: Session
):
"""Test PUT /api/users/:id updates user."""
# Arrange
update_data = {"name": "Updated Name"}
# Act
response = client.put(
f"/api/users/{test_user.id}",
json=update_data,
headers=auth_headers
)
# Assert
assert response.status_code == 200
data = response.json()
assert data["name"] == "Updated Name"
# Verify in database
db.refresh(test_user)
assert test_user.name == "Updated Name"
def test_update_user_without_auth_returns_401(
self, client: TestClient, test_user: User
):
"""Test PUT /api/users/:id without auth returns 401."""
# Arrange
update_data = {"name": "Updated Name"}
# Act
response = client.put(
f"/api/users/{test_user.id}",
json=update_data
)
# Assert
assert response.status_code == 401
def test_delete_user_returns_no_content(
self, client: TestClient, test_user: User, auth_headers: dict, db: Session
):
"""Test DELETE /api/users/:id deletes user."""
# Act
response = client.delete(
f"/api/users/{test_user.id}",
headers=auth_headers
)
# Assert
assert response.status_code == 204
# Verify in database
deleted_user = db.query(User).filter_by(id=test_user.id).first()
assert deleted_user is None
Deliverable: API integration tests
Test database operations:
# tests/integration/test_user_repository.py
"""
Integration tests for User repository database operations.
"""
import pytest
from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from src.models import User
from src.repositories import UserRepository
class TestUserRepository:
"""Tests for UserRepository database operations."""
@pytest.fixture
def repository(self, db: Session) -> UserRepository:
"""Create repository instance."""
return UserRepository(db)
def test_create_user_saves_to_database(
self, repository: UserRepository, db: Session
):
"""Test create saves user to database."""
# Arrange
user_data = {
"name": "Test User",
"email": "[email protected]",
"password": "password"
}
# Act
user = repository.create(user_data)
# Assert
assert user.id is not None
# Verify in database
saved_user = db.query(User).filter_by(id=user.id).first()
assert saved_user is not None
assert saved_user.name == user_data["name"]
def test_create_duplicate_email_raises_error(
self, repository: UserRepository
):
"""Test creating user with duplicate email raises error."""
# Arrange
user_data = {"name": "User", "email": "[email protected]"}
repository.create(user_data)
# Act & Assert
with pytest.raises(IntegrityError):
repository.create(user_data)
def test_find_by_id_returns_user(
self, repository: UserRepository, test_user: User
):
"""Test find_by_id returns correct user."""
# Act
user = repository.find_by_id(test_user.id)
# Assert
assert user is not None
assert user.id == test_user.id
assert user.email == test_user.email
def test_find_by_email_returns_user(
self, repository: UserRepository, test_user: User
):
"""Test find_by_email returns correct user."""
# Act
user = repository.find_by_email(test_user.email)
# Assert
assert user is not None
assert user.id == test_user.id
def test_update_modifies_user(
self, repository: UserRepository, test_user: User, db: Session
):
"""Test update modifies user in database."""
# Arrange
update_data = {"name": "Updated Name"}
# Act
updated_user = repository.update(test_user.id, update_data)
# Assert
assert updated_user.name == "Updated Name"
# Verify in database
db.refresh(test_user)
assert test_user.name == "Updated Name"
def test_delete_removes_user(
self, repository: UserRepository, test_user: User, db: Session
):
"""Test delete removes user from database."""
# Act
repository.delete(test_user.id)
# Assert - Verify removed from database
deleted_user = db.query(User).filter_by(id=test_user.id).first()
assert deleted_user is None
Deliverable: Database integration tests
Test end-to-end workflows:
# tests/integration/test_user_workflows.py
"""
Integration tests for user-related workflows.
"""
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from src.models import User, EmailVerification
class TestUserRegistrationWorkflow:
"""Tests for complete user registration workflow."""
def test_complete_registration_flow(
self, client: TestClient, db: Session
):
"""Test complete user registration and verification flow."""
# Step 1: Register new user
register_data = {
"name": "New User",
"email": "[email protected]",
"password": "SecurePass123"
}
response = client.post("/api/register", json=register_data)
assert response.status_code == 201
user_data = response.json()
user_id = user_data["id"]
assert user_data["email_verified"] is False
# Step 2: Verify email verification record created
verification = db.query(EmailVerification).filter_by(
user_id=user_id
).first()
assert verification is not None
assert verification.is_used is False
# Step 3: Verify email with token
verify_response = client.post(
"/api/verify-email",
json={"token": verification.token}
)
assert verify_response.status_code == 200
# Step 4: Verify user is now verified
user = db.query(User).filter_by(id=user_id).first()
assert user.email_verified is True
# Step 5: Verify can login
login_response = client.post(
"/api/login",
json={
"email": register_data["email"],
"password": register_data["password"]
}
)
assert login_response.status_code == 200
assert "access_token" in login_response.json()
# Step 6: Access protected resource with token
token = login_response.json()["access_token"]
headers = {"Authorization": f"Bearer {token}"}
profile_response = client.get("/api/profile", headers=headers)
assert profile_response.status_code == 200
profile = profile_response.json()
assert profile["email"] == register_data["email"]
assert profile["email_verified"] is True
Deliverable: Workflow integration tests
Authentication tests:
class TestAuthentication:
"""Tests for authentication flows."""
def test_login_valid_credentials_returns_token(
self, client: TestClient, test_user: User
):
"""Test login with valid credentials returns token."""
# Arrange
login_data = {
"email": test_user.email,
"password": "password" # Assuming test_user has this password
}
# Act
response = client.post("/api/login", json=login_data)
# Assert
assert response.status_code == 200
data = response.json()
assert "access_token" in data
assert "token_type" in data
assert data["token_type"] == "bearer"
def test_login_invalid_password_returns_401(
self, client: TestClient, test_user: User
):
"""Test login with invalid password returns 401."""
# Arrange
login_data = {
"email": test_user.email,
"password": "wrong_password"
}
# Act
response = client.post("/api/login", json=login_data)
# Assert
assert response.status_code == 401
def test_protected_endpoint_without_token_returns_401(
self, client: TestClient
):
"""Test protected endpoint without token returns 401."""
# Act
response = client.get("/api/profile")
# Assert
assert response.status_code == 401
def test_protected_endpoint_with_valid_token_returns_data(
self, client: TestClient, auth_headers: dict
):
"""Test protected endpoint with valid token returns data."""
# Act
response = client.get("/api/profile", headers=auth_headers)
# Assert
assert response.status_code == 200
class TestAuthorization:
"""Tests for authorization checks."""
def test_admin_endpoint_with_admin_user_succeeds(
self, client: TestClient, admin_user: User, admin_headers: dict
):
"""Test admin endpoint allows admin user."""
# Act
response = client.get("/api/admin/users", headers=admin_headers)
# Assert
assert response.status_code == 200
def test_admin_endpoint_with_regular_user_returns_403(
self, client: TestClient, test_user: User, auth_headers: dict
):
"""Test admin endpoint denies regular user."""
# Act
response = client.get("/api/admin/users", headers=auth_headers)
# Assert
assert response.status_code == 403
Deliverable: Auth/authz integration tests
# Python (pytest)
pytest tests/integration/ -v
pytest tests/integration/test_api.py -v
pytest tests/integration/ -v --cov=src
# JavaScript/TypeScript (Jest)
npm run test:integration
jest tests/integration/**/*.test.ts --coverage
# Run with test database
DATABASE_URL=sqlite:///./test.db pytest tests/integration/
Before completing integration tests:
Input: System components to test together Process: Setup → Test interactions → Verify → Cleanup Output: Integration test suite validating component interactions Next Step: End-to-end testing or deployment
Handles the full Supabase workflow from schema changes to deployment, with built-in security guardrails that catch common traps like RLS...
Comprehensive guides and best practices for Neon Serverless Postgres, covering setup, connection methods, authentication, and platform APIs.
Guide for setting up and using Firebase Authentication. Use this skill when the user's app requires user sign-in, user management, or secure data access using auth rules.
A skill to evaluate how secure Firestore security rules are. Use this when Firestore security rules are updated to ensure that the generated rules are extremely secure and robust.
Official skill for integrating Firebase AI Logic (Gemini API) into web applications. Covers setup, multimodal inference, structured output, and security.
Complete Better Auth server and client setup with database adapters, session management, plugins, and security configuration.
Deploy and manage projects on Vercel using token-based authentication. Use when working with Vercel CLI using access tokens rather than interactive login — e.g. "deploy to vercel", "set up vercel", "add environment variables to vercel".
Complete Cloudflare platform integration with decision trees for compute, storage, AI, networking, security, and infrastructure-as-code.
Run Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment.
Send, read, and manage Gmail messages, drafts, labels, and account settings.
Comprehensive website auditing across 230+ rules in 21 categories including SEO, performance, security, and accessibility.
Shared authentication, CLI syntax, and output formatting patterns for gws Google Workspace commands.
Discover your celebrity doppelgänger with StarByFace!
GeoSpy: Pricing, Features, FAQs, and Alternatives for AI Teams
Detect AI-generated voices to protect against audio fraud.
Ensure Your Content's Originality with AI Plagiarism Checker
Upscale images by 400% without quality loss
Protect your social media from copyright disputes
Accurately Detect AI-Generated Content with TheChecker.AI
Chrome extension that detects and flags AI-generated content