97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { createImagePromptMuseumRouteHandler } from '@electron/api/routes/image-prompt-museum';
|
|
|
|
function createResponse() {
|
|
const chunks: string[] = [];
|
|
const res = {
|
|
statusCode: 0,
|
|
setHeader: vi.fn(),
|
|
end: vi.fn((chunk?: string) => {
|
|
if (chunk) chunks.push(chunk);
|
|
}),
|
|
} as unknown as ServerResponse;
|
|
return {
|
|
res,
|
|
get json() {
|
|
return JSON.parse(chunks.join('')) as Record<string, unknown>;
|
|
},
|
|
};
|
|
}
|
|
|
|
describe('Prompt Museum Main route boundary', () => {
|
|
const fetchImpl = vi.fn<typeof fetch>();
|
|
const getAccessToken = vi.fn();
|
|
|
|
beforeEach(() => {
|
|
fetchImpl.mockReset();
|
|
getAccessToken.mockReset();
|
|
});
|
|
|
|
it('does not claim unrelated routes', async () => {
|
|
const handler = createImagePromptMuseumRouteHandler({ fetchImpl, getAccessToken });
|
|
const response = createResponse();
|
|
|
|
await expect(handler(
|
|
{ method: 'GET' } as IncomingMessage,
|
|
response.res,
|
|
new URL('http://127.0.0.1/api/works/projects'),
|
|
{} as never,
|
|
)).resolves.toBe(false);
|
|
expect(fetchImpl).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('forwards only the allowed list query and the Works Square token', async () => {
|
|
getAccessToken.mockResolvedValue('works-token');
|
|
fetchImpl.mockResolvedValue(new Response(JSON.stringify({
|
|
success: true,
|
|
data: { items: [], facets: { useCases: [], styles: [], subjects: [] }, nextCursor: null },
|
|
}), { status: 200, headers: { 'Content-Type': 'application/json' } }));
|
|
const handler = createImagePromptMuseumRouteHandler({
|
|
fetchImpl,
|
|
getAccessToken,
|
|
apiBaseUrl: 'https://square.example',
|
|
});
|
|
const response = createResponse();
|
|
|
|
await expect(handler(
|
|
{ method: 'GET' } as IncomingMessage,
|
|
response.res,
|
|
new URL('http://127.0.0.1/api/works/image-prompt-museum?q=editorial&unknown=do-not-forward&limit=24'),
|
|
{} as never,
|
|
)).resolves.toBe(true);
|
|
|
|
expect(fetchImpl).toHaveBeenCalledWith(
|
|
'https://square.example/api/image-prompt-museum?q=editorial&limit=24',
|
|
expect.objectContaining({
|
|
method: 'GET',
|
|
headers: {
|
|
Accept: 'application/json',
|
|
Authorization: 'Bearer works-token',
|
|
},
|
|
}),
|
|
);
|
|
expect(response.json).toMatchObject({ success: true });
|
|
});
|
|
|
|
it('returns a stable auth error without calling the upstream service', async () => {
|
|
getAccessToken.mockResolvedValue(null);
|
|
const handler = createImagePromptMuseumRouteHandler({ fetchImpl, getAccessToken });
|
|
const response = createResponse();
|
|
|
|
await handler(
|
|
{ method: 'GET' } as IncomingMessage,
|
|
response.res,
|
|
new URL('http://127.0.0.1/api/works/image-prompt-museum'),
|
|
{} as never,
|
|
);
|
|
|
|
expect(response.res.statusCode).toBe(401);
|
|
expect(response.json).toMatchObject({
|
|
success: false,
|
|
code: 'PROMPT_MUSEUM_AUTH_REQUIRED',
|
|
});
|
|
expect(fetchImpl).not.toHaveBeenCalled();
|
|
});
|
|
});
|