mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
add jest testing for ui
This commit is contained in:
parent
fff1f63e2c
commit
98f9a3ebfd
5 changed files with 3699 additions and 2 deletions
14
tests/proxy_admin_ui_tests/jest.config.js
Normal file
14
tests/proxy_admin_ui_tests/jest.config.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
transform: {
|
||||
'^.+\\.(ts|tsx)$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: 'tsconfig.json',
|
||||
jsx: 'react'
|
||||
}
|
||||
]
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node']
|
||||
};
|
||||
3542
tests/proxy_admin_ui_tests/package-lock.json
generated
3542
tests/proxy_admin_ui_tests/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -9,6 +9,11 @@
|
|||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.47.2",
|
||||
"@types/node": "^22.5.5"
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^22.5.5",
|
||||
"@types/react": "^19.0.8",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.7.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
/**
|
||||
* Unit Tests for fetch_available_models_team_key.tsx
|
||||
*
|
||||
* How to run:
|
||||
* 1. Install Jest (and ts-jest) if not already installed:
|
||||
* npm install --save-dev jest ts-jest @types/jest
|
||||
* 2. Ensure you have a jest config. For a quick setup, you can create "jest.config.js" or "jest.config.ts".
|
||||
* 3. Run the tests:
|
||||
* npx jest tests/proxy_admin_ui_tests/test_fetch_available_models_team_key.unit.test.ts
|
||||
*
|
||||
* or add a script to your package.json:
|
||||
* "scripts": {
|
||||
* "test:unit": "jest"
|
||||
* }
|
||||
* and then run:
|
||||
* npm run test:unit
|
||||
*/
|
||||
|
||||
import { describe, it, expect, jest } from '@jest/globals';
|
||||
|
||||
// If "modelAvailableCall" comes from ../networking, mock it:
|
||||
jest.mock('../../ui/litellm-dashboard/src/components/networking', () => {
|
||||
return {
|
||||
modelAvailableCall: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
import {
|
||||
fetchAvailableModelsForTeamOrKey,
|
||||
getModelDisplayName,
|
||||
unfurlWildcardModelsInList,
|
||||
} from '../../ui/litellm-dashboard/src/components/key_team_helpers/fetch_available_models_team_key';
|
||||
import { modelAvailableCall } from '../../ui/litellm-dashboard/src/components/networking';
|
||||
|
||||
// Define the type for the modelAvailableCall response
|
||||
type ModelAvailableResponse = {
|
||||
data: Array<{ id: string }>;
|
||||
};
|
||||
|
||||
// Update the mock typing
|
||||
const mockModelAvailableCall = modelAvailableCall as unknown as jest.MockedFunction<
|
||||
(accessToken: String, userID: String, userRole: String, return_wildcard_routes?: boolean) => Promise<ModelAvailableResponse>
|
||||
>;
|
||||
|
||||
describe('fetchAvailableModelsForTeamOrKey', () => {
|
||||
it('returns undefined if userID or userRole is null', async () => {
|
||||
const result1 = await fetchAvailableModelsForTeamOrKey(null as any, 'someRole', 'accessToken');
|
||||
const result2 = await fetchAvailableModelsForTeamOrKey('someUser', null as any, 'accessToken');
|
||||
expect(result1).toBeUndefined();
|
||||
expect(result2).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns sorted providerModels followed by specificModels', async () => {
|
||||
mockModelAvailableCall.mockResolvedValue({
|
||||
data: [{ id: 'openai/*' }, { id: 'openai/gpt-3.5' }, { id: 'anthropic/*' }, { id: 'openai/gpt-4' }],
|
||||
});
|
||||
|
||||
const result = await fetchAvailableModelsForTeamOrKey('someUser', 'someRole', 'accessToken');
|
||||
// We expect all provider wildcards sorted first, then specific
|
||||
// The function doesn't re-sort among wildcards but does place them before specifics
|
||||
// So the result should have "openai/*" and "anthropic/*" first, then "openai/gpt-3.5" and "openai/gpt-4"
|
||||
expect(result).toEqual(['openai/*', 'anthropic/*', 'openai/gpt-3.5', 'openai/gpt-4']);
|
||||
});
|
||||
|
||||
it('handles errors gracefully and logs to console', async () => {
|
||||
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mockModelAvailableCall.mockRejectedValue(new Error('Test Error'));
|
||||
|
||||
const result = await fetchAvailableModelsForTeamOrKey('someUser', 'someRole', 'accessToken');
|
||||
expect(result).toBeUndefined();
|
||||
expect(consoleSpy).toHaveBeenCalledWith('Error fetching user models:', expect.any(Error));
|
||||
|
||||
consoleSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getModelDisplayName', () => {
|
||||
it('returns "All <provider> models" for wildcard patterns', () => {
|
||||
const wildcardName = getModelDisplayName('openai/*');
|
||||
expect(wildcardName).toBe('All openai models');
|
||||
});
|
||||
|
||||
it('returns the original model string if not a wildcard', () => {
|
||||
const normalName = getModelDisplayName('openai/gpt-4');
|
||||
expect(normalName).toBe('openai/gpt-4');
|
||||
});
|
||||
});
|
||||
|
||||
describe('unfurlWildcardModelsInList', () => {
|
||||
it('expands wildcard models correctly', () => {
|
||||
const teamModels = ['openai/*', 'anthropic/claude-2'];
|
||||
const allModels = ['openai/gpt-3.5', 'openai/gpt-4', 'anthropic/claude-2', 'anthropic/*'];
|
||||
|
||||
const result = unfurlWildcardModelsInList(teamModels, allModels);
|
||||
// The openai/* should expand to openai/gpt-3.5 & openai/gpt-4,
|
||||
// that wildcard is pushed to top, then specific models, in the order described by the function
|
||||
// So the returned array should have wildcard ("openai/*"), then expansions, then any direct listing
|
||||
expect(result).toEqual([
|
||||
'openai/*',
|
||||
'openai/gpt-3.5',
|
||||
'openai/gpt-4',
|
||||
'anthropic/claude-2', // direct mention
|
||||
]);
|
||||
});
|
||||
|
||||
it('returns teamModels unchanged if no wildcard is present', () => {
|
||||
const teamModels = ['openai/gpt-3.5', 'anthropic/claude-2'];
|
||||
const allModels = ['openai/gpt-3.5', 'openai/gpt-4', 'anthropic/claude-2'];
|
||||
|
||||
const result = unfurlWildcardModelsInList(teamModels, allModels);
|
||||
// No wildcard to expand, so we just return the same array
|
||||
expect(result).toEqual(['openai/gpt-3.5', 'anthropic/claude-2']);
|
||||
});
|
||||
});
|
||||
24
tests/proxy_admin_ui_tests/tsconfig.json
Normal file
24
tests/proxy_admin_ui_tests/tsconfig.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"jsx": "react",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"*": ["*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"tests/**/*",
|
||||
"ui/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue