summaryrefslogtreecommitdiff
path: root/spec/frontend/pipelines/pipelines_ci_templates_spec.js
blob: 7064f7448ec414b5c99c5c2547e8e1bd4ed108a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
import '~/commons';
import { GlButton, GlSprintf } from '@gitlab/ui';
import { sprintf } from '~/locale';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { mockTracking } from 'helpers/tracking_helper';
import { stubExperiments } from 'helpers/experimentation_helper';
import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
import ExperimentTracking from '~/experimentation/experiment_tracking';
import PipelinesCiTemplate from '~/pipelines/components/pipelines_list/pipelines_ci_templates.vue';
import {
  RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME,
  RUNNERS_SETTINGS_LINK_CLICKED_EVENT,
  RUNNERS_DOCUMENTATION_LINK_CLICKED_EVENT,
  RUNNERS_SETTINGS_BUTTON_CLICKED_EVENT,
  I18N,
} from '~/pipeline_editor/constants';

const pipelineEditorPath = '/-/ci/editor';
const suggestedCiTemplates = [
  { name: 'Android', logo: '/assets/illustrations/logos/android.svg' },
  { name: 'Bash', logo: '/assets/illustrations/logos/bash.svg' },
  { name: 'C++', logo: '/assets/illustrations/logos/c_plus_plus.svg' },
];

jest.mock('~/experimentation/experiment_tracking');

describe('Pipelines CI Templates', () => {
  let wrapper;
  let trackingSpy;

  const createWrapper = (propsData = {}, stubs = {}) => {
    return shallowMountExtended(PipelinesCiTemplate, {
      provide: {
        pipelineEditorPath,
        suggestedCiTemplates,
      },
      propsData,
      stubs,
    });
  };

  const findTestTemplateLinks = () => wrapper.findAll('[data-testid="test-template-link"]');
  const findTemplateDescriptions = () => wrapper.findAll('[data-testid="template-description"]');
  const findTemplateLinks = () => wrapper.findAll('[data-testid="template-link"]');
  const findTemplateNames = () => wrapper.findAll('[data-testid="template-name"]');
  const findTemplateLogos = () => wrapper.findAll('[data-testid="template-logo"]');
  const findSettingsLink = () => wrapper.findByTestId('settings-link');
  const findDocumentationLink = () => wrapper.findByTestId('documentation-link');
  const findSettingsButton = () => wrapper.findByTestId('settings-button');

  afterEach(() => {
    wrapper.destroy();
    wrapper = null;
  });

  describe('renders test template', () => {
    beforeEach(() => {
      wrapper = createWrapper();
    });

    it('links to the getting started template', () => {
      expect(findTestTemplateLinks().at(0).attributes('href')).toBe(
        pipelineEditorPath.concat('?template=Getting-Started'),
      );
    });
  });

  describe('renders template list', () => {
    beforeEach(() => {
      wrapper = createWrapper();
    });

    it('renders all suggested templates', () => {
      const content = wrapper.text();

      expect(content).toContain('Android', 'Bash', 'C++');
    });

    it('has the correct template name', () => {
      expect(findTemplateNames().at(0).text()).toBe('Android');
    });

    it('links to the correct template', () => {
      expect(findTemplateLinks().at(0).attributes('href')).toBe(
        pipelineEditorPath.concat('?template=Android'),
      );
    });

    it('has the description of the template', () => {
      expect(findTemplateDescriptions().at(0).text()).toBe(
        sprintf(I18N.templates.description, { name: 'Android' }),
      );
    });

    it('has the right logo of the template', () => {
      expect(findTemplateLogos().at(0).attributes('src')).toBe(
        '/assets/illustrations/logos/android.svg',
      );
    });
  });

  describe('tracking', () => {
    beforeEach(() => {
      wrapper = createWrapper();
      trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
    });

    it('sends an event when template is clicked', () => {
      findTemplateLinks().at(0).vm.$emit('click');

      expect(trackingSpy).toHaveBeenCalledTimes(1);
      expect(trackingSpy).toHaveBeenCalledWith(undefined, 'template_clicked', {
        label: 'Android',
      });
    });

    it('sends an event when Getting-Started template is clicked', () => {
      findTestTemplateLinks().at(0).vm.$emit('click');

      expect(trackingSpy).toHaveBeenCalledTimes(1);
      expect(trackingSpy).toHaveBeenCalledWith(undefined, 'template_clicked', {
        label: 'Getting-Started',
      });
    });
  });

  describe('when the runners_availability_section experiment is active', () => {
    beforeEach(() => {
      stubExperiments({ runners_availability_section: 'candidate' });
    });

    describe('when runners are available', () => {
      beforeEach(() => {
        wrapper = createWrapper({ anyRunnersAvailable: true }, { GitlabExperiment, GlSprintf });
      });

      it('show the runners available section', () => {
        expect(wrapper.text()).toContain(I18N.runners.title);
      });

      it('tracks an event when clicking the settings link', () => {
        findSettingsLink().vm.$emit('click');

        expect(ExperimentTracking).toHaveBeenCalledWith(
          RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME,
        );
        expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith(
          RUNNERS_SETTINGS_LINK_CLICKED_EVENT,
        );
      });

      it('tracks an event when clicking the documentation link', () => {
        findDocumentationLink().vm.$emit('click');

        expect(ExperimentTracking).toHaveBeenCalledWith(
          RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME,
        );
        expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith(
          RUNNERS_DOCUMENTATION_LINK_CLICKED_EVENT,
        );
      });
    });

    describe('when runners are not available', () => {
      beforeEach(() => {
        wrapper = createWrapper({ anyRunnersAvailable: false }, { GitlabExperiment, GlButton });
      });

      it('show the no runners available section', () => {
        expect(wrapper.text()).toContain(I18N.noRunners.title);
      });

      it('tracks an event when clicking the settings button', () => {
        findSettingsButton().trigger('click');

        expect(ExperimentTracking).toHaveBeenCalledWith(
          RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME,
        );
        expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith(
          RUNNERS_SETTINGS_BUTTON_CLICKED_EVENT,
        );
      });
    });
  });

  describe.each`
    experimentVariant | anyRunnersAvailable | templatesRendered
    ${'control'}      | ${true}             | ${true}
    ${'control'}      | ${false}            | ${true}
    ${'candidate'}    | ${true}             | ${true}
    ${'candidate'}    | ${false}            | ${false}
  `(
    'when the runners_availability_section experiment variant is $experimentVariant and runners are available: $anyRunnersAvailable',
    ({ experimentVariant, anyRunnersAvailable, templatesRendered }) => {
      beforeEach(() => {
        stubExperiments({ runners_availability_section: experimentVariant });
        wrapper = createWrapper({ anyRunnersAvailable });
      });

      it(`renders the templates: ${templatesRendered}`, () => {
        expect(findTestTemplateLinks().exists()).toBe(templatesRendered);
        expect(findTemplateLinks().exists()).toBe(templatesRendered);
      });
    },
  );
});