Loading...
Loading...
Use when implementing features with test-driven development, writing tests before code, building domain-rich business logic, or following hexagonal architecture
npx skill4agent add johanspannare/awesome-claude-extensions pragmatic-tdd// ❌ AVOID: Testing internal details
test('UserValidator.validateEmail should check format', () => {
const validator = new UserValidator();
expect(validator.validateEmail('test@example.com')).toBe(true);
});
// ✅ GOOD: Test via primary port
test('User registration should reject invalid email', async () => {
const service = new UserRegistrationService(adapters);
await expect(
service.registerUser({ email: 'invalid-email', ...})
).rejects.toThrow('Invalid email format');
});// ❌ AVOID: Mocking internal domain logic
const mockValidator = {
validateEmail: jest.fn().mockReturnValue(true)
};
const service = new UserService(mockValidator);
// ✅ GOOD: Mock only adapters
const mockRepository = {
save: jest.fn(),
findByEmail: jest.fn()
};
const service = new UserRegistrationService(mockRepository, new EmailService());
// Domain logic and validators run real code// ❌ AVOID: Testing parts in isolation
test('CompetitorChecker returns true for competitor domain', () => {
const checker = new CompetitorChecker(['competitor.com']);
expect(checker.isCompetitor('user@competitor.com')).toBe(true);
});
// ✅ GOOD: Test the entire flow
test('Users from competitor domains should be flagged for review', async () => {
const service = new UserRegistrationService(adapters);
const result = await service.registerUser({
email: 'john@competitor.com',
name: 'John Doe'
});
expect(result.status).toBe('PENDING_REVIEW');
expect(result.flagReason).toBe('COMPETITOR_DOMAIN');
expect(mockEmailService.sendAdminAlert).toHaveBeenCalled();
});1. RED: Write test for behavior (via primary port)
└─> Test fails (function doesn't exist yet)
2. GREEN: Implement minimal domain logic
└─> Test passes
3. REFACTOR: Improve internal structure
└─> Tests remain green (they test behavior, not structure)┌─────────────────────────────────────────┐
│ Primary Ports (TEST HERE) │
│ - UserRegistrationService │
│ - OrderProcessingService │
└─────────────┬───────────────────────────┘
│
┌─────────────▼───────────────────────────┐
│ Domain Layer (Real code in tests) │
│ - User, Order (Entities) │
│ - DomainValidators │
│ - Business Rules │
└─────────────┬───────────────────────────┘
│
┌─────────────▼───────────────────────────┐
│ Adapters (MOCK HERE) │
│ - UserRepository (DB) │
│ - EmailService (SMTP) │
│ - PaymentGateway (HTTP) │
└─────────────────────────────────────────┘describe('UserRegistrationService', () => {
let service: UserRegistrationService;
let mockUserRepo: MockUserRepository;
let mockEmailService: MockEmailService;
beforeEach(() => {
mockUserRepo = new MockUserRepository();
mockEmailService = new MockEmailService();
service = new UserRegistrationService(
mockUserRepo,
mockEmailService,
['competitor.com', 'rival.io']
);
});
test('should flag competitor domain users for review', async () => {
const userData = {
email: 'john@competitor.com',
name: 'John Doe',
password: 'securePass123'
};
const result = await service.registerUser(userData);
expect(result.status).toBe('PENDING_REVIEW');
expect(result.flagReason).toBe('COMPETITOR_DOMAIN');
expect(result.user.isActive).toBe(false);
expect(mockEmailService.adminAlerts).toHaveLength(1);
});
});class UserRegistrationService {
constructor(
private userRepo: UserRepository,
private emailService: EmailService,
private competitorDomains: string[]
) {}
async registerUser(data: UserRegistrationData): Promise<RegistrationResult> {
const domain = this.extractDomain(data.email);
const isCompetitor = this.competitorDomains.includes(domain);
const user = new User(
data.email,
data.name,
await this.hashPassword(data.password),
!isCompetitor,
isCompetitor ? 'COMPETITOR_DOMAIN' : undefined
);
await this.userRepo.save(user);
if (isCompetitor) {
await this.emailService.sendAdminAlert({
subject: 'Competitor Signup Detected',
body: `User ${data.email} from competitor domain attempted signup`
});
return { status: 'PENDING_REVIEW', flagReason: 'COMPETITOR_DOMAIN', user };
}
await this.emailService.sendWelcome(user.email, user.name);
return { status: 'ACTIVE', user };
}
private extractDomain(email: string): string {
return email.split('@')[1];
}
}// Extract domain logic
class CompetitorDetector {
constructor(private competitorDomains: string[]) {}
isCompetitorEmail(email: string): boolean {
const domain = email.split('@')[1];
return this.competitorDomains.includes(domain);
}
}
// Service uses detector - tests still GREEN
class UserRegistrationService {
constructor(
private userRepo: UserRepository,
private emailService: EmailService,
private competitorDetector: CompetitorDetector
) {}
async registerUser(data: UserRegistrationData): Promise<RegistrationResult> {
const isCompetitor = this.competitorDetector.isCompetitorEmail(data.email);
// ... rest of logic
}
}UserRegistrationService