31

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()
        })
    })

2 Answers 2

38

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

Sign up to request clarification or add additional context in comments.

1 Comment

e.g for the async case: expect(() => getFruitStock('pineapples')).rejects.toThrowError(/diabetes/)
16

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/expect.html#rejects to skip some boilerplate.

1 Comment

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.'))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.