fix(spy): point ESM namespace spy error to module mocking docs (#10707)

Co-authored-by: Ryan Tang <[email protected]>
This commit is contained in:
Ryan Tang
2026-07-29 08:25:09 +02:00
committed by GitHub
co-authored by Ryan Tang
parent 3cccd163be
commit 9586a12f6e
3 changed files with 35 additions and 2 deletions
+1 -1
View File
@@ -410,7 +410,7 @@ export function spyOn<T extends object, K extends keyof any>(
|| error.message.includes('can\'t redefine non-configurable property'))
) {
throw new TypeError(
`Cannot spy on export "${String(key)}". Module namespace is not configurable in ESM. See: https://vitest.dev/guide/browser/#limitations`,
`Cannot spy on export "${String(key)}". Module namespace is not configurable in ESM. See: https://vitest.dev/guide/mocking/modules#mocking-a-module`,
{ cause: error },
)
}
+1 -1
View File
@@ -12,7 +12,7 @@ it('spying on an esm module prints an error', () => {
}
})()
expect(error.name).toBe('TypeError')
expect(error.message).toMatchInlineSnapshot(`"Cannot spy on export "calculator". Module namespace is not configurable in ESM. See: https://vitest.dev/guide/browser/#limitations"`)
expect(error.message).toMatchInlineSnapshot(`"Cannot spy on export "calculator". Module namespace is not configurable in ESM. See: https://vitest.dev/guide/mocking/modules#mocking-a-module"`)
expect(error.cause).toBeInstanceOf(TypeError)
})
+33
View File
@@ -19,6 +19,39 @@ describe('vi.spyOn() edge cases', () => {
expect(fn3.length).toBe(3)
})
test('spying on a non-configurable ESM namespace export points to the module mocking docs, not browser mode', () => {
// Fake an ES module namespace: `Symbol.toStringTag` is 'Module' and the
// export is non-configurable, so `Object.defineProperty` throws
// "Cannot redefine property" — the same guard the real ESM path hits.
const namespace: Record<string, unknown> = {}
Object.defineProperty(namespace, Symbol.toStringTag, { value: 'Module' })
Object.defineProperty(namespace, 'answer', {
value: () => 42,
enumerable: true,
configurable: false,
writable: false,
})
Object.preventExtensions(namespace)
const error = (() => {
try {
vi.spyOn(namespace as any, 'answer')
expect.unreachable()
}
catch (err) {
return err as Error
}
})()
expect(error).toBeInstanceOf(TypeError)
expect(error.message).toContain('Cannot spy on export "answer"')
// This error fires in Node too, so it must not send users to the
// browser-mode-only docs (issue #9467). It should point at the
// environment-agnostic module mocking guide instead.
expect(error.message).toContain('https://vitest.dev/guide/mocking/modules#mocking-a-module')
expect(error.message).not.toContain('/guide/browser')
})
test('can spy on a proxy with undefined descriptor\'s value', () => {
const obj = new Proxy<{ fn: () => number }>({} as any, {
get(_, prop) {