99 lines
2.8 KiB
JavaScript
99 lines
2.8 KiB
JavaScript
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
vi.mock('../../opencode/auth.js', () => ({
|
|
readAuthFile: () => ({ crof: { key: 'test-token' } }),
|
|
}));
|
|
|
|
import { fetchQuota } from './crof.js';
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
const mockResponse = (body, init = {}) => ({
|
|
ok: true,
|
|
status: 200,
|
|
json: async () => body,
|
|
...init,
|
|
});
|
|
|
|
describe('Crof quota provider', () => {
|
|
it('reports credits balance as valueLabel with null percent', async () => {
|
|
// Documented /usage_api/ response from https://crof.ai/docs.md
|
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(
|
|
mockResponse({ usable_requests: 450, credits: 12.3456 }),
|
|
));
|
|
|
|
const result = await fetchQuota();
|
|
|
|
expect(result.ok).toBe(true);
|
|
expect(result.providerId).toBe('crof');
|
|
expect(result.usage.windows.credits.usedPercent).toBeNull();
|
|
expect(result.usage.windows.credits.valueLabel).toBe('$12.35');
|
|
expect(result.usage.windows.credits.windowSeconds).toBeNull();
|
|
expect(result.usage.windows.credits.resetAt).toBeNull();
|
|
});
|
|
|
|
it('tolerates missing credits field', async () => {
|
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(
|
|
mockResponse({ usable_requests: 0 }),
|
|
));
|
|
|
|
const result = await fetchQuota();
|
|
|
|
expect(result.ok).toBe(true);
|
|
expect(result.usage.windows.credits.valueLabel).toBeUndefined();
|
|
expect(result.usage.windows.credits.usedPercent).toBeNull();
|
|
});
|
|
|
|
it('parses numeric-string credits', async () => {
|
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(
|
|
mockResponse({ credits: '99.5' }),
|
|
));
|
|
|
|
const result = await fetchQuota();
|
|
|
|
expect(result.usage.windows.credits.valueLabel).toBe('$99.50');
|
|
});
|
|
|
|
it('maps 401 to session-expired error', async () => {
|
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
|
|
ok: false,
|
|
status: 401,
|
|
json: async () => ({}),
|
|
}));
|
|
|
|
const result = await fetchQuota();
|
|
|
|
expect(result.ok).toBe(false);
|
|
expect(result.configured).toBe(true);
|
|
expect(result.error).toBe('Session expired — please re-authenticate with CrofAI');
|
|
});
|
|
|
|
it('surfaces non-401 API errors with status', async () => {
|
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
|
|
ok: false,
|
|
status: 503,
|
|
json: async () => ({}),
|
|
}));
|
|
|
|
const result = await fetchQuota();
|
|
|
|
expect(result.ok).toBe(false);
|
|
expect(result.error).toBe('API error: 503');
|
|
});
|
|
|
|
it('reports invalid-response on JSON parse failure', async () => {
|
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
|
|
ok: true,
|
|
status: 200,
|
|
json: async () => { throw new SyntaxError('Unexpected token'); },
|
|
}));
|
|
|
|
const result = await fetchQuota();
|
|
|
|
expect(result.ok).toBe(false);
|
|
expect(result.error).toBe('Invalid response from provider');
|
|
});
|
|
});
|