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 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,

View file

@ -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');

View file

@ -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 },

View file

@ -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';

View file

@ -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(<AgentDetail {...defaultProps} />);
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 () => {

View file

@ -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<typeof useChatContext>;
// 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<typeof useChatContext>);
render(
<MarketplaceProvider>

View file

@ -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(() => {