1
1
// import { type SSRContext, renderToString } from '@vue/server-renderer'
2
- import { createVaporSSRApp , renderEffect , setText , template } from '../src'
3
- import { nextTick , ref } from '@vue/runtime-dom'
2
+ import {
3
+ child ,
4
+ createVaporSSRApp ,
5
+ delegateEvents ,
6
+ next ,
7
+ renderEffect ,
8
+ setClass ,
9
+ setText ,
10
+ template ,
11
+ } from '../src'
12
+ import { nextTick , ref , toDisplayString } from '@vue/runtime-dom'
4
13
5
14
function mountWithHydration ( html : string , setup : ( ) => any ) {
6
15
const container = document . createElement ( 'div' )
16
+ document . body . appendChild ( container )
7
17
container . innerHTML = html
8
18
const app = createVaporSSRApp ( {
9
19
setup,
@@ -14,17 +24,19 @@ function mountWithHydration(html: string, setup: () => any) {
14
24
}
15
25
}
16
26
17
- // const triggerEvent = (type: string, el: Element) => {
18
- // const event = new Event(type)
19
- // el.dispatchEvent(event)
20
- // }
27
+ const triggerEvent = ( type : string , el : Element ) => {
28
+ const event = new Event ( type , { bubbles : true } )
29
+ el . dispatchEvent ( event )
30
+ }
21
31
22
32
describe ( 'SSR hydration' , ( ) => {
33
+ delegateEvents ( 'click' )
34
+
23
35
beforeEach ( ( ) => {
24
36
document . body . innerHTML = ''
25
37
} )
26
38
27
- test ( 'text' , async ( ) => {
39
+ test ( 'root text' , async ( ) => {
28
40
const msg = ref ( 'foo' )
29
41
const t = template ( ' ' )
30
42
const { container } = mountWithHydration ( 'foo' , ( ) => {
@@ -38,128 +50,99 @@ describe('SSR hydration', () => {
38
50
expect ( container . textContent ) . toBe ( 'bar' )
39
51
} )
40
52
41
- test ( 'empty text' , async ( ) => {
42
- const t0 = template ( '<div></div>' , true )
43
- const { container } = mountWithHydration ( '<div></div>' , ( ) => t0 ( ) )
44
- expect ( container . innerHTML ) . toBe ( '<div></div>' )
45
- expect ( `Hydration children mismatch in <div>` ) . not . toHaveBeenWarned ( )
46
- } )
47
-
48
- test ( 'comment' , ( ) => {
53
+ test ( 'root comment' , ( ) => {
49
54
const t0 = template ( '<!---->' )
50
55
const { container } = mountWithHydration ( '<!---->' , ( ) => t0 ( ) )
51
56
expect ( container . innerHTML ) . toBe ( '<!---->' )
52
57
expect ( `Hydration children mismatch in <div>` ) . not . toHaveBeenWarned ( )
53
58
} )
54
59
55
- // test('static before text', () => {
56
- // const t0 = template(' A ')
57
- // const t1 = template('<span>foo bar</span>')
58
- // const t2 = template(' ')
59
- // const msg = ref('hello')
60
- // const { container } = mountWithHydration(
61
- // ' A <span>foo bar</span>hello',
62
- // () => {
63
- // const n0 = t0()
64
- // const n1 = t1()
65
- // const n2 = t2()
66
- // const n3 = createTextNode()
67
- // renderEffect(() => setText(n3, toDisplayString(msg.value)))
68
- // return [n0, n1, n2, n3]
69
- // },
70
- // )
71
- // })
72
-
73
- // test('static (multiple elements)', () => {
74
- // const staticContent = '<div></div><span>hello</span>'
75
- // const html = `<div><div>hi</div>` + staticContent + `<div>ho</div></div>`
76
-
77
- // const n1 = h('div', 'hi')
78
- // const s = createStaticVNode('', 2)
79
- // const n2 = h('div', 'ho')
80
-
81
- // const { container } = mountWithHydration(html, () => h('div', [n1, s, n2]))
82
-
83
- // const div = container.firstChild!
84
-
85
- // expect(n1.el).toBe(div.firstChild)
86
- // expect(n2.el).toBe(div.lastChild)
87
- // expect(s.el).toBe(div.childNodes[1])
88
- // expect(s.anchor).toBe(div.childNodes[2])
89
- // expect(s.children).toBe(staticContent)
90
- // })
91
-
92
- // // #6008
93
- // test('static (with text node as starting node)', () => {
94
- // const html = ` A <span>foo</span> B`
95
- // const { vnode, container } = mountWithHydration(html, () =>
96
- // createStaticVNode(` A <span>foo</span> B`, 3),
97
- // )
98
- // expect(vnode.el).toBe(container.firstChild)
99
- // expect(vnode.anchor).toBe(container.lastChild)
100
- // expect(`Hydration node mismatch`).not.toHaveBeenWarned()
101
- // })
102
-
103
- // test('static with content adoption', () => {
104
- // const html = ` A <span>foo</span> B`
105
- // const { vnode, container } = mountWithHydration(html, () =>
106
- // createStaticVNode(``, 3),
107
- // )
108
- // expect(vnode.el).toBe(container.firstChild)
109
- // expect(vnode.anchor).toBe(container.lastChild)
110
- // expect(vnode.children).toBe(html)
111
- // expect(`Hydration node mismatch`).not.toHaveBeenWarned()
112
- // })
113
-
114
- // test('element with text children', async () => {
115
- // const msg = ref('foo')
116
- // const { vnode, container } = mountWithHydration(
117
- // '<div class="foo">foo</div>',
118
- // () => h('div', { class: msg.value }, msg.value),
119
- // )
120
- // expect(vnode.el).toBe(container.firstChild)
121
- // expect(container.firstChild!.textContent).toBe('foo')
122
- // msg.value = 'bar'
123
- // await nextTick()
124
- // expect(container.innerHTML).toBe(`<div class="bar">bar</div>`)
125
- // })
60
+ test ( 'root with mixed element and text' , async ( ) => {
61
+ const t0 = template ( ' A' )
62
+ const t1 = template ( '<span>foo bar</span>' )
63
+ const t2 = template ( ' ' )
64
+ const msg = ref ( 'hello' )
65
+ const { container } = mountWithHydration (
66
+ ' A<span>foo bar</span>hello' ,
67
+ ( ) => {
68
+ const n0 = t0 ( )
69
+ const n1 = t1 ( )
70
+ const n2 = t2 ( )
71
+ renderEffect ( ( ) => setText ( n2 as Text , toDisplayString ( msg . value ) ) )
72
+ return [ n0 , n1 , n2 ]
73
+ } ,
74
+ )
75
+ expect ( container . innerHTML ) . toBe ( ' A<span>foo bar</span>hello' )
76
+ msg . value = 'bar'
77
+ await nextTick ( )
78
+ expect ( container . innerHTML ) . toBe ( ' A<span>foo bar</span>bar' )
79
+ } )
126
80
127
- // // #7285
128
- // test('element with multiple continuous text vnodes', async () => {
129
- // // should no mismatch warning
130
- // const { container } = mountWithHydration('<div>foo0o</div>', () =>
131
- // h('div', ['fo', createTextVNode('o'), 0, 'o']),
132
- // )
133
- // expect(container.textContent).toBe('foo0o')
134
- // })
81
+ test ( 'empty element' , async ( ) => {
82
+ const t0 = template ( '<div></div>' , true )
83
+ const { container } = mountWithHydration ( '<div></div>' , ( ) => t0 ( ) )
84
+ expect ( container . innerHTML ) . toBe ( '<div></div>' )
85
+ expect ( `Hydration children mismatch in <div>` ) . not . toHaveBeenWarned ( )
86
+ } )
135
87
136
- // test('element with elements children', async () => {
137
- // const msg = ref('foo')
138
- // const fn = vi.fn()
139
- // const { vnode, container } = mountWithHydration(
140
- // '<div><span>foo</span><span class="foo"></span></div>',
141
- // () =>
142
- // h('div', [
143
- // h('span', msg.value),
144
- // h('span', { class: msg.value, onClick: fn }),
145
- // ]),
146
- // )
147
- // expect(vnode.el).toBe(container.firstChild)
148
- // expect((vnode.children as VNode[])[0].el).toBe(
149
- // container.firstChild!.childNodes[0],
150
- // )
151
- // expect((vnode.children as VNode[])[1].el).toBe(
152
- // container.firstChild!.childNodes[1],
153
- // )
88
+ test ( 'element with text children' , async ( ) => {
89
+ const t0 = template ( '<div> </div>' , true )
90
+ const msg = ref ( 'foo' )
91
+ const { container } = mountWithHydration (
92
+ '<div class="foo">foo</div>' ,
93
+ ( ) => {
94
+ const n0 = t0 ( ) as Element
95
+ const x0 = child ( n0 ) as Text
96
+ renderEffect ( ( ) => {
97
+ const _msg = msg . value
98
+
99
+ setText ( x0 , toDisplayString ( _msg ) )
100
+ setClass ( n0 , _msg )
101
+ } )
102
+ return n0
103
+ } ,
104
+ )
105
+ expect ( container . innerHTML ) . toBe ( `<div class="foo">foo</div>` )
106
+ msg . value = 'bar'
107
+ await nextTick ( )
108
+ expect ( container . innerHTML ) . toBe ( `<div class="bar">bar</div>` )
109
+ } )
154
110
155
- // // event handler
156
- // triggerEvent('click', vnode.el.querySelector('.foo')!)
157
- // expect(fn).toHaveBeenCalled()
111
+ test ( 'element with elements children' , async ( ) => {
112
+ const t0 = template ( '<div><span> </span><span></span></div>' , true )
113
+ const msg = ref ( 'foo' )
114
+ const fn = vi . fn ( )
115
+ const { container } = mountWithHydration (
116
+ '<div><span>foo</span><span class="foo"></span></div>' ,
117
+ ( ) => {
118
+ const n2 = t0 ( ) as Element
119
+ const n0 = child ( n2 ) as Element
120
+ const n1 = next ( n0 ) as Element
121
+ const x0 = child ( n0 ) as Text
122
+ ; ( n1 as any ) . $evtclick = fn
123
+ renderEffect ( ( ) => {
124
+ const _msg = msg . value
125
+
126
+ setText ( x0 , toDisplayString ( _msg ) )
127
+ setClass ( n1 , _msg )
128
+ } )
129
+ return n2
130
+ } ,
131
+ )
132
+ expect ( container . innerHTML ) . toBe (
133
+ `<div><span>foo</span><span class="foo"></span></div>` ,
134
+ )
135
+
136
+ // event handler
137
+ triggerEvent ( 'click' , container . querySelector ( '.foo' ) ! )
138
+ expect ( fn ) . toHaveBeenCalled ( )
158
139
159
- // msg.value = 'bar'
160
- // await nextTick()
161
- // expect(vnode.el.innerHTML).toBe(`<span>bar</span><span class="bar"></span>`)
162
- // })
140
+ msg . value = 'bar'
141
+ await nextTick ( )
142
+ expect ( container . innerHTML ) . toBe (
143
+ `<div><span>bar</span><span class="bar"></span></div>` ,
144
+ )
145
+ } )
163
146
164
147
// test('element with ref', () => {
165
148
// const el = ref()
0 commit comments