1import nock from 'nock';
2import fetch from 'node-fetch';
3import path from 'path';
4import { Stream } from 'stream';
5import { promisify } from 'util';
6
7import { asMock } from '../../../__tests__/asMock';
8import * as Log from '../../../log';
9import { wrapFetchWithProgress } from '../wrapFetchWithProgress';
10
11const fs = jest.requireActual('fs') as typeof import('fs');
12const pipeline = promisify(Stream.pipeline);
13
14jest.mock(`../../../log`);
15
16describe(wrapFetchWithProgress, () => {
17  beforeEach(() => {
18    asMock(Log.warn).mockClear();
19  });
20  it('should call the progress callback', async () => {
21    const url = 'https://example.com';
22
23    const scope = nock(url)
24      .get('/asset')
25      .reply(() => {
26        const fixturePath = path.join(__dirname, './fixtures/panda.png');
27        return [
28          // Status
29          200,
30          // Data
31          fs.createReadStream(fixturePath),
32          {
33            // Headers for progress
34            'Content-Length': fs.statSync(fixturePath).size,
35          },
36        ];
37      });
38
39    const onProgress = jest.fn();
40
41    await pipeline(
42      (
43        await wrapFetchWithProgress(fetch)(url + '/asset', {
44          onProgress,
45        })
46      ).body,
47      require('fs').createWriteStream('/foobar')
48    );
49    // Ensure this example is called more than once.
50    expect(onProgress).toHaveBeenCalledTimes(4);
51    expect(onProgress).toHaveBeenNthCalledWith(1, {
52      loaded: 65536,
53      progress: 0.43515444476906323,
54      total: 150604,
55    });
56
57    // Ensure progress ends on 1.0
58    expect(onProgress).toHaveBeenLastCalledWith({
59      loaded: 150604,
60      progress: 1,
61      total: 150604,
62    });
63    expect(scope.isDone()).toBe(true);
64  });
65
66  it('should warn that a request is missing the content length header', async () => {
67    const url = 'https://example.com';
68
69    // Return no Content-Length header.
70    const scope = nock(url).get('/asset').reply(200, '');
71
72    const onProgress = jest.fn();
73
74    await wrapFetchWithProgress(fetch)(url + '/asset', {
75      onProgress,
76    });
77    expect(Log.warn).toHaveBeenCalledWith(
78      'Progress callback not supported for network request because "Content-Length" header missing or invalid in response from URL:',
79      'https://example.com/asset'
80    );
81
82    expect(scope.isDone()).toBe(true);
83  });
84});
85