summaryrefslogtreecommitdiff
path: root/spec/frontend/error_tracking_settings/components/app_spec.js
blob: 4a0bbb1acbebcfd60d4bb62101ed2ee7e897a840 (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
import { GlFormRadioGroup, GlFormRadio, GlFormInputGroup } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { TEST_HOST } from 'helpers/test_constants';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import ErrorTrackingSettings from '~/error_tracking_settings/components/app.vue';
import ErrorTrackingForm from '~/error_tracking_settings/components/error_tracking_form.vue';
import ProjectDropdown from '~/error_tracking_settings/components/project_dropdown.vue';
import createStore from '~/error_tracking_settings/store';

Vue.use(Vuex);

const TEST_GITLAB_DSN = 'https://gitlab.example.com/123456';

describe('error tracking settings app', () => {
  let store;
  let wrapper;

  const defaultProps = {
    initialEnabled: 'true',
    initialIntegrated: 'false',
    initialApiHost: TEST_HOST,
    initialToken: 'someToken',
    initialProject: null,
    listProjectsEndpoint: TEST_HOST,
    operationsSettingsEndpoint: TEST_HOST,
    gitlabDsn: TEST_GITLAB_DSN,
  };

  function mountComponent({
    glFeatures = { integratedErrorTracking: false },
    props = defaultProps,
  } = {}) {
    wrapper = extendedWrapper(
      shallowMount(ErrorTrackingSettings, {
        store, // Override the imported store
        propsData: { ...props },
        provide: {
          glFeatures,
        },
        stubs: {
          GlFormInputGroup, // we need this non-shallow to query for a component within a slot
        },
      }),
    );
  }

  const findBackendSettingsSection = () => wrapper.findByTestId('tracking-backend-settings');
  const findBackendSettingsRadioGroup = () =>
    findBackendSettingsSection().findComponent(GlFormRadioGroup);
  const findBackendSettingsRadioButtons = () =>
    findBackendSettingsRadioGroup().findAllComponents(GlFormRadio);
  const findElementWithText = (wrappers, text) => wrappers.filter((item) => item.text() === text);
  const findSentrySettings = () => wrapper.findByTestId('sentry-setting-form');
  const findDsnSettings = () => wrapper.findByTestId('gitlab-dsn-setting-form');
  const findEnabledCheckbox = () => wrapper.findByTestId('error-tracking-enabled');

  const enableGitLabErrorTracking = async () => {
    findBackendSettingsRadioGroup().vm.$emit('change', true);
    await nextTick();
  };

  beforeEach(() => {
    store = createStore();

    mountComponent();
  });

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

  describe('section', () => {
    it('renders the form and dropdown', () => {
      expect(wrapper.find(ErrorTrackingForm).exists()).toBeTruthy();
      expect(wrapper.find(ProjectDropdown).exists()).toBeTruthy();
    });

    it('renders the Save Changes button', () => {
      expect(wrapper.find('.js-error-tracking-button').exists()).toBeTruthy();
    });

    it('enables the button by default', () => {
      expect(wrapper.find('.js-error-tracking-button').attributes('disabled')).toBeFalsy();
    });

    it('disables the button when saving', async () => {
      store.state.settingsLoading = true;

      await nextTick();
      expect(wrapper.find('.js-error-tracking-button').attributes('disabled')).toBeTruthy();
    });
  });

  describe('tracking-backend settings', () => {
    it('does not contain backend settings section', () => {
      expect(findBackendSettingsSection().exists()).toBe(false);
    });

    it('shows the sentry form', () => {
      expect(findSentrySettings().exists()).toBe(true);
    });

    describe('enabled setting is true', () => {
      describe('integrated setting is true', () => {
        beforeEach(() => {
          mountComponent({
            props: { ...defaultProps, initialEnabled: 'true', initialIntegrated: 'true' },
          });
        });

        it('displays enabled as false', () => {
          expect(findEnabledCheckbox().attributes('checked')).toBeUndefined();
        });
      });

      describe('integrated setting is false', () => {
        beforeEach(() => {
          mountComponent({
            props: { ...defaultProps, initialEnabled: 'true', initialIntegrated: 'false' },
          });
        });

        it('displays enabled as true', () => {
          expect(findEnabledCheckbox().attributes('checked')).toBe('true');
        });
      });
    });

    describe('integrated_error_tracking feature flag enabled', () => {
      beforeEach(() => {
        mountComponent({
          glFeatures: { integratedErrorTracking: true },
        });
      });

      it('contains a form-group with the correct label', () => {
        expect(findBackendSettingsSection().attributes('label')).toBe('Error tracking backend');
      });

      it('contains a radio group', () => {
        expect(findBackendSettingsRadioGroup().exists()).toBe(true);
      });

      it('contains the correct radio buttons', () => {
        expect(findBackendSettingsRadioButtons()).toHaveLength(2);

        expect(findElementWithText(findBackendSettingsRadioButtons(), 'Sentry')).toHaveLength(1);
        expect(findElementWithText(findBackendSettingsRadioButtons(), 'GitLab')).toHaveLength(1);
      });

      it('hides the Sentry settings when GitLab is selected as a tracking-backend', async () => {
        expect(findSentrySettings().exists()).toBe(true);

        await enableGitLabErrorTracking();

        expect(findSentrySettings().exists()).toBe(false);
      });

      describe('GitLab DSN section', () => {
        it('is visible when GitLab is selected as a tracking-backend and DSN is present', async () => {
          expect(findDsnSettings().exists()).toBe(false);

          await enableGitLabErrorTracking();

          expect(findDsnSettings().exists()).toBe(true);
        });

        it('contains copy-to-clipboard functionality for the GitLab DSN string', async () => {
          await enableGitLabErrorTracking();

          const clipBoardInput = findDsnSettings().findComponent(GlFormInputGroup);
          const clipBoardButton = findDsnSettings().findComponent(ClipboardButton);

          expect(clipBoardInput.props('value')).toBe(TEST_GITLAB_DSN);
          expect(clipBoardInput.attributes('readonly')).toBeTruthy();
          expect(clipBoardButton.props('text')).toBe(TEST_GITLAB_DSN);
        });
      });

      it.each([true, false])(
        'calls the `updateIntegrated` action when the setting changes to `%s`',
        (integrated) => {
          jest.spyOn(store, 'dispatch').mockImplementation();

          expect(store.dispatch).toHaveBeenCalledTimes(0);

          findBackendSettingsRadioGroup().vm.$emit('change', integrated);

          expect(store.dispatch).toHaveBeenCalledTimes(1);
          expect(store.dispatch).toHaveBeenCalledWith('updateIntegrated', integrated);
        },
      );
    });
  });
});