Files
DeskClaw/tests/unit/provider-validation.test.ts

158 lines
5.2 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
const proxyAwareFetch = vi.fn();
vi.mock('@electron/utils/proxy-fetch', () => ({
proxyAwareFetch,
}));
describe('validateApiKeyWithProvider', () => {
beforeEach(() => {
proxyAwareFetch.mockReset();
proxyAwareFetch.mockResolvedValue(
new Response(JSON.stringify({ data: [] }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
})
);
});
it('validates MiniMax CN keys with Anthropic headers', async () => {
const { validateApiKeyWithProvider } = await import('@electron/services/providers/provider-validation');
const result = await validateApiKeyWithProvider('minimax-portal-cn', 'sk-cn-test');
expect(result).toMatchObject({ valid: true });
expect(proxyAwareFetch).toHaveBeenCalledWith(
'https://api.minimaxi.com/anthropic/v1/models?limit=1',
expect.objectContaining({
headers: expect.objectContaining({
'x-api-key': 'sk-cn-test',
'anthropic-version': '2023-06-01',
}),
})
);
});
it('still validates OpenAI-compatible providers with bearer auth', async () => {
const { validateApiKeyWithProvider } = await import('@electron/services/providers/provider-validation');
const result = await validateApiKeyWithProvider('openai', 'sk-openai-test');
expect(result).toMatchObject({ valid: true });
expect(proxyAwareFetch).toHaveBeenCalledWith(
'https://api.openai.com/v1/models?limit=1',
expect.objectContaining({
headers: expect.objectContaining({
Authorization: 'Bearer sk-openai-test',
}),
})
);
});
it('falls back to /responses for openai-responses when /models is unavailable', async () => {
proxyAwareFetch
.mockResolvedValueOnce(
new Response(JSON.stringify({ error: { message: 'Not Found' } }), {
status: 404,
headers: { 'Content-Type': 'application/json' },
})
)
.mockResolvedValueOnce(
new Response(JSON.stringify({ error: { message: 'Unknown model' } }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
})
);
const { validateApiKeyWithProvider } = await import('@electron/services/providers/provider-validation');
const result = await validateApiKeyWithProvider('custom', 'sk-response-test', {
baseUrl: 'https://responses.example.com/v1',
apiProtocol: 'openai-responses',
});
expect(result).toMatchObject({ valid: true });
expect(proxyAwareFetch).toHaveBeenNthCalledWith(
1,
'https://responses.example.com/v1/models?limit=1',
expect.objectContaining({
headers: expect.objectContaining({
Authorization: 'Bearer sk-response-test',
}),
})
);
expect(proxyAwareFetch).toHaveBeenNthCalledWith(
2,
'https://responses.example.com/v1/responses',
expect.objectContaining({
method: 'POST',
})
);
});
it('falls back to /chat/completions for openai-completions when /models is unavailable', async () => {
proxyAwareFetch
.mockResolvedValueOnce(
new Response(JSON.stringify({ error: { message: 'Not Found' } }), {
status: 404,
headers: { 'Content-Type': 'application/json' },
})
)
.mockResolvedValueOnce(
new Response(JSON.stringify({ error: { message: 'Unknown model' } }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
})
);
const { validateApiKeyWithProvider } = await import('@electron/services/providers/provider-validation');
const result = await validateApiKeyWithProvider('custom', 'sk-chat-test', {
baseUrl: 'https://chat.example.com/v1',
apiProtocol: 'openai-completions',
});
expect(result).toMatchObject({ valid: true });
expect(proxyAwareFetch).toHaveBeenNthCalledWith(
2,
'https://chat.example.com/v1/chat/completions',
expect.objectContaining({
method: 'POST',
})
);
});
it('does not duplicate endpoint suffix when baseUrl already points to /responses', async () => {
proxyAwareFetch
.mockResolvedValueOnce(
new Response(JSON.stringify({ error: { message: 'Not Found' } }), {
status: 404,
headers: { 'Content-Type': 'application/json' },
})
)
.mockResolvedValueOnce(
new Response(JSON.stringify({ error: { message: 'Unknown model' } }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
})
);
const { validateApiKeyWithProvider } = await import('@electron/services/providers/provider-validation');
const result = await validateApiKeyWithProvider('custom', 'sk-endpoint-test', {
baseUrl: 'https://openrouter.ai/api/v1/responses',
apiProtocol: 'openai-responses',
});
expect(result).toMatchObject({ valid: true });
expect(proxyAwareFetch).toHaveBeenNthCalledWith(
1,
'https://openrouter.ai/api/v1/models?limit=1',
expect.anything(),
);
expect(proxyAwareFetch).toHaveBeenNthCalledWith(
2,
'https://openrouter.ai/api/v1/responses',
expect.anything(),
);
});
});