'Jest returning error when calling mockReturnValueOnce with jest.spyOn()

jest --passWithNoTests --silent --noStackTrace --runInBand --watch -c jest-unit-config.js

Project repo

Error in jest.spyOn(bcrypt, 'hash').mockRejectedValue(new Error('Async error message'))

error TS2345: Argument of type 'Error' is not assignable to parameter of type 'never'.
31 jest.spyOn(bcrypt, 'hash').mockRejectedValue(new Error('Async error message'))

    import bcrypt from 'bcrypt'
    import { BcryptAdapter } from './bcrypt-adapter'

    jest.mock('bcrypt', () => ({
      async hash (): Promise<string> {
        return 'hash'
      }
    }))
    const salt = 12
    const makeSut = (): BcryptAdapter => {
      return new BcryptAdapter(salt)
    }
    
    describe('Bcrypt Adapter', () => `{`
    
      test('Should throw if bcrypt throws', async () => {
        const sut = makeSut()
        jest.spyOn(bcrypt, 'hash').mockRejectedValue(new Error('Async error message'))
        const promise = sut.encrypt('any_value')
        await expect(promise).rejects.toThrow()
      })
    })

If I use .mockImplementantion instead of .mockRejectedValue, another error occurs:

  test('Should throw if bcrypt throws', async () => {
    const sut = makeSut()
    jest.spyOn(bcrypt, 'hash').mockImplementation((): Promise<any> => { Promise.reject(new Error()) })
    const promise = sut.encrypt('any_value')
    await expect(promise).rejects.toThrow()
  })

error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. 31 jest.spyOn(bcrypt, 'hash').mockImplementation((): Promise => { Promise.reject(new Error()) })

BcryptAdapter.encrypt

  async encrypt (value: string): Promise<string> {
    const hash = await bcrypt.hash(value, this.salt)
    return hash
  }

Package version:

    "@types/jest": "^27.5.0",
    "jest": "^28.1.0",
    "ts-jest": "^28.0.2",
    "typescript": "^4.6.4"

node v16.14.0

I know there is a workaround using .mockImplementation((): never => {throw new Error()}) but the question here is why the first two approaches didn't work.



Solution 1:[1]

Could you help remove this code

jest.mock('bcrypt', () => ({
    async hash (): Promise<string> {
       return 'hash'
    }
}))

because you use jest.spyOn to mock it return Error instead of string. Also I think we dont need jest.mock when using jest.spyOn here

Solution 2:[2]

You need a Mac device to run on iOS. By selecting a simulator, you can easily run from vscode/android studio/xcode. Also you don't need to change any code but if you want to show different style in different platform, you need to change those code accordingly.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Thu Vo
Solution 2 Nazmul Hasan