fix: resolve all test failures after vitest 2.x upgrade

- Attach rejects handler before advancing timers (vitest 2.x strict mode)
- Fix FK constraint cleanup order in test setup
- Fix 7-char prefix matching test data
- Add INSERT OR IGNORE for deposit concurrency safety
- Add secondary ORDER BY for deterministic transaction ordering
- Update summary-service test assertions to match current prompt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-02-07 19:41:11 +09:00
parent fa7d8b2d1a
commit bd25316fd3
7 changed files with 253 additions and 194 deletions

View File

@@ -8,10 +8,6 @@
* 4. 타임아웃 처리
* 5. 재시도 로직 통합
* 6. 커스텀 헤더 및 옵션
*
* Note: Vitest may report "unhandled errors" due to timing issues with
* fake timers and async promise rejections. All tests pass successfully
* (25/25 passing) - these are expected error logs, not test failures.
*/
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
import { z } from 'zod';
@@ -144,13 +140,12 @@ describe('callApi', () => {
json: async () => ({ error: 'Resource not found' }),
});
await expect(async () => {
const promise = callApi('https://api.example.com/missing', {
retries: 0, // 재시도 없음
});
await vi.runAllTimersAsync();
await promise;
}).rejects.toThrow();
const promise = callApi('https://api.example.com/missing', {
retries: 0, // 재시도 없음
});
const expectPromise = expect(promise).rejects.toThrow();
await vi.runAllTimersAsync();
await expectPromise;
});
it('should throw error on 5xx server error', async () => {
@@ -161,13 +156,12 @@ describe('callApi', () => {
json: async () => ({ error: 'Server crashed' }),
});
await expect(async () => {
const promise = callApi('https://api.example.com/error', {
retries: 0,
});
await vi.runAllTimersAsync();
await promise;
}).rejects.toThrow();
const promise = callApi('https://api.example.com/error', {
retries: 0,
});
const expectPromise = expect(promise).rejects.toThrow();
await vi.runAllTimersAsync();
await expectPromise;
});
it('should include status code in error message', async () => {
@@ -178,13 +172,12 @@ describe('callApi', () => {
json: async () => ({}),
});
await expect(async () => {
const promise = callApi('https://api.example.com/forbidden', {
retries: 0,
});
await vi.runAllTimersAsync();
await promise;
}).rejects.toThrow(/403/);
const promise = callApi('https://api.example.com/forbidden', {
retries: 0,
});
const expectPromise = expect(promise).rejects.toThrow(/403/);
await vi.runAllTimersAsync();
await expectPromise;
});
});
@@ -230,14 +223,13 @@ describe('callApi', () => {
json: async () => invalidData,
});
await expect(async () => {
const promise = callApi('https://api.example.com/user', {
schema: UserSchema,
retries: 0,
});
await vi.runAllTimersAsync();
await promise;
}).rejects.toThrow();
const promise = callApi('https://api.example.com/user', {
schema: UserSchema,
retries: 0,
});
const expectPromise = expect(promise).rejects.toThrow();
await vi.runAllTimersAsync();
await expectPromise;
});
it('should throw error on invalid schema (wrong type)', async () => {
@@ -252,14 +244,13 @@ describe('callApi', () => {
json: async () => invalidData,
});
await expect(async () => {
const promise = callApi('https://api.example.com/user', {
schema: UserSchema,
retries: 0,
});
await vi.runAllTimersAsync();
await promise;
}).rejects.toThrow();
const promise = callApi('https://api.example.com/user', {
schema: UserSchema,
retries: 0,
});
const expectPromise = expect(promise).rejects.toThrow();
await vi.runAllTimersAsync();
await expectPromise;
});
it('should throw error on invalid email format', async () => {
@@ -274,14 +265,13 @@ describe('callApi', () => {
json: async () => invalidData,
});
await expect(async () => {
const promise = callApi('https://api.example.com/user', {
schema: UserSchema,
retries: 0,
});
await vi.runAllTimersAsync();
await promise;
}).rejects.toThrow();
const promise = callApi('https://api.example.com/user', {
schema: UserSchema,
retries: 0,
});
const expectPromise = expect(promise).rejects.toThrow();
await vi.runAllTimersAsync();
await expectPromise;
});
});
@@ -301,19 +291,18 @@ describe('callApi', () => {
};
});
await expect(async () => {
const promise = callApi('https://api.example.com/slow', {
retries: 0,
});
const promise = callApi('https://api.example.com/slow', {
retries: 0,
});
// 타임아웃 전에는 에러 없음
await vi.advanceTimersByTimeAsync(29000);
// 타임아웃 전에는 에러 없음
await vi.advanceTimersByTimeAsync(29000);
// 타임아웃 발생
await vi.advanceTimersByTimeAsync(2000);
await vi.runAllTimersAsync();
await promise;
}).rejects.toThrow();
// 타임아웃 발생
await vi.advanceTimersByTimeAsync(2000);
const expectPromise = expect(promise).rejects.toThrow();
await vi.runAllTimersAsync();
await expectPromise;
});
it('should use custom timeout value', async () => {
@@ -330,20 +319,19 @@ describe('callApi', () => {
};
});
await expect(async () => {
const promise = callApi('https://api.example.com/slow', {
timeout: 5000, // 5초 타임아웃
retries: 0,
});
const promise = callApi('https://api.example.com/slow', {
timeout: 5000, // 5초 타임아웃
retries: 0,
});
// 타임아웃 전
await vi.advanceTimersByTimeAsync(4000);
// 타임아웃 전
await vi.advanceTimersByTimeAsync(4000);
// 타임아웃 발생
await vi.advanceTimersByTimeAsync(2000);
await vi.runAllTimersAsync();
await promise;
}).rejects.toThrow();
// 타임아웃 발생
await vi.advanceTimersByTimeAsync(2000);
const expectPromise = expect(promise).rejects.toThrow();
await vi.runAllTimersAsync();
await expectPromise;
});
it('should complete before timeout', async () => {
@@ -435,13 +423,12 @@ describe('callApi', () => {
json: async () => ({}),
});
await expect(async () => {
const promise = callApi('https://api.example.com/always-fails', {
retries: 2,
});
await vi.runAllTimersAsync();
await promise;
}).rejects.toThrow();
const promise = callApi('https://api.example.com/always-fails', {
retries: 2,
});
const expectPromise = expect(promise).rejects.toThrow();
await vi.runAllTimersAsync();
await expectPromise;
expect(mockFetch).toHaveBeenCalledTimes(3); // 초기 + 2회 재시도
});
@@ -453,13 +440,12 @@ describe('callApi', () => {
json: async () => ({}),
});
await expect(async () => {
const promise = callApi('https://api.example.com/missing', {
retries: 3,
});
await vi.runAllTimersAsync();
await promise;
}).rejects.toThrow();
const promise = callApi('https://api.example.com/missing', {
retries: 3,
});
const expectPromise = expect(promise).rejects.toThrow();
await vi.runAllTimersAsync();
await expectPromise;
// 재시도 로직은 4xx 에러를 재시도하지 않음 (retryWithBackoff 구현에 따라 다름)
});
});