// File: frontend/components/admin/ai/__tests__/RuntimeParametersPanel.test.tsx
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import RuntimeParametersPanel from '../RuntimeParametersPanel';
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key,
}),
}));
const mockGetSandboxProfile = vi.fn();
const mockSaveSandboxProfile = vi.fn();
const mockResetSandboxProfile = vi.fn();
const mockApplyProfile = vi.fn();
vi.mock('@/lib/services/admin-ai.service', () => ({
adminAiService: {
getSandboxProfile: (...args: any) => mockGetSandboxProfile(...args),
saveSandboxProfile: (...args: any) => mockSaveSandboxProfile(...args),
resetSandboxProfile: (...args: any) => mockResetSandboxProfile(...args),
applyProfile: (...args: any) => mockApplyProfile(...args),
},
}));
vi.mock('uuid', () => ({
v7: () => 'mock-uuid-v7',
}));
vi.mock('sonner', () => ({
toast: {
success: vi.fn(),
error: vi.fn(),
},
}));
// ResizeObserver mock is needed for Radix UI select
class ResizeObserver {
observe() {}
unobserve() {}
disconnect() {}
}
window.ResizeObserver = ResizeObserver;
describe('RuntimeParametersPanel', () => {
const mockParams = {
temperature: 0.7,
topP: 0.9,
repeatPenalty: 1.1,
maxTokens: 2048,
numCtx: 4096,
keepAliveSeconds: 300,
canonicalModel: 'np-dms-ai-test',
};
beforeEach(() => {
vi.clearAllMocks();
mockGetSandboxProfile.mockResolvedValue(mockParams);
window.PointerEvent = MouseEvent as any;
});
it('renders loading state initially', () => {
// We mock promise without resolving immediately to see loading state
let resolvePromise: any;
mockGetSandboxProfile.mockReturnValue(new Promise((resolve) => {
resolvePromise = resolve;
}));
render();
expect(screen.getByText(/กำลังโหลดพารามิเตอร์/)).toBeInTheDocument();
// Resolve to avoid act warnings
resolvePromise(mockParams);
});
it('renders parameters after loading', async () => {
render();
await waitFor(() => {
expect(screen.getByText('sandbox_test.runtime_parameters')).toBeInTheDocument();
});
expect(screen.getByText('np-dms-ai-test')).toBeInTheDocument();
expect(screen.getByDisplayValue('2048')).toBeInTheDocument();
expect(screen.getByDisplayValue('4096')).toBeInTheDocument();
expect(screen.getByDisplayValue('300')).toBeInTheDocument();
});
it('calls save draft correctly', async () => {
const user = userEvent.setup();
mockSaveSandboxProfile.mockResolvedValue(mockParams);
render();
await waitFor(() => {
expect(screen.getByText('sandbox_test.runtime_parameters')).toBeInTheDocument();
});
const saveButton = screen.getByRole('button', { name: /บันทึกแบบร่าง/i });
await user.click(saveButton);
expect(mockSaveSandboxProfile).toHaveBeenCalledWith('standard', mockParams, 'mock-uuid-v7');
const { toast } = await import('sonner');
expect(toast.success).toHaveBeenCalledWith('บันทึกแบบร่าง Sandbox สำเร็จ');
});
it('calls apply to production correctly', async () => {
const user = userEvent.setup();
mockApplyProfile.mockResolvedValue(true);
render();
await waitFor(() => {
expect(screen.getByText('sandbox_test.runtime_parameters')).toBeInTheDocument();
});
const applyButton = screen.getByRole('button', { name: /ปรับใช้จริง/i });
await user.click(applyButton);
expect(mockApplyProfile).toHaveBeenCalledWith('standard', 'mock-uuid-v7');
const { toast } = await import('sonner');
expect(toast.success).toHaveBeenCalledWith('ปรับใช้พารามิเตอร์จริงสำเร็จ');
});
});