openai-api-mock 0.1.22 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/test.yml +30 -0
- package/jest.config.js +15 -0
- package/package.json +15 -4
- package/readme.md +33 -7
- package/src/index.js +122 -0
- package/{main.test.js → src/index.test.js} +2 -1
- package/main.js +0 -42
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ dev ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ dev ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
node-version: [16.x, 18.x, 20.x]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
21
|
+
uses: actions/setup-node@v4
|
|
22
|
+
with:
|
|
23
|
+
node-version: ${{ matrix.node-version }}
|
|
24
|
+
cache: 'npm'
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: npm ci
|
|
28
|
+
|
|
29
|
+
- name: Run tests
|
|
30
|
+
run: npm test
|
package/jest.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openai-api-mock",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"description": "A Node.js module for mocking OpenAI API responses in a development environment",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,20 +14,31 @@
|
|
|
14
14
|
"development",
|
|
15
15
|
"testing",
|
|
16
16
|
"chatgpt",
|
|
17
|
-
"interceptor"
|
|
17
|
+
"interceptor",
|
|
18
|
+
"sandbox",
|
|
19
|
+
"fake",
|
|
20
|
+
"mocking",
|
|
21
|
+
"ai",
|
|
22
|
+
"artificial intelligence",
|
|
23
|
+
"machine learning"
|
|
18
24
|
],
|
|
19
25
|
"scripts": {
|
|
20
|
-
"test":"node --experimental-vm-modules node_modules/jest/bin/jest.js"
|
|
26
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
27
|
+
"coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage"
|
|
21
28
|
},
|
|
22
29
|
"author": "Chiheb Nabil",
|
|
23
30
|
"license": "MIT",
|
|
24
|
-
"main": "
|
|
31
|
+
"main": "./src/index.js",
|
|
25
32
|
"dependencies": {
|
|
26
33
|
"@faker-js/faker": "^9.0.0",
|
|
27
34
|
"nock": "^13.5.4"
|
|
28
35
|
},
|
|
29
36
|
"devDependencies": {
|
|
30
37
|
"jest": "^29.7.0",
|
|
38
|
+
"node-fetch": "^3.3.2",
|
|
31
39
|
"openai": "^4.52.4"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=16.0.0"
|
|
32
43
|
}
|
|
33
44
|
}
|
package/readme.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# OpenAI API Mock
|
|
2
2
|
|
|
3
|
-
This is a Node.js module for mocking OpenAI API responses in a development environment.
|
|
3
|
+
This is a Node.js module for mocking OpenAI API responses in a development environment.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/chihebnabil/openai-api-mock/actions/workflows/test.yml)
|
|
4
6
|
|
|
5
7
|
It's useful for testing and development purposes when you don't want to make actual API calls.
|
|
6
8
|
|
|
@@ -28,18 +30,42 @@ import { mockOpenAIResponse } from 'openai-api-mock';
|
|
|
28
30
|
Then, call the mockOpenAIResponse function to set up the mock response:
|
|
29
31
|
|
|
30
32
|
```js
|
|
33
|
+
// Basic usage
|
|
31
34
|
mockOpenAIResponse();
|
|
32
|
-
```
|
|
33
|
-
This function intercepts HTTP calls to the OpenAI endpoint and returns a mock response. The mock response is generated based on the requestBody of the code, and it supports complex (function call) requestBody structures like arrays and nested objects.
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
// Force mocking regardless of environment
|
|
36
37
|
mockOpenAIResponse(true);
|
|
38
|
+
|
|
39
|
+
// With configuration options
|
|
40
|
+
mockOpenAIResponse(false, {
|
|
41
|
+
includeErrors: true, // Simulate random API errors
|
|
42
|
+
latency: 1000, // Add 1 second delay to responses
|
|
43
|
+
logRequests: true // Log incoming requests to console
|
|
44
|
+
});
|
|
37
45
|
```
|
|
38
46
|
|
|
39
|
-
The
|
|
40
|
-
|
|
47
|
+
The function accepts two parameters:
|
|
48
|
+
- `force` (boolean): Determines whether the mock response should be used regardless of the environment. If false or not provided, mocking only occurs in development environment.
|
|
49
|
+
- `options` (object): Additional configuration options
|
|
50
|
+
- `includeErrors` (boolean): When true, randomly simulates API errors
|
|
51
|
+
- `latency` (number): Adds artificial delay to responses in milliseconds
|
|
52
|
+
- `logRequests` (boolean): Logs incoming requests to console for debugging
|
|
41
53
|
|
|
42
|
-
|
|
54
|
+
The function returns an object with control methods:
|
|
55
|
+
```js
|
|
56
|
+
const mock = mockOpenAIResponse();
|
|
57
|
+
|
|
58
|
+
// Check if mocking is active
|
|
59
|
+
console.log(mock.isActive);
|
|
60
|
+
|
|
61
|
+
// Stop all mocks
|
|
62
|
+
mock.stopMocking();
|
|
63
|
+
|
|
64
|
+
// Add custom endpoint mock
|
|
65
|
+
mock.addCustomEndpoint('POST', '/v1/custom', (uri, body) => {
|
|
66
|
+
return [200, { custom: 'response' }];
|
|
67
|
+
});
|
|
68
|
+
```
|
|
43
69
|
|
|
44
70
|
### Example responses
|
|
45
71
|
|
package/src/index.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import nock from 'nock';
|
|
2
|
+
import { getChatResponce } from './chat.js';
|
|
3
|
+
import { createChatStream } from './chat.stream.js';
|
|
4
|
+
import { getImageResponce } from './image.js';
|
|
5
|
+
|
|
6
|
+
const OPEN_AI_BASE_URL = 'https://api.openai.com';
|
|
7
|
+
const CHAT_COMPLETIONS_ENDPOINT = '/v1/chat/completions';
|
|
8
|
+
const IMAGE_GENERATIONS_ENDPOINT = '/v1/images/generations';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Mock OpenAI API responses
|
|
12
|
+
* @param {boolean} force - Force mocking regardless of environment
|
|
13
|
+
* @param {Object} options - Additional configuration options
|
|
14
|
+
* @param {boolean} options.includeErrors - Whether to include error scenarios in mocking
|
|
15
|
+
* @param {number} options.latency - Artificial latency in ms to simulate network delay
|
|
16
|
+
* @param {boolean} options.logRequests - Whether to log incoming requests
|
|
17
|
+
* @returns {Object} An object with control methods for the mocks
|
|
18
|
+
*/
|
|
19
|
+
function mockOpenAIResponse(force = false, options = {}) {
|
|
20
|
+
const {
|
|
21
|
+
includeErrors = false,
|
|
22
|
+
latency = 0,
|
|
23
|
+
logRequests = false
|
|
24
|
+
} = options;
|
|
25
|
+
|
|
26
|
+
const env = process.env.NODE_ENV || 'development';
|
|
27
|
+
|
|
28
|
+
// Only proceed if in development or forced
|
|
29
|
+
if (env !== 'development' && !force) {
|
|
30
|
+
return { isActive: false, stopMocking };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Add delay if latency is specified
|
|
34
|
+
const delayResponse = latency > 0 ?
|
|
35
|
+
nock.defaults({ delayConnection: latency }) : null;
|
|
36
|
+
|
|
37
|
+
// Mock chat completions endpoint
|
|
38
|
+
const chatScope = nock(OPEN_AI_BASE_URL)
|
|
39
|
+
.post(CHAT_COMPLETIONS_ENDPOINT)
|
|
40
|
+
.reply(function (uri, requestBody) {
|
|
41
|
+
if (logRequests) {
|
|
42
|
+
console.log(`[openai-api-mock] Chat request:`, JSON.stringify(requestBody, null, 2));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
// Validate minimal required fields
|
|
47
|
+
if (!requestBody.model || !requestBody.messages || !Array.isArray(requestBody.messages)) {
|
|
48
|
+
return [400, { error: { message: 'Invalid request. Missing required fields.' } }];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Simulate random errors if enabled
|
|
52
|
+
if (includeErrors && Math.random() < 0.05) {
|
|
53
|
+
return [429, { error: { message: 'Rate limit exceeded' } }];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const isSteaming = requestBody.stream === true;
|
|
57
|
+
|
|
58
|
+
if (isSteaming) {
|
|
59
|
+
const stream = createChatStream(requestBody);
|
|
60
|
+
return [200, stream];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return [200, getChatResponce(requestBody)];
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('[openai-api-mock] Error processing chat request:', error);
|
|
66
|
+
return [500, { error: { message: 'Internal server error in mock' } }];
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Mock image generations endpoint
|
|
71
|
+
const imageScope = nock(OPEN_AI_BASE_URL)
|
|
72
|
+
.post(IMAGE_GENERATIONS_ENDPOINT)
|
|
73
|
+
.reply(function (uri, requestBody) {
|
|
74
|
+
if (logRequests) {
|
|
75
|
+
console.log(`[openai-api-mock] Image request:`, JSON.stringify(requestBody, null, 2));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
// Validate minimal required fields
|
|
80
|
+
if (!requestBody.prompt) {
|
|
81
|
+
return [400, { error: { message: 'Invalid request. Missing prompt.' } }];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Simulate random errors if enabled
|
|
85
|
+
if (includeErrors && Math.random() < 0.05) {
|
|
86
|
+
return [400, { error: { message: 'Your request was rejected as a result of our safety system.' } }];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return [200, getImageResponce(requestBody)];
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error('[openai-api-mock] Error processing image request:', error);
|
|
92
|
+
return [500, { error: { message: 'Internal server error in mock' } }];
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Enable other network connections
|
|
97
|
+
nock.enableNetConnect(host => host !== "api.openai.com");
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
isActive: true,
|
|
101
|
+
stopMocking,
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Adds a custom endpoint mock
|
|
105
|
+
* @param {string} method - HTTP method (GET, POST, etc.)
|
|
106
|
+
* @param {string} path - Path to mock (e.g., '/v1/custom')
|
|
107
|
+
* @param {Function} handler - Handler function that returns [statusCode, responseBody]
|
|
108
|
+
*/
|
|
109
|
+
addCustomEndpoint(method, path, handler) {
|
|
110
|
+
nock(OPEN_AI_BASE_URL)[method.toLowerCase()](path).reply(handler);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Stop all active mocks
|
|
117
|
+
*/
|
|
118
|
+
function stopMocking() {
|
|
119
|
+
nock.cleanAll();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { mockOpenAIResponse, stopMocking };
|
package/main.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import nock from 'nock';
|
|
2
|
-
import { getChatResponce } from './src/chat.js';
|
|
3
|
-
import { createChatStream } from './src/chat.stream.js';
|
|
4
|
-
import { getImageResponce } from './src/image.js';
|
|
5
|
-
|
|
6
|
-
const OPEN_AI_BASE_URL = 'https://api.openai.com';
|
|
7
|
-
const CHAT_COMPLETIONS_ENDPOINT = '/v1/chat/completions';
|
|
8
|
-
const IMAGE_GENERATIONS_ENDPOINT = '/v1/images/generations';
|
|
9
|
-
|
|
10
|
-
function mockOpenAIResponse(force = false) {
|
|
11
|
-
var env = process.env.NODE_ENV || 'development';
|
|
12
|
-
// Intercept the HTTP call and return the mock response
|
|
13
|
-
if (env === 'development' || force) {
|
|
14
|
-
nock(OPEN_AI_BASE_URL)
|
|
15
|
-
.post(CHAT_COMPLETIONS_ENDPOINT)
|
|
16
|
-
.reply(function (uri, requestBody) {
|
|
17
|
-
let isSteaming = (requestBody.stream && requestBody.stream == true) ? true : false
|
|
18
|
-
|
|
19
|
-
if (isSteaming) {
|
|
20
|
-
const stream = createChatStream();
|
|
21
|
-
return [200, stream];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return [200, getChatResponce(requestBody)];
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
nock(OPEN_AI_BASE_URL)
|
|
28
|
-
.post(IMAGE_GENERATIONS_ENDPOINT)
|
|
29
|
-
.reply(function (uri, requestBody) {
|
|
30
|
-
return [200, getImageResponce(requestBody)];
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// Mocking only the chat completion endpoint, not blocking other requests
|
|
34
|
-
nock.enableNetConnect(host => host !== "api.openai.com");
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function stopMocking() {
|
|
39
|
-
nock.cleanAll();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export { mockOpenAIResponse, stopMocking };
|