mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
140 lines
5 KiB
TypeScript
140 lines
5 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { createComponentRenderer } from '@/__tests__/render';
|
|
import MetricsInput from '../EditDefinition/MetricsInput.vue';
|
|
import userEvent from '@testing-library/user-event';
|
|
|
|
const renderComponent = createComponentRenderer(MetricsInput);
|
|
|
|
describe('MetricsInput', () => {
|
|
let props: { modelValue: Array<{ name: string }> };
|
|
|
|
beforeEach(() => {
|
|
props = {
|
|
modelValue: [{ name: 'Metric 1' }, { name: 'Metric 2' }],
|
|
};
|
|
});
|
|
|
|
it('should render correctly with initial metrics', () => {
|
|
const { getAllByPlaceholderText } = renderComponent({ props });
|
|
const inputs = getAllByPlaceholderText('Enter metric name');
|
|
expect(inputs).toHaveLength(2);
|
|
expect(inputs[0]).toHaveValue('Metric 1');
|
|
expect(inputs[1]).toHaveValue('Metric 2');
|
|
});
|
|
|
|
it('should update a metric when typing in the input', async () => {
|
|
const { getAllByPlaceholderText, emitted } = renderComponent({
|
|
props: {
|
|
modelValue: [{ name: '' }],
|
|
},
|
|
});
|
|
const inputs = getAllByPlaceholderText('Enter metric name');
|
|
await userEvent.type(inputs[0], 'Updated Metric 1');
|
|
|
|
// Every character typed triggers an update event. Let's check the last emission.
|
|
const allEmits = emitted('update:modelValue');
|
|
expect(allEmits).toBeTruthy();
|
|
// The last emission should contain the fully updated name
|
|
const lastEmission = allEmits[allEmits.length - 1];
|
|
expect(lastEmission).toEqual([[{ name: 'Updated Metric 1' }]]);
|
|
});
|
|
|
|
it('should render correctly with no initial metrics', () => {
|
|
props.modelValue = [];
|
|
const { queryAllByRole, getByText } = renderComponent({ props });
|
|
const inputs = queryAllByRole('textbox');
|
|
expect(inputs).toHaveLength(0);
|
|
expect(getByText('New metric')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should handle adding multiple metrics', async () => {
|
|
const { getByText, emitted } = renderComponent({ props });
|
|
const addButton = getByText('New metric');
|
|
|
|
await userEvent.click(addButton);
|
|
await userEvent.click(addButton);
|
|
await userEvent.click(addButton);
|
|
|
|
// Each click adds a new metric
|
|
const updateEvents = emitted('update:modelValue');
|
|
expect(updateEvents).toHaveLength(3);
|
|
|
|
// Check the structure of one of the emissions
|
|
// Initial: [{ name: 'Metric 1' }, { name: 'Metric 2' }]
|
|
// After first click: [{ name: 'Metric 1' }, { name: 'Metric 2' }, { name: '' }]
|
|
expect(updateEvents[0]).toEqual([[{ name: 'Metric 1' }, { name: 'Metric 2' }, { name: '' }]]);
|
|
});
|
|
|
|
it('should emit "deleteMetric" event when a delete button is clicked', async () => {
|
|
const { getAllByRole, emitted } = renderComponent({ props });
|
|
|
|
// Each metric row has a delete button, identified by "button"
|
|
const deleteButtons = getAllByRole('button', { name: '' });
|
|
expect(deleteButtons).toHaveLength(props.modelValue.length);
|
|
|
|
// Click on the delete button for the second metric
|
|
await userEvent.click(deleteButtons[1]);
|
|
|
|
expect(emitted('deleteMetric')).toBeTruthy();
|
|
expect(emitted('deleteMetric')[0]).toEqual([{ name: 'Metric 2' }]);
|
|
});
|
|
|
|
it('should emit multiple update events as the user types and reflect the final name correctly', async () => {
|
|
const { getAllByPlaceholderText, emitted } = renderComponent({
|
|
props: {
|
|
modelValue: [{ name: '' }],
|
|
},
|
|
});
|
|
const inputs = getAllByPlaceholderText('Enter metric name');
|
|
await userEvent.type(inputs[0], 'ABC');
|
|
|
|
const allEmits = emitted('update:modelValue');
|
|
expect(allEmits).toBeTruthy();
|
|
// Each character typed should emit a new value
|
|
expect(allEmits.length).toBe(3);
|
|
expect(allEmits[2]).toEqual([[{ name: 'ABC' }]]);
|
|
});
|
|
|
|
it('should not break if metrics are empty and still allow adding a new metric', async () => {
|
|
props.modelValue = [];
|
|
const { queryAllByRole, getByText, emitted } = renderComponent({ props });
|
|
|
|
// No metrics initially
|
|
const inputs = queryAllByRole('textbox');
|
|
expect(inputs).toHaveLength(0);
|
|
|
|
const addButton = getByText('New metric');
|
|
await userEvent.click(addButton);
|
|
|
|
const updates = emitted('update:modelValue');
|
|
expect(updates).toBeTruthy();
|
|
expect(updates[0]).toEqual([[{ name: '' }]]);
|
|
|
|
// After adding one metric, we should now have an input
|
|
const { getAllByPlaceholderText } = renderComponent({
|
|
props: { modelValue: [{ name: '' }] },
|
|
});
|
|
const updatedInputs = getAllByPlaceholderText('Enter metric name');
|
|
expect(updatedInputs).toHaveLength(1);
|
|
});
|
|
|
|
it('should handle deleting the first metric and still display remaining metrics correctly', async () => {
|
|
const { getAllByPlaceholderText, getAllByRole, rerender, emitted } = renderComponent({
|
|
props,
|
|
});
|
|
const inputs = getAllByPlaceholderText('Enter metric name');
|
|
expect(inputs).toHaveLength(2);
|
|
|
|
const deleteButtons = getAllByRole('button', { name: '' });
|
|
await userEvent.click(deleteButtons[0]);
|
|
|
|
expect(emitted('deleteMetric')).toBeTruthy();
|
|
expect(emitted('deleteMetric')[0]).toEqual([{ name: 'Metric 1' }]);
|
|
|
|
await rerender({ modelValue: [{ name: 'Metric 2' }] });
|
|
const updatedInputs = getAllByPlaceholderText('Enter metric name');
|
|
expect(updatedInputs).toHaveLength(1);
|
|
expect(updatedInputs[0]).toHaveValue('Metric 2');
|
|
});
|
|
});
|