chore: fix ESLint issues and Test Mocks

This commit is contained in:
Danny Avila 2025-07-24 11:20:16 -04:00
parent a17826fe39
commit cec1ec0c79
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
7 changed files with 119 additions and 17 deletions

View file

@ -11,7 +11,6 @@ let File;
let Agent; let Agent;
let AclEntry; let AclEntry;
let User; let User;
let AccessRole;
let modelsToCleanup = []; let modelsToCleanup = [];
describe('File Access Control', () => { describe('File Access Control', () => {
@ -36,7 +35,6 @@ describe('File Access Control', () => {
Agent = dbModels.Agent; Agent = dbModels.Agent;
AclEntry = dbModels.AclEntry; AclEntry = dbModels.AclEntry;
User = dbModels.User; User = dbModels.User;
AccessRole = dbModels.AccessRole;
// Seed default roles // Seed default roles
await seedDefaultRoles(); await seedDefaultRoles();
@ -149,7 +147,7 @@ describe('File Access Control', () => {
}); });
// Create agent // Create agent
const agent = await createAgent({ await createAgent({
id: agentId, id: agentId,
name: 'Test Agent', name: 'Test Agent',
author: authorId, author: authorId,

View file

@ -2,7 +2,6 @@ const express = require('express');
const request = require('supertest'); const request = require('supertest');
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const { v4: uuidv4 } = require('uuid'); const { v4: uuidv4 } = require('uuid');
const { PERMISSION_BITS } = require('librechat-data-provider');
const { MongoMemoryServer } = require('mongodb-memory-server'); const { MongoMemoryServer } = require('mongodb-memory-server');
const { createMethods } = require('@librechat/data-schemas'); const { createMethods } = require('@librechat/data-schemas');
const { createAgent } = require('~/models/Agent'); const { createAgent } = require('~/models/Agent');

View file

@ -28,7 +28,11 @@ describe('loadDefaultInterface', () => {
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true }, [PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
[PermissionTypes.BOOKMARKS]: { [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.MULTI_CONVO]: { [Permissions.USE]: true },
[PermissionTypes.AGENTS]: { [Permissions.USE]: true }, [PermissionTypes.AGENTS]: { [Permissions.USE]: true },
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true }, [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },

View file

@ -1,7 +1,4 @@
import React, { useMemo } from 'react'; import React from 'react';
import { EModelEndpoint } from 'librechat-data-provider';
import { ChatContext } from '~/Providers'; import { ChatContext } from '~/Providers';
import { useChatHelpers } from '~/hooks'; import { useChatHelpers } from '~/hooks';

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-require-imports */
import React from 'react'; import React from 'react';
import { render, screen, waitFor } from '@testing-library/react'; import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
@ -6,10 +7,10 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { RecoilRoot } from 'recoil'; import { RecoilRoot } from 'recoil';
import type t from 'librechat-data-provider'; import type t from 'librechat-data-provider';
import { Constants, EModelEndpoint } from 'librechat-data-provider';
import AgentDetail from '../AgentDetail'; import AgentDetail from '../AgentDetail';
import { useToast } from '~/hooks'; import { useToast } from '~/hooks';
import useLocalize from '~/hooks/useLocalize';
// Mock dependencies // Mock dependencies
jest.mock('react-router-dom', () => ({ jest.mock('react-router-dom', () => ({
@ -20,11 +21,7 @@ jest.mock('react-router-dom', () => ({
jest.mock('~/hooks', () => ({ jest.mock('~/hooks', () => ({
useToast: jest.fn(), useToast: jest.fn(),
useMediaQuery: jest.fn(() => false), // Mock as desktop by default useMediaQuery: jest.fn(() => false), // Mock as desktop by default
})); useLocalize: jest.fn(),
jest.mock('~/hooks/useLocalize', () => ({
__esModule: true,
default: jest.fn(),
})); }));
jest.mock('~/utils/agents', () => ({ 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 // Mock clipboard API
const mockWriteText = jest.fn(); const mockWriteText = jest.fn();
@ -96,8 +102,24 @@ describe('AgentDetail', () => {
jest.clearAllMocks(); jest.clearAllMocks();
(useNavigate as jest.Mock).mockReturnValue(mockNavigate); (useNavigate as jest.Mock).mockReturnValue(mockNavigate);
(useToast as jest.Mock).mockReturnValue({ showToast: mockShowToast }); (useToast as jest.Mock).mockReturnValue({ showToast: mockShowToast });
const { useLocalize } = require('~/hooks');
(useLocalize as jest.Mock).mockReturnValue(mockLocalize); (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 // Setup clipboard mock if it doesn't exist
if (!navigator.clipboard) { if (!navigator.clipboard) {
Object.defineProperty(navigator, 'clipboard', { Object.defineProperty(navigator, 'clipboard', {
@ -176,12 +198,36 @@ describe('AgentDetail', () => {
describe('Interactions', () => { describe('Interactions', () => {
it('should navigate to chat when Start Chat button is clicked', async () => { it('should navigate to chat when Start Chat button is clicked', async () => {
const user = userEvent.setup(); 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(<AgentDetail {...defaultProps} />); renderWithProviders(<AgentDetail {...defaultProps} />);
const startChatButton = screen.getByRole('button', { name: 'com_agents_start_chat' }); const startChatButton = screen.getByRole('button', { name: 'com_agents_start_chat' });
await user.click(startChatButton); 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 () => { it('should not navigate when agent is null', async () => {

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-require-imports */
import React from 'react'; import React from 'react';
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
@ -17,6 +18,11 @@ jest.mock('~/Providers', () => ({
useChatContext: jest.fn(), useChatContext: jest.fn(),
})); }));
// Mock useChatHelpers to avoid Recoil dependency
jest.mock('~/hooks', () => ({
useChatHelpers: jest.fn(),
}));
const mockedUseChatContext = useChatContext as jest.MockedFunction<typeof useChatContext>; const mockedUseChatContext = useChatContext as jest.MockedFunction<typeof useChatContext>;
// Test component that consumes the context // Test component that consumes the context
@ -35,6 +41,16 @@ const TestConsumer: React.FC = () => {
describe('MarketplaceProvider', () => { describe('MarketplaceProvider', () => {
beforeEach(() => { beforeEach(() => {
mockedUseChatContext.mockClear(); 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', () => { it('provides correct marketplace context values', () => {
@ -46,7 +62,7 @@ describe('MarketplaceProvider', () => {
}, },
}; };
mockedUseChatContext.mockReturnValue(mockContext); mockedUseChatContext.mockReturnValue(mockContext as ReturnType<typeof useChatContext>);
render( render(
<MarketplaceProvider> <MarketplaceProvider>

View file

@ -34,6 +34,7 @@ jest.mock('react-router-dom', () => ({
jest.mock('@tanstack/react-query', () => ({ jest.mock('@tanstack/react-query', () => ({
useQueryClient: jest.fn(), useQueryClient: jest.fn(),
useQuery: jest.fn(),
})); }));
jest.mock('~/Providers', () => ({ jest.mock('~/Providers', () => ({
@ -51,6 +52,15 @@ jest.mock('~/hooks/Conversations/useDefaultConvo', () => ({
default: jest.fn(), default: jest.fn(),
})); }));
jest.mock('~/hooks/AuthContext', () => ({
useAuthContext: jest.fn(),
}));
jest.mock('~/hooks/Agents/useAgentsMap', () => ({
__esModule: true,
default: jest.fn(() => ({})),
}));
jest.mock('~/utils', () => ({ jest.mock('~/utils', () => ({
getConvoSwitchLogic: jest.fn(() => ({ getConvoSwitchLogic: jest.fn(() => ({
template: {}, template: {},
@ -63,6 +73,8 @@ jest.mock('~/utils', () => ({
getModelSpecIconURL: jest.fn(() => 'icon-url'), getModelSpecIconURL: jest.fn(() => 'icon-url'),
removeUnavailableTools: jest.fn((preset) => preset), removeUnavailableTools: jest.fn((preset) => preset),
logger: { log: jest.fn() }, logger: { log: jest.fn() },
getInitialTheme: jest.fn(() => 'light'),
applyFontSize: jest.fn(),
})); }));
// Mock the tQueryParamsSchema // Mock the tQueryParamsSchema
@ -82,6 +94,21 @@ jest.mock('librechat-data-provider', () => ({
EModelEndpoint: { custom: 'custom', assistants: 'assistants', agents: 'agents' }, 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 // Mock global window.history
global.window = Object.create(window); global.window = Object.create(window);
global.window.history = { global.window.history = {
@ -103,6 +130,14 @@ describe('useQueryParams', () => {
// Reset mock for window.history.replaceState // Reset mock for window.history.replaceState
jest.spyOn(window.history, 'replaceState').mockClear(); 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 // Create mocks for all dependencies
const mockSearchParams = new URLSearchParams(); const mockSearchParams = new URLSearchParams();
(useSearchParams as jest.Mock).mockReturnValue([mockSearchParams, jest.fn()]); (useSearchParams as jest.Mock).mockReturnValue([mockSearchParams, jest.fn()]);
@ -147,6 +182,13 @@ describe('useQueryParams', () => {
const mockGetDefaultConversation = jest.fn().mockReturnValue({}); const mockGetDefaultConversation = jest.fn().mockReturnValue({});
(useDefaultConvo as jest.Mock).mockReturnValue(mockGetDefaultConversation); (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(() => { afterEach(() => {