0

The case is to write a unit test for uploadFile which should upload file to Google Storage bucket using Jest and to mock createReadStream function on the File object.

my-service.ts:

async uploadFile(file: FileUpload): Promise<{
url: string
path: string}> {
 try {
  file.createReadStream().pipe(
   bucket
    .createWriteStream({
     ...some options
    })
    .on('error', (err) => {
     reject(err)})
    .on('finish', async () => {
     resolve({
      url: 'file-url',
      path: 'file-path'
     })
    })
   
 }
}

my-service.spec.ts:

  describe('#uploadFile', () => {
    it('uploads file', async () => {
      const bucketMock = new Bucket('the-bucket-mock')
      const bucketFileMock = new File(bucketMock, 'the-file')

      const fileUploadMock = {
        filename: 'the-file',
        mimetype: 'mimetype',
        encoding: 'encoding',
        createReadStream: jest.fn().mockImplementation((stream) => {
          pipe: jest.fn()
        }),
      }

      jest
        .spyOn(fileUploadMock, 'createReadStream')
        .mockImplementation((stream) => {
          stream.pipe()
          return Promise.resolve({
            url: 'url-result',
            path: 'file-path-result',
          })
        })

      const uploadFileResult = await myService.uploadFile(fileUploadMock)

      expect(uploadFileResult).toBeCalled()
    })
  })
Dmitry S.
  • 1,544
  • 2
  • 13
  • 22

1 Answers1

1

This portion of your code:

        createReadStream: jest.fn().mockImplementation((stream) => {
          pipe: jest.fn()
        }),

Is not doing what you think it's doing. You believe that the function you're passing into mockImplementation is returning an object that looks like {pipe: jest.fn()}, however, that's not what's happening. If the first thing an arrow function encounters after the arrow is an open curly bracket, that now tells TS/JS that you're inside a function body, which no longer has an implicit return. Similar to if you wrote:

// Nothing happens here, and it returns undefined
function (stream) {
  pipe: jest.fn()
}

The fix to this would be:

(stream) => {
  return { pipe: jest.fn() };
}

Or if you wanted to preserve the succinctness of arrow operators, you just need to make sure that the first thing after the arrow isn't a curly bracket, i.e.:

// Parenthesis help! 
(stream) => ({
  pipe: jest.fn()
})
user3781737
  • 932
  • 7
  • 17