mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-21 11:49:59 +00:00
334 lines
11 KiB
TypeScript
334 lines
11 KiB
TypeScript
import { setActivePinia } from 'pinia';
|
|
import { createTestingPinia } from '@pinia/testing';
|
|
import { useTestDefinitionForm } from '../composables/useTestDefinitionForm';
|
|
import { useTestDefinitionStore } from '@/stores/testDefinition.store.ee';
|
|
import { mockedStore } from '@/__tests__/utils';
|
|
import type { TestDefinitionRecord } from '@/api/testDefinition.ee';
|
|
|
|
const TEST_DEF_A: TestDefinitionRecord = {
|
|
id: '1',
|
|
name: 'Test Definition A',
|
|
description: 'Description A',
|
|
evaluationWorkflowId: '456',
|
|
workflowId: '123',
|
|
annotationTagId: '789',
|
|
annotationTag: null,
|
|
};
|
|
const TEST_DEF_B: TestDefinitionRecord = {
|
|
id: '2',
|
|
name: 'Test Definition B',
|
|
workflowId: '123',
|
|
description: 'Description B',
|
|
annotationTag: null,
|
|
};
|
|
const TEST_DEF_NEW: TestDefinitionRecord = {
|
|
id: '3',
|
|
workflowId: '123',
|
|
name: 'New Test Definition',
|
|
description: 'New Description',
|
|
annotationTag: null,
|
|
};
|
|
|
|
beforeEach(() => {
|
|
const pinia = createTestingPinia();
|
|
setActivePinia(pinia);
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('useTestDefinitionForm', () => {
|
|
it('should initialize with default props', () => {
|
|
const { state } = useTestDefinitionForm();
|
|
|
|
expect(state.value.description.value).toBe('');
|
|
expect(state.value.name.value).toContain('My Test');
|
|
expect(state.value.tags.value).toEqual([]);
|
|
expect(state.value.metrics).toEqual([]);
|
|
expect(state.value.evaluationWorkflow.value).toBe('');
|
|
});
|
|
|
|
it('should load test data', async () => {
|
|
const { loadTestData, state } = useTestDefinitionForm();
|
|
const fetchSpy = vi.spyOn(useTestDefinitionStore(), 'fetchAll');
|
|
const fetchMetricsSpy = vi.spyOn(useTestDefinitionStore(), 'fetchMetrics').mockResolvedValue([
|
|
{
|
|
id: 'metric1',
|
|
name: 'Metric 1',
|
|
testDefinitionId: TEST_DEF_A.id,
|
|
},
|
|
]);
|
|
const evaluationsStore = mockedStore(useTestDefinitionStore);
|
|
|
|
evaluationsStore.testDefinitionsById = {
|
|
[TEST_DEF_A.id]: TEST_DEF_A,
|
|
[TEST_DEF_B.id]: TEST_DEF_B,
|
|
};
|
|
|
|
await loadTestData(TEST_DEF_A.id);
|
|
expect(fetchSpy).toBeCalled();
|
|
expect(fetchMetricsSpy).toBeCalledWith(TEST_DEF_A.id);
|
|
expect(state.value.name.value).toEqual(TEST_DEF_A.name);
|
|
expect(state.value.description.value).toEqual(TEST_DEF_A.description);
|
|
expect(state.value.tags.value).toEqual([TEST_DEF_A.annotationTagId]);
|
|
expect(state.value.evaluationWorkflow.value).toEqual(TEST_DEF_A.evaluationWorkflowId);
|
|
expect(state.value.metrics).toEqual([
|
|
{ id: 'metric1', name: 'Metric 1', testDefinitionId: TEST_DEF_A.id },
|
|
]);
|
|
});
|
|
|
|
it('should gracefully handle loadTestData when no test definition found', async () => {
|
|
const { loadTestData, state } = useTestDefinitionForm();
|
|
const fetchSpy = vi.spyOn(useTestDefinitionStore(), 'fetchAll');
|
|
const evaluationsStore = mockedStore(useTestDefinitionStore);
|
|
|
|
evaluationsStore.testDefinitionsById = {};
|
|
|
|
await loadTestData('unknown-id');
|
|
expect(fetchSpy).toBeCalled();
|
|
// Should remain unchanged since no definition found
|
|
expect(state.value.description.value).toBe('');
|
|
expect(state.value.name.value).toContain('My Test');
|
|
expect(state.value.tags.value).toEqual([]);
|
|
expect(state.value.metrics).toEqual([]);
|
|
});
|
|
|
|
it('should handle errors while loading test data', async () => {
|
|
const { loadTestData } = useTestDefinitionForm();
|
|
const fetchSpy = vi
|
|
.spyOn(useTestDefinitionStore(), 'fetchAll')
|
|
.mockRejectedValue(new Error('Fetch Failed'));
|
|
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
|
|
await loadTestData(TEST_DEF_A.id);
|
|
expect(fetchSpy).toBeCalled();
|
|
expect(consoleErrorSpy).toBeCalledWith('Failed to load test data', expect.any(Error));
|
|
consoleErrorSpy.mockRestore();
|
|
});
|
|
|
|
it('should save a new test', async () => {
|
|
const { createTest, state } = useTestDefinitionForm();
|
|
const createSpy = vi.spyOn(useTestDefinitionStore(), 'create').mockResolvedValue(TEST_DEF_NEW);
|
|
|
|
state.value.name.value = TEST_DEF_NEW.name;
|
|
state.value.description.value = TEST_DEF_NEW.description ?? '';
|
|
|
|
const newTest = await createTest('123');
|
|
expect(createSpy).toBeCalledWith({
|
|
name: TEST_DEF_NEW.name,
|
|
description: TEST_DEF_NEW.description,
|
|
workflowId: '123',
|
|
});
|
|
expect(newTest).toEqual(TEST_DEF_NEW);
|
|
});
|
|
|
|
it('should handle errors when creating a new test', async () => {
|
|
const { createTest } = useTestDefinitionForm();
|
|
const createSpy = vi
|
|
.spyOn(useTestDefinitionStore(), 'create')
|
|
.mockRejectedValue(new Error('Create Failed'));
|
|
|
|
await expect(createTest('123')).rejects.toThrow('Create Failed');
|
|
expect(createSpy).toBeCalled();
|
|
});
|
|
|
|
it('should update an existing test', async () => {
|
|
const { updateTest, state } = useTestDefinitionForm();
|
|
const updatedBTest = {
|
|
...TEST_DEF_B,
|
|
updatedAt: '2022-01-01T00:00:00.000Z',
|
|
createdAt: '2022-01-01T00:00:00.000Z',
|
|
};
|
|
const updateSpy = vi.spyOn(useTestDefinitionStore(), 'update').mockResolvedValue(updatedBTest);
|
|
|
|
state.value.name.value = TEST_DEF_B.name;
|
|
state.value.description.value = TEST_DEF_B.description ?? '';
|
|
|
|
const updatedTest = await updateTest(TEST_DEF_A.id);
|
|
expect(updateSpy).toBeCalledWith({
|
|
id: TEST_DEF_A.id,
|
|
name: TEST_DEF_B.name,
|
|
description: TEST_DEF_B.description,
|
|
});
|
|
expect(updatedTest).toEqual(updatedBTest);
|
|
});
|
|
|
|
it('should throw an error if no testId is provided when updating a test', async () => {
|
|
const { updateTest } = useTestDefinitionForm();
|
|
await expect(updateTest('')).rejects.toThrow('Test ID is required for updating a test');
|
|
});
|
|
|
|
it('should handle errors when updating a test', async () => {
|
|
const { updateTest, state } = useTestDefinitionForm();
|
|
const updateSpy = vi
|
|
.spyOn(useTestDefinitionStore(), 'update')
|
|
.mockRejectedValue(new Error('Update Failed'));
|
|
|
|
state.value.name.value = 'Test';
|
|
state.value.description.value = 'Some description';
|
|
|
|
await expect(updateTest(TEST_DEF_A.id)).rejects.toThrow('Update Failed');
|
|
expect(updateSpy).toBeCalled();
|
|
});
|
|
|
|
it('should delete a metric', async () => {
|
|
const { state, deleteMetric } = useTestDefinitionForm();
|
|
const evaluationsStore = mockedStore(useTestDefinitionStore);
|
|
const deleteMetricSpy = vi.spyOn(evaluationsStore, 'deleteMetric');
|
|
|
|
state.value.metrics = [
|
|
{
|
|
id: 'metric1',
|
|
name: 'Metric 1',
|
|
testDefinitionId: '1',
|
|
},
|
|
{
|
|
id: 'metric2',
|
|
name: 'Metric 2',
|
|
testDefinitionId: '1',
|
|
},
|
|
];
|
|
|
|
await deleteMetric('metric1', TEST_DEF_A.id);
|
|
expect(deleteMetricSpy).toBeCalledWith({ id: 'metric1', testDefinitionId: TEST_DEF_A.id });
|
|
expect(state.value.metrics).toEqual([
|
|
{ id: 'metric2', name: 'Metric 2', testDefinitionId: '1' },
|
|
]);
|
|
});
|
|
|
|
it('should update metrics', async () => {
|
|
const { state, updateMetrics } = useTestDefinitionForm();
|
|
const evaluationsStore = mockedStore(useTestDefinitionStore);
|
|
const updateMetricSpy = vi.spyOn(evaluationsStore, 'updateMetric');
|
|
const createMetricSpy = vi
|
|
.spyOn(evaluationsStore, 'createMetric')
|
|
.mockResolvedValue({ id: 'metric_new', name: 'Metric 2', testDefinitionId: TEST_DEF_A.id });
|
|
|
|
state.value.metrics = [
|
|
{
|
|
id: 'metric1',
|
|
name: 'Metric 1',
|
|
testDefinitionId: TEST_DEF_A.id,
|
|
},
|
|
{
|
|
id: '',
|
|
name: 'Metric 2',
|
|
testDefinitionId: TEST_DEF_A.id,
|
|
}, // New metric that needs creation
|
|
];
|
|
|
|
await updateMetrics(TEST_DEF_A.id);
|
|
expect(createMetricSpy).toHaveBeenCalledWith({
|
|
name: 'Metric 2',
|
|
testDefinitionId: TEST_DEF_A.id,
|
|
});
|
|
expect(updateMetricSpy).toHaveBeenCalledWith({
|
|
name: 'Metric 1',
|
|
id: 'metric1',
|
|
testDefinitionId: TEST_DEF_A.id,
|
|
});
|
|
expect(state.value.metrics).toEqual([
|
|
{ id: 'metric1', name: 'Metric 1', testDefinitionId: TEST_DEF_A.id },
|
|
{ id: 'metric_new', name: 'Metric 2', testDefinitionId: TEST_DEF_A.id },
|
|
]);
|
|
});
|
|
|
|
it('should start editing a field', () => {
|
|
const { state, startEditing } = useTestDefinitionForm();
|
|
|
|
startEditing('name');
|
|
expect(state.value.name.isEditing).toBe(true);
|
|
expect(state.value.name.tempValue).toBe(state.value.name.value);
|
|
|
|
startEditing('tags');
|
|
expect(state.value.tags.isEditing).toBe(true);
|
|
expect(state.value.tags.tempValue).toEqual(state.value.tags.value);
|
|
});
|
|
|
|
it('should do nothing if startEditing is called while already editing', () => {
|
|
const { state, startEditing } = useTestDefinitionForm();
|
|
state.value.name.isEditing = true;
|
|
state.value.name.tempValue = 'Original Name';
|
|
|
|
startEditing('name');
|
|
// Should remain unchanged because it was already editing
|
|
expect(state.value.name.isEditing).toBe(true);
|
|
expect(state.value.name.tempValue).toBe('Original Name');
|
|
});
|
|
|
|
it('should save changes to a field', () => {
|
|
const { state, startEditing, saveChanges } = useTestDefinitionForm();
|
|
|
|
// Name
|
|
startEditing('name');
|
|
state.value.name.tempValue = 'New Name';
|
|
saveChanges('name');
|
|
expect(state.value.name.isEditing).toBe(false);
|
|
expect(state.value.name.value).toBe('New Name');
|
|
|
|
// Tags
|
|
startEditing('tags');
|
|
state.value.tags.tempValue = ['123'];
|
|
saveChanges('tags');
|
|
expect(state.value.tags.isEditing).toBe(false);
|
|
expect(state.value.tags.value).toEqual(['123']);
|
|
});
|
|
|
|
it('should cancel editing a field', () => {
|
|
const { state, startEditing, cancelEditing } = useTestDefinitionForm();
|
|
|
|
const originalName = state.value.name.value;
|
|
startEditing('name');
|
|
state.value.name.tempValue = 'New Name';
|
|
cancelEditing('name');
|
|
expect(state.value.name.isEditing).toBe(false);
|
|
expect(state.value.name.tempValue).toBe(originalName);
|
|
|
|
const originalTags = [...state.value.tags.value];
|
|
startEditing('tags');
|
|
state.value.tags.tempValue = ['123'];
|
|
cancelEditing('tags');
|
|
expect(state.value.tags.isEditing).toBe(false);
|
|
expect(state.value.tags.tempValue).toEqual(originalTags);
|
|
});
|
|
|
|
it('should handle keydown - Escape', () => {
|
|
const { state, startEditing, handleKeydown } = useTestDefinitionForm();
|
|
|
|
startEditing('name');
|
|
handleKeydown(new KeyboardEvent('keydown', { key: 'Escape' }), 'name');
|
|
expect(state.value.name.isEditing).toBe(false);
|
|
|
|
startEditing('tags');
|
|
handleKeydown(new KeyboardEvent('keydown', { key: 'Escape' }), 'tags');
|
|
expect(state.value.tags.isEditing).toBe(false);
|
|
});
|
|
|
|
it('should handle keydown - Enter', () => {
|
|
const { state, startEditing, handleKeydown } = useTestDefinitionForm();
|
|
|
|
startEditing('name');
|
|
state.value.name.tempValue = 'New Name';
|
|
handleKeydown(new KeyboardEvent('keydown', { key: 'Enter' }), 'name');
|
|
expect(state.value.name.isEditing).toBe(false);
|
|
expect(state.value.name.value).toBe('New Name');
|
|
|
|
startEditing('tags');
|
|
state.value.tags.tempValue = ['123'];
|
|
handleKeydown(new KeyboardEvent('keydown', { key: 'Enter' }), 'tags');
|
|
expect(state.value.tags.isEditing).toBe(false);
|
|
expect(state.value.tags.value).toEqual(['123']);
|
|
});
|
|
|
|
it('should not save changes when shift+Enter is pressed', () => {
|
|
const { state, startEditing, handleKeydown } = useTestDefinitionForm();
|
|
|
|
startEditing('name');
|
|
state.value.name.tempValue = 'New Name With Shift';
|
|
handleKeydown(new KeyboardEvent('keydown', { key: 'Enter', shiftKey: true }), 'name');
|
|
expect(state.value.name.isEditing).toBe(true);
|
|
expect(state.value.name.value).not.toBe('New Name With Shift');
|
|
});
|
|
});
|