@@ -23,32 +23,50 @@ import createWrapper from './create-wrapper'
23
23
import { orderWatchers } from './order-watchers'
24
24
25
25
export default class Wrapper implements BaseWrapper {
26
- vnode : VNode | null ;
27
- vm: Component | null ;
26
+ + vnode : VNode | null ;
27
+ + vm : Component | null ;
28
28
_emitted : { [ name : string ] : Array < Array < any > > } ;
29
29
_emittedByOrder: Array < { name : string , args : Array < any > } > ;
30
30
isVm: boolean ;
31
- element: Element ;
31
+ + element : Element ;
32
32
update: Function ;
33
- options: WrapperOptions ;
33
+ + options : WrapperOptions ;
34
34
version: number ;
35
35
isFunctionalComponent: boolean ;
36
36
37
37
constructor ( node : VNode | Element , options : WrapperOptions ) {
38
- if ( node instanceof Element ) {
39
- this . element = node
40
- this . vnode = null
41
- } else {
42
- this . vnode = node
43
- this . element = node . elm
38
+ const vnode = node instanceof Element ? null : node
39
+ const element = node instanceof Element ? node : node . elm
40
+ // Prevent redefine by VueWrapper
41
+ if ( this . constructor . name === 'Wrapper' ) {
42
+ // $FlowIgnore
43
+ Object . defineProperty ( this , 'vnode' , {
44
+ get : ( ) => vnode ,
45
+ set : ( ) => { }
46
+ } )
47
+ // $FlowIgnore
48
+ Object . defineProperty ( this , 'element' , {
49
+ get : ( ) => element ,
50
+ set : ( ) => { }
51
+ } )
52
+ // $FlowIgnore
53
+ Object . defineProperty ( this , 'vm' , {
54
+ get : ( ) => undefined ,
55
+ set : ( ) => { }
56
+ } )
44
57
}
58
+ const frozenOptions = Object . freeze ( options )
59
+ // $FlowIgnore
60
+ Object . defineProperty ( this , 'options' , {
61
+ get : ( ) => frozenOptions ,
62
+ set : ( ) => { }
63
+ } )
45
64
if (
46
65
this . vnode &&
47
66
( this . vnode [ FUNCTIONAL_OPTIONS ] || this . vnode . functionalContext )
48
67
) {
49
68
this . isFunctionalComponent = true
50
69
}
51
- this . options = options
52
70
this . version = Number (
53
71
`${ Vue . version . split ( '.' ) [ 0 ] } .${ Vue . version . split ( '.' ) [ 1 ] } `
54
72
)
@@ -112,7 +130,7 @@ export default class Wrapper implements BaseWrapper {
112
130
*/
113
131
emitted ( event ?: string ) {
114
132
if ( ! this . _emitted && ! this . vm ) {
115
- throwError ( `wrapper . emitted ( ) can only be called on a Vue ` + ` instance `)
133
+ throwError ( `wrapper . emitted ( ) can only be called on a Vue instance `)
116
134
}
117
135
if ( event ) {
118
136
return this . _emitted [ event ]
@@ -126,7 +144,7 @@ export default class Wrapper implements BaseWrapper {
126
144
emittedByOrder ( ) {
127
145
if ( ! this . _emittedByOrder && ! this . vm ) {
128
146
throwError (
129
- `wrapper . emittedByOrder ( ) can only be called on a ` + ` Vue instance `
147
+ `wrapper . emittedByOrder ( ) can only be called on a Vue instance `
130
148
)
131
149
}
132
150
return this . _emittedByOrder
@@ -155,13 +173,7 @@ export default class Wrapper implements BaseWrapper {
155
173
`visible has been deprecated and will be removed in ` +
156
174
`version 1, use isVisible instead`
157
175
)
158
-
159
176
let element = this . element
160
-
161
- if ( ! element ) {
162
- return false
163
- }
164
-
165
177
while ( element ) {
166
178
if (
167
179
element . style &&
@@ -188,17 +200,17 @@ export default class Wrapper implements BaseWrapper {
188
200
189
201
if ( typeof attribute !== 'string' ) {
190
202
throwError (
191
- `wrapper.hasAttribute() must be passed attribute as ` + ` a string`
203
+ `wrapper.hasAttribute() must be passed attribute as a string`
192
204
)
193
205
}
194
206
195
207
if ( typeof value !== 'string' ) {
196
208
throwError (
197
- `wrapper.hasAttribute() must be passed value as a ` + ` string`
209
+ `wrapper.hasAttribute() must be passed value as a string`
198
210
)
199
211
}
200
212
201
- return ! ! ( this . element && this . element . getAttribute ( attribute ) === value )
213
+ return ! ! ( this . element . getAttribute ( attribute ) === value )
202
214
}
203
215
204
216
/**
@@ -270,7 +282,7 @@ export default class Wrapper implements BaseWrapper {
270
282
)
271
283
272
284
if ( typeof style !== 'string' ) {
273
- throwError ( `wrapper.hasStyle() must be passed style as a ` + ` string`)
285
+ throwError ( `wrapper.hasStyle() must be passed style as a string` )
274
286
}
275
287
276
288
if ( typeof value !== 'string' ) {
@@ -413,11 +425,6 @@ export default class Wrapper implements BaseWrapper {
413
425
*/
414
426
isVisible ( ) : boolean {
415
427
let element = this . element
416
-
417
- if ( ! element ) {
418
- return false
419
- }
420
-
421
428
while ( element ) {
422
429
if (
423
430
element . style &&
@@ -669,41 +676,32 @@ export default class Wrapper implements BaseWrapper {
669
676
* Sets element value and triggers input event
670
677
*/
671
678
setValue ( value : any ) {
672
- const el = this . element
673
-
674
- if ( ! el ) {
675
- throwError (
676
- `cannot call wrapper.setValue() on a wrapper ` + `without an element`
677
- )
678
- }
679
-
680
- const tag = el . tagName
679
+ const tagName = this . element . tagName
681
680
const type = this . attributes ( ) . type
682
- const event = 'input'
683
681
684
- if ( tag === 'SELECT' ) {
682
+ if ( tagName === 'SELECT' ) {
685
683
throwError (
686
684
`wrapper.setValue() cannot be called on a <select> ` +
687
685
`element. Use wrapper.setSelected() instead`
688
686
)
689
- } else if ( tag === 'INPUT' && type === 'checkbox' ) {
687
+ } else if ( tagName === 'INPUT' && type === 'checkbox' ) {
690
688
throwError (
691
689
`wrapper.setValue() cannot be called on a <input ` +
692
690
`type="checkbox" /> element. Use ` +
693
691
`wrapper.setChecked() instead`
694
692
)
695
- } else if ( tag === 'INPUT' && type === 'radio' ) {
693
+ } else if ( tagName === 'INPUT' && type === 'radio' ) {
696
694
throwError (
697
695
`wrapper.setValue() cannot be called on a <input ` +
698
696
`type="radio" /> element. Use wrapper.setChecked() ` +
699
697
`instead`
700
698
)
701
- } else if ( tag === 'INPUT' || tag === 'textarea' ) {
699
+ } else if ( tagName === 'INPUT' || tagName === 'textarea' ) {
702
700
// $FlowIgnore
703
- el . value = value
704
- this . trigger ( event )
701
+ this . element . value = value
702
+ this . trigger ( 'input' )
705
703
} else {
706
- throwError ( `wrapper.setValue() cannot be called on this ` + ` element`)
704
+ throwError ( `wrapper.setValue() cannot be called on this element` )
707
705
}
708
706
}
709
707
@@ -714,36 +712,26 @@ export default class Wrapper implements BaseWrapper {
714
712
if ( typeof checked !== 'boolean' ) {
715
713
throwError ( 'wrapper.setChecked() must be passed a boolean' )
716
714
}
717
-
718
- const el = this . element
719
-
720
- if ( ! el ) {
721
- throwError (
722
- `cannot call wrapper.setChecked() on a wrapper ` + `without an element`
723
- )
724
- }
725
-
726
- const tag = el . tagName
715
+ const tagName = this . element . tagName
727
716
const type = this . attributes ( ) . type
728
- const event = 'change'
729
717
730
- if ( tag === 'SELECT' ) {
718
+ if ( tagName === 'SELECT' ) {
731
719
throwError (
732
720
`wrapper.setChecked() cannot be called on a ` +
733
721
`<select> element. Use wrapper.setSelected() ` +
734
722
`instead`
735
723
)
736
- } else if ( tag === 'INPUT' && type === 'checkbox' ) {
724
+ } else if ( tagName === 'INPUT' && type === 'checkbox' ) {
737
725
// $FlowIgnore
738
- if ( el . checked !== checked ) {
726
+ if ( this . element . checked !== checked ) {
739
727
if ( ! navigator . userAgent . includes ( 'jsdom' ) ) {
740
728
// $FlowIgnore
741
- el . checked = checked
729
+ this . element . checked = checked
742
730
}
743
731
this . trigger ( 'click' )
744
- this . trigger ( event )
732
+ this . trigger ( 'change' )
745
733
}
746
- } else if ( tag === 'INPUT' && type === 'radio' ) {
734
+ } else if ( tagName === 'INPUT' && type === 'radio' ) {
747
735
if ( ! checked ) {
748
736
throwError (
749
737
`wrapper.setChecked() cannot be called with ` +
@@ -752,87 +740,72 @@ export default class Wrapper implements BaseWrapper {
752
740
)
753
741
} else {
754
742
// $FlowIgnore
755
- if ( ! el . checked ) {
743
+ if ( ! this . element . checked ) {
756
744
this . trigger ( 'click' )
757
- this . trigger ( event )
745
+ this . trigger ( 'change' )
758
746
}
759
747
}
760
- } else if ( tag === 'INPUT' || tag === 'textarea' ) {
748
+ } else if ( tagName === 'INPUT' || tagName === 'textarea' ) {
761
749
throwError (
762
750
`wrapper.setChecked() cannot be called on "text" ` +
763
751
`inputs. Use wrapper.setValue() instead`
764
752
)
765
753
} else {
766
- throwError ( `wrapper.setChecked() cannot be called on this ` + ` element`)
754
+ throwError ( `wrapper.setChecked() cannot be called on this element` )
767
755
}
768
756
}
769
757
770
758
/**
771
759
* Selects <option></option> element
772
760
*/
773
761
setSelected ( ) {
774
- const el = this . element
775
-
776
- if ( ! el ) {
777
- throwError (
778
- `cannot call wrapper.setSelected() on a wrapper ` + `without an element`
779
- )
780
- }
781
-
782
- const tag = el . tagName
762
+ const tagName = this . element . tagName
783
763
const type = this . attributes ( ) . type
784
- const event = 'change'
785
764
786
- if ( tag === 'OPTION' ) {
765
+ if ( tagName === 'OPTION' ) {
787
766
// $FlowIgnore
788
- el . selected = true
767
+ this . element . selected = true
789
768
// $FlowIgnore
790
- if ( el . parentElement . tagName === 'OPTGROUP' ) {
769
+ if ( this . element . parentElement . tagName === 'OPTGROUP' ) {
791
770
// $FlowIgnore
792
- createWrapper ( el . parentElement . parentElement , this . options ) . trigger (
793
- event
794
- )
771
+ createWrapper ( this . element . parentElement . parentElement , this . options )
772
+ . trigger ( 'change' )
795
773
} else {
796
774
// $FlowIgnore
797
- createWrapper ( el . parentElement , this . options ) . trigger ( event )
775
+ createWrapper ( this . element . parentElement , this . options )
776
+ . trigger ( 'change' )
798
777
}
799
- } else if ( tag === 'SELECT' ) {
778
+ } else if ( tagName === 'SELECT' ) {
800
779
throwError (
801
780
`wrapper.setSelected() cannot be called on select. ` +
802
781
`Call it on one of its options`
803
782
)
804
- } else if ( tag === 'INPUT' && type === 'checkbox' ) {
783
+ } else if ( tagName === 'INPUT' && type === 'checkbox' ) {
805
784
throwError (
806
785
`wrapper.setSelected() cannot be called on a <input ` +
807
786
`type="checkbox" /> element. Use ` +
808
787
`wrapper.setChecked() instead`
809
788
)
810
- } else if ( tag === 'INPUT' && type === 'radio' ) {
789
+ } else if ( tagName === 'INPUT' && type === 'radio' ) {
811
790
throwError (
812
791
`wrapper.setSelected() cannot be called on a <input ` +
813
792
`type="radio" /> element. Use wrapper.setChecked() ` +
814
793
`instead`
815
794
)
816
- } else if ( tag === 'INPUT' || tag === 'textarea' ) {
795
+ } else if ( tagName === 'INPUT' || tagName === 'textarea' ) {
817
796
throwError (
818
797
`wrapper.setSelected() cannot be called on "text" ` +
819
798
`inputs. Use wrapper.setValue() instead`
820
799
)
821
800
} else {
822
- throwError ( `wrapper.setSelected() cannot be called on this ` + ` element`)
801
+ throwError ( `wrapper.setSelected() cannot be called on this element` )
823
802
}
824
803
}
825
804
826
805
/**
827
806
* Return text of wrapper element
828
807
*/
829
808
text ( ) : string {
830
- if ( ! this . element ) {
831
- throwError (
832
- `cannot call wrapper.text() on a wrapper without an ` + `element`
833
- )
834
- }
835
-
836
809
return this . element . textContent . trim ( )
837
810
}
838
811
@@ -859,12 +832,6 @@ export default class Wrapper implements BaseWrapper {
859
832
throwError ( 'wrapper.trigger() must be passed a string' )
860
833
}
861
834
862
- if ( ! this . element ) {
863
- throwError (
864
- `cannot call wrapper.trigger() on a wrapper without ` + `an element`
865
- )
866
- }
867
-
868
835
if ( options . target ) {
869
836
throwError (
870
837
`you cannot set the target value of an event. See ` +
0 commit comments