diff --git a/api/models/File.spec.js b/api/models/File.spec.js
index 7eabc37553..99464fdbd0 100644
--- a/api/models/File.spec.js
+++ b/api/models/File.spec.js
@@ -11,7 +11,6 @@ let File;
let Agent;
let AclEntry;
let User;
-let AccessRole;
let modelsToCleanup = [];
describe('File Access Control', () => {
@@ -36,7 +35,6 @@ describe('File Access Control', () => {
Agent = dbModels.Agent;
AclEntry = dbModels.AclEntry;
User = dbModels.User;
- AccessRole = dbModels.AccessRole;
// Seed default roles
await seedDefaultRoles();
@@ -149,7 +147,7 @@ describe('File Access Control', () => {
});
// Create agent
- const agent = await createAgent({
+ await createAgent({
id: agentId,
name: 'Test Agent',
author: authorId,
diff --git a/api/server/routes/files/files.agents.test.js b/api/server/routes/files/files.agents.test.js
index eebc591f8c..0ef5580ebc 100644
--- a/api/server/routes/files/files.agents.test.js
+++ b/api/server/routes/files/files.agents.test.js
@@ -2,7 +2,6 @@ const express = require('express');
const request = require('supertest');
const mongoose = require('mongoose');
const { v4: uuidv4 } = require('uuid');
-const { PERMISSION_BITS } = require('librechat-data-provider');
const { MongoMemoryServer } = require('mongodb-memory-server');
const { createMethods } = require('@librechat/data-schemas');
const { createAgent } = require('~/models/Agent');
diff --git a/api/server/services/start/interface.spec.js b/api/server/services/start/interface.spec.js
index 974becb5bb..e50f4514c2 100644
--- a/api/server/services/start/interface.spec.js
+++ b/api/server/services/start/interface.spec.js
@@ -28,7 +28,11 @@ describe('loadDefaultInterface', () => {
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true },
- [PermissionTypes.MEMORIES]: { [Permissions.USE]: true, [Permissions.OPT_OUT]: undefined, [Permissions.OPT_OUT]: undefined },
+ [PermissionTypes.MEMORIES]: {
+ [Permissions.USE]: true,
+ [Permissions.OPT_OUT]: undefined,
+ [Permissions.OPT_OUT]: undefined,
+ },
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true },
[PermissionTypes.AGENTS]: { [Permissions.USE]: true },
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },
diff --git a/client/src/components/SidePanel/Agents/MarketplaceContext.tsx b/client/src/components/SidePanel/Agents/MarketplaceContext.tsx
index f77ddc0cae..09c88e3291 100644
--- a/client/src/components/SidePanel/Agents/MarketplaceContext.tsx
+++ b/client/src/components/SidePanel/Agents/MarketplaceContext.tsx
@@ -1,7 +1,4 @@
-import React, { useMemo } from 'react';
-
-import { EModelEndpoint } from 'librechat-data-provider';
-
+import React from 'react';
import { ChatContext } from '~/Providers';
import { useChatHelpers } from '~/hooks';
diff --git a/client/src/components/SidePanel/Agents/__tests__/AgentDetail.spec.tsx b/client/src/components/SidePanel/Agents/__tests__/AgentDetail.spec.tsx
index 364ac82aec..9bf44b1f96 100644
--- a/client/src/components/SidePanel/Agents/__tests__/AgentDetail.spec.tsx
+++ b/client/src/components/SidePanel/Agents/__tests__/AgentDetail.spec.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-require-imports */
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
@@ -6,10 +7,10 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { RecoilRoot } from 'recoil';
import type t from 'librechat-data-provider';
+import { Constants, EModelEndpoint } from 'librechat-data-provider';
import AgentDetail from '../AgentDetail';
import { useToast } from '~/hooks';
-import useLocalize from '~/hooks/useLocalize';
// Mock dependencies
jest.mock('react-router-dom', () => ({
@@ -20,11 +21,7 @@ jest.mock('react-router-dom', () => ({
jest.mock('~/hooks', () => ({
useToast: jest.fn(),
useMediaQuery: jest.fn(() => false), // Mock as desktop by default
-}));
-
-jest.mock('~/hooks/useLocalize', () => ({
- __esModule: true,
- default: jest.fn(),
+ useLocalize: jest.fn(),
}));
jest.mock('~/utils/agents', () => ({
@@ -33,6 +30,15 @@ jest.mock('~/utils/agents', () => ({
)),
}));
+jest.mock('~/Providers', () => ({
+ useChatContext: jest.fn(),
+}));
+
+jest.mock('@tanstack/react-query', () => ({
+ ...jest.requireActual('@tanstack/react-query'),
+ useQueryClient: jest.fn(),
+}));
+
// Mock clipboard API
const mockWriteText = jest.fn();
@@ -96,8 +102,24 @@ describe('AgentDetail', () => {
jest.clearAllMocks();
(useNavigate as jest.Mock).mockReturnValue(mockNavigate);
(useToast as jest.Mock).mockReturnValue({ showToast: mockShowToast });
+ const { useLocalize } = require('~/hooks');
(useLocalize as jest.Mock).mockReturnValue(mockLocalize);
+ // Mock useChatContext
+ const { useChatContext } = require('~/Providers');
+ (useChatContext as jest.Mock).mockReturnValue({
+ conversation: { conversationId: 'test-convo-id' },
+ newConversation: jest.fn(),
+ });
+
+ // Mock useQueryClient
+ const { useQueryClient } = require('@tanstack/react-query');
+ (useQueryClient as jest.Mock).mockReturnValue({
+ getQueryData: jest.fn(),
+ setQueryData: jest.fn(),
+ invalidateQueries: jest.fn(),
+ });
+
// Setup clipboard mock if it doesn't exist
if (!navigator.clipboard) {
Object.defineProperty(navigator, 'clipboard', {
@@ -176,12 +198,36 @@ describe('AgentDetail', () => {
describe('Interactions', () => {
it('should navigate to chat when Start Chat button is clicked', async () => {
const user = userEvent.setup();
+ const mockNewConversation = jest.fn();
+ const mockQueryClient = {
+ getQueryData: jest.fn().mockReturnValue(null),
+ setQueryData: jest.fn(),
+ invalidateQueries: jest.fn(),
+ };
+
+ // Update mocks for this test
+ const { useChatContext } = require('~/Providers');
+ (useChatContext as jest.Mock).mockReturnValue({
+ conversation: { conversationId: 'test-convo-id' },
+ newConversation: mockNewConversation,
+ });
+
+ const { useQueryClient } = require('@tanstack/react-query');
+ (useQueryClient as jest.Mock).mockReturnValue(mockQueryClient);
+
renderWithProviders();
const startChatButton = screen.getByRole('button', { name: 'com_agents_start_chat' });
await user.click(startChatButton);
- expect(mockNavigate).toHaveBeenCalledWith('/c/new?agent_id=test-agent-id');
+ expect(mockNewConversation).toHaveBeenCalledWith({
+ template: {
+ conversationId: Constants.NEW_CONVO,
+ endpoint: EModelEndpoint.agents,
+ agent_id: 'test-agent-id',
+ title: 'Chat with Test Agent',
+ },
+ });
});
it('should not navigate when agent is null', async () => {
diff --git a/client/src/components/SidePanel/Agents/__tests__/MarketplaceContext.spec.tsx b/client/src/components/SidePanel/Agents/__tests__/MarketplaceContext.spec.tsx
index d61ed00544..49ff4cfda0 100644
--- a/client/src/components/SidePanel/Agents/__tests__/MarketplaceContext.spec.tsx
+++ b/client/src/components/SidePanel/Agents/__tests__/MarketplaceContext.spec.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-require-imports */
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
@@ -17,6 +18,11 @@ jest.mock('~/Providers', () => ({
useChatContext: jest.fn(),
}));
+// Mock useChatHelpers to avoid Recoil dependency
+jest.mock('~/hooks', () => ({
+ useChatHelpers: jest.fn(),
+}));
+
const mockedUseChatContext = useChatContext as jest.MockedFunction;
// Test component that consumes the context
@@ -35,6 +41,16 @@ const TestConsumer: React.FC = () => {
describe('MarketplaceProvider', () => {
beforeEach(() => {
mockedUseChatContext.mockClear();
+
+ // Mock useChatHelpers return value
+ const { useChatHelpers } = require('~/hooks');
+ (useChatHelpers as jest.Mock).mockReturnValue({
+ conversation: {
+ endpoint: EModelEndpoint.agents,
+ conversationId: 'marketplace',
+ title: 'Agent Marketplace',
+ },
+ });
});
it('provides correct marketplace context values', () => {
@@ -46,7 +62,7 @@ describe('MarketplaceProvider', () => {
},
};
- mockedUseChatContext.mockReturnValue(mockContext);
+ mockedUseChatContext.mockReturnValue(mockContext as ReturnType);
render(
diff --git a/client/src/hooks/Input/useQueryParams.spec.ts b/client/src/hooks/Input/useQueryParams.spec.ts
index 52a5a877a0..9647fc2d76 100644
--- a/client/src/hooks/Input/useQueryParams.spec.ts
+++ b/client/src/hooks/Input/useQueryParams.spec.ts
@@ -34,6 +34,7 @@ jest.mock('react-router-dom', () => ({
jest.mock('@tanstack/react-query', () => ({
useQueryClient: jest.fn(),
+ useQuery: jest.fn(),
}));
jest.mock('~/Providers', () => ({
@@ -51,6 +52,15 @@ jest.mock('~/hooks/Conversations/useDefaultConvo', () => ({
default: jest.fn(),
}));
+jest.mock('~/hooks/AuthContext', () => ({
+ useAuthContext: jest.fn(),
+}));
+
+jest.mock('~/hooks/Agents/useAgentsMap', () => ({
+ __esModule: true,
+ default: jest.fn(() => ({})),
+}));
+
jest.mock('~/utils', () => ({
getConvoSwitchLogic: jest.fn(() => ({
template: {},
@@ -63,6 +73,8 @@ jest.mock('~/utils', () => ({
getModelSpecIconURL: jest.fn(() => 'icon-url'),
removeUnavailableTools: jest.fn((preset) => preset),
logger: { log: jest.fn() },
+ getInitialTheme: jest.fn(() => 'light'),
+ applyFontSize: jest.fn(),
}));
// Mock the tQueryParamsSchema
@@ -82,6 +94,21 @@ jest.mock('librechat-data-provider', () => ({
EModelEndpoint: { custom: 'custom', assistants: 'assistants', agents: 'agents' },
}));
+// Mock data-provider hooks
+jest.mock('~/data-provider', () => ({
+ useGetAgentByIdQuery: jest.fn(() => ({
+ data: null,
+ isLoading: false,
+ error: null,
+ })),
+ useAgentListingDefaultPermissionLevel: jest.fn(() => 'view'),
+ useListAgentsQuery: jest.fn(() => ({
+ data: null,
+ isLoading: false,
+ error: null,
+ })),
+}));
+
// Mock global window.history
global.window = Object.create(window);
global.window.history = {
@@ -103,6 +130,14 @@ describe('useQueryParams', () => {
// Reset mock for window.history.replaceState
jest.spyOn(window.history, 'replaceState').mockClear();
+ // Reset data-provider mocks
+ const dataProvider = jest.requireMock('~/data-provider');
+ (dataProvider.useGetAgentByIdQuery as jest.Mock).mockReturnValue({
+ data: null,
+ isLoading: false,
+ error: null,
+ });
+
// Create mocks for all dependencies
const mockSearchParams = new URLSearchParams();
(useSearchParams as jest.Mock).mockReturnValue([mockSearchParams, jest.fn()]);
@@ -147,6 +182,13 @@ describe('useQueryParams', () => {
const mockGetDefaultConversation = jest.fn().mockReturnValue({});
(useDefaultConvo as jest.Mock).mockReturnValue(mockGetDefaultConversation);
+
+ // Mock useAuthContext
+ const { useAuthContext } = jest.requireMock('~/hooks/AuthContext');
+ (useAuthContext as jest.Mock).mockReturnValue({
+ user: { id: 'test-user-id' },
+ isAuthenticated: true,
+ });
});
afterEach(() => {