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