@@ -12,6 +12,7 @@ import {
12
12
} from '@vue/runtime-dom'
13
13
import { renderToString } from '@vue/server-renderer'
14
14
import { mockWarn } from '@vue/shared'
15
+ import { SSRContext } from 'packages/server-renderer/src/renderToString'
15
16
16
17
function mountWithHydration ( html : string , render : ( ) => any ) {
17
18
const container = document . createElement ( 'div' )
@@ -157,7 +158,7 @@ describe('SSR hydration', () => {
157
158
const fn = jest . fn ( )
158
159
const portalContainer = document . createElement ( 'div' )
159
160
portalContainer . id = 'portal'
160
- portalContainer . innerHTML = `<span>foo</span><span class="foo"></span>`
161
+ portalContainer . innerHTML = `<span>foo</span><span class="foo"></span><!----> `
161
162
document . body . appendChild ( portalContainer )
162
163
163
164
const { vnode, container } = mountWithHydration ( '<!--portal-->' , ( ) =>
@@ -182,7 +183,69 @@ describe('SSR hydration', () => {
182
183
msg . value = 'bar'
183
184
await nextTick ( )
184
185
expect ( portalContainer . innerHTML ) . toBe (
185
- `<span>bar</span><span class="bar"></span>`
186
+ `<span>bar</span><span class="bar"></span><!---->`
187
+ )
188
+ } )
189
+
190
+ test ( 'Portal (multiple + integration)' , async ( ) => {
191
+ const msg = ref ( 'foo' )
192
+ const fn1 = jest . fn ( )
193
+ const fn2 = jest . fn ( )
194
+
195
+ const Comp = ( ) => [
196
+ h ( Portal , { target : '#portal2' } , [
197
+ h ( 'span' , msg . value ) ,
198
+ h ( 'span' , { class : msg . value , onClick : fn1 } )
199
+ ] ) ,
200
+ h ( Portal , { target : '#portal2' } , [
201
+ h ( 'span' , msg . value + '2' ) ,
202
+ h ( 'span' , { class : msg . value + '2' , onClick : fn2 } )
203
+ ] )
204
+ ]
205
+
206
+ const portalContainer = document . createElement ( 'div' )
207
+ portalContainer . id = 'portal2'
208
+ const ctx : SSRContext = { }
209
+ const mainHtml = await renderToString ( h ( Comp ) , ctx )
210
+ expect ( mainHtml ) . toMatchInlineSnapshot (
211
+ `"<!--[--><!--portal--><!--portal--><!--]-->"`
212
+ )
213
+
214
+ const portalHtml = ctx . portals ! [ '#portal2' ]
215
+ expect ( portalHtml ) . toMatchInlineSnapshot (
216
+ `"<span>foo</span><span class=\\"foo\\"></span><!----><span>foo2</span><span class=\\"foo2\\"></span><!---->"`
217
+ )
218
+
219
+ portalContainer . innerHTML = portalHtml
220
+ document . body . appendChild ( portalContainer )
221
+
222
+ const { vnode, container } = mountWithHydration ( mainHtml , Comp )
223
+ expect ( vnode . el ) . toBe ( container . firstChild )
224
+ const portalVnode1 = ( vnode . children as VNode [ ] ) [ 0 ]
225
+ const portalVnode2 = ( vnode . children as VNode [ ] ) [ 1 ]
226
+ expect ( portalVnode1 . el ) . toBe ( container . childNodes [ 1 ] )
227
+ expect ( portalVnode2 . el ) . toBe ( container . childNodes [ 2 ] )
228
+
229
+ expect ( ( portalVnode1 as any ) . children [ 0 ] . el ) . toBe (
230
+ portalContainer . childNodes [ 0 ]
231
+ )
232
+ expect ( portalVnode1 . anchor ) . toBe ( portalContainer . childNodes [ 2 ] )
233
+ expect ( ( portalVnode2 as any ) . children [ 0 ] . el ) . toBe (
234
+ portalContainer . childNodes [ 3 ]
235
+ )
236
+ expect ( portalVnode2 . anchor ) . toBe ( portalContainer . childNodes [ 5 ] )
237
+
238
+ // // event handler
239
+ triggerEvent ( 'click' , portalContainer . querySelector ( '.foo' ) ! )
240
+ expect ( fn1 ) . toHaveBeenCalled ( )
241
+
242
+ triggerEvent ( 'click' , portalContainer . querySelector ( '.foo2' ) ! )
243
+ expect ( fn2 ) . toHaveBeenCalled ( )
244
+
245
+ msg . value = 'bar'
246
+ await nextTick ( )
247
+ expect ( portalContainer . innerHTML ) . toMatchInlineSnapshot (
248
+ `"<span>bar</span><span class=\\"bar\\"></span><!----><span>bar2</span><span class=\\"bar2\\"></span><!---->"`
186
249
)
187
250
} )
188
251
0 commit comments