@@ -22,13 +22,17 @@ import { ShapeFlags } from './utils/vueShared'
22
22
*/
23
23
function createVMProxy < T extends ComponentPublicInstance > (
24
24
vm : T ,
25
- setupState : Record < string , any >
25
+ setupState : Record < string , any > ,
26
+ exposed : Record < string , any > | null
26
27
) : T {
27
28
return new Proxy ( vm , {
28
29
get ( vm , key , receiver ) {
29
30
if ( vm . $ . exposed && vm . $ . exposeProxy && key in vm . $ . exposeProxy ) {
30
31
// first if the key is exposed
31
32
return Reflect . get ( vm . $ . exposeProxy , key , receiver )
33
+ } else if ( exposed && key in exposed ) {
34
+ // first if the key is exposed
35
+ return Reflect . get ( exposed , key , receiver )
32
36
} else if ( key in setupState ) {
33
37
// second if the key is acccessible from the setupState
34
38
return Reflect . get ( setupState , key , receiver )
@@ -107,11 +111,31 @@ export class VueWrapper<
107
111
// if we return it as `vm`
108
112
// This does not work for functional components though (as they have no vm)
109
113
// or for components with a setup that returns a render function (as they have an empty proxy)
110
- // in both cases, we return `vm` directly instead
114
+ // in both cases, we return `vm` directly instead.
115
+ //
116
+ // NOTE https://github.com/vuejs/test-utils/issues/2591
117
+ // I'm sry i'm not entirely sure why, but exposed properties — via expose/defineExpose
118
+ // are not assigned to the componentVM when the the `vm` argument provided
119
+ // to this constructor comes from `findComponent` — as in, not the original instance
120
+ // but already the proxied one. I suspect that is by design because according
121
+ // to the defineExpose docs, the exposed properties become "available for the
122
+ // parent component via templateRefs, which is the the case reported in the issue
123
+ // (in fact using templateRefs and doing .findComponent({ ref: 'refName' }) works
124
+ // as expected). But using "expose" via option or setup script does not keep
125
+ // this consistenticy and dependending on how setup return is done, the exposed
126
+ // might not be added to the vm even if exposed.
127
+ // So this can be considered highjacking the vuiedesign.
128
+ // It's up to the VTU to decide if it want to provide the convience of having
129
+ // a single interface without
130
+ // https://vuejs.org/api/sfc-script-setup.html#defineexpose
131
+ // https://vuejs.org/api/composition-api-setup.html#exposing-public-properties
132
+ // https://vuejs.org/api/options-state.html#expose
133
+ //
111
134
if ( hasSetupState ( vm ) ) {
112
- this . componentVM = createVMProxy < T > ( vm , vm . $ . setupState )
135
+ this . componentVM = createVMProxy < T > ( vm , vm . $ . setupState , vm . $ . exposed )
113
136
} else {
114
137
this . componentVM = vm
138
+ Object . assign ( this . componentVM , vm . $ . exposed )
115
139
}
116
140
this . __setProps = setProps
117
141
0 commit comments