Skip to content

Commit

Permalink
feat: give helpful message, when using vi.mock (#2047)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va committed Sep 18, 2022
1 parent a31767d commit 96d1267
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 7 deletions.
8 changes: 8 additions & 0 deletions examples/mocks/test/error-mock.spec.ts
@@ -0,0 +1,8 @@
vi.mock('../src/default', () => {
throw new Error('some error')
})

test('when using top level variable, gives helpful message', async () => {
await expect(() => import('../src/default').then(m => m.default)).rejects
.toThrowErrorMatchingInlineSnapshot('"[vitest] There was an error, when mocking a module. If you are using vi.mock, make sure you are not using top level variables inside, since this call is hoisted. Read more: https://vitest.dev/api/#vi-mock"')
})
10 changes: 5 additions & 5 deletions examples/mocks/test/factory.test.ts
Expand Up @@ -48,11 +48,11 @@ vi.mock('../src/default.ts', () => null)

describe('mocking with factory', () => {
test('missing exports on mock', () => {
expect(() => example.default).toThrowError('[vitest] No "default" export is defined on the "mock:/src/example.ts"')
expect(() => example.boolean).toThrowError('[vitest] No "boolean" export is defined on the "mock:/src/example.ts"')
expect(() => example.object).toThrowError('[vitest] No "object" export is defined on the "mock:/src/example.ts"')
expect(() => example.array).toThrowError('[vitest] No "array" export is defined on the "mock:/src/example.ts"')
expect(() => example.someClasses).toThrowError('[vitest] No "someClasses" export is defined on the "mock:/src/example.ts"')
expect(() => example.default).toThrowError('[vitest] No "default" export is defined on the "/src/example.ts"')
expect(() => example.boolean).toThrowError('[vitest] No "boolean" export is defined on the "/src/example.ts"')
expect(() => example.object).toThrowError('[vitest] No "object" export is defined on the "/src/example.ts"')
expect(() => example.array).toThrowError('[vitest] No "array" export is defined on the "/src/example.ts"')
expect(() => example.someClasses).toThrowError('[vitest] No "someClasses" export is defined on the "/src/example.ts"')
})

it('non-object return on factory gives error', async () => {
Expand Down
17 changes: 15 additions & 2 deletions packages/vitest/src/runtime/mocker.ts
Expand Up @@ -106,13 +106,26 @@ export class VitestMocker {
const cached = this.moduleCache.get(dep)?.exports
if (cached)
return cached
const exports = await mock()
let exports: any
try {
exports = await mock()
}
catch (err) {
const vitestError = new Error(
'[vitest] There was an error, when mocking a module. '
+ 'If you are using vi.mock, make sure you are not using top level variables inside, since this call is hoisted. '
+ 'Read more: https://vitest.dev/api/#vi-mock')
vitestError.cause = err
throw vitestError
}

if (exports === null || typeof exports !== 'object')
throw new Error('[vitest] vi.mock(path: string, factory?: () => unknown) is not returning an object. Did you mean to return an object with a "default" key?')

this.moduleCache.set(dep, { exports })

const filepath = dep.slice('mock:'.length)

const exportHandler = {
get(target: Record<string, any>, prop: any) {
const val = target[prop]
Expand All @@ -123,7 +136,7 @@ export class VitestMocker {
return target.then.bind(target)
}
else if (!(prop in target)) {
throw new Error(`[vitest] No "${prop}" export is defined on the "${dep}"`)
throw new Error(`[vitest] No "${prop}" export is defined on the "${filepath}"`)
}

return val
Expand Down

0 comments on commit 96d1267

Please sign in to comment.