|
|
@ -1,5 +1,5 @@ |
|
|
|
import Vue from 'vue' |
|
|
|
import { patch } from 'web/runtime/patch' |
|
|
|
import * as nodeOps from 'web/runtime/node-ops' |
|
|
|
import VNode from 'core/vdom/vnode' |
|
|
|
|
|
|
|
describe('hydration', () => { |
|
|
@ -13,13 +13,13 @@ describe('hydration', () => { |
|
|
|
const result = [] |
|
|
|
function init (vnode) { result.push(vnode) } |
|
|
|
function createServerRenderedDOM () { |
|
|
|
const root = nodeOps.createElement('div') |
|
|
|
const root = document.createElement('div') |
|
|
|
root.setAttribute('server-rendered', 'true') |
|
|
|
const span = nodeOps.createElement('span') |
|
|
|
const span = document.createElement('span') |
|
|
|
root.appendChild(span) |
|
|
|
const div = nodeOps.createElement('div') |
|
|
|
const child1 = nodeOps.createElement('span') |
|
|
|
const child2 = nodeOps.createElement('span') |
|
|
|
const div = document.createElement('div') |
|
|
|
const child1 = document.createElement('span') |
|
|
|
const child2 = document.createElement('span') |
|
|
|
child1.textContent = 'hi' |
|
|
|
child2.textContent = 'ho' |
|
|
|
div.appendChild(child1) |
|
|
@ -62,42 +62,14 @@ describe('hydration', () => { |
|
|
|
expect(node0.children[0].id).toBe('bar') |
|
|
|
}) |
|
|
|
|
|
|
|
it('should hydrate components when server-rendered DOM tree is same as virtual DOM tree', () => { |
|
|
|
const result = [] |
|
|
|
function init (vnode) { result.push(vnode) } |
|
|
|
function createServerRenderedDOM () { |
|
|
|
const root = nodeOps.createElement('vue-component-1') |
|
|
|
root.setAttribute('server-rendered', 'true') |
|
|
|
const span = nodeOps.createElement('span') |
|
|
|
root.appendChild(span) |
|
|
|
const div = nodeOps.createElement('div') |
|
|
|
const child1 = nodeOps.createElement('span') |
|
|
|
const child2 = nodeOps.createElement('span') |
|
|
|
div.appendChild(child1) |
|
|
|
div.appendChild(child2) |
|
|
|
root.appendChild(div) |
|
|
|
return root |
|
|
|
} |
|
|
|
const node0 = createServerRenderedDOM() |
|
|
|
const vnode1 = new VNode('vue-component-1', {}, [ |
|
|
|
new VNode('span', {}), |
|
|
|
new VNode('div', { hook: { init }}, [ |
|
|
|
new VNode('span', {}), |
|
|
|
new VNode('span', {}) |
|
|
|
]) |
|
|
|
]) |
|
|
|
patch(node0, vnode1) |
|
|
|
expect(result.length).toBe(1) |
|
|
|
}) |
|
|
|
|
|
|
|
it('should warn message that virtual DOM tree is not matching when hydrate element', () => { |
|
|
|
function createServerRenderedDOM () { |
|
|
|
const root = nodeOps.createElement('div') |
|
|
|
const root = document.createElement('div') |
|
|
|
root.setAttribute('server-rendered', 'true') |
|
|
|
const span = nodeOps.createElement('span') |
|
|
|
const span = document.createElement('span') |
|
|
|
root.appendChild(span) |
|
|
|
const div = nodeOps.createElement('div') |
|
|
|
const child1 = nodeOps.createElement('span') |
|
|
|
const div = document.createElement('div') |
|
|
|
const child1 = document.createElement('span') |
|
|
|
div.appendChild(child1) |
|
|
|
root.appendChild(div) |
|
|
|
return root |
|
|
@ -113,4 +85,64 @@ describe('hydration', () => { |
|
|
|
patch(node0, vnode1) |
|
|
|
expect('The client-side rendered virtual DOM tree is not matching').toHaveBeenWarned() |
|
|
|
}) |
|
|
|
|
|
|
|
// component hydration is better off with a more e2e approach
|
|
|
|
it('should hydrate components when server-rendered DOM tree is same as virtual DOM tree', done => { |
|
|
|
const dom = document.createElement('div') |
|
|
|
dom.setAttribute('server-rendered', 'true') |
|
|
|
dom.innerHTML = '<span>foo</span><div class="b a"><span>foo qux</span></div>' |
|
|
|
const originalNode1 = dom.children[0] |
|
|
|
const originalNode2 = dom.children[1] |
|
|
|
|
|
|
|
const vm = new Vue({ |
|
|
|
template: '<div><span>{{msg}}</span><test class="a" :msg="msg"></test></div>', |
|
|
|
data: { |
|
|
|
msg: 'foo' |
|
|
|
}, |
|
|
|
components: { |
|
|
|
test: { |
|
|
|
props: ['msg'], |
|
|
|
data () { |
|
|
|
return { a: 'qux' } |
|
|
|
}, |
|
|
|
template: '<div class="b"><span>{{msg}} {{a}}</span></div>' |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
expect(() => { vm.$mount(dom) }).not.toThrow() |
|
|
|
expect('not matching server-rendered content').not.toHaveBeenWarned() |
|
|
|
expect(vm.$el).toBe(dom) |
|
|
|
expect(vm.$children[0].$el).toBe(originalNode2) |
|
|
|
expect(vm.$el.children[0]).toBe(originalNode1) |
|
|
|
expect(vm.$el.children[1]).toBe(originalNode2) |
|
|
|
vm.msg = 'bar' |
|
|
|
waitForUpdate(() => { |
|
|
|
expect(vm.$el.innerHTML).toBe('<span>bar</span><div class="b a"><span>bar qux</span></div>') |
|
|
|
vm.$children[0].a = 'ququx' |
|
|
|
}).then(() => { |
|
|
|
expect(vm.$el.innerHTML).toBe('<span>bar</span><div class="b a"><span>bar ququx</span></div>') |
|
|
|
}).then(done) |
|
|
|
}) |
|
|
|
|
|
|
|
it('should warn failed hydration for non-matching DOM in child component', () => { |
|
|
|
const dom = document.createElement('div') |
|
|
|
dom.setAttribute('server-rendered', 'true') |
|
|
|
dom.innerHTML = '<div><span>foo</span></div>' |
|
|
|
|
|
|
|
const vm = new Vue({ |
|
|
|
template: '<div><test :msg="msg"></test></div>', |
|
|
|
components: { |
|
|
|
test: { |
|
|
|
data () { |
|
|
|
return { a: 'qux' } |
|
|
|
}, |
|
|
|
template: '<div><span>{{a}}</span></div>' |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
vm.$mount(dom) |
|
|
|
expect('not matching server-rendered content').toHaveBeenWarned() |
|
|
|
}) |
|
|
|
}) |
|
|
|