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

@@ -145,9 +145,12 @@ describe('retryWithBackoff', () => {
const promise = retryWithBackoff(mockFn, { maxRetries: 2 });
await vi.runAllTimersAsync();
// Attach error handler before advancing timers
const expectPromise = expect(promise).rejects.toThrow(RetryError);
await vi.runAllTimersAsync();
await expectPromise;
await expect(promise).rejects.toThrow(RetryError);
expect(mockFn).toHaveBeenCalledTimes(3); // Initial + 2 retries
});
@@ -159,21 +162,20 @@ describe('retryWithBackoff', () => {
const promise = retryWithBackoff(mockFn, { maxRetries: 1 });
// Attach catch handler before advancing timers
const errorPromise = promise.catch(error => error);
await vi.runAllTimersAsync();
try {
await promise;
expect.fail('Should have thrown RetryError');
} catch (error) {
expect(error).toBeInstanceOf(RetryError);
const error = await errorPromise;
expect(error).toBeInstanceOf(RetryError);
const retryError = error as RetryError;
expect(retryError.name).toBe('RetryError');
expect(retryError.attempts).toBe(2); // Initial + 1 retry
expect(retryError.lastError).toBe(originalError);
expect(retryError.lastError.message).toBe('Original failure');
expect(retryError.lastError.stack).toBe('Original stack trace');
}
const retryError = error as RetryError;
expect(retryError.name).toBe('RetryError');
expect(retryError.attempts).toBe(2); // Initial + 1 retry
expect(retryError.lastError).toBe(originalError);
expect(retryError.lastError.message).toBe('Original failure');
expect(retryError.lastError.stack).toBe('Original stack trace');
});
it('should include attempts count in RetryError message', async () => {
@@ -181,16 +183,15 @@ describe('retryWithBackoff', () => {
const promise = retryWithBackoff(mockFn, { maxRetries: 2 });
// Attach catch handler before advancing timers
const errorPromise = promise.catch(error => error);
await vi.runAllTimersAsync();
try {
await promise;
expect.fail('Should have thrown RetryError');
} catch (error) {
const retryError = error as RetryError;
expect(retryError.message).toContain('3 attempts'); // Initial + 2 retries
expect(retryError.message).toContain('API error');
}
const error = await errorPromise;
const retryError = error as RetryError;
expect(retryError.message).toContain('3 attempts'); // Initial + 2 retries
expect(retryError.message).toContain('API error');
});
});
@@ -294,11 +295,14 @@ describe('retryWithBackoff', () => {
jitter: false,
});
// Attach error handler before advancing timers
const expectPromise = expect(promise).rejects.toThrow(RetryError);
// After several retries, delay should cap at 10000ms
// Let's verify it doesn't exceed 10000ms by checking timer behavior
await vi.runAllTimersAsync();
await expect(promise).rejects.toThrow(RetryError);
await expectPromise;
expect(mockFn).toHaveBeenCalledTimes(21); // Initial + 20 retries
});
});
@@ -395,9 +399,12 @@ describe('retryWithBackoff', () => {
maxRetries: customMaxRetries,
});
// Attach error handler before advancing timers
const expectPromise = expect(promise).rejects.toThrow(RetryError);
await vi.runAllTimersAsync();
await expect(promise).rejects.toThrow(RetryError);
await expectPromise;
expect(mockFn).toHaveBeenCalledTimes(customMaxRetries + 1); // Initial + retries
});
@@ -470,9 +477,12 @@ describe('retryWithBackoff', () => {
const promise = retryWithBackoff(mockFn, { maxRetries: 0 });
// Attach error handler before advancing timers
const expectPromise = expect(promise).rejects.toThrow(RetryError);
await vi.runAllTimersAsync();
await expect(promise).rejects.toThrow(RetryError);
await expectPromise;
expect(mockFn).toHaveBeenCalledTimes(1); // Only initial attempt
});
});
@@ -483,17 +493,16 @@ describe('retryWithBackoff', () => {
const promise = retryWithBackoff(mockFn, { maxRetries: 1 });
// Attach catch handler before advancing timers
const errorPromise = promise.catch(error => error);
await vi.runAllTimersAsync();
try {
await promise;
expect.fail('Should have thrown RetryError');
} catch (error) {
expect(error).toBeInstanceOf(RetryError);
const retryError = error as RetryError;
expect(retryError.lastError).toBeInstanceOf(Error);
expect(retryError.lastError.message).toBe('String error');
}
const error = await errorPromise;
expect(error).toBeInstanceOf(RetryError);
const retryError = error as RetryError;
expect(retryError.lastError).toBeInstanceOf(Error);
expect(retryError.lastError.message).toBe('String error');
});
it('should handle undefined rejections', async () => {
@@ -501,17 +510,16 @@ describe('retryWithBackoff', () => {
const promise = retryWithBackoff(mockFn, { maxRetries: 1 });
// Attach catch handler before advancing timers
const errorPromise = promise.catch(error => error);
await vi.runAllTimersAsync();
try {
await promise;
expect.fail('Should have thrown RetryError');
} catch (error) {
expect(error).toBeInstanceOf(RetryError);
const retryError = error as RetryError;
expect(retryError.lastError).toBeInstanceOf(Error);
expect(retryError.lastError.message).toBe('undefined');
}
const error = await errorPromise;
expect(error).toBeInstanceOf(RetryError);
const retryError = error as RetryError;
expect(retryError.lastError).toBeInstanceOf(Error);
expect(retryError.lastError.message).toBe('undefined');
});
it('should work with serviceName for metrics tracking', async () => {
@@ -567,22 +575,21 @@ describe('retryWithBackoff', () => {
const promise = retryWithBackoff(mockFn, { maxRetries: 2 });
// Attach catch handler before advancing timers
const errorPromise = promise.catch(error => error);
await vi.runAllTimersAsync();
try {
await promise;
expect.fail('Should have thrown RetryError');
} catch (error) {
expect(error).toBeInstanceOf(RetryError);
expect(error).toBeInstanceOf(Error);
const error = await errorPromise;
expect(error).toBeInstanceOf(RetryError);
expect(error).toBeInstanceOf(Error);
const retryError = error as RetryError;
expect(retryError.name).toBe('RetryError');
expect(retryError.attempts).toBe(3); // Initial + 2 retries
expect(retryError.lastError).toBe(originalError);
expect(retryError.message).toContain('3 attempts');
expect(retryError.message).toContain('Test error');
}
const retryError = error as RetryError;
expect(retryError.name).toBe('RetryError');
expect(retryError.attempts).toBe(3); // Initial + 2 retries
expect(retryError.lastError).toBe(originalError);
expect(retryError.message).toContain('3 attempts');
expect(retryError.message).toContain('Test error');
});
it('should be catchable as Error', async () => {
@@ -590,17 +597,17 @@ describe('retryWithBackoff', () => {
const promise = retryWithBackoff(mockFn, { maxRetries: 0 });
await vi.runAllTimersAsync();
// Attach catch handler before advancing timers
let caughtError: Error | null = null;
try {
await promise;
} catch (error) {
const errorPromise = promise.catch(error => {
if (error instanceof Error) {
caughtError = error;
}
}
return error;
});
await vi.runAllTimersAsync();
await errorPromise;
expect(caughtError).not.toBeNull();
expect(caughtError).toBeInstanceOf(Error);