@@ -3,6 +3,13 @@ import VNode from 'core/vdom/vnode'
3
3
import { patch } from 'web/runtime/patch'
4
4
import { SSR_ATTR } from 'shared/constants'
5
5
6
+ function createMockSSRDOM ( innerHTML ) {
7
+ const dom = document . createElement ( 'div' )
8
+ dom . setAttribute ( SSR_ATTR , 'true' )
9
+ dom . innerHTML = innerHTML
10
+ return dom
11
+ }
12
+
6
13
describe ( 'vdom patch: hydration' , ( ) => {
7
14
let vnode0
8
15
beforeEach ( ( ) => {
@@ -89,9 +96,7 @@ describe('vdom patch: hydration', () => {
89
96
90
97
// component hydration is better off with a more e2e approach
91
98
it ( 'should hydrate components when server-rendered DOM tree is same as virtual DOM tree' , done => {
92
- const dom = document . createElement ( 'div' )
93
- dom . setAttribute ( SSR_ATTR , 'true' )
94
- dom . innerHTML = '<span>foo</span><div class="b a"><span>foo qux</span></div><!---->'
99
+ const dom = createMockSSRDOM ( '<span>foo</span><div class="b a"><span>foo qux</span></div><!---->' )
95
100
const originalNode1 = dom . children [ 0 ]
96
101
const originalNode2 = dom . children [ 1 ]
97
102
@@ -131,9 +136,7 @@ describe('vdom patch: hydration', () => {
131
136
} )
132
137
133
138
it ( 'should warn failed hydration for non-matching DOM in child component' , ( ) => {
134
- const dom = document . createElement ( 'div' )
135
- dom . setAttribute ( SSR_ATTR , 'true' )
136
- dom . innerHTML = '<div><span></span></div>'
139
+ const dom = createMockSSRDOM ( '<div><span></span></div>' )
137
140
138
141
new Vue ( {
139
142
template : '<div><test></test></div>' ,
@@ -148,9 +151,7 @@ describe('vdom patch: hydration', () => {
148
151
} )
149
152
150
153
it ( 'should overwrite textNodes in the correct position but with mismatching text without warning' , ( ) => {
151
- const dom = document . createElement ( 'div' )
152
- dom . setAttribute ( SSR_ATTR , 'true' )
153
- dom . innerHTML = '<div><span>foo</span></div>'
154
+ const dom = createMockSSRDOM ( '<div><span>foo</span></div>' )
154
155
155
156
new Vue ( {
156
157
template : '<div><test></test></div>' ,
@@ -169,9 +170,7 @@ describe('vdom patch: hydration', () => {
169
170
} )
170
171
171
172
it ( 'should pick up elements with no children and populate without warning' , done => {
172
- const dom = document . createElement ( 'div' )
173
- dom . setAttribute ( SSR_ATTR , 'true' )
174
- dom . innerHTML = '<div><span></span></div>'
173
+ const dom = createMockSSRDOM ( '<div><span></span></div>' )
175
174
const span = dom . querySelector ( 'span' )
176
175
177
176
const vm = new Vue ( {
@@ -195,4 +194,107 @@ describe('vdom patch: hydration', () => {
195
194
expect ( vm . $el . innerHTML ) . toBe ( '<div><span>foo</span></div>' )
196
195
} ) . then ( done )
197
196
} )
197
+
198
+ it ( 'should hydrate async component' , done => {
199
+ const dom = createMockSSRDOM ( '<span>foo</span>' )
200
+ const span = dom . querySelector ( 'span' )
201
+
202
+ const Foo = resolve => setTimeout ( ( ) => {
203
+ resolve ( {
204
+ data : ( ) => ( { msg : 'foo' } ) ,
205
+ template : `<span>{{ msg }}</span>`
206
+ } )
207
+ } , 0 )
208
+
209
+ const vm = new Vue ( {
210
+ template : '<div><foo ref="foo" /></div>' ,
211
+ components : { Foo }
212
+ } ) . $mount ( dom )
213
+
214
+ expect ( 'not matching server-rendered content' ) . not . toHaveBeenWarned ( )
215
+ expect ( dom . innerHTML ) . toBe ( '<span>foo</span>' )
216
+ expect ( vm . $refs . foo ) . toBeUndefined ( )
217
+
218
+ setTimeout ( ( ) => {
219
+ expect ( dom . innerHTML ) . toBe ( '<span>foo</span>' )
220
+ expect ( vm . $refs . foo ) . not . toBeUndefined ( )
221
+ vm . $refs . foo . msg = 'bar'
222
+ waitForUpdate ( ( ) => {
223
+ expect ( dom . innerHTML ) . toBe ( '<span>bar</span>' )
224
+ expect ( dom . querySelector ( 'span' ) ) . toBe ( span )
225
+ } ) . then ( done )
226
+ } , 0 )
227
+ } )
228
+
229
+ it ( 'should hydrate async component without showing loading' , done => {
230
+ const dom = createMockSSRDOM ( '<span>foo</span>' )
231
+ const span = dom . querySelector ( 'span' )
232
+
233
+ const Foo = ( ) => ( {
234
+ component : new Promise ( resolve => {
235
+ setTimeout ( ( ) => {
236
+ resolve ( {
237
+ data : ( ) => ( { msg : 'foo' } ) ,
238
+ template : `<span>{{ msg }}</span>`
239
+ } )
240
+ } , 10 )
241
+ } ) ,
242
+ delay : 1 ,
243
+ loading : {
244
+ render : h => h ( 'span' , 'loading' )
245
+ }
246
+ } )
247
+
248
+ const vm = new Vue ( {
249
+ template : '<div><foo ref="foo" /></div>' ,
250
+ components : { Foo }
251
+ } ) . $mount ( dom )
252
+
253
+ expect ( 'not matching server-rendered content' ) . not . toHaveBeenWarned ( )
254
+ expect ( dom . innerHTML ) . toBe ( '<span>foo</span>' )
255
+ expect ( vm . $refs . foo ) . toBeUndefined ( )
256
+
257
+ setTimeout ( ( ) => {
258
+ expect ( dom . innerHTML ) . toBe ( '<span>foo</span>' )
259
+ } , 1 )
260
+
261
+ setTimeout ( ( ) => {
262
+ expect ( dom . innerHTML ) . toBe ( '<span>foo</span>' )
263
+ expect ( vm . $refs . foo ) . not . toBeUndefined ( )
264
+ vm . $refs . foo . msg = 'bar'
265
+ waitForUpdate ( ( ) => {
266
+ expect ( dom . innerHTML ) . toBe ( '<span>bar</span>' )
267
+ expect ( dom . querySelector ( 'span' ) ) . toBe ( span )
268
+ } ) . then ( done )
269
+ } , 10 )
270
+ } )
271
+
272
+ it ( 'should hydrate async component by replacing DOM if error occurs' , done => {
273
+ const dom = createMockSSRDOM ( '<span>foo</span>' )
274
+
275
+ const Foo = ( ) => ( {
276
+ component : new Promise ( ( resolve , reject ) => {
277
+ setTimeout ( ( ) => {
278
+ reject ( 'something went wrong' )
279
+ } , 10 )
280
+ } ) ,
281
+ error : {
282
+ render : h => h ( 'span' , 'error' )
283
+ }
284
+ } )
285
+
286
+ new Vue ( {
287
+ template : '<div><foo ref="foo" /></div>' ,
288
+ components : { Foo }
289
+ } ) . $mount ( dom )
290
+
291
+ expect ( 'not matching server-rendered content' ) . not . toHaveBeenWarned ( )
292
+ expect ( dom . innerHTML ) . toBe ( '<span>foo</span>' )
293
+
294
+ setTimeout ( ( ) => {
295
+ expect ( 'Failed to resolve async' ) . toHaveBeenWarned ( )
296
+ expect ( dom . innerHTML ) . toBe ( '<span>error</span>' )
297
+ done ( )
298
+ } , 10 )
299
+ } )
198
300
} )
0 commit comments