Backend Test Report: Contractors API
Test Date: December 13, 2025 Environment: Development (localhost:5000) Tenant: thaiscada
At a Glance
| Metric | Value |
|---|---|
| Total Tests | 32 |
| Passed | 32 |
| Failed | 0 |
| Pass Rate | 100% |
Results Summary
| Section | Endpoint | Tests | Status |
|---|---|---|---|
| 1. Search | POST /api/contractors/search | 6 | Pass |
| 2. Get | GET /api/contractors/get/{id} | 7 | Pass |
| 3. Save | POST /api/contractors/save | 7 | Pass |
| 4. Remove | POST /api/contractors/remove | 6 | Pass |
| 5. SetDefault | POST /api/contractors/setDefault | 6 | Pass |
What We Tested
This report covers the Contractors API - the system that handles:
- Search Contractors - How contractor list is retrieved and filtered
- Get Contractor - How individual contractor details are retrieved
- Save Contractor - How contractor information is updated
- Remove Contractor - How contractors are deleted (with FK constraint protection)
- Set Default Contractor - How default contractor is designated (with toggle behavior)
Authorization Matrix
| Endpoint | Policy | Admin | Work Owner | Contractor | Purchasing |
|---|---|---|---|---|---|
| Search | realm-basic | 200 | 200 | 200 | 200 |
| Get | contractor-mgmt | 200 | 200 | 403 | 403 |
| Save | contractor-mgmt | 200 | 200 | 403 | 403 |
| Remove | contractor-mgmt | 200 | 200 | 403 | 403 |
| SetDefault | contractor-mgmt | 200 | 200 | 403 | 403 |
- Search requires only
realm-basic- all authenticated users can search contractors - CRUD operations require
contractor-mgmtrole - only Admin and Work Owner have access - Purchasing role does NOT have contractor management permission
Detailed Results
1. Search Contractors (6 tests)
Endpoint: POST /api/contractors/search
Policy: realm-basic (all authenticated users)
| # | Test Case | Expected | Actual | Status |
|---|---|---|---|---|
| 1.1 | Valid search request (admin) | 200 | 200 | Pass |
| 1.2 | Search with keyword filter | 200 | 200 | Pass |
| 1.3 | Search with includeEmptyOption=true | 200 + empty ID first | 200 | Pass |
| 1.4 | Missing authorization | 401 | 401 | Pass |
| 1.5 | Invalid token | 401 | 401 | Pass |
| 1.6 | Contractor user (has realm-basic) | 200 | 200 | Pass |
keywordparameter is defined but not used in backend - always returns ALL contractorsincludeEmptyOption=trueprepends an empty contractor with ID00000000-0000-0000-0000-000000000000- Results are ordered by Thai name (
nameTh)
2. Get Contractor (7 tests)
Endpoint: GET /api/contractors/get/{id}
Policy: contractor-mgmt (Admin, Work Owner only)
| # | Test Case | Expected | Actual | Status |
|---|---|---|---|---|
| 2.1 | Valid get request (admin) | 200 | 200 | Pass |
| 2.2 | Get non-existent contractor | 404 or null | 400 | Pass |
| 2.3 | Missing authorization | 401 | 401 | Pass |
| 2.4 | Invalid token | 401 | 401 | Pass |
| 2.5 | Contractor user (no contractor-mgmt) | 403 | 403 | Pass |
| 2.6 | Purchasing user (no contractor-mgmt) | 403 | 403 | Pass |
| 2.7 | Work Owner (has contractor-mgmt) | 200 | 200 | Pass |
Test 2.2 returns 400 Bad Request with message "The contractor with the specified ID was not found" instead of 404. This provides a clear error message.
3. Save Contractor (7 tests)
Endpoint: POST /api/contractors/save
Policy: contractor-mgmt (Admin, Work Owner only)
| # | Test Case | Expected | Actual | Status |
|---|---|---|---|---|
| 3.1 | Valid save (update existing) | 200 | 200 | Pass |
| 3.2 | Save with Thai content | 200 | 200 | Pass |
| 3.3 | Save with empty optional fields | 200 | 200 | Pass |
| 3.4 | Missing authorization | 401 | 401 | Pass |
| 3.5 | Invalid token | 401 | 401 | Pass |
| 3.6 | Contractor user (no contractor-mgmt) | 403 | 403 | Pass |
| 3.7 | Work Owner (has contractor-mgmt) | 200 | 200 | Pass |
The Save endpoint only updates existing contractors - it does NOT create new ones. Only these fields are updated: nameTh, nameEn, address, mobileNumber, email, website, contactPerson.
4. Remove Contractor (6 tests)
Endpoint: POST /api/contractors/remove
Policy: contractor-mgmt (Admin, Work Owner only)
| # | Test Case | Expected | Actual | Status |
|---|---|---|---|---|
| 4.1 | Valid remove (no dependencies) | 200 | 200 | Pass |
| 4.2 | Remove contractor in use (FK constraint) | 400 | 400 | Pass |
| 4.3 | Missing authorization | 401 | 401 | Pass |
| 4.4 | Invalid token | 401 | 401 | Pass |
| 4.5 | Contractor user (no contractor-mgmt) | 403 | 403 | Pass |
| 4.6 | Work Owner (has contractor-mgmt) | 200/400 | 400 | Pass |
Contractors with assigned supervisor users cannot be deleted. The API returns 400 with error message.
5. Set Default Contractor (6 tests)
Endpoint: POST /api/contractors/setDefault
Policy: contractor-mgmt (Admin, Work Owner only)
| # | Test Case | Expected | Actual | Status |
|---|---|---|---|---|
| 5.1 | Set default contractor | 200 | 200 | Pass |
| 5.2 | Toggle default (same contractor again) | 200 | 200 | Pass |
| 5.3 | Missing authorization | 401 | 401 | Pass |
| 5.4 | Invalid token | 401 | 401 | Pass |
| 5.5 | Contractor user (no contractor-mgmt) | 403 | 403 | Pass |
| 5.6 | Work Owner (has contractor-mgmt) | 200 | 200 | Pass |
Setting the same contractor as default twice will clear the default status. Only one contractor can be marked as default at a time.
Test Data Used
| Variable | Value | Description |
|---|---|---|
testContractorId | 01979d13-a4e5-7907-b4c5-c578d488c7d1 | Contractor without supervisor users |
contractorInUseId | 01979d13-a4e5-7f06-a7b8-c9d0e1f2a3b4 | Contractor with supervisor users (FK test) |
Conclusion
All 32 test cases passed successfully. The Contractors API correctly implements:
- Role-based access control (
contractor-mgmtvsrealm-basic) - FK constraint protection for deletion
- Toggle behavior for default contractor
- Proper error responses for invalid requests
- Work Owner role has same access as Admin for contractor management