clusters_bundle_spec.js 11.8 KB
Newer Older
1
import Clusters from '~/clusters/clusters_bundle';
2
import { APPLICATION_STATUS, INGRESS_DOMAIN_SUFFIX } from '~/clusters/constants';
3 4 5 6 7
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { loadHTMLFixture } from 'helpers/fixtures';
import { setTestTimeout } from 'helpers/timeout';
import $ from 'jquery';
8

9
const { INSTALLING, INSTALLABLE, INSTALLED } = APPLICATION_STATUS;
10

11
describe('Clusters', () => {
12
  setTestTimeout(1000);
13

14
  let cluster;
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
  let mock;

  const mockGetClusterStatusRequest = () => {
    const { statusPath } = document.querySelector('.js-edit-cluster-form').dataset;

    mock = new MockAdapter(axios);

    mock.onGet(statusPath).reply(200);
  };

  beforeEach(() => {
    loadHTMLFixture('clusters/show_cluster.html');
  });

  beforeEach(() => {
    mockGetClusterStatusRequest();
  });
32 33 34 35 36 37 38

  beforeEach(() => {
    cluster = new Clusters();
  });

  afterEach(() => {
    cluster.destroy();
39
    mock.restore();
40 41 42
  });

  describe('toggle', () => {
Mike Greiling's avatar
Mike Greiling committed
43 44 45 46 47 48 49
    it('should update the button and the input field on click', done => {
      const toggleButton = document.querySelector(
        '.js-cluster-enable-toggle-area .js-project-feature-toggle',
      );
      const toggleInput = document.querySelector(
        '.js-cluster-enable-toggle-area .js-project-feature-toggle-input',
      );
50

51 52 53 54 55
      $(toggleInput).one('trigger-change', () => {
        expect(toggleButton.classList).not.toContain('is-checked');
        expect(toggleInput.getAttribute('value')).toEqual('false');
        done();
      });
56

57
      toggleButton.click();
58 59 60
    });
  });

Filipa Lacerda's avatar
Filipa Lacerda committed
61
  describe('showToken', () => {
62
    it('should update token field type', () => {
Filipa Lacerda's avatar
Filipa Lacerda committed
63
      cluster.showTokenButton.click();
64

Mike Greiling's avatar
Mike Greiling committed
65
      expect(cluster.tokenField.getAttribute('type')).toEqual('text');
Filipa Lacerda's avatar
Filipa Lacerda committed
66 67

      cluster.showTokenButton.click();
68

Mike Greiling's avatar
Mike Greiling committed
69
      expect(cluster.tokenField.getAttribute('type')).toEqual('password');
Filipa Lacerda's avatar
Filipa Lacerda committed
70
    });
71 72 73 74

    it('should update show token button text', () => {
      cluster.showTokenButton.click();

Mike Greiling's avatar
Mike Greiling committed
75
      expect(cluster.showTokenButton.textContent).toEqual('Hide');
76 77 78

      cluster.showTokenButton.click();

Mike Greiling's avatar
Mike Greiling committed
79
      expect(cluster.showTokenButton.textContent).toEqual('Show');
80
    });
Filipa Lacerda's avatar
Filipa Lacerda committed
81 82
  });

83 84 85 86 87 88 89 90 91 92
  describe('checkForNewInstalls', () => {
    const INITIAL_APP_MAP = {
      helm: { status: null, title: 'Helm Tiller' },
      ingress: { status: null, title: 'Ingress' },
      runner: { status: null, title: 'GitLab Runner' },
    };

    it('does not show alert when things transition from initial null state to something', () => {
      cluster.checkForNewInstalls(INITIAL_APP_MAP, {
        ...INITIAL_APP_MAP,
93
        helm: { status: INSTALLABLE, title: 'Helm Tiller' },
94 95
      });

96
      const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text');
97

98
      expect(flashMessage).toBeNull();
99 100 101
    });

    it('shows an alert when something gets newly installed', () => {
Mike Greiling's avatar
Mike Greiling committed
102 103 104
      cluster.checkForNewInstalls(
        {
          ...INITIAL_APP_MAP,
105
          helm: { status: INSTALLING, title: 'Helm Tiller' },
Mike Greiling's avatar
Mike Greiling committed
106 107 108
        },
        {
          ...INITIAL_APP_MAP,
109
          helm: { status: INSTALLED, title: 'Helm Tiller' },
Mike Greiling's avatar
Mike Greiling committed
110 111
        },
      );
112

113
      const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text');
114

115
      expect(flashMessage).not.toBeNull();
Mike Greiling's avatar
Mike Greiling committed
116 117 118
      expect(flashMessage.textContent.trim()).toEqual(
        'Helm Tiller was successfully installed on your Kubernetes cluster',
      );
119 120 121
    });

    it('shows an alert when multiple things gets newly installed', () => {
Mike Greiling's avatar
Mike Greiling committed
122 123 124
      cluster.checkForNewInstalls(
        {
          ...INITIAL_APP_MAP,
125 126
          helm: { status: INSTALLING, title: 'Helm Tiller' },
          ingress: { status: INSTALLABLE, title: 'Ingress' },
Mike Greiling's avatar
Mike Greiling committed
127 128 129
        },
        {
          ...INITIAL_APP_MAP,
130 131
          helm: { status: INSTALLED, title: 'Helm Tiller' },
          ingress: { status: INSTALLED, title: 'Ingress' },
Mike Greiling's avatar
Mike Greiling committed
132 133
        },
      );
134

135
      const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text');
136

137
      expect(flashMessage).not.toBeNull();
Mike Greiling's avatar
Mike Greiling committed
138 139 140
      expect(flashMessage.textContent.trim()).toEqual(
        'Helm Tiller, Ingress was successfully installed on your Kubernetes cluster',
      );
141 142 143 144 145 146
    });
  });

  describe('updateContainer', () => {
    describe('when creating cluster', () => {
      it('should show the creating container', () => {
147 148
        cluster.updateContainer(null, 'creating');

Mike Greiling's avatar
Mike Greiling committed
149
        expect(cluster.creatingContainer.classList.contains('hidden')).toBeFalsy();
150

Mike Greiling's avatar
Mike Greiling committed
151
        expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy();
152

Mike Greiling's avatar
Mike Greiling committed
153
        expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy();
154 155 156 157
      });

      it('should continue to show `creating` banner with subsequent updates of the same status', () => {
        cluster.updateContainer('creating', 'creating');
158

Mike Greiling's avatar
Mike Greiling committed
159
        expect(cluster.creatingContainer.classList.contains('hidden')).toBeFalsy();
160

Mike Greiling's avatar
Mike Greiling committed
161
        expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy();
162

Mike Greiling's avatar
Mike Greiling committed
163
        expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy();
164 165 166 167
      });
    });

    describe('when cluster is created', () => {
168
      it('should show the success container and fresh the page', () => {
169
        cluster.updateContainer(null, 'created');
170

Mike Greiling's avatar
Mike Greiling committed
171
        expect(cluster.creatingContainer.classList.contains('hidden')).toBeTruthy();
172

Mike Greiling's avatar
Mike Greiling committed
173
        expect(cluster.successContainer.classList.contains('hidden')).toBeFalsy();
174

Mike Greiling's avatar
Mike Greiling committed
175
        expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy();
176
      });
177 178 179 180

      it('should not show a banner when status is already `created`', () => {
        cluster.updateContainer('created', 'created');

Mike Greiling's avatar
Mike Greiling committed
181
        expect(cluster.creatingContainer.classList.contains('hidden')).toBeTruthy();
182

Mike Greiling's avatar
Mike Greiling committed
183
        expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy();
184

Mike Greiling's avatar
Mike Greiling committed
185
        expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy();
186
      });
187 188 189 190
    });

    describe('when cluster has error', () => {
      it('should show the error container', () => {
191
        cluster.updateContainer(null, 'errored', 'this is an error');
192

Mike Greiling's avatar
Mike Greiling committed
193
        expect(cluster.creatingContainer.classList.contains('hidden')).toBeTruthy();
194

Mike Greiling's avatar
Mike Greiling committed
195
        expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy();
196

Mike Greiling's avatar
Mike Greiling committed
197
        expect(cluster.errorContainer.classList.contains('hidden')).toBeFalsy();
198

Mike Greiling's avatar
Mike Greiling committed
199
        expect(cluster.errorReasonContainer.textContent).toContain('this is an error');
200
      });
201 202 203 204

      it('should show `error` banner when previously `creating`', () => {
        cluster.updateContainer('creating', 'errored');

Mike Greiling's avatar
Mike Greiling committed
205
        expect(cluster.creatingContainer.classList.contains('hidden')).toBeTruthy();
206

Mike Greiling's avatar
Mike Greiling committed
207
        expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy();
208

Mike Greiling's avatar
Mike Greiling committed
209
        expect(cluster.errorContainer.classList.contains('hidden')).toBeFalsy();
210
      });
211 212 213 214
    });
  });

  describe('installApplication', () => {
215
    it('tries to install helm', () => {
216
      jest.spyOn(cluster.service, 'installApplication').mockResolvedValueOnce();
217

218
      cluster.store.state.applications.helm.status = INSTALLABLE;
219

220
      cluster.installApplication({ id: 'helm' });
221

222
      expect(cluster.store.state.applications.helm.status).toEqual(INSTALLING);
223
      expect(cluster.store.state.applications.helm.requestReason).toEqual(null);
224
      expect(cluster.service.installApplication).toHaveBeenCalledWith('helm', undefined);
225 226
    });

227
    it('tries to install ingress', () => {
228
      jest.spyOn(cluster.service, 'installApplication').mockResolvedValueOnce();
229

230
      cluster.store.state.applications.ingress.status = INSTALLABLE;
231

232
      cluster.installApplication({ id: 'ingress' });
233

234
      expect(cluster.store.state.applications.ingress.status).toEqual(INSTALLING);
235
      expect(cluster.store.state.applications.ingress.requestReason).toEqual(null);
236
      expect(cluster.service.installApplication).toHaveBeenCalledWith('ingress', undefined);
237 238
    });

239
    it('tries to install runner', () => {
240
      jest.spyOn(cluster.service, 'installApplication').mockResolvedValueOnce();
241

242
      cluster.store.state.applications.runner.status = INSTALLABLE;
243

244
      cluster.installApplication({ id: 'runner' });
245

246
      expect(cluster.store.state.applications.runner.status).toEqual(INSTALLING);
247
      expect(cluster.store.state.applications.runner.requestReason).toEqual(null);
248
      expect(cluster.service.installApplication).toHaveBeenCalledWith('runner', undefined);
249 250
    });

251
    it('tries to install jupyter', () => {
252
      jest.spyOn(cluster.service, 'installApplication').mockResolvedValueOnce();
253

Mike Greiling's avatar
Mike Greiling committed
254 255 256 257
      cluster.installApplication({
        id: 'jupyter',
        params: { hostname: cluster.store.state.applications.jupyter.hostname },
      });
258

259
      cluster.store.state.applications.jupyter.status = INSTALLABLE;
260
      expect(cluster.store.state.applications.jupyter.requestReason).toEqual(null);
Mike Greiling's avatar
Mike Greiling committed
261 262 263
      expect(cluster.service.installApplication).toHaveBeenCalledWith('jupyter', {
        hostname: cluster.store.state.applications.jupyter.hostname,
      });
264 265
    });

266 267 268 269
    it('sets error request status when the request fails', () => {
      jest
        .spyOn(cluster.service, 'installApplication')
        .mockRejectedValueOnce(new Error('STUBBED ERROR'));
270

271
      cluster.store.state.applications.helm.status = INSTALLABLE;
272

273
      const promise = cluster.installApplication({ id: 'helm' });
274

275
      expect(cluster.store.state.applications.helm.status).toEqual(INSTALLING);
276 277 278
      expect(cluster.store.state.applications.helm.requestReason).toEqual(null);
      expect(cluster.service.installApplication).toHaveBeenCalled();

279
      return promise.then(() => {
280 281 282
        expect(cluster.store.state.applications.helm.status).toEqual(INSTALLABLE);
        expect(cluster.store.state.applications.helm.installFailed).toBe(true);

283 284
        expect(cluster.store.state.applications.helm.requestReason).toBeDefined();
      });
285 286
    });
  });
287 288 289

  describe('handleSuccess', () => {
    beforeEach(() => {
290 291 292 293
      jest.spyOn(cluster.store, 'updateStateFromServer').mockReturnThis();
      jest.spyOn(cluster, 'toggleIngressDomainHelpText').mockReturnThis();
      jest.spyOn(cluster, 'checkForNewInstalls').mockReturnThis();
      jest.spyOn(cluster, 'updateContainer').mockReturnThis();
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315

      cluster.handleSuccess({ data: {} });
    });

    it('updates clusters store', () => {
      expect(cluster.store.updateStateFromServer).toHaveBeenCalled();
    });

    it('checks for new installable apps', () => {
      expect(cluster.checkForNewInstalls).toHaveBeenCalled();
    });

    it('toggles ingress domain help text', () => {
      expect(cluster.toggleIngressDomainHelpText).toHaveBeenCalled();
    });

    it('updates message containers', () => {
      expect(cluster.updateContainer).toHaveBeenCalled();
    });
  });

  describe('toggleIngressDomainHelpText', () => {
316 317
    let ingressPreviousState;
    let ingressNewState;
318

319
    beforeEach(() => {
320 321
      ingressPreviousState = { externalIp: null };
      ingressNewState = { externalIp: '127.0.0.1' };
322
    });
323

324
    describe(`when ingress have an external ip assigned`, () => {
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
      beforeEach(() => {
        cluster.toggleIngressDomainHelpText(ingressPreviousState, ingressNewState);
      });

      it('displays custom domain help text', () => {
        expect(cluster.ingressDomainHelpText.classList.contains('hide')).toEqual(false);
      });

      it('updates ingress external ip address', () => {
        expect(cluster.ingressDomainSnippet.textContent).toEqual(
          `${ingressNewState.externalIp}${INGRESS_DOMAIN_SUFFIX}`,
        );
      });
    });

340
    describe(`when ingress does not have an external ip assigned`, () => {
341
      it('hides custom domain help text', () => {
342
        ingressPreviousState.externalIp = '127.0.0.1';
343
        ingressNewState.externalIp = null;
344
        cluster.ingressDomainHelpText.classList.remove('hide');
345 346 347 348 349 350

        cluster.toggleIngressDomainHelpText(ingressPreviousState, ingressNewState);

        expect(cluster.ingressDomainHelpText.classList.contains('hide')).toEqual(true);
      });
    });
351
  });
352
});