summaryrefslogtreecommitdiff
path: root/spec/frontend/lib/utils/axios_startup_calls_spec.js
blob: e12bf7255606d163aa98a84ce15c3e2aca4bba7a (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
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import setupAxiosStartupCalls from '~/lib/utils/axios_startup_calls';

describe('setupAxiosStartupCalls', () => {
  const AXIOS_RESPONSE = { text: 'AXIOS_RESPONSE' };
  const STARTUP_JS_RESPONSE = { text: 'STARTUP_JS_RESPONSE' };
  let mock;

  function mockFetchCall(status) {
    const p = {
      ok: status >= 200 && status < 300,
      status,
      headers: new Headers({ 'Content-Type': 'application/json' }),
      statusText: `MOCK-FETCH ${status}`,
      clone: () => p,
      json: () => Promise.resolve(STARTUP_JS_RESPONSE),
    };
    return Promise.resolve(p);
  }

  function mockConsoleWarn() {
    jest.spyOn(console, 'warn').mockImplementation();
  }

  function expectConsoleWarn(path) {
    // eslint-disable-next-line no-console
    expect(console.warn).toHaveBeenCalledWith(expect.stringMatching(path), expect.any(Error));
  }

  beforeEach(() => {
    window.gl = {};
    mock = new MockAdapter(axios);
    mock.onGet('/non-startup').reply(200, AXIOS_RESPONSE);
    mock.onGet('/startup').reply(200, AXIOS_RESPONSE);
    mock.onGet('/startup-failing').reply(200, AXIOS_RESPONSE);
  });

  afterEach(() => {
    delete window.gl;
    axios.interceptors.request.handlers = [];
    mock.restore();
  });

  it('if no startupCalls are registered: does not register a request interceptor', () => {
    setupAxiosStartupCalls(axios);

    expect(axios.interceptors.request.handlers.length).toBe(0);
  });

  describe('if startupCalls are registered', () => {
    beforeEach(() => {
      window.gl.startup_calls = {
        '/startup': {
          fetchCall: mockFetchCall(200),
        },
        '/startup-failing': {
          fetchCall: mockFetchCall(400),
        },
      };
      setupAxiosStartupCalls(axios);
    });

    it('registers a request interceptor', () => {
      expect(axios.interceptors.request.handlers.length).toBe(1);
    });

    it('detaches the request interceptor if every startup call has been made', async () => {
      expect(axios.interceptors.request.handlers[0]).not.toBeNull();

      await axios.get('/startup');
      mockConsoleWarn();
      await axios.get('/startup-failing');

      // Axios sets the interceptor to null
      expect(axios.interceptors.request.handlers[0]).toBeNull();
    });

    it('delegates to startup calls if URL is registered and call is successful', async () => {
      const { headers, data, status, statusText } = await axios.get('/startup');

      expect(headers).toEqual({ 'content-type': 'application/json' });
      expect(status).toBe(200);
      expect(statusText).toBe('MOCK-FETCH 200');
      expect(data).toEqual(STARTUP_JS_RESPONSE);
      expect(data).not.toEqual(AXIOS_RESPONSE);
    });

    it('delegates to startup calls exactly once', async () => {
      await axios.get('/startup');
      const { data } = await axios.get('/startup');

      expect(data).not.toEqual(STARTUP_JS_RESPONSE);
      expect(data).toEqual(AXIOS_RESPONSE);
    });

    it('does not delegate to startup calls if the call is failing', async () => {
      mockConsoleWarn();
      const { data } = await axios.get('/startup-failing');

      expect(data).not.toEqual(STARTUP_JS_RESPONSE);
      expect(data).toEqual(AXIOS_RESPONSE);
      expectConsoleWarn('/startup-failing');
    });

    it('does not delegate to startup call if URL is not registered', async () => {
      const { data } = await axios.get('/non-startup');

      expect(data).toEqual(AXIOS_RESPONSE);
      expect(data).not.toEqual(STARTUP_JS_RESPONSE);
    });
  });

  describe('startup call', () => {
    let oldGon;

    beforeEach(() => {
      oldGon = window.gon;
      window.gon = { gitlab_url: 'https://example.org/gitlab' };
    });

    afterEach(() => {
      window.gon = oldGon;
    });

    it('removes GitLab Base URL from startup call', async () => {
      window.gl.startup_calls = {
        '/startup': {
          fetchCall: mockFetchCall(200),
        },
      };
      setupAxiosStartupCalls(axios);

      const { data } = await axios.get('https://example.org/gitlab/startup');

      expect(data).toEqual(STARTUP_JS_RESPONSE);
    });

    it('sorts the params in the requested API url', async () => {
      window.gl.startup_calls = {
        '/startup?alpha=true&bravo=true': {
          fetchCall: mockFetchCall(200),
        },
      };
      setupAxiosStartupCalls(axios);

      // Use a full url instead of passing options = { params: { ... } } to axios.get
      // to ensure the params are listed in the specified order.
      const { data } = await axios.get('https://example.org/gitlab/startup?bravo=true&alpha=true');

      expect(data).toEqual(STARTUP_JS_RESPONSE);
    });
  });
});