/ libs / typescript / integrations / helpers / openaiTestHelper.ts
openaiTestHelper.ts
  1  /**
  2   * MSW-based OpenAI API mock server for testing
  3   * Provides realistic OpenAI API responses for comprehensive testing
  4   */
  5  
  6  import { http, HttpResponse } from 'msw';
  7  import {
  8    ChatCompletion,
  9    ChatCompletionCreateParams,
 10    CreateEmbeddingResponse,
 11    EmbeddingCreateParams,
 12  } from 'openai/resources/index';
 13  import { ResponseCreateParams, Response } from 'openai/resources/responses/responses';
 14  import { setupServer } from 'msw/node';
 15  
 16  /**
 17   * Create a realistic chat completion response
 18   */
 19  function createChatCompletionResponse(request: ChatCompletionCreateParams): ChatCompletion {
 20    const timestamp = Math.floor(Date.now() / 1000);
 21    const requestId = `chatcmpl-${Math.random().toString(36).substring(2, 15)}`;
 22  
 23    return {
 24      id: requestId,
 25      object: 'chat.completion',
 26      created: timestamp,
 27      model: request.model,
 28      choices: [
 29        {
 30          index: 0,
 31          message: {
 32            role: 'assistant',
 33            content: 'Test response content',
 34            refusal: null,
 35          },
 36          finish_reason: 'stop',
 37          logprobs: null,
 38        },
 39      ],
 40      usage: {
 41        prompt_tokens: 100,
 42        completion_tokens: 200,
 43        total_tokens: 300,
 44      },
 45    };
 46  }
 47  
 48  /**
 49   * Create a mock response for Responses API
 50   */
 51  function createResponsesResponse(request: ResponseCreateParams): Response {
 52    return {
 53      id: 'responses-123',
 54      object: 'response',
 55      model: request.model || '',
 56      output: [
 57        {
 58          id: 'response-123',
 59          content: [
 60            {
 61              type: 'output_text',
 62              text: 'Dummy output',
 63              annotations: [],
 64            },
 65          ],
 66          role: 'assistant',
 67          status: 'completed',
 68          type: 'message',
 69        },
 70      ],
 71      usage: {
 72        input_tokens: 36,
 73        output_tokens: 87,
 74        total_tokens: 123,
 75        input_tokens_details: {
 76          cached_tokens: 0,
 77        },
 78        output_tokens_details: {
 79          reasoning_tokens: 0,
 80        },
 81      },
 82      created_at: 123,
 83      output_text: 'Dummy output',
 84      error: null,
 85      incomplete_details: null,
 86      instructions: null,
 87      metadata: null,
 88      parallel_tool_calls: false,
 89      temperature: 0.5,
 90      tools: [],
 91      top_p: 1,
 92      tool_choice: 'auto',
 93    };
 94  }
 95  
 96  /**
 97   * Create a mock response for Embeddings API
 98   */
 99  function createEmbeddingResponse(request: EmbeddingCreateParams): CreateEmbeddingResponse {
100    const inputs = Array.isArray(request.input) ? request.input : [request.input];
101  
102    return {
103      object: 'list',
104      data: inputs.map((_, index) => ({
105        object: 'embedding',
106        index,
107        embedding: Array(1536)
108          .fill(0)
109          .map(() => Math.random() * 0.1 - 0.05),
110      })),
111      model: request.model,
112      usage: {
113        prompt_tokens: inputs.length * 10,
114        total_tokens: inputs.length * 10,
115      },
116    };
117  }
118  
119  /**
120   * Main MSW handlers for OpenAI API endpoints
121   */
122  export const openAIMockHandlers = [
123    http.post('https://api.openai.com/v1/chat/completions', async ({ request }) => {
124      const body = (await request.json()) as ChatCompletionCreateParams;
125      return HttpResponse.json(createChatCompletionResponse(body));
126    }),
127    http.post('https://api.openai.com/v1/responses', async ({ request }) => {
128      const body = (await request.json()) as ResponseCreateParams;
129      return HttpResponse.json(createResponsesResponse(body));
130    }),
131    http.post('https://api.openai.com/v1/embeddings', async ({ request }) => {
132      const body = (await request.json()) as EmbeddingCreateParams;
133      return HttpResponse.json(createEmbeddingResponse(body));
134    }),
135  ];
136  
137  export const openAIMswServer = setupServer(...openAIMockHandlers);
138  
139  export function useMockOpenAIServer(): void {
140    beforeAll(() => openAIMswServer.listen());
141    afterEach(() => openAIMswServer.resetHandlers());
142    afterAll(() => openAIMswServer.close());
143  }