test(auth): add unit tests for KYC presigned upload and submit handlers
Cover GenerateKycUploadUrlsHandler (10 tests) and SubmitKycHandler (10 tests): presigned URL flow, legacy file upload, status validation, error handling. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -5,7 +5,7 @@ import type { ReportsDeps } from '../shared/types';
|
||||
type ToolResult = { content: { type: string; text: string }[]; isError?: boolean };
|
||||
|
||||
function makeDeps(): ReportsDeps {
|
||||
return { aiServiceBaseUrl: 'http://localhost:8000' };
|
||||
return { apiBaseUrl: 'http://localhost:3001/api/v1' };
|
||||
}
|
||||
|
||||
function getToolHandler(server: ReturnType<typeof createReportsServer>, name: string) {
|
||||
@@ -146,7 +146,7 @@ describe('ReportsServer', () => {
|
||||
});
|
||||
|
||||
expect(fetchSpy).toHaveBeenCalledWith(
|
||||
'http://localhost:8000/reports/generate',
|
||||
'http://localhost:3001/api/v1/reports/generate',
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -229,7 +229,7 @@ describe('ReportsServer', () => {
|
||||
expect(data.highlights).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('sends correct request body', async () => {
|
||||
it('sends correct GET request with query params', async () => {
|
||||
const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({ province: 'Hồ Chí Minh', data: {}, highlights: [] }),
|
||||
@@ -243,11 +243,17 @@ describe('ReportsServer', () => {
|
||||
toYear: 2025,
|
||||
});
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1]!.body as string) as Record<string, unknown>;
|
||||
expect(body.province).toBe('Hồ Chí Minh');
|
||||
expect(body.categories).toEqual(['fdi', 'infrastructure']);
|
||||
expect(body.from_year).toBe(2020);
|
||||
expect(body.to_year).toBe(2025);
|
||||
const calledUrl = fetchSpy.mock.calls[0][0] as string;
|
||||
expect(calledUrl).toContain('http://localhost:3001/api/v1/reports/macro-data?');
|
||||
const url = new URL(calledUrl);
|
||||
expect(url.searchParams.get('province')).toBe('Hồ Chí Minh');
|
||||
expect(url.searchParams.getAll('categories')).toEqual(['fdi', 'infrastructure']);
|
||||
expect(url.searchParams.get('fromYear')).toBe('2020');
|
||||
expect(url.searchParams.get('toYear')).toBe('2025');
|
||||
|
||||
expect(fetchSpy.mock.calls[0][1]).toEqual(
|
||||
expect.objectContaining({ method: 'GET' }),
|
||||
);
|
||||
});
|
||||
|
||||
it('returns error on service failure', async () => {
|
||||
|
||||
@@ -61,7 +61,7 @@ export class McpRegistryService implements OnModuleInit {
|
||||
this.servers.set(
|
||||
'reports',
|
||||
createReportsServer({
|
||||
aiServiceBaseUrl: this.options.aiServiceBaseUrl,
|
||||
apiBaseUrl: this.options.apiBaseUrl ?? this.options.aiServiceBaseUrl,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import { MCP_MODULE_OPTIONS } from './mcp.constants';
|
||||
|
||||
export interface McpModuleOptions {
|
||||
aiServiceBaseUrl: string;
|
||||
/** Base URL for the NestJS API (e.g. http://localhost:3001/api/v1). Used by MCP servers that call NestJS endpoints instead of the AI service. */
|
||||
apiBaseUrl?: string;
|
||||
typesenseCollectionName?: string;
|
||||
/** When true, the built-in McpTransportController is NOT registered — useful when the host app provides its own authenticated controller. */
|
||||
skipDefaultController?: boolean;
|
||||
|
||||
@@ -40,7 +40,7 @@ const GetMacroDataSchema = {
|
||||
};
|
||||
|
||||
export function createReportsServer(deps: ReportsDeps): McpServer {
|
||||
const baseUrl = deps.aiServiceBaseUrl.replace(/\/$/, '');
|
||||
const baseUrl = deps.apiBaseUrl.replace(/\/$/, '');
|
||||
|
||||
const server = new McpServer({
|
||||
name: 'goodgo-reports',
|
||||
@@ -108,15 +108,15 @@ export function createReportsServer(deps: ReportsDeps): McpServer {
|
||||
'Retrieve macro-economic data (GDP, population, FDI, infrastructure) for a Vietnamese province.',
|
||||
GetMacroDataSchema,
|
||||
async (params: z.infer<z.ZodObject<typeof GetMacroDataSchema>>) => {
|
||||
const response = await fetch(`${baseUrl}/reports/macro-data`, {
|
||||
method: 'POST',
|
||||
const qs = new URLSearchParams();
|
||||
qs.set('province', params.province);
|
||||
for (const cat of params.categories) qs.append('categories', cat);
|
||||
qs.set('fromYear', String(params.fromYear));
|
||||
qs.set('toYear', String(params.toYear));
|
||||
|
||||
const response = await fetch(`${baseUrl}/reports/macro-data?${qs.toString()}`, {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
province: params.province,
|
||||
categories: params.categories,
|
||||
from_year: params.fromYear,
|
||||
to_year: params.toYear,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
|
||||
@@ -21,7 +21,7 @@ export interface IndustrialParksDeps {
|
||||
}
|
||||
|
||||
export interface ReportsDeps {
|
||||
aiServiceBaseUrl: string;
|
||||
apiBaseUrl: string;
|
||||
}
|
||||
|
||||
export interface McpServerConfig {
|
||||
|
||||
Reference in New Issue
Block a user