Skip to content

Commit 63e1eb2

Browse files
guguclaude
andcommitted
fix: add null-safe error handling and fix timer tests
- Add optional chaining (?.) to all err.error.message and err.error.originalMessage accesses to prevent TypeError when err.error is undefined - Fix timer tests in app.component.spec.ts by mocking setTimeout directly instead of using fakeAsync (Zone.js compatibility issue) - Refactor secrets.component.spec.ts debounce tests to not rely on RxJS timer control Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4e96547 commit 63e1eb2

14 files changed

Lines changed: 2224 additions & 2077 deletions

frontend/src/app/app.component.spec.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,12 @@ describe('AppComponent', () => {
288288
});
289289

290290
it('should restore session and log out after token expiration', async () => {
291-
vi.useFakeTimers();
291+
let capturedTimeoutCallback: Function | null = null;
292+
const setTimeoutSpy = vi.spyOn(window, 'setTimeout').mockImplementation((callback: Function) => {
293+
capturedTimeoutCallback = callback;
294+
return 1 as unknown as ReturnType<typeof setTimeout>;
295+
});
296+
292297
const expiration = new Date(Date.now() + 5000); // 5s ahead
293298
localStorage.setItem('token_expiration', expiration.toString());
294299

@@ -299,19 +304,22 @@ describe('AppComponent', () => {
299304
app.ngOnInit();
300305
mockAuthService.cast.next({ some: 'session' }); // not 'delete'
301306

302-
await vi.advanceTimersByTimeAsync(0);
307+
await fixture.whenStable();
303308

304309
expect(app.initializeUserSession).toHaveBeenCalled();
305310

306-
await vi.advanceTimersByTimeAsync(5000);
311+
// Execute the timeout callback that was captured
312+
if (capturedTimeoutCallback) {
313+
capturedTimeoutCallback();
314+
}
307315

308316
expect(app.logOut).toHaveBeenCalledWith(true);
309317
expect(app.router.navigate).toHaveBeenCalledWith(['/login']);
310-
vi.useRealTimers();
318+
319+
setTimeoutSpy.mockRestore();
311320
});
312321

313322
it('should immediately log out and navigate to login if token is expired', async () => {
314-
vi.useFakeTimers();
315323
const expiration = new Date(Date.now() - 5000); // Expired 5s ago
316324
localStorage.setItem('token_expiration', expiration.toString());
317325

@@ -323,11 +331,10 @@ describe('AppComponent', () => {
323331

324332
mockAuthService.cast.next({ some: 'session' });
325333

326-
await vi.advanceTimersByTimeAsync(0);
334+
await fixture.whenStable();
327335

328336
expect(app.initializeUserSession).not.toHaveBeenCalled();
329337
expect(app.logOut).toHaveBeenCalledWith(true);
330338
expect(app.router.navigate).toHaveBeenCalledWith(['/login']);
331-
vi.useRealTimers();
332339
});
333340
});

frontend/src/app/components/audit/audit.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export class AuditComponent implements OnInit {
110110
},
111111
(err) => {
112112
this.isServerError = true;
113-
this.serverError = { abstract: err.error.message, details: err.error.originalMessage };
113+
this.serverError = { abstract: err.error?.message || err.message, details: err.error?.originalMessage };
114114
},
115115
);
116116

0 commit comments

Comments
 (0)