mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-23 03:40:14 +01:00
ESLint fixes
This commit is contained in:
parent
33c4ef03c3
commit
c6e1c65fe7
9 changed files with 114 additions and 56 deletions
|
|
@ -456,7 +456,7 @@ describe('Accessibility Improvements', () => {
|
|||
expect(alert).toHaveAttribute('aria-atomic', 'true');
|
||||
|
||||
// Check heading structure
|
||||
const heading = screen.getByRole('heading', { level: 2 });
|
||||
const heading = screen.getByRole('heading', { level: 3 });
|
||||
expect(heading).toHaveAttribute('id', 'error-title');
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { MemoryRouter, useNavigate } from 'react-router-dom';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
|
|
@ -19,6 +19,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', () => ({
|
||||
|
|
@ -33,11 +34,7 @@ jest.mock('~/utils/agents', () => ({
|
|||
}));
|
||||
|
||||
// Mock clipboard API
|
||||
Object.assign(navigator, {
|
||||
clipboard: {
|
||||
writeText: jest.fn(),
|
||||
},
|
||||
});
|
||||
const mockWriteText = jest.fn();
|
||||
|
||||
const mockNavigate = jest.fn();
|
||||
const mockShowToast = jest.fn();
|
||||
|
|
@ -55,17 +52,23 @@ const mockAgent: t.Agent = {
|
|||
provider: 'openai',
|
||||
instructions: 'You are a helpful test agent',
|
||||
tools: [],
|
||||
code_interpreter: false,
|
||||
file_search: false,
|
||||
author: 'test-user-id',
|
||||
author_name: 'Test User',
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
created_at: new Date().getTime(),
|
||||
version: 1,
|
||||
support_contact: {
|
||||
name: 'Support Team',
|
||||
email: 'support@test.com',
|
||||
},
|
||||
model_parameters: {
|
||||
model: undefined,
|
||||
temperature: null,
|
||||
maxContextTokens: null,
|
||||
max_context_tokens: null,
|
||||
max_output_tokens: null,
|
||||
top_p: null,
|
||||
frequency_penalty: null,
|
||||
presence_penalty: null,
|
||||
},
|
||||
};
|
||||
|
||||
// Helper function to render with providers
|
||||
|
|
@ -95,8 +98,19 @@ describe('AgentDetail', () => {
|
|||
(useToast as jest.Mock).mockReturnValue({ showToast: mockShowToast });
|
||||
(useLocalize as jest.Mock).mockReturnValue(mockLocalize);
|
||||
|
||||
// Reset clipboard mock
|
||||
(navigator.clipboard.writeText as jest.Mock).mockResolvedValue(undefined);
|
||||
// Setup clipboard mock if it doesn't exist
|
||||
if (!navigator.clipboard) {
|
||||
Object.defineProperty(navigator, 'clipboard', {
|
||||
value: {
|
||||
writeText: mockWriteText,
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
} else {
|
||||
// If clipboard exists, spy on it
|
||||
jest.spyOn(navigator.clipboard, 'writeText').mockImplementation(mockWriteText);
|
||||
}
|
||||
mockWriteText.mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
|
|
@ -224,11 +238,17 @@ describe('AgentDetail', () => {
|
|||
const copyLinkButton = screen.getByRole('button', { name: 'com_agents_copy_link' });
|
||||
await user.click(copyLinkButton);
|
||||
|
||||
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
|
||||
`${window.location.origin}/c/new?agent_id=test-agent-id`,
|
||||
);
|
||||
expect(mockShowToast).toHaveBeenCalledWith({
|
||||
message: 'Link copied',
|
||||
// Wait for async clipboard operation to complete
|
||||
await waitFor(() => {
|
||||
expect(mockWriteText).toHaveBeenCalledWith(
|
||||
`${window.location.origin}/c/new?agent_id=test-agent-id`,
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockShowToast).toHaveBeenCalledWith({
|
||||
message: 'Link copied',
|
||||
});
|
||||
});
|
||||
|
||||
// Dropdown should close
|
||||
|
|
@ -241,7 +261,7 @@ describe('AgentDetail', () => {
|
|||
|
||||
it('should show error toast when clipboard write fails', async () => {
|
||||
const user = userEvent.setup();
|
||||
(navigator.clipboard.writeText as jest.Mock).mockRejectedValue(new Error('Clipboard error'));
|
||||
mockWriteText.mockRejectedValue(new Error('Clipboard error'));
|
||||
|
||||
renderWithProviders(<AgentDetail {...defaultProps} />);
|
||||
|
||||
|
|
@ -252,6 +272,11 @@ describe('AgentDetail', () => {
|
|||
const copyLinkButton = screen.getByRole('button', { name: 'com_agents_copy_link' });
|
||||
await user.click(copyLinkButton);
|
||||
|
||||
// Wait for clipboard operation to fail and error toast to show
|
||||
await waitFor(() => {
|
||||
expect(mockWriteText).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockShowToast).toHaveBeenCalledWith({
|
||||
message: 'com_agents_link_copy_failed',
|
||||
|
|
@ -261,7 +286,7 @@ describe('AgentDetail', () => {
|
|||
|
||||
it('should call onClose when dialog is closed', () => {
|
||||
const mockOnClose = jest.fn();
|
||||
render(<AgentDetail {...defaultProps} onClose={mockOnClose} isOpen={false} />);
|
||||
renderWithProviders(<AgentDetail {...defaultProps} onClose={mockOnClose} isOpen={false} />);
|
||||
|
||||
// Since we're testing the onOpenChange callback, we need to trigger it
|
||||
// This would normally be done by the Dialog component when ESC is pressed or overlay is clicked
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import '@testing-library/jest-dom';
|
||||
import CategoryTabs from '../CategoryTabs';
|
||||
|
|
|
|||
|
|
@ -301,5 +301,3 @@ describe('ErrorDisplay', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
export default {};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import '@testing-library/jest-dom';
|
||||
import SearchBar from '../SearchBar';
|
||||
|
|
@ -9,7 +9,7 @@ jest.mock('~/hooks/useLocalize', () => () => (key: string) => key);
|
|||
|
||||
// Mock useDebounce hook
|
||||
jest.mock('~/hooks', () => ({
|
||||
useDebounce: (value: string, delay: number) => value, // Return value immediately for testing
|
||||
useDebounce: (value: string) => value, // Return value immediately for testing
|
||||
}));
|
||||
|
||||
describe('SearchBar', () => {
|
||||
|
|
|
|||
|
|
@ -193,8 +193,6 @@ export const useUploadAgentAvatarMutation = (
|
|||
t.AgentAvatarVariables, // request
|
||||
unknown // context
|
||||
> => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation([MutationKeys.agentAvatarUpload], {
|
||||
mutationFn: ({ postCreation, ...variables }: t.AgentAvatarVariables) =>
|
||||
dataService.uploadAgentAvatar(variables),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { renderHook } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import useAgentCategories from '../useAgentCategories';
|
||||
import { AGENT_CATEGORIES, EMPTY_AGENT_CATEGORY } from '~/constants/agentCategories';
|
||||
import { EMPTY_AGENT_CATEGORY } from '~/constants/agentCategories';
|
||||
|
||||
// Mock the useLocalize hook
|
||||
jest.mock('~/hooks/useLocalize', () => ({
|
||||
|
|
@ -11,25 +13,68 @@ jest.mock('~/hooks/useLocalize', () => ({
|
|||
},
|
||||
}));
|
||||
|
||||
describe('useAgentCategories', () => {
|
||||
it('should return processed categories with correct structure', () => {
|
||||
const { result } = renderHook(() => useAgentCategories());
|
||||
// Mock the data provider
|
||||
jest.mock('~/data-provider/Agents', () => ({
|
||||
useGetAgentCategoriesQuery: jest.fn(() => ({
|
||||
data: [
|
||||
{ value: 'general', label: 'com_ui_agent_category_general' },
|
||||
{ value: 'hr', label: 'com_ui_agent_category_hr' },
|
||||
{ value: 'rd', label: 'com_ui_agent_category_rd' },
|
||||
{ value: 'finance', label: 'com_ui_agent_category_finance' },
|
||||
{ value: 'it', label: 'com_ui_agent_category_it' },
|
||||
{ value: 'sales', label: 'com_ui_agent_category_sales' },
|
||||
{ value: 'aftersales', label: 'com_ui_agent_category_aftersales' },
|
||||
{ value: 'promoted', label: 'Promoted' }, // Should be filtered out
|
||||
{ value: 'all', label: 'All' }, // Should be filtered out
|
||||
],
|
||||
isLoading: false,
|
||||
error: null,
|
||||
})),
|
||||
}));
|
||||
|
||||
// Check that we have the expected number of categories
|
||||
expect(result.current.categories.length).toBe(AGENT_CATEGORIES.length);
|
||||
const createWrapper = () => {
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return ({ children }: { children: React.ReactNode }) => (
|
||||
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||
);
|
||||
};
|
||||
|
||||
describe('useAgentCategories', () => {
|
||||
it('should return processed categories with correct structure', async () => {
|
||||
const { result } = renderHook(() => useAgentCategories(), {
|
||||
wrapper: createWrapper(),
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
// Check that we have the expected number of categories (excluding 'promoted' and 'all')
|
||||
expect(result.current.categories.length).toBe(7);
|
||||
});
|
||||
|
||||
// Check that the first category has the expected structure
|
||||
const firstCategory = result.current.categories[0];
|
||||
const firstOriginalCategory = AGENT_CATEGORIES[0];
|
||||
|
||||
expect(firstCategory.value).toBe(firstOriginalCategory.value);
|
||||
|
||||
// Check that labels are properly translated
|
||||
expect(firstCategory.label).toBe('General (Translated)');
|
||||
expect(firstCategory.value).toBe('general');
|
||||
expect(firstCategory.label).toBe('com_ui_agent_category_general');
|
||||
expect(firstCategory.className).toBe('w-full');
|
||||
|
||||
// Verify special categories are filtered out
|
||||
const categoryValues = result.current.categories.map((cat) => cat.value);
|
||||
expect(categoryValues).not.toContain('promoted');
|
||||
expect(categoryValues).not.toContain('all');
|
||||
|
||||
// Check the empty category
|
||||
expect(result.current.emptyCategory.value).toBe(EMPTY_AGENT_CATEGORY.value);
|
||||
expect(result.current.emptyCategory.label).toBeTruthy();
|
||||
expect(result.current.emptyCategory.label).toBe('General (Translated)');
|
||||
expect(result.current.emptyCategory.className).toBe('w-full');
|
||||
|
||||
// Check loading state
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.error).toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
import { useMemo } from 'react';
|
||||
import {
|
||||
MessageSquareQuote,
|
||||
ArrowRightToLine,
|
||||
Settings2, Database,
|
||||
Bookmark,
|
||||
LayoutGrid,
|
||||
} from 'lucide-react';
|
||||
import { MessageSquareQuote, ArrowRightToLine, Settings2, Database, Bookmark } from 'lucide-react';
|
||||
import {
|
||||
isAssistantsEndpoint,
|
||||
isAgentsEndpoint,
|
||||
|
|
@ -27,7 +21,6 @@ import FilesPanel from '~/components/SidePanel/Files/Panel';
|
|||
import MCPPanel from '~/components/SidePanel/MCP/MCPPanel';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import { useHasAccess } from '~/hooks';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
export default function useSideNavLinks({
|
||||
hidePanel,
|
||||
|
|
@ -44,7 +37,6 @@ export default function useSideNavLinks({
|
|||
interfaceConfig: Partial<TInterfaceConfig>;
|
||||
endpointsConfig: TEndpointsConfig;
|
||||
}) {
|
||||
const navigate = useNavigate();
|
||||
const hasAccessToPrompts = useHasAccess({
|
||||
permissionType: PermissionTypes.PROMPTS,
|
||||
permission: Permissions.USE,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ describe('Agent Utilities', () => {
|
|||
id: '1',
|
||||
name: 'Test Agent',
|
||||
avatar: '/path/to/avatar.png',
|
||||
} as t.Agent;
|
||||
} as unknown as t.Agent;
|
||||
expect(getAgentAvatarUrl(agent)).toBe('/path/to/avatar.png');
|
||||
});
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ describe('Agent Utilities', () => {
|
|||
id: '1',
|
||||
name: 'Test Agent',
|
||||
avatar: '/test-avatar.png',
|
||||
} as t.Agent;
|
||||
} as unknown as t.Agent;
|
||||
|
||||
render(<div>{renderAgentAvatar(agent)}</div>);
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ describe('Agent Utilities', () => {
|
|||
id: '1',
|
||||
name: 'Test Agent',
|
||||
avatar: '/test-avatar.png',
|
||||
} as t.Agent;
|
||||
} as unknown as t.Agent;
|
||||
|
||||
const { rerender } = render(<div>{renderAgentAvatar(agent, { size: 'sm' })}</div>);
|
||||
expect(screen.getByAltText('Test Agent avatar')).toHaveClass('h-12', 'w-12');
|
||||
|
|
@ -107,7 +107,7 @@ describe('Agent Utilities', () => {
|
|||
id: '1',
|
||||
name: 'Test Agent',
|
||||
avatar: '/test-avatar.png',
|
||||
} as t.Agent;
|
||||
} as unknown as t.Agent;
|
||||
|
||||
render(<div>{renderAgentAvatar(agent, { className: 'custom-class' })}</div>);
|
||||
|
||||
|
|
@ -120,7 +120,7 @@ describe('Agent Utilities', () => {
|
|||
id: '1',
|
||||
name: 'Test Agent',
|
||||
avatar: '/test-avatar.png',
|
||||
} as t.Agent;
|
||||
} as unknown as t.Agent;
|
||||
|
||||
const { rerender } = render(<div>{renderAgentAvatar(agent, { showBorder: true })}</div>);
|
||||
expect(screen.getByAltText('Test Agent avatar')).toHaveClass('border-2');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue