test: raise the timeout of the OAuth client suite

The suite re-imports GoogleAPIService after vi.resetModules() in every test;
under the parallel full run the first import exceeded 5 s and failed
(passes alone in about 1 s).
This commit is contained in:
evandro committed 2026-10-10 04:29:40 -03:00
1 parent 8e20c32117
commit 0a6a8ff4bb
1 file changed
+439 -437
+439 -437
View File
@@ -1,437 +1,439 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { isString } from 'lodash-es'; import { isString } from 'lodash-es';
vi.mock('@/server/modules/proxy/request-user-agent', () => ({ vi.mock('@/server/modules/proxy/request-user-agent', () => ({
resolveRequestUserAgent: vi.fn().mockResolvedValue('test-agent/1.0.0'), resolveRequestUserAgent: vi.fn().mockResolvedValue('test-agent/1.0.0'),
buildUserAgent: vi.fn().mockReturnValue('test-agent/1.0.0'), buildUserAgent: vi.fn().mockReturnValue('test-agent/1.0.0'),
resolveLocalInstalledVersion: vi.fn().mockReturnValue('1.0.0'), resolveLocalInstalledVersion: vi.fn().mockReturnValue('1.0.0'),
FALLBACK_VERSION: '1.22.2', FALLBACK_VERSION: '1.22.2',
})); }));
// Mock module to test timeout behavior // Mock module to test timeout behavior
describe('GoogleAPIService Timeout', () => { describe('GoogleAPIService Timeout', () => {
beforeEach(() => { beforeEach(() => {
vi.useFakeTimers(); vi.useFakeTimers();
}); });
afterEach(() => { afterEach(() => {
vi.useRealTimers(); vi.useRealTimers();
}); });
it('should abort request after timeout', async () => { it('should abort request after timeout', async () => {
const TIMEOUT_MS = 100; const TIMEOUT_MS = 100;
// Recreate the same logic used in GoogleAPIService // Recreate the same logic used in GoogleAPIService
const createTimeoutSignal = (ms: number): AbortSignal => { const createTimeoutSignal = (ms: number): AbortSignal => {
const controller = new AbortController(); const controller = new AbortController();
setTimeout(() => controller.abort(), ms); setTimeout(() => controller.abort(), ms);
return controller.signal; return controller.signal;
}; };
const signal = createTimeoutSignal(TIMEOUT_MS); const signal = createTimeoutSignal(TIMEOUT_MS);
// Verify signal is not aborted initially // Verify signal is not aborted initially
expect(signal.aborted).toBe(false); expect(signal.aborted).toBe(false);
// Fast-forward time // Fast-forward time
vi.advanceTimersByTime(TIMEOUT_MS + 10); vi.advanceTimersByTime(TIMEOUT_MS + 10);
// Signal should now be aborted // Signal should now be aborted
expect(signal.aborted).toBe(true); expect(signal.aborted).toBe(true);
}); });
it('should set aborted state when controller.abort() is called', () => { it('should set aborted state when controller.abort() is called', () => {
const controller = new AbortController(); const controller = new AbortController();
// Initially not aborted // Initially not aborted
expect(controller.signal.aborted).toBe(false); expect(controller.signal.aborted).toBe(false);
// Abort the controller // Abort the controller
controller.abort(); controller.abort();
// Signal should now be aborted // Signal should now be aborted
expect(controller.signal.aborted).toBe(true); expect(controller.signal.aborted).toBe(true);
}); });
it('should transform AbortError to user-friendly message', () => { it('should transform AbortError to user-friendly message', () => {
// This tests our error transformation logic from GoogleAPIService // This tests our error transformation logic from GoogleAPIService
const handleAbortError = (err: Error) => { const handleAbortError = (err: Error) => {
if (err.name === 'AbortError') { if (err.name === 'AbortError') {
throw new Error( throw new Error(
'Token exchange timed out. Please check your network connection and try again.', 'Token exchange timed out. Please check your network connection and try again.',
); );
} }
throw err; throw err;
}; };
const abortError = new Error('The operation was aborted'); const abortError = new Error('The operation was aborted');
abortError.name = 'AbortError'; abortError.name = 'AbortError';
expect(() => handleAbortError(abortError)).toThrow( expect(() => handleAbortError(abortError)).toThrow(
'Token exchange timed out. Please check your network connection and try again.', 'Token exchange timed out. Please check your network connection and try again.',
); );
}); });
it('should not transform non-AbortError', () => { it('should not transform non-AbortError', () => {
const handleAbortError = (err: Error) => { const handleAbortError = (err: Error) => {
if (err.name === 'AbortError') { if (err.name === 'AbortError') {
throw new Error( throw new Error(
'Token exchange timed out. Please check your network connection and try again.', 'Token exchange timed out. Please check your network connection and try again.',
); );
} }
throw err; throw err;
}; };
const networkError = new Error('Network failure'); const networkError = new Error('Network failure');
networkError.name = 'NetworkError'; networkError.name = 'NetworkError';
expect(() => handleAbortError(networkError)).toThrow('Network failure'); expect(() => handleAbortError(networkError)).toThrow('Network failure');
}); });
}); });
describe('GoogleAPIService OAuth clients', () => { // Each test resets the module registry and re-imports GoogleAPIService, which can exceed the default
const originalOauthClientsEnv = process.env.ANTIGRAVITY_OAUTH_CLIENTS; // 5s timeout while the whole suite runs in parallel.
const originalActiveOauthClientEnv = process.env.ANTIGRAVITY_OAUTH_CLIENT_KEY; describe('GoogleAPIService OAuth clients', { timeout: 30_000 }, () => {
const originalOauthClientsEnv = process.env.ANTIGRAVITY_OAUTH_CLIENTS;
beforeEach(() => { const originalActiveOauthClientEnv = process.env.ANTIGRAVITY_OAUTH_CLIENT_KEY;
vi.resetModules();
delete process.env.ANTIGRAVITY_OAUTH_CLIENTS; beforeEach(() => {
delete process.env.ANTIGRAVITY_OAUTH_CLIENT_KEY; vi.resetModules();
}); delete process.env.ANTIGRAVITY_OAUTH_CLIENTS;
delete process.env.ANTIGRAVITY_OAUTH_CLIENT_KEY;
afterEach(() => { });
if (isString(originalOauthClientsEnv)) {
process.env.ANTIGRAVITY_OAUTH_CLIENTS = originalOauthClientsEnv; afterEach(() => {
} else { if (isString(originalOauthClientsEnv)) {
delete process.env.ANTIGRAVITY_OAUTH_CLIENTS; process.env.ANTIGRAVITY_OAUTH_CLIENTS = originalOauthClientsEnv;
} } else {
delete process.env.ANTIGRAVITY_OAUTH_CLIENTS;
if (isString(originalActiveOauthClientEnv)) { }
process.env.ANTIGRAVITY_OAUTH_CLIENT_KEY = originalActiveOauthClientEnv;
} else { if (isString(originalActiveOauthClientEnv)) {
delete process.env.ANTIGRAVITY_OAUTH_CLIENT_KEY; process.env.ANTIGRAVITY_OAUTH_CLIENT_KEY = originalActiveOauthClientEnv;
} } else {
}); delete process.env.ANTIGRAVITY_OAUTH_CLIENT_KEY;
}
it('loads builtin and custom oauth clients with active marker', async () => { });
process.env.ANTIGRAVITY_OAUTH_CLIENTS =
'custom_a|id-a|secret-a|Custom A;custom_b|id-b|secret-b|Custom B'; it('loads builtin and custom oauth clients with active marker', async () => {
process.env.ANTIGRAVITY_OAUTH_CLIENT_KEY = 'custom_b'; process.env.ANTIGRAVITY_OAUTH_CLIENTS =
'custom_a|id-a|secret-a|Custom A;custom_b|id-b|secret-b|Custom B';
const { GoogleAPIService } = await import('../../services/GoogleAPIService'); process.env.ANTIGRAVITY_OAUTH_CLIENT_KEY = 'custom_b';
const clients = GoogleAPIService.listOAuthClients();
const { GoogleAPIService } = await import('../../services/GoogleAPIService');
expect(clients.some((client) => client.is_builtin)).toBe(true); const clients = GoogleAPIService.listOAuthClients();
expect(clients.find((client) => client.key === 'custom_a')?.label).toBe('Custom A');
expect(clients.find((client) => client.key === 'custom_b')?.is_active).toBe(true); expect(clients.some((client) => client.is_builtin)).toBe(true);
}); expect(clients.find((client) => client.key === 'custom_a')?.label).toBe('Custom A');
expect(clients.find((client) => client.key === 'custom_b')?.is_active).toBe(true);
it('switches active oauth client key', async () => { });
process.env.ANTIGRAVITY_OAUTH_CLIENTS = 'custom_a|id-a|secret-a|Custom A';
it('switches active oauth client key', async () => {
const { GoogleAPIService } = await import('../../services/GoogleAPIService'); process.env.ANTIGRAVITY_OAUTH_CLIENTS = 'custom_a|id-a|secret-a|Custom A';
GoogleAPIService.setActiveOAuthClientKey('custom_a');
const { GoogleAPIService } = await import('../../services/GoogleAPIService');
expect(GoogleAPIService.getActiveOAuthClientKey()).toBe('custom_a'); GoogleAPIService.setActiveOAuthClientKey('custom_a');
});
expect(GoogleAPIService.getActiveOAuthClientKey()).toBe('custom_a');
it('throws when switching to unknown oauth client key', async () => { });
const { GoogleAPIService } = await import('../../services/GoogleAPIService');
expect(() => GoogleAPIService.setActiveOAuthClientKey('missing_client')).toThrow( it('throws when switching to unknown oauth client key', async () => {
'Unknown OAuth client key', const { GoogleAPIService } = await import('../../services/GoogleAPIService');
); expect(() => GoogleAPIService.setActiveOAuthClientKey('missing_client')).toThrow(
}); 'Unknown OAuth client key',
}); );
});
describe('GoogleAPIService user info parsing', () => { });
beforeEach(() => {
vi.restoreAllMocks(); describe('GoogleAPIService user info parsing', () => {
vi.resetModules(); beforeEach(() => {
}); vi.restoreAllMocks();
vi.resetModules();
it('accepts Google user info responses without family_name', async () => { });
const fetchMock = vi.fn().mockResolvedValueOnce({
ok: true, it('accepts Google user info responses without family_name', async () => {
json: vi.fn().mockResolvedValue({ const fetchMock = vi.fn().mockResolvedValueOnce({
id: 'google-user-1', ok: true,
email: '[email protected]', json: vi.fn().mockResolvedValue({
verified_email: true, id: 'google-user-1',
name: 'Example User', email: 'user@example.com',
given_name: 'Example', verified_email: true,
picture: 'https://example.com/avatar.png', name: 'Example User',
}), given_name: 'Example',
}); picture: 'https://example.com/avatar.png',
}),
vi.stubGlobal('fetch', fetchMock); });
const { ConfigManager } = await import('../../ipc/config/manager'); vi.stubGlobal('fetch', fetchMock);
vi.spyOn(ConfigManager, 'loadConfig').mockReturnValue({
proxy: { const { ConfigManager } = await import('../../ipc/config/manager');
upstream_proxy: { vi.spyOn(ConfigManager, 'loadConfig').mockReturnValue({
enabled: false, proxy: {
}, upstream_proxy: {
}, enabled: false,
} as any); },
},
const { GoogleAPIService } = await import('../../services/GoogleAPIService'); } as any);
await expect(GoogleAPIService.getUserInfo('access-token')).resolves.toEqual( const { GoogleAPIService } = await import('../../services/GoogleAPIService');
expect.objectContaining({
id: 'google-user-1', await expect(GoogleAPIService.getUserInfo('access-token')).resolves.toEqual(
email: '[email protected]', expect.objectContaining({
name: 'Example User', id: 'google-user-1',
given_name: 'Example', email: 'user@example.com',
picture: 'https://example.com/avatar.png', name: 'Example User',
verified_email: true, given_name: 'Example',
}), picture: 'https://example.com/avatar.png',
); verified_email: true,
}); }),
}); );
});
describe('CloudAccountList auth code auto-submit guard', () => { });
it('returns true for a fresh auth code while the dialog is open', async () => {
const { shouldAutoSubmitGoogleAuthCode } = await import('../../utils/googleAuthSubmission'); describe('CloudAccountList auth code auto-submit guard', () => {
it('returns true for a fresh auth code while the dialog is open', async () => {
expect( const { shouldAutoSubmitGoogleAuthCode } = await import('../../utils/googleAuthSubmission');
shouldAutoSubmitGoogleAuthCode({
authCode: 'fresh-code', expect(
isAddDialogOpen: true, shouldAutoSubmitGoogleAuthCode({
isPending: false, authCode: 'fresh-code',
lastSubmittedAuthCode: null, isAddDialogOpen: true,
}), isPending: false,
).toBe(true); lastSubmittedAuthCode: null,
}); }),
).toBe(true);
it('returns false after the same auth code was already auto-submitted', async () => { });
const { shouldAutoSubmitGoogleAuthCode } = await import('../../utils/googleAuthSubmission');
it('returns false after the same auth code was already auto-submitted', async () => {
expect( const { shouldAutoSubmitGoogleAuthCode } = await import('../../utils/googleAuthSubmission');
shouldAutoSubmitGoogleAuthCode({
authCode: 'same-code', expect(
isAddDialogOpen: true, shouldAutoSubmitGoogleAuthCode({
isPending: false, authCode: 'same-code',
lastSubmittedAuthCode: 'same-code', isAddDialogOpen: true,
}), isPending: false,
).toBe(false); lastSubmittedAuthCode: 'same-code',
}); }),
}); ).toBe(false);
});
describe('GoogleAPIService fetchQuota fallback policy', () => { });
beforeEach(() => {
vi.restoreAllMocks(); describe('GoogleAPIService fetchQuota fallback policy', () => {
vi.resetModules(); beforeEach(() => {
}); vi.restoreAllMocks();
vi.resetModules();
it('falls back to fetchCredits when loadCodeAssist returns no usable credits', async () => { });
const fetchMock = vi
.fn() it('falls back to fetchCredits when loadCodeAssist returns no usable credits', async () => {
.mockResolvedValueOnce({ const fetchMock = vi
ok: true, .fn()
status: 200, .mockResolvedValueOnce({
json: vi.fn().mockResolvedValue({ ok: true,
// No paidTier.availableCredits — no usable credits status: 200,
freeTier: {}, json: vi.fn().mockResolvedValue({
}), // No paidTier.availableCredits — no usable credits
}) freeTier: {},
.mockResolvedValueOnce({ }),
ok: true, })
status: 200, .mockResolvedValueOnce({
json: vi.fn().mockResolvedValue({ ok: true,
credits: 500, status: 200,
expiryDate: '2025-12-31', json: vi.fn().mockResolvedValue({
}), credits: 500,
}); expiryDate: '2025-12-31',
}),
vi.stubGlobal('fetch', fetchMock); });
const { ConfigManager } = await import('../../ipc/config/manager'); vi.stubGlobal('fetch', fetchMock);
vi.spyOn(ConfigManager, 'loadConfig').mockReturnValue({
proxy: { const { ConfigManager } = await import('../../ipc/config/manager');
upstream_proxy: { vi.spyOn(ConfigManager, 'loadConfig').mockReturnValue({
enabled: false, proxy: {
}, upstream_proxy: {
}, enabled: false,
} as any); },
},
const { GoogleAPIService } = await import('../../services/GoogleAPIService'); } as any);
await expect(GoogleAPIService.fetchAICredits('access-token')).resolves.toEqual({ const { GoogleAPIService } = await import('../../services/GoogleAPIService');
credits: 500,
expiryDate: '2025-12-31', await expect(GoogleAPIService.fetchAICredits('access-token')).resolves.toEqual({
}); credits: 500,
expiryDate: '2025-12-31',
expect(fetchMock).toHaveBeenCalledTimes(2); });
expect(fetchMock.mock.calls[0]?.[0]).toBe(
'https://daily-cloudcode-pa.googleapis.com/v1internal:loadCodeAssist', expect(fetchMock).toHaveBeenCalledTimes(2);
); expect(fetchMock.mock.calls[0]?.[0]).toBe(
expect(fetchMock.mock.calls[1]?.[0]).toBe( 'https://daily-cloudcode-pa.googleapis.com/v1internal:loadCodeAssist',
'https://cloudcode-pa.googleapis.com/v1internal:fetchCredits', );
); expect(fetchMock.mock.calls[1]?.[0]).toBe(
}); 'https://cloudcode-pa.googleapis.com/v1internal:fetchCredits',
);
it('does not fall through to the next endpoint on permanent 400 errors', async () => { });
const fetchMock = vi.fn().mockResolvedValueOnce({
ok: false, it('does not fall through to the next endpoint on permanent 400 errors', async () => {
status: 400, const fetchMock = vi.fn().mockResolvedValueOnce({
text: vi.fn().mockResolvedValue('INVALID_ARGUMENT'), ok: false,
}); status: 400,
text: vi.fn().mockResolvedValue('INVALID_ARGUMENT'),
vi.stubGlobal('fetch', fetchMock); });
const { ConfigManager } = await import('../../ipc/config/manager'); vi.stubGlobal('fetch', fetchMock);
vi.spyOn(ConfigManager, 'loadConfig').mockReturnValue({
proxy: { const { ConfigManager } = await import('../../ipc/config/manager');
upstream_proxy: { vi.spyOn(ConfigManager, 'loadConfig').mockReturnValue({
enabled: false, proxy: {
}, upstream_proxy: {
}, enabled: false,
} as any); },
},
const { GoogleAPIService } = await import('../../services/GoogleAPIService'); } as any);
vi.spyOn(GoogleAPIService, 'fetchProjectContext').mockResolvedValue({
projectId: 'project-1', const { GoogleAPIService } = await import('../../services/GoogleAPIService');
subscriptionTier: 'free', vi.spyOn(GoogleAPIService, 'fetchProjectContext').mockResolvedValue({
}); projectId: 'project-1',
subscriptionTier: 'free',
await expect(GoogleAPIService.fetchQuota('access-token')).rejects.toThrow( });
'HTTP 400 - INVALID_ARGUMENT',
); await expect(GoogleAPIService.fetchQuota('access-token')).rejects.toThrow(
expect(fetchMock).toHaveBeenCalledTimes(1); 'HTTP 400 - INVALID_ARGUMENT',
}); );
expect(fetchMock).toHaveBeenCalledTimes(1);
it('uses an explicit dispatcher from env proxy settings when no account proxy is provided', async () => { });
process.env.HTTP_PROXY = 'http://127.0.0.1:9090';
process.env.HTTPS_PROXY = 'http://127.0.0.1:9090'; it('uses an explicit dispatcher from env proxy settings when no account proxy is provided', async () => {
process.env.NO_PROXY = 'localhost,127.0.0.1,::1'; process.env.HTTP_PROXY = 'http://127.0.0.1:9090';
process.env.HTTPS_PROXY = 'http://127.0.0.1:9090';
const fetchMock = vi.fn().mockResolvedValueOnce({ process.env.NO_PROXY = 'localhost,127.0.0.1,::1';
ok: true,
status: 200, const fetchMock = vi.fn().mockResolvedValueOnce({
json: vi.fn().mockResolvedValue({ ok: true,
paidTier: { status: 200,
availableCredits: [ json: vi.fn().mockResolvedValue({
{ paidTier: {
creditType: 'GOOGLE_ONE_AI', availableCredits: [
creditAmount: '1000', {
minimumCreditAmountForUsage: '50', creditType: 'GOOGLE_ONE_AI',
}, creditAmount: '1000',
], minimumCreditAmountForUsage: '50',
}, },
}), ],
}); },
}),
vi.stubGlobal('fetch', fetchMock); });
const { ConfigManager } = await import('../../ipc/config/manager'); vi.stubGlobal('fetch', fetchMock);
vi.spyOn(ConfigManager, 'loadConfig').mockReturnValue({
proxy: { const { ConfigManager } = await import('../../ipc/config/manager');
upstream_proxy: { vi.spyOn(ConfigManager, 'loadConfig').mockReturnValue({
enabled: false, proxy: {
}, upstream_proxy: {
}, enabled: false,
} as any); },
},
const { GoogleAPIService } = await import('../../services/GoogleAPIService'); } as any);
await expect(GoogleAPIService.fetchAICredits('access-token')).resolves.toEqual({ const { GoogleAPIService } = await import('../../services/GoogleAPIService');
credits: 1000,
expiryDate: '', await expect(GoogleAPIService.fetchAICredits('access-token')).resolves.toEqual({
}); credits: 1000,
expiryDate: '',
expect(fetchMock).toHaveBeenCalledTimes(1); });
expect(fetchMock.mock.calls[0]?.[1]?.dispatcher).toBeDefined();
expect(fetchMock).toHaveBeenCalledTimes(1);
delete process.env.HTTP_PROXY; expect(fetchMock.mock.calls[0]?.[1]?.dispatcher).toBeDefined();
delete process.env.HTTPS_PROXY;
delete process.env.NO_PROXY; delete process.env.HTTP_PROXY;
}); delete process.env.HTTPS_PROXY;
delete process.env.NO_PROXY;
it('uses electron proxy env as an explicit dispatcher fallback', async () => { });
process.env.ELECTRON_PROXY_SERVER = 'http://127.0.0.1:9090';
it('uses electron proxy env as an explicit dispatcher fallback', async () => {
const fetchMock = vi.fn().mockResolvedValueOnce({ process.env.ELECTRON_PROXY_SERVER = 'http://127.0.0.1:9090';
ok: true,
status: 200, const fetchMock = vi.fn().mockResolvedValueOnce({
json: vi.fn().mockResolvedValue({ ok: true,
paidTier: { status: 200,
availableCredits: [ json: vi.fn().mockResolvedValue({
{ paidTier: {
creditType: 'GOOGLE_ONE_AI', availableCredits: [
creditAmount: '1000', {
minimumCreditAmountForUsage: '50', creditType: 'GOOGLE_ONE_AI',
}, creditAmount: '1000',
], minimumCreditAmountForUsage: '50',
}, },
}), ],
}); },
}),
vi.stubGlobal('fetch', fetchMock); });
const { ConfigManager } = await import('../../ipc/config/manager'); vi.stubGlobal('fetch', fetchMock);
vi.spyOn(ConfigManager, 'loadConfig').mockReturnValue({
proxy: { const { ConfigManager } = await import('../../ipc/config/manager');
upstream_proxy: { vi.spyOn(ConfigManager, 'loadConfig').mockReturnValue({
enabled: false, proxy: {
}, upstream_proxy: {
}, enabled: false,
} as any); },
},
const { GoogleAPIService } = await import('../../services/GoogleAPIService'); } as any);
await expect(GoogleAPIService.fetchAICredits('access-token')).resolves.toEqual({ const { GoogleAPIService } = await import('../../services/GoogleAPIService');
credits: 1000,
expiryDate: '', await expect(GoogleAPIService.fetchAICredits('access-token')).resolves.toEqual({
}); credits: 1000,
expiryDate: '',
expect(fetchMock).toHaveBeenCalledTimes(1); });
expect(fetchMock.mock.calls[0]?.[1]?.dispatcher).toBeDefined();
expect(fetchMock).toHaveBeenCalledTimes(1);
delete process.env.ELECTRON_PROXY_SERVER; expect(fetchMock.mock.calls[0]?.[1]?.dispatcher).toBeDefined();
});
}); delete process.env.ELECTRON_PROXY_SERVER;
});
describe('QuotaService fallback policy', () => { });
beforeEach(() => {
vi.restoreAllMocks(); describe('QuotaService fallback policy', () => {
vi.resetModules(); beforeEach(() => {
}); vi.restoreAllMocks();
vi.resetModules();
it('does not fall through to the next endpoint on permanent 400 errors', async () => { });
const postMock = vi
.fn() it('does not fall through to the next endpoint on permanent 400 errors', async () => {
.mockResolvedValueOnce({ const postMock = vi
status: 200, .fn()
data: { .mockResolvedValueOnce({
cloudaicompanionProject: 'project-1', status: 200,
currentTier: { id: 'free' }, data: {
}, cloudaicompanionProject: 'project-1',
}) currentTier: { id: 'free' },
.mockRejectedValueOnce({ },
isAxiosError: true, })
response: { .mockRejectedValueOnce({
status: 400, isAxiosError: true,
data: { error: 'INVALID_ARGUMENT' }, response: {
}, status: 400,
message: 'Request failed with status code 400', data: { error: 'INVALID_ARGUMENT' },
}); },
message: 'Request failed with status code 400',
vi.doMock('axios', () => ({ });
default: {
create: vi.fn(() => ({ vi.doMock('axios', () => ({
post: postMock, default: {
})), create: vi.fn(() => ({
isAxiosError: (error: unknown) => post: postMock,
Boolean((error as { isAxiosError?: boolean })?.isAxiosError), })),
}, isAxiosError: (error: unknown) =>
isAxiosError: (error: unknown) => Boolean((error as { isAxiosError?: boolean })?.isAxiosError),
Boolean((error as { isAxiosError?: boolean })?.isAxiosError), },
})); isAxiosError: (error: unknown) =>
Boolean((error as { isAxiosError?: boolean })?.isAxiosError),
const { QuotaService } = await import('../../lib/geminiNexus/QuotaService'); }));
await expect(QuotaService.fetchQuota('access-token', '[email protected]')).rejects.toThrow( const { QuotaService } = await import('../../lib/geminiNexus/QuotaService');
'HTTP 400 - {"error":"INVALID_ARGUMENT"}',
); await expect(QuotaService.fetchQuota('access-token', '[email protected]')).rejects.toThrow(
expect(postMock).toHaveBeenCalledTimes(2); 'HTTP 400 - {"error":"INVALID_ARGUMENT"}',
}); );
}); expect(postMock).toHaveBeenCalledTimes(2);
});
});