import nock from 'nock'; import fetch from 'node-fetch'; import path from 'path'; import { Stream } from 'stream'; import { promisify } from 'util'; import { asMock } from '../../../__tests__/asMock'; import * as Log from '../../../log'; import { wrapFetchWithProgress } from '../wrapFetchWithProgress'; const fs = jest.requireActual('fs') as typeof import('fs'); const pipeline = promisify(Stream.pipeline); jest.mock(`../../../log`); describe(wrapFetchWithProgress, () => { beforeEach(() => { asMock(Log.warn).mockClear(); }); it('should call the progress callback', async () => { const url = 'https://example.com'; const scope = nock(url) .get('/asset') .reply(() => { const fixturePath = path.join(__dirname, './fixtures/panda.png'); return [ // Status 200, // Data fs.createReadStream(fixturePath), { // Headers for progress 'Content-Length': fs.statSync(fixturePath).size, }, ]; }); const onProgress = jest.fn(); await pipeline( ( await wrapFetchWithProgress(fetch)(url + '/asset', { onProgress, }) ).body, require('fs').createWriteStream('/foobar') ); // Ensure this example is called more than once. expect(onProgress).toHaveBeenCalledTimes(4); expect(onProgress).toHaveBeenNthCalledWith(1, { loaded: 65536, progress: 0.43515444476906323, total: 150604, }); // Ensure progress ends on 1.0 expect(onProgress).toHaveBeenLastCalledWith({ loaded: 150604, progress: 1, total: 150604, }); expect(scope.isDone()).toBe(true); }); it('should warn that a request is missing the content length header', async () => { const url = 'https://example.com'; // Return no Content-Length header. const scope = nock(url).get('/asset').reply(200, ''); const onProgress = jest.fn(); await wrapFetchWithProgress(fetch)(url + '/asset', { onProgress, }); expect(Log.warn).toHaveBeenCalledWith( 'Progress callback not supported for network request because "Content-Length" header missing or invalid in response from URL:', 'https://example.com/asset' ); expect(scope.isDone()).toBe(true); }); });