Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
.FormLayout {
width: 800px;
}

.GoldenQAHelper {
margin-top: 8px;
}
Expand Down Expand Up @@ -47,11 +43,16 @@

.GoldenQaRow {
display: flex;
align-items: flex-start;
align-items: center;
gap: 12px;
}

.UploadGoldenQaButton {
margin-top: 40px;
white-space: nowrap;
border-radius: 20px !important;
flex-shrink: 0;
}

.GoldenQaHelperText {
margin-top: 6px;
}
191 changes: 166 additions & 25 deletions src/containers/AIEvals/AIEvaluationCreate/AIEvaluationCreate.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,58 @@ import {
createGoldenQaCustomSuccessMock,
createGoldenQaSuccessMock,
getAIEvaluationCreateMocks,
getAssistantConfigVersionsEmptyMock,
getAssistantConfigVersionsErrorMock,
getAssistantConfigVersionsLoadingMock,
getAssistantConfigVersionsMultipleNamesMock,
getAssistantConfigVersionsMock,
getCreateEvaluationNetworkErrorMock,
getCreateEvaluationSuccessMock,
getListAiEvaluationsMock,
} from 'mocks/AIEvaluations';
import AIEvaluationCreate, { DUMMY_CREATE, DUMMY_GET_ITEM } from './AIEvaluationCreate';
import { setNotification } from 'common/notification';
import AIEvaluationCreate from './AIEvaluationCreate';

const defaultMocks = getAIEvaluationCreateMocks(DUMMY_GET_ITEM, DUMMY_CREATE);
vi.mock('common/notification', () => ({
setNotification: vi.fn(),
setErrorMessage: vi.fn(),
}));

const defaultMocks = getAIEvaluationCreateMocks();

const wrapper = (mocks: any[] = defaultMocks) => (
<MockedProvider mocks={mocks}>
<MemoryRouter initialEntries={['/ai-evaluations/create']}>
<Routes>
<Route path="/ai-evaluations/create" element={<AIEvaluationCreate />} />
<Route path="/chat" element={<div>Chat Page</div>} />
</Routes>
</MemoryRouter>
</MockedProvider>
);

const fillAndSubmitForm = async (evaluationName = 'test_evaluation') => {
await waitFor(() => {
expect(screen.getByText('Create AI Evaluation')).toBeInTheDocument();
});

fireEvent.change(screen.getByPlaceholderText('Give a unique name for the evaluation experiment'), {
target: { value: evaluationName },
});

const assistantDropdown = screen.getAllByTestId('dropdown')[1];
const selectTrigger =
assistantDropdown.querySelector('[role="combobox"]') ?? assistantDropdown.querySelector('button');
fireEvent.mouseDown(selectTrigger!);

await waitFor(() => {
expect(screen.getByRole('option', { name: 'Test Assistant (Version 2)' })).toBeInTheDocument();
});
fireEvent.click(screen.getByRole('option', { name: 'Test Assistant (Version 2)' }));

fireEvent.click(screen.getByText('Run Evaluation'));
};

describe('AIEvaluationCreate', () => {
beforeEach(() => {
vi.clearAllMocks();
Expand Down Expand Up @@ -150,10 +187,10 @@ describe('AIEvaluationCreate', () => {
render(wrapper());

await waitFor(() => {
expect(screen.getByPlaceholderText('Give a unique name for the evaluation experiment.')).toBeInTheDocument();
expect(screen.getByPlaceholderText('Give a unique name for the evaluation experiment')).toBeInTheDocument();
});

const nameInput = screen.getByPlaceholderText('Give a unique name for the evaluation experiment.');
const nameInput = screen.getByPlaceholderText('Give a unique name for the evaluation experiment');
fireEvent.change(nameInput, { target: { value: 'valid_name' } });
fireEvent.click(screen.getByText('Run Evaluation'));

Expand All @@ -162,52 +199,156 @@ describe('AIEvaluationCreate', () => {
});
});

test('shows validation error for invalid evaluation name pattern', async () => {
test('accepts any non-empty evaluation name', async () => {
render(wrapper());

await waitFor(() => {
expect(screen.getByPlaceholderText('Give a unique name for the evaluation experiment.')).toBeInTheDocument();
expect(screen.getByPlaceholderText('Give a unique name for the evaluation experiment')).toBeInTheDocument();
});

const nameInput = screen.getByPlaceholderText('Give a unique name for the evaluation experiment.');
fireEvent.change(nameInput, { target: { value: 'invalid name with spaces' } });
fireEvent.click(screen.getByText('Run Evaluation'));
const nameInput = screen.getByPlaceholderText('Give a unique name for the evaluation experiment');
fireEvent.change(nameInput, { target: { value: 'valid_evaluation-name123' } });

expect((nameInput as HTMLInputElement).value).toBe('valid_evaluation-name123');
});

test('shows assistant options from query using assistantName and versionNumber', async () => {
render(wrapper([...defaultMocks]));

await waitFor(() => {
expect(screen.getByText('Create AI Evaluation')).toBeInTheDocument();
});

const dropdowns = screen.getAllByTestId('dropdown');
const assistantDropdown = dropdowns[1];
const selectTrigger =
assistantDropdown.querySelector('[role="combobox"]') ?? assistantDropdown.querySelector('button');
fireEvent.mouseDown(selectTrigger!);

await waitFor(() => {
expect(screen.getByText('Invalid evaluation name')).toBeInTheDocument();
expect(screen.getByText('Test Assistant (Version 2)')).toBeInTheDocument();
expect(screen.getByText('Test Assistant (Version 1)')).toBeInTheDocument();
});
});

test('accepts valid evaluation name with alphanumeric, underscore and hyphen', async () => {
test('Run Evaluation submit button is visible and enabled', async () => {
render(wrapper());

await waitFor(() => {
expect(screen.getByPlaceholderText('Give a unique name for the evaluation experiment.')).toBeInTheDocument();
expect(screen.getByTestId('submitActionButton')).toBeInTheDocument();
expect(screen.getByTestId('submitActionButton')).toHaveTextContent('Run Evaluation');
expect(screen.getByTestId('submitActionButton')).not.toBeDisabled();
});
});

const nameInput = screen.getByPlaceholderText('Give a unique name for the evaluation experiment.');
fireEvent.change(nameInput, { target: { value: 'valid_evaluation-name123' } });
test('shows Fetching assistants... while assistant config versions are loading', async () => {
const mocks = [getAssistantConfigVersionsLoadingMock];
render(wrapper(mocks));

expect((nameInput as HTMLInputElement).value).toBe('valid_evaluation-name123');
await waitFor(() => {
expect(screen.getByText('Create AI Evaluation')).toBeInTheDocument();
});

const dropdowns = screen.getAllByTestId('dropdown');
const assistantDropdown = dropdowns[1];
const selectTrigger =
assistantDropdown.querySelector('[role="combobox"]') ?? assistantDropdown.querySelector('button');
fireEvent.mouseDown(selectTrigger!);

await waitFor(() => {
expect(screen.getByText('Fetching assistants...')).toBeInTheDocument();
});
});

test('shows assistant helper text', async () => {
render(wrapper());
test('shows error notification when fetching assistant config versions fails', async () => {
render(wrapper([getAssistantConfigVersionsErrorMock]));

await waitFor(() => {
expect(setNotification).toHaveBeenCalledWith('Failed to fetch assistants', 'warning');
});
});

test('shows No assistants available when assistant config versions list is empty', async () => {
const mocks = [getAssistantConfigVersionsEmptyMock];
render(wrapper(mocks));

await waitFor(() => {
expect(screen.getByText('Create AI Evaluation')).toBeInTheDocument();
});

expect(screen.getByText("This list includes all assistants and versions you've created.")).toBeInTheDocument();
const dropdowns = screen.getAllByTestId('dropdown');
const assistantDropdown = dropdowns[1];
const selectTrigger =
assistantDropdown.querySelector('[role="combobox"]') ?? assistantDropdown.querySelector('button');
fireEvent.mouseDown(selectTrigger!);

await waitFor(() => {
expect(screen.getByText('No assistants available')).toBeInTheDocument();
});
});

test('Run Evaluation submit button is visible and enabled', async () => {
render(wrapper());
test('shows all assistant config versions with correct labels for multiple assistant names', async () => {
const mocks = [getAssistantConfigVersionsMultipleNamesMock];
render(wrapper(mocks));

await waitFor(() => {
expect(screen.getByTestId('submitActionButton')).toBeInTheDocument();
expect(screen.getByTestId('submitActionButton')).toHaveTextContent('Run Evaluation');
expect(screen.getByTestId('submitActionButton')).not.toBeDisabled();
expect(screen.getByText('Create AI Evaluation')).toBeInTheDocument();
});

const dropdowns = screen.getAllByTestId('dropdown');
const assistantDropdown = dropdowns[1];
const selectTrigger =
assistantDropdown.querySelector('[role="combobox"]') ?? assistantDropdown.querySelector('button');
fireEvent.mouseDown(selectTrigger!);

await waitFor(() => {
expect(screen.getByText('Alpha Assistant (Version 1)')).toBeInTheDocument();
expect(screen.getByText('Beta Assistant (Version 1)')).toBeInTheDocument();
expect(screen.getByText('Beta Assistant (Version 2)')).toBeInTheDocument();
});
});

test('calls createEvaluation with correct parameters when form is submitted', async () => {
let capturedVariables: any = null;
const captureMock = {
request: { query: getCreateEvaluationSuccessMock.request.query },
variableMatcher: (vars: any) => {
capturedVariables = vars;
return true;
},
result: { data: { createEvaluation: { status: 'queued', __typename: 'EvaluationPayload' } } },
};
render(wrapper([getListAiEvaluationsMock, getAssistantConfigVersionsMock, captureMock]));

await fillAndSubmitForm('test_evaluation');

await waitFor(() => {
expect(capturedVariables?.input).toMatchObject({
experimentName: 'test_evaluation',
configId: 'kaapi-uuid-a1',
configVersion: '1',
});
});
});

test('shows success notification and navigates to chat on successful submission', async () => {
render(wrapper([getListAiEvaluationsMock, getAssistantConfigVersionsMock, getCreateEvaluationSuccessMock]));

await fillAndSubmitForm();

await waitFor(() => {
expect(setNotification).toHaveBeenCalledWith('Evaluation started successfully!');
expect(screen.getByText('Chat Page')).toBeInTheDocument();
});
});

test('shows error notification when evaluation API call fails', async () => {
render(wrapper([getListAiEvaluationsMock, getAssistantConfigVersionsMock, getCreateEvaluationNetworkErrorMock]));

await fillAndSubmitForm();

await waitFor(() => {
expect(setNotification).toHaveBeenCalledWith('Evaluation failed', 'warning');
});
});

Expand Down Expand Up @@ -284,8 +425,8 @@ describe('AIEvaluationCreate', () => {
render(
wrapper([
...defaultMocks,
createGoldenQaCustomSuccessMock('first_qa', 1),
createGoldenQaCustomSuccessMock('second_qa', 1),
createGoldenQaCustomSuccessMock('first_qa', 1, '100'),
createGoldenQaCustomSuccessMock('second_qa', 1, '200'),
])
);

Expand Down
Loading
Loading