diff --git a/src/createInstance.ts b/src/createInstance.ts index e37c8c2ad..9e2067cbe 100644 --- a/src/createInstance.ts +++ b/src/createInstance.ts @@ -246,7 +246,18 @@ export function createInstance( for (const [k, v] of Object.entries( global.mocks as { [key: string]: any } )) { - ;(this as any)[k] = v + // the proxy rejects `$x` when `x` is an internal instance field + // (e.g. `$u` from uView), so we define these directly on the context + if (k[0] === '$' && k.slice(1) in this.$) { + Object.defineProperty((this.$ as any).ctx, k, { + configurable: true, + enumerable: true, + writable: true, + value: v + }) + } else { + ;(this as any)[k] = v + } } } } diff --git a/tests/mountingOptions/mocks.spec.ts b/tests/mountingOptions/mocks.spec.ts index 39909932c..e1a8f3fe5 100644 --- a/tests/mountingOptions/mocks.spec.ts +++ b/tests/mountingOptions/mocks.spec.ts @@ -151,4 +151,43 @@ describe('mocks', () => { expect(wrapper.text()).toContain('hello') expect(wrapper.text()).toContain('mocked') }) + + it('mocks a global property named after an internal instance field', () => { + // `$u` (uView) matches the internal `u` field of the component instance + const Foo = defineComponent({ + template: '
{{ $u.title }} {{ title }}
', + data() { + return { title: (this as any).$u.title } + } + }) + + const wrapper = mount(Foo, { + global: { + mocks: { $u: { title: 'mocked' } } + } + }) + + expect(wrapper.text()).toBe('mocked mocked') + }) + + it('overrides a global property named after an internal instance field', () => { + const Foo = defineComponent({ + template: '
{{ $u.title }}
' + }) + + const wrapper = mount(Foo, { + global: { + plugins: [ + { + install(app) { + app.config.globalProperties.$u = { title: 'real' } + } + } + ], + mocks: { $u: { title: 'mocked' } } + } + }) + + expect(wrapper.text()).toBe('mocked') + }) }) diff --git a/tests/renderToString.spec.ts b/tests/renderToString.spec.ts index 5e515b37b..4fc087661 100644 --- a/tests/renderToString.spec.ts +++ b/tests/renderToString.spec.ts @@ -83,4 +83,16 @@ describe('renderToString', () => { spy.mockRestore() }) + + it('applies a global mock named after an internal instance field', async () => { + const Component = defineComponent({ + template: '
{{ $u.title }}
' + }) + + const contents = await renderToString(Component, { + global: { mocks: { $u: { title: 'mocked' } } } + }) + + expect(contents).toBe('
mocked
') + }) })