333 lines
9.1 KiB
JavaScript
333 lines
9.1 KiB
JavaScript
import { mount } from '@vue/test-utils';
|
|
import MockAdapter from 'axios-mock-adapter';
|
|
import { TEST_HOST } from 'helpers/test_constants';
|
|
import waitForPromises from 'helpers/wait_for_promises';
|
|
import CustomMetricsFormFields from '~/custom_metrics/components/custom_metrics_form_fields.vue';
|
|
import axios from '~/lib/utils/axios_utils';
|
|
|
|
const { CancelToken } = axios;
|
|
|
|
describe('custom metrics form fields component', () => {
|
|
let component;
|
|
let mockAxios;
|
|
|
|
const getNamedInput = name => component.element.querySelector(`input[name="${name}"]`);
|
|
const validateQueryPath = `${TEST_HOST}/mock/path`;
|
|
const validQueryResponse = { data: { success: true, query: { valid: true, error: '' } } };
|
|
const csrfToken = 'mockToken';
|
|
const formOperation = 'post';
|
|
const debouncedValidateQueryMock = jest.fn();
|
|
const makeFormData = (data = {}) => ({
|
|
formData: {
|
|
title: '',
|
|
yLabel: '',
|
|
query: '',
|
|
unit: '',
|
|
group: '',
|
|
legend: '',
|
|
...data,
|
|
},
|
|
});
|
|
const mountComponent = (props, methods = {}) => {
|
|
component = mount(CustomMetricsFormFields, {
|
|
propsData: {
|
|
formOperation,
|
|
validateQueryPath,
|
|
...props,
|
|
},
|
|
csrfToken,
|
|
methods,
|
|
});
|
|
};
|
|
|
|
beforeEach(() => {
|
|
mockAxios = new MockAdapter(axios);
|
|
mockAxios.onPost(validateQueryPath).reply(validQueryResponse);
|
|
});
|
|
|
|
afterEach(() => {
|
|
component.destroy();
|
|
mockAxios.restore();
|
|
});
|
|
|
|
it('checks form validity', done => {
|
|
mountComponent({
|
|
metricPersisted: true,
|
|
...makeFormData({
|
|
title: 'title',
|
|
yLabel: 'yLabel',
|
|
unit: 'unit',
|
|
group: 'group',
|
|
}),
|
|
});
|
|
|
|
component.vm.$nextTick(() => {
|
|
expect(component.vm.formIsValid).toBe(false);
|
|
done();
|
|
});
|
|
});
|
|
|
|
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]';
|
|
beforeEach(() => {
|
|
mockAxios.onPost(validateQueryPath).reply(validQueryResponse);
|
|
});
|
|
|
|
it('is empty by default', () => {
|
|
mountComponent();
|
|
|
|
expect(getNamedInput(queryInputName).value).toBe('');
|
|
});
|
|
|
|
it('receives and validates a persisted value', () => {
|
|
const query = 'persistedQuery';
|
|
const axiosPost = jest.spyOn(axios, 'post');
|
|
const source = CancelToken.source();
|
|
mountComponent({ metricPersisted: true, ...makeFormData({ query }) });
|
|
|
|
expect(axiosPost).toHaveBeenCalledWith(
|
|
validateQueryPath,
|
|
{ query },
|
|
{ cancelToken: source.token },
|
|
);
|
|
expect(getNamedInput(queryInputName).value).toBe(query);
|
|
jest.runAllTimers();
|
|
});
|
|
|
|
it('checks validity on user input', () => {
|
|
const query = 'changedQuery';
|
|
mountComponent(
|
|
{},
|
|
{
|
|
debouncedValidateQuery: debouncedValidateQueryMock,
|
|
},
|
|
);
|
|
const queryInput = component.find(`input[name="${queryInputName}"]`);
|
|
queryInput.setValue(query);
|
|
queryInput.trigger('input');
|
|
|
|
expect(debouncedValidateQueryMock).toHaveBeenCalledWith(query);
|
|
});
|
|
|
|
describe('when query validation is in flight', () => {
|
|
beforeEach(() => {
|
|
mountComponent(
|
|
{ metricPersisted: true, ...makeFormData({ query: 'validQuery' }) },
|
|
{
|
|
requestValidation: jest.fn().mockImplementation(
|
|
() =>
|
|
new Promise(resolve =>
|
|
setTimeout(() => {
|
|
resolve(validQueryResponse);
|
|
}, 4000),
|
|
),
|
|
),
|
|
},
|
|
);
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.clearAllTimers();
|
|
});
|
|
|
|
it('expect queryValidateInFlight is in flight', done => {
|
|
const queryInput = component.find(`input[name="${queryInputName}"]`);
|
|
queryInput.setValue('query');
|
|
queryInput.trigger('input');
|
|
|
|
component.vm.$nextTick(() => {
|
|
expect(component.vm.queryValidateInFlight).toBe(true);
|
|
jest.runOnlyPendingTimers();
|
|
waitForPromises()
|
|
.then(() => {
|
|
component.vm.$nextTick(() => {
|
|
expect(component.vm.queryValidateInFlight).toBe(false);
|
|
expect(component.vm.queryIsValid).toBe(true);
|
|
done();
|
|
});
|
|
})
|
|
.catch(done.fail);
|
|
});
|
|
});
|
|
|
|
it('expect loading message to display', done => {
|
|
const queryInput = component.find(`input[name="${queryInputName}"]`);
|
|
queryInput.setValue('query');
|
|
queryInput.trigger('input');
|
|
component.vm.$nextTick(() => {
|
|
expect(component.text()).toContain('Validating query');
|
|
jest.runOnlyPendingTimers();
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('expect loading message to disappear', done => {
|
|
const queryInput = component.find(`input[name="${queryInputName}"]`);
|
|
queryInput.setValue('query');
|
|
queryInput.trigger('input');
|
|
component.vm.$nextTick(() => {
|
|
jest.runOnlyPendingTimers();
|
|
waitForPromises()
|
|
.then(() => {
|
|
component.vm.$nextTick(() => {
|
|
expect(component.vm.queryValidateInFlight).toBe(false);
|
|
expect(component.vm.queryIsValid).toBe(true);
|
|
expect(component.vm.errorMessage).toBe('');
|
|
done();
|
|
});
|
|
})
|
|
.catch(done.fail);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when query is invalid', () => {
|
|
const errorMessage = 'mockErrorMessage';
|
|
const invalidQueryResponse = {
|
|
data: { success: true, query: { valid: false, error: errorMessage } },
|
|
};
|
|
|
|
beforeEach(() => {
|
|
mountComponent(
|
|
{ metricPersisted: true, ...makeFormData({ query: 'invalidQuery' }) },
|
|
{
|
|
requestValidation: jest
|
|
.fn()
|
|
.mockImplementation(() => Promise.resolve(invalidQueryResponse)),
|
|
},
|
|
);
|
|
});
|
|
|
|
it('sets queryIsValid to false', done => {
|
|
component.vm.$nextTick(() => {
|
|
expect(component.vm.queryValidateInFlight).toBe(false);
|
|
expect(component.vm.queryIsValid).toBe(false);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('shows invalid query message', done => {
|
|
component.vm.$nextTick(() => {
|
|
expect(component.text()).toContain(errorMessage);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when query is valid', () => {
|
|
beforeEach(() => {
|
|
mountComponent(
|
|
{ metricPersisted: true, ...makeFormData({ query: 'validQuery' }) },
|
|
{
|
|
requestValidation: jest
|
|
.fn()
|
|
.mockImplementation(() => Promise.resolve(validQueryResponse)),
|
|
},
|
|
);
|
|
});
|
|
|
|
it('sets queryIsValid to true when query is valid', done => {
|
|
component.vm.$nextTick(() => {
|
|
expect(component.vm.queryIsValid).toBe(true);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('shows valid query message', () => {
|
|
expect(component.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);
|
|
});
|
|
});
|
|
});
|