summaryrefslogtreecommitdiff
path: root/spec/frontend/security_configuration/components/training_provider_list_spec.js
blob: 578248e696f27e069dade1a1600a4144f5021979 (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
import { GlAlert, GlLink, GlToggle, GlCard, GlSkeletonLoader } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue';
import configureSecurityTrainingProvidersMutation from '~/security_configuration/graphql/configure_security_training_providers.mutation.graphql';
import waitForPromises from 'helpers/wait_for_promises';
import {
  securityTrainingProviders,
  createMockResolvers,
  testProjectPath,
  textProviderIds,
} from '../mock_data';

Vue.use(VueApollo);

describe('TrainingProviderList component', () => {
  let wrapper;
  let apolloProvider;

  const createApolloProvider = ({ resolvers } = {}) => {
    apolloProvider = createMockApollo([], createMockResolvers({ resolvers }));
  };

  const createComponent = () => {
    wrapper = shallowMount(TrainingProviderList, {
      provide: {
        projectPath: testProjectPath,
      },
      apolloProvider,
    });
  };

  const waitForQueryToBeLoaded = () => waitForPromises();
  const waitForMutationToBeLoaded = waitForQueryToBeLoaded;

  const findCards = () => wrapper.findAllComponents(GlCard);
  const findLinks = () => wrapper.findAllComponents(GlLink);
  const findToggles = () => wrapper.findAllComponents(GlToggle);
  const findFirstToggle = () => findToggles().at(0);
  const findLoader = () => wrapper.findComponent(GlSkeletonLoader);
  const findErrorAlert = () => wrapper.findComponent(GlAlert);

  const toggleFirstProvider = () => findFirstToggle().vm.$emit('change');

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

  describe('with a successful response', () => {
    beforeEach(() => {
      createApolloProvider();
      createComponent();
    });

    describe('when loading', () => {
      it('shows the loader', () => {
        expect(findLoader().exists()).toBe(true);
      });

      it('does not show the cards', () => {
        expect(findCards().exists()).toBe(false);
      });
    });

    describe('basic structure', () => {
      beforeEach(async () => {
        await waitForQueryToBeLoaded();
      });

      it('renders correct amount of cards', () => {
        expect(findCards()).toHaveLength(securityTrainingProviders.length);
      });

      securityTrainingProviders.forEach(({ name, description, url, isEnabled }, index) => {
        it(`shows the name for card ${index}`, () => {
          expect(findCards().at(index).text()).toContain(name);
        });

        it(`shows the description for card ${index}`, () => {
          expect(findCards().at(index).text()).toContain(description);
        });

        it(`shows the learn more link for card ${index}`, () => {
          expect(findLinks().at(index).attributes()).toEqual({
            target: '_blank',
            href: url,
          });
        });

        it(`shows the toggle with the correct value for card ${index}`, () => {
          expect(findToggles().at(index).props('value')).toEqual(isEnabled);
        });

        it('does not show loader when query is populated', () => {
          expect(findLoader().exists()).toBe(false);
        });
      });
    });

    describe('storing training provider settings', () => {
      beforeEach(async () => {
        jest.spyOn(apolloProvider.defaultClient, 'mutate');

        await waitForMutationToBeLoaded();

        toggleFirstProvider();
      });

      it.each`
        loading  | wait     | desc
        ${true}  | ${false} | ${'enables loading of GlToggle when mutation is called'}
        ${false} | ${true}  | ${'disables loading of GlToggle when mutation is complete'}
      `('$desc', async ({ loading, wait }) => {
        if (wait) {
          await waitForMutationToBeLoaded();
        }
        expect(findFirstToggle().props('isLoading')).toBe(loading);
      });

      it('calls mutation when toggle is changed', () => {
        expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledWith(
          expect.objectContaining({
            mutation: configureSecurityTrainingProvidersMutation,
            variables: { input: { enabledProviders: textProviderIds, fullPath: testProjectPath } },
          }),
        );
      });
    });
  });

  describe('with errors', () => {
    const expectErrorAlertToExist = () => {
      expect(findErrorAlert().props()).toMatchObject({
        dismissible: false,
        variant: 'danger',
      });
    };

    describe('when fetching training providers', () => {
      beforeEach(async () => {
        createApolloProvider({
          resolvers: {
            Query: {
              securityTrainingProviders: jest.fn().mockReturnValue(new Error()),
            },
          },
        });
        createComponent();

        await waitForQueryToBeLoaded();
      });

      it('shows an non-dismissible error alert', () => {
        expectErrorAlertToExist();
      });

      it('shows an error description', () => {
        expect(findErrorAlert().text()).toBe(TrainingProviderList.i18n.providerQueryErrorMessage);
      });
    });

    describe('when storing training provider configurations', () => {
      beforeEach(async () => {
        createApolloProvider({
          resolvers: {
            Mutation: {
              configureSecurityTrainingProviders: () => ({
                errors: ['something went wrong!'],
                securityTrainingProviders: [],
              }),
            },
          },
        });
        createComponent();

        await waitForQueryToBeLoaded();
        toggleFirstProvider();
        await waitForMutationToBeLoaded();
      });

      it('shows an non-dismissible error alert', () => {
        expectErrorAlertToExist();
      });

      it('shows an error description', () => {
        expect(findErrorAlert().text()).toBe(TrainingProviderList.i18n.configMutationErrorMessage);
      });
    });
  });
});