docs: consolidate audit and analysis reports into docs/audits/
Move 36 root-level audit/analysis documents and 7 web app audit documents into docs/audits/ directory to declutter the project root. Remove stale EXPLORATION_SUMMARY.txt. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
301
docs/audits/TEST_COVERAGE_QUICK_REFERENCE_ROOT.md
Normal file
301
docs/audits/TEST_COVERAGE_QUICK_REFERENCE_ROOT.md
Normal file
@@ -0,0 +1,301 @@
|
||||
# Test Coverage Quick Reference Guide
|
||||
|
||||
## 17 Untested Source Files Overview
|
||||
|
||||
### INQUIRIES MODULE (4 files)
|
||||
```
|
||||
1. prisma-inquiry.repository.ts — 6 methods to test + 1 private mapper
|
||||
2. inquiries.controller.ts — 4 endpoints to test + guard validation
|
||||
3. create-inquiry.dto.ts — 3 field validations
|
||||
4. list-inquiries.dto.ts — 2 field validations (pagination)
|
||||
```
|
||||
|
||||
### LEADS MODULE (6 files)
|
||||
```
|
||||
5. prisma-lead.repository.ts — 6 methods + stats aggregation
|
||||
6. lead-score.vo.ts — Value object: range 0-100
|
||||
7. leads.controller.ts — 5 endpoints + class-level role guard
|
||||
8. create-lead.dto.ts — 6 field validations
|
||||
9. list-leads.dto.ts — Status enum + pagination
|
||||
10. update-lead-status.dto.ts — Status enum validation
|
||||
```
|
||||
|
||||
### REVIEWS MODULE (5 files)
|
||||
```
|
||||
11. prisma-review.repository.ts — 7 methods + stats with distribution
|
||||
12. rating.vo.ts — Value object: range 1-5 (integers only)
|
||||
13. reviews.controller.ts — 5 endpoints + mixed auth
|
||||
14. create-review.dto.ts — 4 field validations
|
||||
15. list-reviews.dto.ts — 2 DTOs: ListReviewsByTargetDto, ReviewStatsDto
|
||||
```
|
||||
|
||||
### REFERENCE PATTERNS (2 test files)
|
||||
```
|
||||
16. create-inquiry.handler.spec.ts — Handler test pattern
|
||||
17. create-lead.handler.spec.ts — Handler test pattern
|
||||
18. reviews.controller.spec.ts — Controller test pattern
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Test Scenarios by Type
|
||||
|
||||
### REPOSITORIES (3 files)
|
||||
Test checklist for each repository:
|
||||
- [ ] findById() returns entity or null
|
||||
- [ ] save() creates record with correct data mapping
|
||||
- [ ] Paginated methods respect limit cap (100 max)
|
||||
- [ ] Pagination calculation: skip = (page - 1) * take
|
||||
- [ ] Relationships are joined correctly
|
||||
- [ ] Aggregations calculate correctly (stats methods)
|
||||
- [ ] Optional fields handling (null coercion)
|
||||
- [ ] ISO date formatting in DTOs
|
||||
|
||||
**Specific to PrismaInquiryRepository:**
|
||||
- countUnreadByAgent() aggregation
|
||||
- findByListing() includes property.title
|
||||
- findByAgent() joins through listing.agentId
|
||||
|
||||
**Specific to PrismaLeadRepository:**
|
||||
- findByAgent() optional status filter
|
||||
- getStatsByAgent() calculates:
|
||||
- totalLeads count
|
||||
- byStatus object (dict of counts)
|
||||
- conversionRate: (CONVERTED / total) * 100 (2 decimals)
|
||||
- avgScore: average of non-null scores (1 decimal)
|
||||
|
||||
**Specific to PrismaReviewRepository:**
|
||||
- findByUserAndTarget() unique constraint query
|
||||
- getStats() builds distribution object (keys 1-5)
|
||||
- averageRating calculation: (sum / total) * 10 / 10 (1 decimal)
|
||||
|
||||
---
|
||||
|
||||
### VALUE OBJECTS (2 files)
|
||||
Test checklist:
|
||||
- [ ] create() with valid value returns Result.ok()
|
||||
- [ ] create() with invalid value returns Result.err() with correct message
|
||||
- [ ] Getter returns props.value
|
||||
- [ ] Invalid cases covered (negative, > max, non-integer, null)
|
||||
|
||||
**LeadScore validation:**
|
||||
```
|
||||
✓ Valid: 0, 50, 100
|
||||
✗ Invalid: -1, 101, 2.5, null, "50"
|
||||
Error: "Điểm lead phải từ 0 đến 100"
|
||||
```
|
||||
|
||||
**Rating validation:**
|
||||
```
|
||||
✓ Valid: 1, 2, 3, 4, 5
|
||||
✗ Invalid: 0, 6, 2.5, null, "5"
|
||||
Error: "Đánh giá phải từ 1 đến 5 sao"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CONTROLLERS (2 files)
|
||||
Test checklist:
|
||||
- [ ] Each endpoint dispatches correct command/query type
|
||||
- [ ] Parameters are mapped correctly from DTO
|
||||
- [ ] Optional fields become null (e.g., phone ?? null → null)
|
||||
- [ ] Default pagination values applied (page: 1, limit: 20)
|
||||
- [ ] CurrentUser decorator extracts user.sub correctly
|
||||
- [ ] Guard enforcement (@UseGuards, @Roles)
|
||||
- [ ] Return types match (e.g., { deleted: true })
|
||||
|
||||
**InquiriesController specifics:**
|
||||
- POST /inquiries: phone optional → null
|
||||
- GET /inquiries/listing/:listingId: requires JWT
|
||||
- GET /inquiries/agent/me: requires JWT + AGENT role
|
||||
- PATCH /inquiries/:id/read: requires JWT + AGENT role
|
||||
|
||||
**LeadsController specifics:**
|
||||
- ALL endpoints require JWT + AGENT role (class-level @Roles)
|
||||
- POST /leads: score optional, score range validation in command
|
||||
- GET /leads: status filter optional
|
||||
- GET /leads/stats: aggregation query
|
||||
- PATCH /leads/:id/status: only status field in command
|
||||
- DELETE /leads/:id: agentId verification in command
|
||||
|
||||
**ReviewsController specifics:**
|
||||
- POST /reviews: requires JWT (AuthGuard)
|
||||
- GET /reviews: NO auth required (stats are public)
|
||||
- GET /reviews/stats: NO auth required
|
||||
- GET /reviews/me: requires JWT
|
||||
- DELETE /reviews/:id: requires JWT + ownership check in command
|
||||
|
||||
---
|
||||
|
||||
### DTOs (10 files)
|
||||
Test checklist:
|
||||
- [ ] Required fields throw ValidationException if missing
|
||||
- [ ] String max/min length validated
|
||||
- [ ] Number min/max validated
|
||||
- [ ] Enum @IsIn() validates allowed values
|
||||
- [ ] Type transformation (class-transformer @Type)
|
||||
- [ ] Email format validated (@IsEmail)
|
||||
- [ ] Optional fields (@IsOptional) don't throw if omitted
|
||||
|
||||
**Pagination standard (used in 5 DTOs):**
|
||||
- page: optional, @Min(1), default 1
|
||||
- limit: optional, @Min(1), @Max(100), default 20
|
||||
- Both use @Type(() => Number) for string→number transformation
|
||||
|
||||
**Enum validations:**
|
||||
- LeadStatus: ['NEW', 'CONTACTED', 'QUALIFIED', 'NEGOTIATING', 'CONVERTED', 'LOST']
|
||||
- Used in: ListLeadsDto, UpdateLeadStatusDto
|
||||
|
||||
---
|
||||
|
||||
## Test Priority Matrix
|
||||
|
||||
### 🔴 CRITICAL (Business Logic)
|
||||
1. PrismaReviewRepository.getStats() - distribution calculation
|
||||
2. PrismaLeadRepository.getStatsByAgent() - conversion rate formula
|
||||
3. Rating.vo - must be 1-5 integers only
|
||||
4. LeadScore.vo - must be 0-100 range
|
||||
|
||||
### 🟡 HIGH (Data Integrity)
|
||||
1. All repository CRUD methods
|
||||
2. Pagination calculations
|
||||
3. Relationship mapping (user joins, listing joins)
|
||||
4. Controller parameter mapping
|
||||
|
||||
### 🟢 MEDIUM (Validation)
|
||||
1. DTO field validations
|
||||
2. Enum constraints
|
||||
3. Optional field handling
|
||||
4. Guard enforcement
|
||||
|
||||
---
|
||||
|
||||
## Test Execution Order Recommendation
|
||||
|
||||
1. **Value Objects** (2 files) - 2 simple test files
|
||||
2. **DTOs** (10 files) - Use class-validator testing patterns
|
||||
3. **Controllers** (2 files) - Command/query dispatch tests
|
||||
4. **Repositories** (3 files) - Data layer tests with mocked Prisma
|
||||
|
||||
---
|
||||
|
||||
## Mock Setup Template
|
||||
|
||||
### For Repositories:
|
||||
```typescript
|
||||
const mockPrisma = {
|
||||
inquiry: { findUnique: vi.fn(), findMany: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), count: vi.fn() },
|
||||
};
|
||||
const repo = new PrismaInquiryRepository(mockPrisma as any);
|
||||
```
|
||||
|
||||
### For Controllers:
|
||||
```typescript
|
||||
const mockCommandBus = { execute: vi.fn() };
|
||||
const mockQueryBus = { execute: vi.fn() };
|
||||
const controller = new InquiriesController(mockCommandBus as any, mockQueryBus as any);
|
||||
```
|
||||
|
||||
### For Value Objects:
|
||||
```typescript
|
||||
const result = LeadScore.create(75);
|
||||
expect(result.isOk()).toBe(true);
|
||||
expect(result.unwrap().value).toBe(75);
|
||||
```
|
||||
|
||||
### For DTOs:
|
||||
```typescript
|
||||
import { validate } from 'class-validator';
|
||||
const dto = new CreateLeadDto();
|
||||
dto.name = 'Nguyễn Văn A';
|
||||
dto.phone = '0901234567';
|
||||
// ... set other required fields
|
||||
const errors = await validate(dto);
|
||||
expect(errors).toHaveLength(0);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Formulas to Verify
|
||||
|
||||
### Pagination:
|
||||
```
|
||||
skip = (page - 1) * take
|
||||
totalPages = Math.ceil(total / take)
|
||||
take = Math.min(limit, 100)
|
||||
```
|
||||
|
||||
### Lead Conversion Rate:
|
||||
```
|
||||
conversionRate = (convertedCount / totalLeads) * 100
|
||||
Result: rounded to 2 decimals (e.g., 33.33)
|
||||
```
|
||||
|
||||
### Lead Average Score:
|
||||
```
|
||||
avgScore = scoreSum / scoreCount (where score !== null)
|
||||
Result: rounded to 1 decimal (e.g., 75.5)
|
||||
```
|
||||
|
||||
### Review Average Rating:
|
||||
```
|
||||
averageRating = (sum / totalReviews)
|
||||
Result: rounded to 1 decimal (e.g., 4.5)
|
||||
```
|
||||
|
||||
### Review Distribution:
|
||||
```
|
||||
distribution: { 1: count, 2: count, 3: count, 4: count, 5: count }
|
||||
Must initialize all 5 keys, even if 0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Locations for Reference
|
||||
|
||||
```
|
||||
/Users/velikho/Desktop/WORKING/goodgo-platform-ai/apps/api/
|
||||
|
||||
Inquiries:
|
||||
src/modules/inquiries/infrastructure/repositories/prisma-inquiry.repository.ts
|
||||
src/modules/inquiries/presentation/controllers/inquiries.controller.ts
|
||||
src/modules/inquiries/presentation/dto/create-inquiry.dto.ts
|
||||
src/modules/inquiries/presentation/dto/list-inquiries.dto.ts
|
||||
|
||||
Leads:
|
||||
src/modules/leads/infrastructure/repositories/prisma-lead.repository.ts
|
||||
src/modules/leads/domain/value-objects/lead-score.vo.ts
|
||||
src/modules/leads/presentation/controllers/leads.controller.ts
|
||||
src/modules/leads/presentation/dto/create-lead.dto.ts
|
||||
src/modules/leads/presentation/dto/list-leads.dto.ts
|
||||
src/modules/leads/presentation/dto/update-lead-status.dto.ts
|
||||
|
||||
Reviews:
|
||||
src/modules/reviews/infrastructure/repositories/prisma-review.repository.ts
|
||||
src/modules/reviews/domain/value-objects/rating.vo.ts
|
||||
src/modules/reviews/presentation/controllers/reviews.controller.ts
|
||||
src/modules/reviews/presentation/dto/create-review.dto.ts
|
||||
src/modules/reviews/presentation/dto/list-reviews.dto.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Copy reference test patterns:**
|
||||
- Create inquiry and lead handlers already have good test patterns
|
||||
- Controller test for reviews shows endpoint testing approach
|
||||
|
||||
2. **Start with repositories:**
|
||||
- Most complex (Prisma mocking)
|
||||
- Most critical (data layer)
|
||||
- Established patterns in existing tests
|
||||
|
||||
3. **Test DTOs second:**
|
||||
- Quick feedback (class-validator validation)
|
||||
- 10 files but mostly simple
|
||||
|
||||
4. **Controllers and VOs last:**
|
||||
- Build on repository/DTO tests
|
||||
- Depend on handler tests (if testing full flow)
|
||||
|
||||
Reference in New Issue
Block a user