gitlab-org--gitlab-foss/spec/frontend/custom_metrics/components/custom_metrics_form_fields_...

246 lines
6.7 KiB
JavaScript

import { nextTick } from 'vue';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants';
import CustomMetricsFormFields from '~/custom_metrics/components/custom_metrics_form_fields.vue';
import axios from '~/lib/utils/axios_utils';
describe('custom metrics form fields component', () => {
let wrapper;
let mockAxios;
const getNamedInput = (name) => wrapper.element.querySelector(`input[name="${name}"]`);
const validateQueryPath = `${TEST_HOST}/mock/path`;
const validQueryResponse = { success: true, query: { valid: true, error: '' } };
const csrfToken = 'mockToken';
const formOperation = 'post';
const makeFormData = (data = {}) => ({
formData: {
title: '',
yLabel: '',
query: '',
unit: '',
group: '',
legend: '',
...data,
},
});
const mountComponent = (props) => {
wrapper = mount(CustomMetricsFormFields, {
propsData: {
formOperation,
validateQueryPath,
...props,
},
csrfToken,
});
};
beforeEach(() => {
mockAxios = new MockAdapter(axios);
});
afterEach(() => {
wrapper.destroy();
mockAxios.restore();
});
it('checks form validity', async () => {
mockAxios.onPost(validateQueryPath).reply(200, validQueryResponse);
mountComponent({
metricPersisted: true,
...makeFormData({
title: 'title-old',
yLabel: 'yLabel',
unit: 'unit',
group: 'group',
}),
});
wrapper.find(`input[name="prometheus_metric[query]"]`).setValue('query');
await axios.waitForAll();
expect(wrapper.emitted('formValidation')).toStrictEqual([[true]]);
});
describe('hidden inputs', () => {
beforeEach(() => {
mountComponent();
});
it('specifies form operation _method', () => {
expect(getNamedInput('_method', 'input').value).toBe('post');
});
it('specifies authenticity token', () => {
expect(getNamedInput('authenticity_token', 'input').value).toBe(csrfToken);
});
});
describe('name input', () => {
const name = 'prometheus_metric[title]';
it('is empty by default', () => {
mountComponent();
expect(getNamedInput(name).value).toBe('');
});
it('receives a persisted value', () => {
const title = 'mockTitle';
mountComponent(makeFormData({ title }));
expect(getNamedInput(name).value).toBe(title);
});
});
describe('group input', () => {
it('has a default value', () => {
mountComponent();
expect(getNamedInput('prometheus_metric[group]', 'glformradiogroup-stub').value).toBe(
'business',
);
});
});
describe('query input', () => {
const queryInputName = 'prometheus_metric[query]';
it('is empty by default', () => {
mountComponent();
expect(getNamedInput(queryInputName).value).toBe('');
});
it('receives and validates a persisted value', () => {
const query = 'persistedQuery';
jest.spyOn(axios, 'post');
mountComponent({ metricPersisted: true, ...makeFormData({ query }) });
expect(axios.post).toHaveBeenCalledWith(
validateQueryPath,
{ query },
expect.objectContaining({ cancelToken: expect.anything() }),
);
expect(getNamedInput(queryInputName).value).toBe(query);
jest.runAllTimers();
});
it('checks validity on user input', async () => {
const query = 'changedQuery';
mountComponent();
expect(mockAxios.history.post).toHaveLength(0);
const queryInput = wrapper.find(`input[name="${queryInputName}"]`);
queryInput.setValue(query);
await axios.waitForAll();
expect(mockAxios.history.post).toHaveLength(1);
});
describe('when query validation is in flight', () => {
beforeEach(() => {
mountComponent({ metricPersisted: true, ...makeFormData({ query: 'validQuery' }) });
mockAxios.onPost(validateQueryPath).reply(200, validQueryResponse);
});
it('expect loading message to display', async () => {
const queryInput = wrapper.find(`input[name="${queryInputName}"]`);
queryInput.setValue('query');
await nextTick();
expect(wrapper.text()).toContain('Validating query');
});
it('expect loading message to disappear', async () => {
const queryInput = wrapper.find(`input[name="${queryInputName}"]`);
queryInput.setValue('query');
await axios.waitForAll();
expect(wrapper.text()).not.toContain('Validating query');
});
});
describe('when query is invalid', () => {
const errorMessage = 'mockErrorMessage';
const invalidQueryResponse = { success: true, query: { valid: false, error: errorMessage } };
beforeEach(() => {
mockAxios.onPost(validateQueryPath).reply(200, invalidQueryResponse);
mountComponent({ metricPersisted: true, ...makeFormData({ query: 'invalidQuery' }) });
return axios.waitForAll();
});
it('shows invalid query message', async () => {
expect(wrapper.text()).toContain(errorMessage);
});
});
describe('when query is valid', () => {
beforeEach(() => {
mockAxios.onPost(validateQueryPath).reply(200, validQueryResponse);
mountComponent({ metricPersisted: true, ...makeFormData({ query: 'validQuery' }) });
});
it('shows valid query message', async () => {
await axios.waitForAll();
expect(wrapper.text()).toContain('PromQL query is valid');
});
});
});
describe('yLabel input', () => {
const name = 'prometheus_metric[y_label]';
it('is empty by default', () => {
mountComponent();
expect(getNamedInput(name).value).toBe('');
});
it('receives a persisted value', () => {
const yLabel = 'mockYLabel';
mountComponent(makeFormData({ yLabel }));
expect(getNamedInput(name).value).toBe(yLabel);
});
});
describe('unit input', () => {
const name = 'prometheus_metric[unit]';
it('is empty by default', () => {
mountComponent();
expect(getNamedInput(name).value).toBe('');
});
it('receives a persisted value', () => {
const unit = 'mockUnit';
mountComponent(makeFormData({ unit }));
expect(getNamedInput(name).value).toBe(unit);
});
});
describe('legend input', () => {
const name = 'prometheus_metric[legend]';
it('is empty by default', () => {
mountComponent();
expect(getNamedInput(name).value).toBe('');
});
it('receives a persisted value', () => {
const legend = 'mockLegend';
mountComponent(makeFormData({ legend }));
expect(getNamedInput(name).value).toBe(legend);
});
});
});