Commit 6b3867a3 authored by anna_vovchenko's avatar anna_vovchenko Committed by Anna Vovchenko

Added tracking events for the validation errors

To collect the metrics on ci variables creation
we are adding tracking events
for the validation errors in the ci_variable modal

Changelog: added
parent 78226340
......@@ -17,6 +17,7 @@ import {
import Cookies from 'js-cookie';
import { mapActions, mapState } from 'vuex';
import { __ } from '~/locale';
import Tracking from '~/tracking';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { mapComputed } from '~/vuex_shared/bindings';
import {
......@@ -25,10 +26,14 @@ import {
AWS_TIP_DISMISSED_COOKIE_NAME,
AWS_TIP_MESSAGE,
CONTAINS_VARIABLE_REFERENCE_MESSAGE,
EVENT_LABEL,
EVENT_ACTION,
} from '../constants';
import CiEnvironmentsDropdown from './ci_environments_dropdown.vue';
import { awsTokens, awsTokenList } from './ci_variable_autocomplete_tokens';
const trackingMixin = Tracking.mixin({ label: EVENT_LABEL });
export default {
modalId: ADD_CI_VARIABLE_MODAL_ID,
tokens: awsTokens,
......@@ -51,10 +56,14 @@ export default {
GlModal,
GlSprintf,
},
mixins: [glFeatureFlagsMixin()],
mixins: [glFeatureFlagsMixin(), trackingMixin],
data() {
return {
isTipDismissed: Cookies.get(AWS_TIP_DISMISSED_COOKIE_NAME) === 'true',
isValidationErrorEventSent: {
displaysMaskedError: false,
displaysVariableReferenceError: false,
},
};
},
computed: {
......@@ -147,6 +156,15 @@ export default {
return this.variable.secret_value === '' || (this.tokenValidationState && this.maskedState);
},
},
watch: {
variable: {
handler() {
this.trackVariableValidationErrors();
},
deep: true,
immediate: true,
},
},
methods: {
...mapActions([
'addVariable',
......@@ -179,6 +197,7 @@ export default {
this.clearModal();
this.resetSelectedEnvironment();
this.resetValidationErrorEvents();
},
updateOrAddVariable() {
if (this.variableBeingEdited) {
......@@ -193,6 +212,25 @@ export default {
this.setVariableProtected();
}
},
trackVariableValidationErrors() {
if (this.displayMaskedError && !this.isValidationErrorEventSent.displaysMaskedError) {
this.track(EVENT_ACTION, { property: 'displaysMaskedError' });
this.isValidationErrorEventSent.displaysMaskedError = true;
}
if (
this.containsVariableReference &&
!this.isValidationErrorEventSent.displaysVariableReferenceError
) {
this.track(EVENT_ACTION, { property: 'displaysVariableReferenceError' });
this.isValidationErrorEventSent.displaysVariableReferenceError = true;
}
},
resetValidationErrorEvents() {
this.isValidationErrorEventSent = {
displaysMaskedError: false,
displaysVariableReferenceError: false,
};
},
},
};
</script>
......
......@@ -19,6 +19,9 @@ export const AWS_TIP_MESSAGE = __(
'%{deployLinkStart}Use a template to deploy to ECS%{deployLinkEnd}, or use a docker image to %{commandsLinkStart}run AWS commands in GitLab CI/CD%{commandsLinkEnd}.',
);
export const EVENT_LABEL = 'ci_variable_modal';
export const EVENT_ACTION = 'validation_error';
// AWS TOKEN CONSTANTS
export const AWS_ACCESS_KEY_ID = 'AWS_ACCESS_KEY_ID';
export const AWS_DEFAULT_REGION = 'AWS_DEFAULT_REGION';
......
import { GlButton, GlFormInput } from '@gitlab/ui';
import { createLocalVue, shallowMount, mount } from '@vue/test-utils';
import Vuex from 'vuex';
import { mockTracking } from 'helpers/tracking_helper';
import CiEnvironmentsDropdown from '~/ci_variable_list/components/ci_environments_dropdown.vue';
import CiVariableModal from '~/ci_variable_list/components/ci_variable_modal.vue';
import { AWS_ACCESS_KEY_ID } from '~/ci_variable_list/constants';
import { AWS_ACCESS_KEY_ID, EVENT_LABEL, EVENT_ACTION } from '~/ci_variable_list/constants';
import createStore from '~/ci_variable_list/store';
import mockData from '../services/mock_data';
import ModalStub from '../stubs';
......@@ -14,6 +15,7 @@ localVue.use(Vuex);
describe('Ci variable modal', () => {
let wrapper;
let store;
let trackingSpy;
const createComponent = (method, options = {}) => {
store = createStore({ isGroup: options.isGroup });
......@@ -124,10 +126,10 @@ describe('Ci variable modal', () => {
});
describe.each`
value | secret | rendered
${'value'} | ${'secret_value'} | ${false}
${'dollar$ign'} | ${'dollar$ign'} | ${true}
`('Adding a new variable', ({ value, secret, rendered }) => {
value | secret | rendered | event_sent
${'value'} | ${'secret_value'} | ${false} | ${0}
${'dollar$ign'} | ${'dollar$ign'} | ${true} | ${1}
`('Adding a new variable', ({ value, secret, rendered, event_sent }) => {
beforeEach(() => {
const [variable] = mockData.mockVariables;
const invalidKeyVariable = {
......@@ -138,12 +140,17 @@ describe('Ci variable modal', () => {
};
createComponent(mount);
store.state.variable = invalidKeyVariable;
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
});
it(`${rendered ? 'renders' : 'does not render'} the variable reference warning`, () => {
const warning = wrapper.find(`[data-testid='contains-variable-reference']`);
expect(warning.exists()).toBe(rendered);
});
it(`${rendered ? 'sends' : 'does not send'} the variable reference tracking event`, () => {
expect(trackingSpy).toHaveBeenCalledTimes(event_sent);
});
});
describe('Editing a variable', () => {
......@@ -226,6 +233,7 @@ describe('Ci variable modal', () => {
};
createComponent(mount);
store.state.variable = invalidMaskVariable;
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
});
it('disables the submit button', () => {
......@@ -235,6 +243,13 @@ describe('Ci variable modal', () => {
it('shows the correct error text', () => {
expect(findModal().text()).toContain(maskError);
});
it('sends the correct tracking event', () => {
expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTION, {
label: EVENT_LABEL,
property: 'displaysMaskedError',
});
});
});
describe('when both states are valid', () => {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment