Add ClinePass across server and VS Code quota paths. Reject malformed windows, preserve valid sibling limits, align credential fallback, and report timeout failures accurately. Validated 30 server quota tests, 129 VS Code quota tests and VS Code type-check. Oxlint findings are confined to pre-existing VS Code code.
104 lines
5.3 KiB
JavaScript
104 lines
5.3 KiB
JavaScript
import { describe, expect, it } from 'vitest';
|
|
import { fetchQuota, isConfigured } from './cline-pass.js';
|
|
|
|
const readAuth = () => ({ 'cline-pass': { key: 'test-token' } });
|
|
|
|
// Response shape verified by the contributor against the live ClinePass API.
|
|
const documentedPayload = {
|
|
data: { limits: [
|
|
{ type: 'five_hour', percentUsed: 43, resetsAt: '2026-09-08T17:00:44.598174595Z' },
|
|
{ type: 'weekly', percentUsed: 17 },
|
|
{ type: 'monthly', percentUsed: 8 },
|
|
] },
|
|
success: true,
|
|
};
|
|
|
|
describe('ClinePass quota provider', () => {
|
|
it('maps the documented windows and sends credentials only in headers', async () => {
|
|
const result = await fetchQuota({ readAuth, fetchImpl: async (url, options) => {
|
|
expect(url).toBe('https://api.cline.bot/api/v1/users/me/plan/usage-limits');
|
|
expect(new Headers(options.headers).get('Authorization')).toBe('Bearer test-token');
|
|
expect(options.signal).toBeInstanceOf(AbortSignal);
|
|
return Response.json(documentedPayload);
|
|
} });
|
|
expect(result.ok).toBe(true);
|
|
expect(result.providerId).toBe('cline-pass');
|
|
expect(Object.keys(result.usage.windows)).toEqual(['5h', 'weekly', 'monthly']);
|
|
expect(result.usage.windows['5h'].usedPercent).toBe(43);
|
|
expect(result.usage.windows['5h'].remainingPercent).toBe(57);
|
|
expect(result.usage.windows['5h'].windowSeconds).toBe(18_000);
|
|
expect(result.usage.windows['5h'].resetAt).toBe(Date.parse('2026-09-08T17:00:44.598174595Z'));
|
|
expect(result.usage.windows.weekly.usedPercent).toBe(17);
|
|
expect(result.usage.windows.weekly.windowSeconds).toBe(604_800);
|
|
expect(result.usage.windows.monthly.usedPercent).toBe(8);
|
|
expect(result.usage.windows.monthly.windowSeconds).toBeNull();
|
|
expect(JSON.stringify(result)).not.toContain('test-token');
|
|
});
|
|
|
|
it.each([0, '0', '51'])('accepts finite percentage %s', async (percentUsed) => {
|
|
const result = await fetchQuota({ readAuth, fetchImpl: async () => Response.json({ data: { limits: [{ type: 'weekly', percentUsed }] } }) });
|
|
expect(result.ok).toBe(true);
|
|
expect(result.usage.windows.weekly.usedPercent).toBe(Number(percentUsed));
|
|
});
|
|
|
|
it.each([
|
|
{ type: 'constructor', percentUsed: 5 }, { type: 'toString', percentUsed: 5 },
|
|
{ type: '__proto__', percentUsed: 5 }, { type: 'quarterly', percentUsed: 5 },
|
|
{ type: 'weekly', percentUsed: '' }, { type: 'weekly', percentUsed: ' ' },
|
|
{ type: 'weekly', percentUsed: null }, { type: 'weekly', percentUsed: true },
|
|
{ type: 'weekly', percentUsed: 'NaN' }, null,
|
|
])('ignores malformed windows without discarding valid siblings: %j', async (limit) => {
|
|
const invalid = await fetchQuota({ readAuth, fetchImpl: async () => Response.json({ data: { limits: [limit] } }) });
|
|
expect(invalid.ok).toBe(false);
|
|
expect(invalid.configured).toBe(true);
|
|
expect(invalid.usage).toBeNull();
|
|
const mixed = await fetchQuota({ readAuth, fetchImpl: async () => Response.json({ data: { limits: [limit, { type: 'monthly', percentUsed: 8 }] } }) });
|
|
expect(mixed.ok).toBe(true);
|
|
expect(Object.keys(mixed.usage.windows)).toEqual(['monthly']);
|
|
});
|
|
|
|
it.each([null, [], {}, { data: null }, { data: { limits: [] } }])('rejects empty or malformed payload %j', async (payload) => {
|
|
const result = await fetchQuota({ readAuth, fetchImpl: async () => Response.json(payload) });
|
|
expect(result.ok).toBe(false);
|
|
expect(result.usage).toBeNull();
|
|
expect(result.error).toBe('No quota data in response');
|
|
});
|
|
|
|
it.each([{ key: '' }, { key: ' ' }, { key: 42 }, {}])('uses a usable token when the key is malformed: %j', async (entry) => {
|
|
const auth = { 'cline-pass': { ...entry, token: 'test-token' } };
|
|
expect(isConfigured(auth)).toBe(true);
|
|
const result = await fetchQuota({ readAuth: () => auth, fetchImpl: async (_url, options) => {
|
|
expect(new Headers(options.headers).get('Authorization')).toBe('Bearer test-token');
|
|
return Response.json(documentedPayload);
|
|
} });
|
|
expect(result.ok).toBe(true);
|
|
});
|
|
|
|
it.each([{}, { 'cline-pass': { key: '' } }, { 'cline-pass': { key: 42 } }])('does not fetch without usable credentials: %j', async (auth) => {
|
|
expect(isConfigured(auth)).toBe(false);
|
|
const result = await fetchQuota({ readAuth: () => auth, fetchImpl: async () => { throw new Error('Unexpected fetch'); } });
|
|
expect(result.configured).toBe(false);
|
|
expect(result.error).toBe('Not configured');
|
|
});
|
|
|
|
it.each([[401, 'Session expired — please re-authenticate with ClinePass'], [503, 'API error: 503']])('reports HTTP %s', async (status, error) => {
|
|
const result = await fetchQuota({ readAuth, fetchImpl: async () => new Response(null, { status }) });
|
|
expect(result.ok).toBe(false);
|
|
expect(result.usage).toBeNull();
|
|
expect(result.error).toBe(error);
|
|
});
|
|
|
|
it('reports invalid JSON', async () => {
|
|
const result = await fetchQuota({ readAuth, fetchImpl: async () => new Response('{') });
|
|
expect(result.error).toBe('Invalid response from provider');
|
|
});
|
|
|
|
it('recognizes the timeout exception from AbortSignal.timeout', async () => {
|
|
const result = await fetchQuota({ readAuth, fetchImpl: async () => { throw new DOMException('Timed out', 'TimeoutError'); } });
|
|
expect(result.ok).toBe(false);
|
|
expect(result.configured).toBe(true);
|
|
expect(result.usage).toBeNull();
|
|
expect(result.error).toBe('Request timed out');
|
|
});
|
|
});
|