Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions src/vueWrapper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { App, ComponentPublicInstance, VNode } from 'vue'
import { nextTick, proxyRefs } from 'vue'
import { nextTick, proxyRefs, unref } from 'vue'

import { config } from './config'
import domEvents from './constants/dom-events'
Expand Down Expand Up @@ -27,14 +27,17 @@ function createVMProxy<T extends ComponentPublicInstance>(
): T {
return new Proxy(vm, {
get(vm, key, receiver) {
if (vm.$.exposed && vm.$.exposeProxy && key in vm.$.exposeProxy) {
// first if the key is exposed
if (vm.$.exposeProxy && key in vm.$.exposeProxy) {
// first if the key is exposed in exposeProxy
return Reflect.get(vm.$.exposeProxy, key, receiver)
} else if (vm.$.exposed && key in vm.$.exposed) {
// second if the key is exposed
return unref(Reflect.get(vm.$.exposed, key, receiver))
} else if (key in setupState) {
// second if the key is acccessible from the setupState
// third if the key is acccessible from the setupState
return Reflect.get(setupState, key, receiver)
} else if (key in vm.$.appContext.config.globalProperties) {
// third if the key is a global property
// fourth if the key is a global property
return Reflect.get(
vm.$.appContext.config.globalProperties,
key,
Expand Down
84 changes: 84 additions & 0 deletions tests/expose.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,88 @@
expect(spiedIncrement).toHaveBeenCalled()
expect(wrapper.html()).toContain('-1')
})

describe('when exposeProxy is null', () => {
const nullifyExposeProxy = (vm: any) => {
vm.$.exposeProxy = null
}

it('access vm on simple components with custom `expose`', async () => {
const wrapper = mount(DefineExpose)
const vm = wrapper.vm

nullifyExposeProxy(vm)
commonTests(vm)

// returned state shuold be accessible
expect(vm.returnedState).toBe('returnedState')

// non-exposed and non-returned state should not be accessible
expect(
(vm as unknown as { stateNonExposedAndNonReturned: undefined })
.stateNonExposedAndNonReturned
).toBe(undefined)
})

it('access vm on simple components with custom `expose` and a setup returning a render function', async () => {
const wrapper = mount(DefineExposeWithRenderFunction)
const vm = wrapper.vm

nullifyExposeProxy(vm)
commonTests(vm)

// can't access `refUseByRenderFnButNotExposed` as it is not exposed
// and we are in a component with a setup returning a render function
expect(
(vm as unknown as { refUseByRenderFnButNotExposed: undefined })
.refUseByRenderFnButNotExposed
).toBeUndefined()
})

it('access vm with <script setup> and defineExpose()', async () => {
const wrapper = mount(ScriptSetupExpose)
const vm = wrapper.vm as unknown as {
inc: () => void
resetCount: () => void
count: number
refNonExposed: string
refNonExposedGetter: () => string
}

nullifyExposeProxy(vm)
commonTests(vm)

await wrapper.find('button').trigger('click')
expect(wrapper.html()).toContain('1')

// can access state/method/ref as it is exposed via `defineExpose()`
expect(vm.count).toBe(1)
vm.resetCount()
expect(vm.count).toBe(0)

// non-exposed state/method/ref should be accessible
vm.inc()
expect(vm.count).toBe(1)
expect(vm.refNonExposed).toBe('refNonExposed')
vm.refNonExposed = 'newRefNonExposed'
expect(vm.refNonExposedGetter()).toBe('newRefNonExposed')
})

it('access vm with <script setup> even without defineExpose()', async () => {
const wrapper = mount(ScriptSetup)

nullifyExposeProxy(wrapper.vm)

await wrapper.find('button').trigger('click')
expect(wrapper.html()).toContain('1')
// can access `count` even if it is _not_ exposed
// @ts-ignore we need better types here, see https://github.com/vuejs/test-utils/issues/972

Check failure on line 233 in tests/expose.spec.ts

View workflow job for this annotation

GitHub Actions / build (24)

typescript-eslint(prefer-ts-expect-error)

Enforce using `@ts-expect-error` over `@ts-ignore`
expect(wrapper.vm.count).toBe(1)

// @ts-ignore we need better types here, see https://github.com/vuejs/test-utils/issues/972

Check failure on line 236 in tests/expose.spec.ts

View workflow job for this annotation

GitHub Actions / build (24)

typescript-eslint(prefer-ts-expect-error)

Enforce using `@ts-expect-error` over `@ts-ignore`
wrapper.vm.count = 2
await nextTick()
expect(wrapper.html()).toContain('2')
})
})
})
Loading