diff --git a/examples/mocks/src/dynamic-module.js b/examples/mocks/src/dynamic-module.js new file mode 100644 index 000000000000..336ce12bb910 --- /dev/null +++ b/examples/mocks/src/dynamic-module.js @@ -0,0 +1 @@ +export {} diff --git a/examples/mocks/src/retry-dynamic-import.ts b/examples/mocks/src/retry-dynamic-import.ts new file mode 100644 index 000000000000..4c4c34685397 --- /dev/null +++ b/examples/mocks/src/retry-dynamic-import.ts @@ -0,0 +1,16 @@ +export async function retryDynamicImport() { + let retryTimes = 0 + const load = async () => { + try { + return await import('./dynamic-module.js') + } + catch (e) { + if (retryTimes === 3) + throw new Error('import dynamic module failed.') + retryTimes += 1 + return await load() + } + } + + return await load() +} diff --git a/examples/mocks/test/retry-dynamic-import.test.ts b/examples/mocks/test/retry-dynamic-import.test.ts new file mode 100644 index 000000000000..8aa7ee1922e4 --- /dev/null +++ b/examples/mocks/test/retry-dynamic-import.test.ts @@ -0,0 +1,17 @@ +import { retryDynamicImport } from '../src/retry-dynamic-import' + +vi.mock('../src/dynamic-module', () => { + return { foo: 'bar' } +}) + +describe('retry-dynamic-import', () => { + it('should dynamic import module success', async () => { + expect(await retryDynamicImport()).toEqual({ foo: 'bar' }) + }) + it('should throw when retry over 3 times', async () => { + vi.doMock('../src/dynamic-module', () => { + throw new Error('foobar') + }) + await expect(retryDynamicImport()).rejects.toThrowError(new Error('import dynamic module failed.')) + }) +}) diff --git a/packages/vitest/src/runtime/mocker.ts b/packages/vitest/src/runtime/mocker.ts index adfd9485e981..908581ed2fa5 100644 --- a/packages/vitest/src/runtime/mocker.ts +++ b/packages/vitest/src/runtime/mocker.ts @@ -423,11 +423,14 @@ export class VitestMocker { return exports } if (typeof mock === 'function' && !callstack.includes(mockPath) && !callstack.includes(url)) { - callstack.push(mockPath) - const result = await this.callFunctionMock(mockPath, mock) - const indexMock = callstack.indexOf(mockPath) - callstack.splice(indexMock, 1) - return result + try { + callstack.push(mockPath) + return await this.callFunctionMock(mockPath, mock) + } + finally { + const indexMock = callstack.indexOf(mockPath) + callstack.splice(indexMock, 1) + } } if (typeof mock === 'string' && !callstack.includes(mock)) return mock