75 lines
2.8 KiB
TypeScript
75 lines
2.8 KiB
TypeScript
// @vitest-environment node
|
|
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
getAccount: vi.fn(),
|
|
updateAccount: vi.fn(),
|
|
resolveCredential: vi.fn(),
|
|
getFreshCredential: vi.fn(),
|
|
markExpired: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('../../electron/services/providers/provider-service', () => ({
|
|
getProviderService: () => ({
|
|
getAccount: mocks.getAccount,
|
|
updateAccount: mocks.updateAccount,
|
|
}),
|
|
}));
|
|
|
|
vi.mock('../../electron/coding-runtime/pi/provider-config', async (importOriginal) => ({
|
|
...await importOriginal<typeof import('../../electron/coding-runtime/pi/provider-config')>(),
|
|
resolvePiProviderCredentialFromSecretStore: mocks.resolveCredential,
|
|
}));
|
|
|
|
vi.mock('../../electron/services/works-square-ai-gateway', () => ({
|
|
getFreshWorksSquareAIGatewayCredential: mocks.getFreshCredential,
|
|
markWorksSquareAIGatewayCredentialExpired: mocks.markExpired,
|
|
}));
|
|
|
|
import {
|
|
CodingProviderCredentialRefreshError,
|
|
isCodingProviderAuthenticationError,
|
|
refreshCodingProviderCredential,
|
|
} from '../../electron/api/coding-provider-auth';
|
|
import { PiProviderConfigError } from '../../electron/coding-runtime/pi/provider-config';
|
|
|
|
describe('coding Provider credential refresh boundary', () => {
|
|
beforeEach(() => {
|
|
for (const mock of Object.values(mocks)) mock.mockReset();
|
|
});
|
|
|
|
it('types a rejected production refresh callback as an authentication failure', async () => {
|
|
mocks.getAccount.mockRejectedValueOnce(new Error('secure store unavailable'));
|
|
|
|
const failure = await refreshCodingProviderCredential('account-a').catch((error) => error);
|
|
expect(failure).toBeInstanceOf(CodingProviderCredentialRefreshError);
|
|
expect(isCodingProviderAuthenticationError(failure)).toBe(true);
|
|
});
|
|
|
|
it('types a missing refreshed Works credential as an authentication failure', async () => {
|
|
mocks.getAccount.mockResolvedValueOnce({
|
|
id: 'account-works',
|
|
enabled: true,
|
|
authMode: 'api_key',
|
|
metadata: { worksSquareCredentialMode: 'works_square_ai_gateway' },
|
|
});
|
|
mocks.getFreshCredential.mockResolvedValueOnce(null);
|
|
|
|
const failure = await refreshCodingProviderCredential('account-works').catch((error) => error);
|
|
expect(mocks.markExpired).toHaveBeenCalledTimes(1);
|
|
expect(failure).toBeInstanceOf(CodingProviderCredentialRefreshError);
|
|
expect(isCodingProviderAuthenticationError(failure)).toBe(true);
|
|
expect(mocks.updateAccount).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('classifies only the typed missing Provider credential as authentication-required', () => {
|
|
expect(isCodingProviderAuthenticationError(
|
|
new PiProviderConfigError('PROVIDER_AUTH_REQUIRED', 'Provider credential is unavailable'),
|
|
)).toBe(true);
|
|
expect(isCodingProviderAuthenticationError(
|
|
new PiProviderConfigError('PROVIDER_INVALID', 'Provider configuration is invalid'),
|
|
)).toBe(false);
|
|
});
|
|
});
|