|
7 | 7 | import _omit from 'lodash/omit'; |
8 | 8 | import auditsDbQueries from '../../../models/audits.db.queries'; |
9 | 9 | import { SurveyObjectsAndAuditsFactory } from '../SurveyObjectsAndAuditsFactory'; |
10 | | -import { setProjectConfig } from '../../../config/projectConfig'; |
| 10 | +import { AuditService } from '../AuditService'; |
| 11 | +import type { AuditForObject } from 'evolution-common/lib/services/audits/types'; |
| 12 | +import type { Interview } from 'evolution-common/lib/services/baseObjects/interview/Interview'; |
| 13 | +import type { Household } from 'evolution-common/lib/services/baseObjects/Household'; |
| 14 | +import type { Home } from 'evolution-common/lib/services/baseObjects/Home'; |
11 | 15 |
|
12 | 16 | jest.mock('../../../models/audits.db.queries', () => ({ |
13 | 17 | setAuditsForInterview: jest.fn(), |
14 | 18 | updateAudit: jest.fn() |
15 | 19 | })); |
| 20 | +jest.mock('../AuditService', () => ({ |
| 21 | + AuditService: { |
| 22 | + auditInterview: jest.fn() |
| 23 | + } |
| 24 | +})); |
| 25 | + |
16 | 26 | const mockSetAudits = auditsDbQueries.setAuditsForInterview as jest.MockedFunction<typeof auditsDbQueries.setAuditsForInterview>; |
17 | 27 | mockSetAudits.mockImplementation(async (_interviewId, audits) => audits); |
18 | 28 | const mockUpdateAudit = auditsDbQueries.updateAudit as jest.MockedFunction<typeof auditsDbQueries.updateAudit>; |
| 29 | +const mockAuditInterview = jest.mocked(AuditService.auditInterview); |
| 30 | + |
| 31 | +// helper (place near top of file) |
| 32 | +const makeServiceResult = (audits: AuditForObject[]) => ({ |
| 33 | + interview: {} as Interview, |
| 34 | + household: {} as Household, |
| 35 | + home: {} as Home, |
| 36 | + audits, |
| 37 | + auditsByObject: { interview: [], household: [], home: [], persons: {}, journeys: {}, visitedPlaces: {}, trips: {}, segments: {} } |
| 38 | +}); |
19 | 39 |
|
20 | 40 | const interviewId = 3; |
21 | 41 |
|
@@ -74,113 +94,108 @@ describe('createSurveyObjectsAndSaveAuditsToDb', () => { |
74 | 94 | uuid: '123e4567-e89b-12d3-a456-426614174000', |
75 | 95 | participant_id: 1, |
76 | 96 | is_valid: true, |
77 | | - response: { |
78 | | - fieldA: 'a', |
79 | | - fieldB: 'b', |
80 | | - home: { |
81 | | - _uuid: 'home-uuid-123', |
82 | | - address: '123 Test Street', |
83 | | - city: 'Test City' |
84 | | - }, |
85 | | - household: { |
86 | | - _uuid: 'household-uuid-123', |
87 | | - size: 2, |
88 | | - persons: { |
89 | | - 'person-uuid-123': { |
90 | | - _uuid: 'person-uuid-123', |
91 | | - age: 30, |
92 | | - _sequence: 1 |
93 | | - } |
94 | | - } |
95 | | - } |
96 | | - } as any, |
| 97 | + response: {}, |
97 | 98 | validations: {}, |
98 | 99 | is_completed: false, |
99 | | - corrected_response: { |
100 | | - fieldA: 'modifiedA', |
101 | | - fieldB: 'modifiedB', |
102 | | - home: { |
103 | | - _uuid: 'home-uuid-123', |
104 | | - address: '456 Modified Street', |
105 | | - city: 'Modified City' |
106 | | - }, |
107 | | - household: { |
108 | | - _uuid: 'household-uuid-123', |
109 | | - size: 3, |
110 | | - persons: { |
111 | | - 'person-uuid-123': { |
112 | | - _uuid: 'person-uuid-123', |
113 | | - age: 35, |
114 | | - _sequence: 1 |
115 | | - } |
116 | | - } |
117 | | - } |
118 | | - } as any |
| 100 | + corrected_response: {} |
119 | 101 | }; |
120 | 102 |
|
121 | | - const mockInterviewAudits = jest.fn(); |
| 103 | + // Mock audits returned by AuditService |
| 104 | + const mockAuditsFromService: AuditForObject[] = [ |
| 105 | + { |
| 106 | + objectType: 'interview', |
| 107 | + objectUuid: 'interview-uuid-123', |
| 108 | + errorCode: 'TEST_ERROR_1', |
| 109 | + version: 1, |
| 110 | + level: 'error', |
| 111 | + message: 'Test error 1', |
| 112 | + ignore: false |
| 113 | + }, |
| 114 | + { |
| 115 | + objectType: 'household', |
| 116 | + objectUuid: 'household-uuid-123', |
| 117 | + errorCode: 'TEST_ERROR_2', |
| 118 | + version: 1, |
| 119 | + level: 'warning', |
| 120 | + message: 'Test warning 2', |
| 121 | + ignore: false |
| 122 | + } |
| 123 | + ]; |
122 | 124 |
|
123 | 125 | beforeEach(() => { |
124 | 126 | mockSetAudits.mockClear(); |
125 | | - mockInterviewAudits.mockClear(); |
126 | | - setProjectConfig({ auditInterview: mockInterviewAudits }); |
127 | | - }); |
128 | | - |
129 | | - test('audit function not set in config - uses default implementation', async () => { |
130 | | - // Unset the interview audit function |
131 | | - setProjectConfig({ auditInterview: undefined }); |
132 | | - |
133 | | - const objectsAndAudits = await SurveyObjectsAndAuditsFactory.createSurveyObjectsAndSaveAuditsToDb(interviewAttributes); |
134 | | - // Should use default audit implementation, so we expect some audits |
135 | | - expect(objectsAndAudits.audits.length).toBeGreaterThan(0); |
136 | | - expect(mockInterviewAudits).not.toHaveBeenCalled(); |
| 127 | + mockAuditInterview.mockClear(); |
| 128 | + // Mock AuditService to return dummy audits |
| 129 | + mockAuditInterview.mockResolvedValue(makeServiceResult(mockAuditsFromService)); |
137 | 130 | }); |
138 | 131 |
|
139 | 132 | test('corrected_response not set in interview', async () => { |
140 | 133 | await expect(SurveyObjectsAndAuditsFactory.createSurveyObjectsAndSaveAuditsToDb(_omit(interviewAttributes, 'corrected_response'))) |
141 | 134 | .rejects.toThrow('Corrected response is required to create survey objects and audits'); |
142 | | - expect(mockInterviewAudits).not.toHaveBeenCalled(); |
| 135 | + expect(mockAuditInterview).not.toHaveBeenCalled(); |
143 | 136 | }); |
144 | 137 |
|
145 | | - test('Function returns audits from audit service', async () => { |
146 | | - // The new system uses AuditService which produces real audits |
| 138 | + test('Function calls AuditService and returns audits', async () => { |
147 | 139 | const objectsAndAudits = await SurveyObjectsAndAuditsFactory.createSurveyObjectsAndSaveAuditsToDb(interviewAttributes); |
148 | 140 |
|
149 | | - // Should have some audits from the audit system |
150 | | - expect(objectsAndAudits.audits.length).toBeGreaterThan(0); |
151 | | - |
152 | | - // Should have audits for objects with validation errors (home, household, etc.) |
153 | | - // The system only generates audits when there are actual validation errors |
154 | | - expect(objectsAndAudits.audits.length).toBe(3); |
| 141 | + // Should call AuditService |
| 142 | + expect(mockAuditInterview).toHaveBeenCalledTimes(1); |
| 143 | + expect(mockAuditInterview).toHaveBeenCalledWith(interviewAttributes); |
155 | 144 |
|
156 | | - // The old mock interview audit function should not be called anymore |
157 | | - expect(mockInterviewAudits).not.toHaveBeenCalled(); |
| 145 | + // Should return the audits from AuditService |
| 146 | + expect(objectsAndAudits.audits).toEqual(mockAuditsFromService); |
158 | 147 |
|
159 | 148 | // Database should be called to save the audits |
160 | 149 | expect(mockSetAudits).toHaveBeenCalledTimes(1); |
161 | | - expect(mockSetAudits).toHaveBeenCalledWith(interviewId, objectsAndAudits.audits); |
| 150 | + expect(mockSetAudits).toHaveBeenCalledWith(interviewId, mockAuditsFromService); |
162 | 151 | }); |
163 | 152 |
|
164 | 153 | test('Function saves audits to database and returns updated audits', async () => { |
165 | 154 | // Mock the database to add ignore status to all audits when saving |
166 | | - mockSetAudits.mockImplementationOnce(async (_interviewId, audits) => |
167 | | - audits.map((audit) => ({ ...audit, ignore: true })) |
168 | | - ); |
| 155 | + const updatedAudits = mockAuditsFromService.map((audit) => ({ ...audit, ignore: true })); |
| 156 | + mockSetAudits.mockResolvedValueOnce(updatedAudits); |
169 | 157 |
|
170 | 158 | const objectsAndAudits = await SurveyObjectsAndAuditsFactory.createSurveyObjectsAndSaveAuditsToDb(interviewAttributes); |
171 | 159 |
|
172 | | - // Should have some audits from the audit system |
173 | | - expect(objectsAndAudits.audits.length).toBeGreaterThan(0); |
| 160 | + // Should call AuditService |
| 161 | + expect(mockAuditInterview).toHaveBeenCalledTimes(1); |
174 | 162 |
|
175 | 163 | // All audits should have the ignore flag set by the database mock |
176 | 164 | expect(objectsAndAudits.audits.every((audit) => audit.ignore === true)).toBe(true); |
177 | 165 |
|
178 | | - // The old mock interview audit function should not be called anymore |
179 | | - expect(mockInterviewAudits).not.toHaveBeenCalled(); |
| 166 | + // auditsByObject should reflect the updated audits |
| 167 | + expect(objectsAndAudits.auditsByObject?.interview ?? []).toEqual( |
| 168 | + expect.arrayContaining([expect.objectContaining({ objectType: 'interview', ignore: true })]) |
| 169 | + ); |
| 170 | + expect(objectsAndAudits.auditsByObject?.household ?? []).toEqual( |
| 171 | + expect.arrayContaining([expect.objectContaining({ objectType: 'household', ignore: true })]) |
| 172 | + ); |
180 | 173 |
|
181 | 174 | // Database should be called to save the audits |
182 | 175 | expect(mockSetAudits).toHaveBeenCalledTimes(1); |
183 | | - expect(mockSetAudits).toHaveBeenCalledWith(interviewId, expect.any(Array)); |
| 176 | + expect(mockSetAudits).toHaveBeenCalledWith(interviewId, mockAuditsFromService); |
| 177 | + }); |
| 178 | + |
| 179 | + test('Function handles empty audits array', async () => { |
| 180 | + // Mock AuditService to return no audits |
| 181 | + mockAuditInterview.mockResolvedValueOnce(makeServiceResult([])); |
| 182 | + |
| 183 | + const objectsAndAudits = await SurveyObjectsAndAuditsFactory.createSurveyObjectsAndSaveAuditsToDb(interviewAttributes); |
| 184 | + |
| 185 | + // Should call AuditService |
| 186 | + expect(mockAuditInterview).toHaveBeenCalledTimes(1); |
| 187 | + |
| 188 | + // Should have no audits |
| 189 | + expect(objectsAndAudits.audits).toEqual([]); |
| 190 | + |
| 191 | + // auditsByObject should be properly initialized even with no audits |
| 192 | + expect(objectsAndAudits.auditsByObject).toBeDefined(); |
| 193 | + expect(objectsAndAudits.auditsByObject?.interview).toEqual([]); |
| 194 | + expect(objectsAndAudits.auditsByObject?.household).toEqual([]); |
| 195 | + |
| 196 | + // Database should still be called even with empty array |
| 197 | + expect(mockSetAudits).toHaveBeenCalledTimes(1); |
| 198 | + expect(mockSetAudits).toHaveBeenCalledWith(interviewId, []); |
184 | 199 | }); |
185 | 200 | }); |
186 | 201 |
|
0 commit comments