Increase code coverage for core packages (#12872)

This commit is contained in:
Megha Bansal
2025-11-11 20:06:43 -08:00
committed by GitHub
parent e8038c727f
commit 11a0a9b911
18 changed files with 2265 additions and 47 deletions
@@ -714,6 +714,269 @@ describe('MCPOAuthProvider', () => {
).rejects.toThrow('Token exchange failed: invalid_grant - Invalid grant');
});
it('should handle OAuth discovery failure', async () => {
const configWithoutAuth: MCPOAuthConfig = { ...mockConfig };
delete configWithoutAuth.authorizationUrl;
delete configWithoutAuth.tokenUrl;
mockFetch.mockResolvedValueOnce(
createMockResponse({
ok: false,
status: 404,
}),
);
const authProvider = new MCPOAuthProvider();
await expect(
authProvider.authenticate(
'test-server',
configWithoutAuth,
'https://api.example.com',
),
).rejects.toThrow(
'Failed to discover OAuth configuration from MCP server',
);
});
it('should handle authorization server metadata discovery failure', async () => {
const configWithoutClient: MCPOAuthConfig = { ...mockConfig };
delete configWithoutClient.clientId;
mockFetch.mockResolvedValue(
createMockResponse({
ok: false,
status: 404,
}),
);
// Prevent callback server from hanging the test
mockHttpServer.listen.mockImplementation((port, callback) => {
callback?.();
});
const authProvider = new MCPOAuthProvider();
await expect(
authProvider.authenticate('test-server', configWithoutClient),
).rejects.toThrow(
'Failed to fetch authorization server metadata for client registration',
);
});
it('should handle invalid callback request', async () => {
let callbackHandler: unknown;
vi.mocked(http.createServer).mockImplementation((handler) => {
callbackHandler = handler;
return mockHttpServer as unknown as http.Server;
});
mockHttpServer.listen.mockImplementation((port, callback) => {
callback?.();
setTimeout(() => {
const mockReq = {
url: '/invalid-path',
};
const mockRes = {
writeHead: vi.fn(),
end: vi.fn(),
};
(callbackHandler as (req: unknown, res: unknown) => void)(
mockReq,
mockRes,
);
}, 0);
});
const authProvider = new MCPOAuthProvider();
// The test will timeout if the server does not handle the invalid request correctly.
// We are testing that the server does not hang.
await Promise.race([
authProvider.authenticate('test-server', mockConfig),
new Promise((resolve) => setTimeout(resolve, 1000)),
]);
});
it('should handle token exchange failure with non-json response', async () => {
let callbackHandler: unknown;
vi.mocked(http.createServer).mockImplementation((handler) => {
callbackHandler = handler;
return mockHttpServer as unknown as http.Server;
});
mockHttpServer.listen.mockImplementation((port, callback) => {
callback?.();
setTimeout(() => {
const mockReq = {
url: '/oauth/callback?code=auth_code_123&state=bW9ja19zdGF0ZV8xNl9ieXRlcw',
};
const mockRes = {
writeHead: vi.fn(),
end: vi.fn(),
};
(callbackHandler as (req: unknown, res: unknown) => void)(
mockReq,
mockRes,
);
}, 10);
});
mockFetch.mockResolvedValueOnce(
createMockResponse({
ok: false,
status: 500,
contentType: 'text/html',
text: 'Internal Server Error',
}),
);
const authProvider = new MCPOAuthProvider();
await expect(
authProvider.authenticate('test-server', mockConfig),
).rejects.toThrow('Token exchange failed: 500 - Internal Server Error');
});
it('should handle token exchange with unexpected content type', async () => {
let callbackHandler: unknown;
vi.mocked(http.createServer).mockImplementation((handler) => {
callbackHandler = handler;
return mockHttpServer as unknown as http.Server;
});
mockHttpServer.listen.mockImplementation((port, callback) => {
callback?.();
setTimeout(() => {
const mockReq = {
url: '/oauth/callback?code=auth_code_123&state=bW9ja19zdGF0ZV8xNl9ieXRlcw',
};
const mockRes = {
writeHead: vi.fn(),
end: vi.fn(),
};
(callbackHandler as (req: unknown, res: unknown) => void)(
mockReq,
mockRes,
);
}, 10);
});
mockFetch.mockResolvedValueOnce(
createMockResponse({
ok: true,
contentType: 'text/plain',
text: 'access_token=plain_text_token',
}),
);
const authProvider = new MCPOAuthProvider();
const result = await authProvider.authenticate('test-server', mockConfig);
expect(result.accessToken).toBe('plain_text_token');
});
it('should handle refresh token failure with non-json response', async () => {
mockFetch.mockResolvedValueOnce(
createMockResponse({
ok: false,
status: 500,
contentType: 'text/html',
text: 'Internal Server Error',
}),
);
const authProvider = new MCPOAuthProvider();
await expect(
authProvider.refreshAccessToken(
mockConfig,
'invalid_refresh_token',
'https://auth.example.com/token',
),
).rejects.toThrow('Token refresh failed: 500 - Internal Server Error');
});
it('should handle refresh token with unexpected content type', async () => {
mockFetch.mockResolvedValueOnce(
createMockResponse({
ok: true,
contentType: 'text/plain',
text: 'access_token=plain_text_token',
}),
);
const authProvider = new MCPOAuthProvider();
const result = await authProvider.refreshAccessToken(
mockConfig,
'refresh_token',
'https://auth.example.com/token',
);
expect(result.access_token).toBe('plain_text_token');
});
it('should continue authentication when browser fails to open', async () => {
mockOpenBrowserSecurely.mockRejectedValue(new Error('Browser not found'));
let callbackHandler: unknown;
vi.mocked(http.createServer).mockImplementation((handler) => {
callbackHandler = handler;
return mockHttpServer as unknown as http.Server;
});
mockHttpServer.listen.mockImplementation((port, callback) => {
callback?.();
setTimeout(() => {
const mockReq = {
url: '/oauth/callback?code=auth_code_123&state=bW9ja19zdGF0ZV8xNl9ieXRlcw',
};
const mockRes = {
writeHead: vi.fn(),
end: vi.fn(),
};
(callbackHandler as (req: unknown, res: unknown) => void)(
mockReq,
mockRes,
);
}, 10);
});
mockFetch.mockResolvedValueOnce(
createMockResponse({
ok: true,
contentType: 'application/json',
text: JSON.stringify(mockTokenResponse),
json: mockTokenResponse,
}),
);
const authProvider = new MCPOAuthProvider();
const result = await authProvider.authenticate('test-server', mockConfig);
expect(result).toBeDefined();
});
it('should return null when token is expired and no refresh token is available', async () => {
const expiredCredentials = {
serverName: 'test-server',
token: {
...mockToken,
refreshToken: undefined,
expiresAt: Date.now() - 3600000,
},
clientId: 'test-client-id',
tokenUrl: 'https://auth.example.com/token',
updatedAt: Date.now(),
};
const tokenStorage = new MCPOAuthTokenStorage();
vi.mocked(tokenStorage.getCredentials).mockResolvedValue(
expiredCredentials,
);
vi.mocked(tokenStorage.isTokenExpired).mockReturnValue(true);
const authProvider = new MCPOAuthProvider();
const result = await authProvider.getValidToken(
'test-server',
mockConfig,
);
expect(result).toBeNull();
});
it('should handle callback timeout', async () => {
vi.mocked(http.createServer).mockImplementation(
() => mockHttpServer as unknown as http.Server,