5

I want to mock an object method that throws an error but the test is always failing with these errors.

I can't post the image yet but please check the link. It shows the test failing.

throw new Error

Here's my code below:

workload.js

const workload = {
    job: [
        {workload_1: 'workload 1'}
    ],
    createWorkloadJSON: async function(workload){
        await fsp.appendFile('./workload.json',JSON.stringify(workload))
        if(fs.existsSync('./workload.json')) return true
        else throw new Error('workload.json creating failed.')
    }
}

workload.test.js

describe('workload', ()=>{
    afterEach(()=>{
        vi.restoreAllMocks()
    })
    
     it('throws an error when workload.json is not found', async ()=>{
            const spy = vi.spyOn(workload, 'createWorkloadJSON').mockImplementation(async()=>{
                throw new Error('workload.json creating failed.')
            })
            expect(await workload.createWorkloadJSON()).toThrow(new Error('workload.json creating failed.'))
            expect(spy).toHaveBeenCalled()
        })
    })
Shu Pesmerga
  • 63
  • 1
  • 5

2 Answers2

2

Throwing in the test scope will throw in the test. Generally you need to pass a function instead, otherwise it will run in place. In Vitest you can use https://vitest.dev/api/#rejects to skip some boilerplate.

OFRBG
  • 1,653
  • 14
  • 28
  • 1
    Thanks! That worked. I never occurred to me that it was because of its asynchronous nature and writing test for rejected asynchronous code was different It still looks weird that now I have to `await` the `expect()` instead of the function being tested when an async function is being rejected but you'd go the normal way of writing test when a async function is resolved. `await expect(workload.createWorkloadJSON()).rejects.toThrow(new Error('workload.json creation failed.'))` – Shu Pesmerga Nov 18 '22 at 09:50
2

In general you'd use expect(() => yourFunctionCall()).toThrowError() to test for an exception being thrown. (In the OP's case, there was also an async function where the reject had to be captured too.)

Example from the docs:

import { expect, test } from 'vitest'

function getFruitStock(type) {
  if (type === 'pineapples')
    throw new DiabetesError('Pineapples are not good for people with diabetes')

  // Do some other stuff
}

test('throws on pineapples', () => {
  // Test that the error message says "diabetes" somewhere: these are equivalent
  expect(() => getFruitStock('pineapples')).toThrowError(/diabetes/)
  expect(() => getFruitStock('pineapples')).toThrowError('diabetes')

  // Test the exact error message
  expect(() => getFruitStock('pineapples')).toThrowError(
    /^Pineapples are not good for people with diabetes$/,
  )
})

https://vitest.dev/api/expect.html#tothrowerror

broc.seib
  • 21,643
  • 8
  • 63
  • 62