# Phase 7: Testing - Checklist ## ๐Ÿ“‹ Overview This phase covers comprehensive testing of the refactored CRM backend system, including unit tests, integration tests, and manual API testing. --- ## โœ… Completed Tasks None yet - Phase 7 is the final phase and has not been started. --- ## ๐Ÿงช Testing Strategy ### Testing Pyramid ``` /\ / \ E2E Tests (Manual/API) /____\ / \ Integration Tests /________\ / \ Unit Tests /____________\ ``` ### Test Categories 1. **Unit Tests** - Test individual functions in isolation 2. **Integration Tests** - Test service layer with database 3. **API Tests** - Test endpoints with requests/responses 4. **Manual Tests** - Postman/curl testing --- ## ๐Ÿ“ Unit Tests ### Customer Service Tests - [ ] `generateCrmCustomerCode()` - [ ] Generates unique code per branch - [ ] Increments correctly - [ ] Handles empty branch - [ ] `getCustomersByBranch()` - [ ] Returns only branch customers - [ ] Filters by status correctly - [ ] Includes contacts - [ ] Handles empty results - [ ] `getCustomerById()` - [ ] Returns correct customer - [ ] Enforces branch access - [ ] Returns null for non-existent - [ ] Returns null for wrong branch - [ ] `createCustomer()` - [ ] Creates customer with correct branch - [ ] Auto-generates CRM code - [ ] Validates required fields - [ ] Sets createdBy and updatedBy - [ ] `updateCustomer()` - [ ] Updates customer correctly - [ ] Enforces branch access - [ ] Updates erpCustomerCode - [ ] Sets updatedBy - [ ] `deleteCustomer()` - [ ] Soft deletes customer - [ ] Enforces branch access - [ ] Returns error if already deleted ### Contact Service Tests - [ ] `getVisibleContactsForCustomer()` - [ ] Returns only user's contacts (createdBy == userId) - [ ] Returns public contacts (isPublic == true) - [ ] Enforces branch access - [ ] Filters by customerId - [ ] `createContact()` - [ ] Creates contact with correct branch - [ ] Sets createdBy to current user - [ ] Sets isPublic to false by default - [ ] Validates required fields - [ ] `updateContact()` - [ ] Updates contact correctly - [ ] Only allows creator to update - [ ] Can update isPublic flag - [ ] Enforces branch access - [ ] `shareContact()` - [ ] Sets isPublic to true - [ ] Only allows creator to share - [ ] Returns error for non-existent contact - [ ] `unshareContact()` - [ ] Sets isPublic to false - [ ] Only allows creator to unshare - [ ] Returns error for non-existent contact - [ ] `deleteContact()` - [ ] Deletes contact correctly - [ ] Only allows creator to delete - [ ] Enforces branch access ### Quotation Service Tests - [ ] `generateQuotationCode()` - [ ] Generates unique code - [ ] Follows pattern (Q-YYYY-XXXXX) - [ ] `calculateBaseCurrencyAmount()` - [ ] Converts to THB correctly - [ ] Handles THB (exchangeRate = 1) - [ ] Handles different currencies - [ ] Returns null for invalid currency - [ ] `validateQuotationStatus()` - [ ] Allows editing DRAFT - [ ] Prevents editing SENT - [ ] Validates status transitions - [ ] `createQuotation()` - [ ] Creates quotation with correct branch - [ ] Validates currency code - [ ] Validates exchange rate - [ ] Calculates baseCurrencyAmount - [ ] Validates customer has visible contacts - [ ] Sets revisionNo to null (initial) - [ ] Sets parentQuotationId to null (initial) - [ ] `updateQuotation()` - [ ] Updates quotation correctly - [ ] Enforces branch access - [ ] Validates status (only DRAFT) - [ ] Sets updatedBy - [ ] `createRevision()` - [ ] Clones quotation correctly - [ ] Increments revisionNo - [ ] Sets parentQuotationId - [ ] Sets status to DRAFT - [ ] Preserves currency and exchange rate - [ ] `getQuotationVersions()` - [ ] Returns all versions by code - [ ] Includes different currencies - [ ] Orders by revisionNo --- ## ๐Ÿ”— Integration Tests ### Database Integration - [ ] Test database connection - [ ] Test transaction rollback - [ ] Test concurrent access - [ ] Test foreign key constraints ### Service Integration - [ ] Test customer creation with contacts - [ ] Test quotation creation with items - [ ] Test revision creation - [ ] Test contact visibility rules - [ ] Test branch scoping ### API Integration - [ ] Test authentication flow - [ ] Test branch context injection - [ ] Test error handling - [ ] Test response formats --- ## ๐ŸŒ Manual API Tests ### Customer Endpoints #### Get All Customers ```bash GET /api/customers Headers: Authorization: Bearer x-branch-id: Query Params (optional): status: active | inactive | pending Expected Response: { "success": true, "data": [...], "count": 10, "message": "Found 10 customer(s)" } ``` #### Get Customer by ID ```bash GET /api/customers/:id Headers: Authorization: Bearer x-branch-id: Expected Response: { "success": true, "data": { "id": "...", "branchId": "...", "name": "...", "crmCustomerCode": "...", ... } } ``` #### Create Customer ```bash POST /api/customers Headers: Authorization: Bearer x-branch-id: Content-Type: application/json Body: { "name": "Test Customer", "email": "test@example.com", "phone": "1234567890", "company": "Test Company", "address": "123 Test St", "customerStatus": "active", "customerType": "corporate", "taxId": "1234567890123" } Expected Response: { "success": true, "data": { "id": "...", "crmCustomerCode": "CUST-001", // Auto-generated ... }, "message": "Customer created successfully" } ``` #### Update Customer ```bash PUT /api/customers/:id Headers: Authorization: Bearer x-branch-id: Content-Type: application/json Body: { "name": "Updated Customer", "erpCustomerCode": "ERP-001" // Optional } Expected Response: { "success": true, "data": {...}, "message": "Customer updated successfully" } ``` #### Delete Customer ```bash DELETE /api/customers/:id Headers: Authorization: Bearer x-branch-id: Expected Response: { "success": true, "data": { "id": "...", "deletedAt": "2026-04-24T..." }, "message": "Customer deleted successfully" } ``` ### Contact Endpoints #### Get Visible Contacts ```bash GET /api/customers/:customerId/contacts Headers: Authorization: Bearer x-branch-id: Expected Response: { "success": true, "data": [ { "id": "...", "name": "John Doe", "email": "john@example.com", "isPublic": false, ... } ], "count": 5, "message": "Found 5 contact(s)" } ``` #### Create Contact ```bash POST /api/customers/:customerId/contacts Headers: Authorization: Bearer x-branch-id: Content-Type: application/json Body: { "name": "John Doe", "position": "Manager", "phone": "9876543210", "email": "john@example.com", "isPrimary": true } Expected Response: { "success": true, "data": { "id": "...", "name": "John Doe", "isPublic": false, // Default ... }, "message": "Contact created successfully" } ``` #### Share Contact ```bash POST /api/contacts/:contactId/share Headers: Authorization: Bearer x-branch-id: Expected Response: { "success": true, "data": { "id": "...", "name": "John Doe", "isPublic": true, // Now shared ... }, "message": "Contact shared successfully" } ``` ### Quotation Endpoints #### Create Quotation ```bash POST /api/quotations Headers: Authorization: Bearer x-branch-id: Content-Type: application/json Body: { "customerId": "customer-uuid", "quotationDate": "2026-04-24T10:00:00Z", "validUntil": "2026-05-24T10:00:00Z", "currencyCode": "USD", "exchangeRate": 35.5, "subtotal": "1000.00", "discount": "50.00", "taxRate": 7.0, "taxAmount": "66.50", "totalAmount": "1016.50", "notes": "Test quotation" } Expected Response: { "success": true, "data": { "id": "...", "code": "Q-2026-00001", // Auto-generated "baseCurrencyAmount": "36085.75", // THB equivalent "status": "new_job_draft", "revisionNo": null, ... }, "message": "Quotation created successfully" } ``` #### Update Quotation (Draft Only) ```bash PUT /api/quotations/:id Headers: Authorization: Bearer x-branch-id: Content-Type: application/json Body: { "subtotal": "1200.00", "totalAmount": "1219.80" } Expected Response (Success): { "success": true, "data": {...}, "message": "Quotation updated successfully" } Expected Response (Error if SENT): { "success": false, "error": "Quotation cannot be edited. Create a revision instead." } ``` #### Create Revision ```bash POST /api/quotations/:id/revision Headers: Authorization: Bearer x-branch-id: Expected Response: { "success": true, "data": { "id": "...", "code": "Q-2026-00001", // Same code "revisionNo": 1, // Incremented "parentQuotationId": "original-quotation-id", "status": "new_job_draft", // Reset to draft ... }, "message": "Revision created successfully" } ``` #### Get Quotation Versions ```bash GET /api/quotations/code/:code/versions Headers: Authorization: Bearer x-branch-id: Expected Response: { "success": true, "data": [ { "id": "...", "code": "Q-2026-00001", "revisionNo": 0, "currencyCode": "THB", "totalAmount": "1000.00", ... }, { "id": "...", "code": "Q-2026-00001", "revisionNo": 1, "currencyCode": "THB", "totalAmount": "1200.00", ... }, { "id": "...", "code": "Q-2026-00001", "revisionNo": 0, // Different currency version "currencyCode": "USD", "totalAmount": "30.00", ... } ], "count": 3 } ``` --- ## ๐Ÿ› Error Scenarios ### Authentication Errors - [ ] Missing Authorization header - [ ] Invalid token - [ ] Expired token - [ ] Missing x-branch-id header - [ ] Invalid branch ID - [ ] User has no access to branch ### Validation Errors - [ ] Missing required fields - [ ] Invalid email format - [ ] Invalid currency code - [ ] Negative exchange rate - [ ] Invalid status transition - [ ] Creating quotation without visible contacts ### Permission Errors - [ ] Accessing customer from wrong branch - [ ] Updating contact not owned by user - [ ] Sharing contact not owned by user - [ ] Deleting contact not owned by user - [ ] Editing sent quotation (without revision) - [ ] Accessing quotation from wrong branch ### Business Logic Errors - [ ] Duplicate CRM customer code - [ ] Duplicate ERP customer code - [ ] Quotation with no items - [ ] Invalid discount amount - [ ] Invalid tax calculation - [ ] Revision of revision (not allowed) --- ## ๐Ÿ“Š Test Coverage Goals ### Minimum Coverage Targets - **Unit Tests**: 80% code coverage - **Integration Tests**: 60% code coverage - **API Tests**: 100% endpoint coverage ### Critical Path Coverage - [ ] Customer CRUD flow - [ ] Contact visibility flow - [ ] Quotation creation flow - [ ] Revision creation flow - [ ] Multi-currency conversion - [ ] Branch scoping enforcement --- ## ๐Ÿ› ๏ธ Testing Tools ### Recommended Tools - **Unit Tests**: Jest, Vitest - **Integration Tests**: Supertest, @elysiajs/testing - **API Testing**: Postman, Insomnia, curl - **Database Testing**: testcontainers, docker-compose ### Test Data Create test data fixtures: - [ ] Sample customers - [ ] Sample contacts - [ ] Sample quotations - [ ] Sample quotation items - [ ] Test users with different branch access --- ## ๐Ÿ“ Test Execution ### Run All Tests ```bash npm test ``` ### Run Unit Tests Only ```bash npm run test:unit ``` ### Run Integration Tests Only ```bash npm run test:integration ``` ### Run with Coverage ```bash npm run test:coverage ``` ### Run Specific Test File ```bash npm test customers.service.test.ts ``` --- ## ๐ŸŽฏ Success Criteria Phase 7 is complete when: - [ ] All unit tests pass (80% coverage) - [ ] All integration tests pass (60% coverage) - [ ] All API endpoints tested manually - [ ] All error scenarios tested - [ ] Critical path scenarios tested - [ ] Test documentation complete - [ ] CI/CD pipeline configured --- ## ๐Ÿ“‹ Remaining Tasks - [ ] Set up test framework (Jest/Vitest) - [ ] Write unit tests for customer service - [ ] Write unit tests for quotation service - [ ] Write integration tests - [ ] Create Postman collection - [ ] Execute manual API tests - [ ] Document test results - [ ] Fix any bugs found --- ## ๐Ÿ”„ Next Steps After Phase 7: - [ ] Create final project documentation - [ ] Deploy to staging environment - [ ] Conduct user acceptance testing (UAT) - [ ] Deploy to production - [ ] Monitor and maintain --- **Phase 7 Status**: ๐Ÿšง **NOT STARTED** **Overall Project Status**: 85% Complete (Phases 1-6 Done)