mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 08:12:00 +02:00
tests(api): refactor to mock database and network operations (#494)
This commit is contained in:
parent
f92e4f28be
commit
72e9828b76
2 changed files with 103 additions and 27 deletions
|
@ -1,7 +1,16 @@
|
||||||
const mongoose = require('mongoose');
|
const { HumanChatMessage, AIChatMessage } = require('langchain/schema');
|
||||||
const ChatAgent = require('./ChatAgent');
|
const ChatAgent = require('./ChatAgent');
|
||||||
const connectDb = require('../../lib/db/connectDb');
|
const crypto = require('crypto');
|
||||||
const Conversation = require('../../models/Conversation');
|
|
||||||
|
jest.mock('../../lib/db/connectDb');
|
||||||
|
jest.mock('../../models/Conversation', () => {
|
||||||
|
return function () {
|
||||||
|
return {
|
||||||
|
save: jest.fn(),
|
||||||
|
deleteConvos: jest.fn()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
describe('ChatAgent', () => {
|
describe('ChatAgent', () => {
|
||||||
let TestAgent;
|
let TestAgent;
|
||||||
|
@ -13,26 +22,72 @@ describe('ChatAgent', () => {
|
||||||
max_tokens: 2
|
max_tokens: 2
|
||||||
},
|
},
|
||||||
agentOptions: {
|
agentOptions: {
|
||||||
model: 'gpt-3.5-turbo',
|
model: 'gpt-3.5-turbo'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let parentMessageId;
|
let parentMessageId;
|
||||||
let conversationId;
|
let conversationId;
|
||||||
|
const fakeMessages = [];
|
||||||
const userMessage = 'Hello, ChatGPT!';
|
const userMessage = 'Hello, ChatGPT!';
|
||||||
const apiKey = process.env.OPENAI_API_KEY;
|
const apiKey = 'fake-api-key';
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
await connectDb();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestAgent = new ChatAgent(apiKey, options);
|
TestAgent = new ChatAgent(apiKey, options);
|
||||||
});
|
TestAgent.loadHistory = jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation((conversationId, parentMessageId = null) => {
|
||||||
|
if (!conversationId) {
|
||||||
|
TestAgent.currentMessages = [];
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
|
||||||
afterAll(async () => {
|
const orderedMessages = TestAgent.constructor.getMessagesForConversation(
|
||||||
// Delete the messages and conversation created by the test
|
fakeMessages,
|
||||||
await Conversation.deleteConvos(null, { conversationId });
|
parentMessageId
|
||||||
await mongoose.connection.close();
|
);
|
||||||
|
const chatMessages = orderedMessages.map((msg) =>
|
||||||
|
msg?.isCreatedByUser || msg?.role.toLowerCase() === 'user'
|
||||||
|
? new HumanChatMessage(msg.text)
|
||||||
|
: new AIChatMessage(msg.text)
|
||||||
|
);
|
||||||
|
|
||||||
|
TestAgent.currentMessages = orderedMessages;
|
||||||
|
return Promise.resolve(chatMessages);
|
||||||
|
});
|
||||||
|
TestAgent.sendMessage = jest.fn().mockImplementation(async (message, opts = {}) => {
|
||||||
|
if (opts && typeof opts === 'object') {
|
||||||
|
TestAgent.setOptions(opts);
|
||||||
|
}
|
||||||
|
const conversationId = opts.conversationId || crypto.randomUUID();
|
||||||
|
const parentMessageId = opts.parentMessageId || '00000000-0000-0000-0000-000000000000';
|
||||||
|
const userMessageId = opts.overrideParentMessageId || crypto.randomUUID();
|
||||||
|
this.pastMessages = await TestAgent.loadHistory(
|
||||||
|
conversationId,
|
||||||
|
TestAgent.options?.parentMessageId
|
||||||
|
);
|
||||||
|
|
||||||
|
const userMessage = {
|
||||||
|
text: message,
|
||||||
|
sender: 'ChatGPT',
|
||||||
|
isCreatedByUser: true,
|
||||||
|
messageId: userMessageId,
|
||||||
|
parentMessageId,
|
||||||
|
conversationId
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = {
|
||||||
|
sender: 'ChatGPT',
|
||||||
|
text: 'Hello, User!',
|
||||||
|
isCreatedByUser: false,
|
||||||
|
messageId: crypto.randomUUID(),
|
||||||
|
parentMessageId: userMessage.messageId,
|
||||||
|
conversationId
|
||||||
|
};
|
||||||
|
|
||||||
|
fakeMessages.push(userMessage);
|
||||||
|
fakeMessages.push(response);
|
||||||
|
return response;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('initializes ChatAgent without crashing', () => {
|
test('initializes ChatAgent without crashing', () => {
|
||||||
|
|
|
@ -1,8 +1,25 @@
|
||||||
/* eslint-disable jest/no-conditional-expect */
|
const mockUser = {
|
||||||
require('dotenv').config({ path: '../../../.env' });
|
_id: 'fakeId',
|
||||||
const mongoose = require('mongoose');
|
save: jest.fn(),
|
||||||
|
findByIdAndDelete: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
var mockPluginService = {
|
||||||
|
updateUserPluginAuth: jest.fn(),
|
||||||
|
deleteUserPluginAuth: jest.fn(),
|
||||||
|
getUserPluginAuthValue: jest.fn()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
jest.mock('../../../models/User', () => {
|
||||||
|
return function() {
|
||||||
|
return mockUser;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.mock('../../../server/services/PluginService', () => mockPluginService);
|
||||||
|
|
||||||
const User = require('../../../models/User');
|
const User = require('../../../models/User');
|
||||||
const connectDb = require('../../../lib/db/connectDb');
|
|
||||||
const { validateTools, loadTools, availableTools } = require('./index');
|
const { validateTools, loadTools, availableTools } = require('./index');
|
||||||
const PluginService = require('../../../server/services/PluginService');
|
const PluginService = require('../../../server/services/PluginService');
|
||||||
const { BaseChatModel } = require('langchain/chat_models/openai');
|
const { BaseChatModel } = require('langchain/chat_models/openai');
|
||||||
|
@ -21,7 +38,16 @@ describe('Tool Handlers', () => {
|
||||||
const authConfigs = mainPlugin.authConfig;
|
const authConfigs = mainPlugin.authConfig;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await connectDb();
|
mockUser.save.mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
const userAuthValues = {};
|
||||||
|
mockPluginService.getUserPluginAuthValue.mockImplementation((userId, authField) => {
|
||||||
|
return userAuthValues[`${userId}-${authField}`];
|
||||||
|
});
|
||||||
|
mockPluginService.updateUserPluginAuth.mockImplementation((userId, authField, _pluginKey, credential) => {
|
||||||
|
userAuthValues[`${userId}-${authField}`] = credential;
|
||||||
|
});
|
||||||
|
|
||||||
fakeUser = new User({
|
fakeUser = new User({
|
||||||
name: 'Fake User',
|
name: 'Fake User',
|
||||||
username: 'fakeuser',
|
username: 'fakeuser',
|
||||||
|
@ -39,19 +65,13 @@ describe('Tool Handlers', () => {
|
||||||
for (const authConfig of authConfigs) {
|
for (const authConfig of authConfigs) {
|
||||||
await PluginService.updateUserPluginAuth(fakeUser._id, authConfig.authField, pluginKey, mockCredential);
|
await PluginService.updateUserPluginAuth(fakeUser._id, authConfig.authField, pluginKey, mockCredential);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// afterEach(async () => {
|
|
||||||
// // Clean up any test-specific data.
|
|
||||||
// });
|
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
// Delete the fake user & plugin auth
|
await mockUser.findByIdAndDelete(fakeUser._id);
|
||||||
await User.findByIdAndDelete(fakeUser._id);
|
|
||||||
for (const authConfig of authConfigs) {
|
for (const authConfig of authConfigs) {
|
||||||
await PluginService.deleteUserPluginAuth(fakeUser._id, authConfig.authField);
|
await PluginService.deleteUserPluginAuth(fakeUser._id, authConfig.authField);
|
||||||
}
|
}
|
||||||
await mongoose.connection.close();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('validateTools', () => {
|
describe('validateTools', () => {
|
||||||
|
@ -128,6 +148,7 @@ describe('Tool Handlers', () => {
|
||||||
try {
|
try {
|
||||||
await loadTool2();
|
await loadTool2();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line jest/no-conditional-expect
|
||||||
expect(error).toBeDefined();
|
expect(error).toBeDefined();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue