c03459b9b6
fix #5786
526 lines
13 KiB
TypeScript
526 lines
13 KiB
TypeScript
/**
|
|
* @jest-environment node
|
|
*/
|
|
|
|
import { renderToString } from '../src/renderToString'
|
|
import {
|
|
createApp,
|
|
h,
|
|
withDirectives,
|
|
vShow,
|
|
vModelText,
|
|
vModelRadio,
|
|
vModelCheckbox,
|
|
vModelDynamic,
|
|
resolveDirective
|
|
} from 'vue'
|
|
import { ssrGetDirectiveProps, ssrRenderAttrs } from '../src'
|
|
|
|
describe('ssr: directives', () => {
|
|
describe('template v-show', () => {
|
|
test('basic', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
template: `<div v-show="true"/>`
|
|
})
|
|
)
|
|
).toBe(`<div style=""></div>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
template: `<div v-show="false"/>`
|
|
})
|
|
)
|
|
).toBe(`<div style="display:none;"></div>`)
|
|
})
|
|
|
|
test('with static style', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
template: `<div style="color:red" v-show="false"/>`
|
|
})
|
|
)
|
|
).toBe(`<div style="color:red;display:none;"></div>`)
|
|
})
|
|
|
|
test('with dynamic style', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ style: { color: 'red' } }),
|
|
template: `<div :style="style" v-show="false"/>`
|
|
})
|
|
)
|
|
).toBe(`<div style="color:red;display:none;"></div>`)
|
|
})
|
|
|
|
test('with static + dynamic style', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ style: { color: 'red' } }),
|
|
template: `<div :style="style" style="font-size:12;" v-show="false"/>`
|
|
})
|
|
)
|
|
).toBe(`<div style="color:red;font-size:12;display:none;"></div>`)
|
|
})
|
|
})
|
|
|
|
describe('template v-model', () => {
|
|
test('text', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ text: 'hello' }),
|
|
template: `<input v-model="text">`
|
|
})
|
|
)
|
|
).toBe(`<input value="hello">`)
|
|
})
|
|
|
|
test('radio', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ selected: 'foo' }),
|
|
template: `<input type="radio" value="foo" v-model="selected">`
|
|
})
|
|
)
|
|
).toBe(`<input type="radio" value="foo" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ selected: 'foo' }),
|
|
template: `<input type="radio" value="bar" v-model="selected">`
|
|
})
|
|
)
|
|
).toBe(`<input type="radio" value="bar">`)
|
|
|
|
// non-string values
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ selected: 'foo' }),
|
|
template: `<input type="radio" :value="{}" v-model="selected">`
|
|
})
|
|
)
|
|
).toBe(`<input type="radio">`)
|
|
})
|
|
|
|
test('checkbox', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ checked: true }),
|
|
template: `<input type="checkbox" v-model="checked">`
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ checked: false }),
|
|
template: `<input type="checkbox" v-model="checked">`
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox">`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ checked: ['foo'] }),
|
|
template: `<input type="checkbox" value="foo" v-model="checked">`
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" value="foo" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ checked: [] }),
|
|
template: `<input type="checkbox" value="foo" v-model="checked">`
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" value="foo">`)
|
|
})
|
|
|
|
test('textarea', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ foo: 'hello' }),
|
|
template: `<textarea v-model="foo"/>`
|
|
})
|
|
)
|
|
).toBe(`<textarea>hello</textarea>`)
|
|
})
|
|
|
|
test('dynamic type', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ type: 'text', model: 'hello' }),
|
|
template: `<input :type="type" v-model="model">`
|
|
})
|
|
)
|
|
).toBe(`<input type="text" value="hello">`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ type: 'checkbox', model: true }),
|
|
template: `<input :type="type" v-model="model">`
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ type: 'checkbox', model: false }),
|
|
template: `<input :type="type" v-model="model">`
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox">`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ type: 'checkbox', model: ['hello'] }),
|
|
template: `<input :type="type" value="hello" v-model="model">`
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" value="hello" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ type: 'checkbox', model: [] }),
|
|
template: `<input :type="type" value="hello" v-model="model">`
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" value="hello">`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ type: 'radio', model: 'hello' }),
|
|
template: `<input :type="type" value="hello" v-model="model">`
|
|
})
|
|
)
|
|
).toBe(`<input type="radio" value="hello" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({ type: 'radio', model: 'hello' }),
|
|
template: `<input :type="type" value="bar" v-model="model">`
|
|
})
|
|
)
|
|
).toBe(`<input type="radio" value="bar">`)
|
|
})
|
|
|
|
test('with v-bind', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data: () => ({
|
|
obj: { type: 'radio', value: 'hello' },
|
|
model: 'hello'
|
|
}),
|
|
template: `<input v-bind="obj" v-model="model">`
|
|
})
|
|
)
|
|
).toBe(`<input type="radio" value="hello" checked>`)
|
|
})
|
|
})
|
|
|
|
describe('vnode v-show', () => {
|
|
test('basic', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(h('div'), [[vShow, true]])
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<div></div>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(h('div'), [[vShow, false]])
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<div style="display:none;"></div>`)
|
|
})
|
|
|
|
test('with merge', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(
|
|
h('div', {
|
|
style: {
|
|
color: 'red'
|
|
}
|
|
}),
|
|
[[vShow, false]]
|
|
)
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<div style="color:red;display:none;"></div>`)
|
|
})
|
|
})
|
|
|
|
describe('vnode v-model', () => {
|
|
test('text', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(h('input'), [[vModelText, 'hello']])
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input value="hello">`)
|
|
})
|
|
|
|
test('radio', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(
|
|
h('input', { type: 'radio', value: 'hello' }),
|
|
[[vModelRadio, 'hello']]
|
|
)
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="radio" value="hello" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(
|
|
h('input', { type: 'radio', value: 'hello' }),
|
|
[[vModelRadio, 'foo']]
|
|
)
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="radio" value="hello">`)
|
|
})
|
|
|
|
test('checkbox', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(h('input', { type: 'checkbox' }), [
|
|
[vModelCheckbox, true]
|
|
])
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(h('input', { type: 'checkbox' }), [
|
|
[vModelCheckbox, false]
|
|
])
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox">`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(
|
|
h('input', { type: 'checkbox', value: 'foo' }),
|
|
[[vModelCheckbox, ['foo']]]
|
|
)
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" value="foo" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(
|
|
h('input', { type: 'checkbox', value: 'foo' }),
|
|
[[vModelCheckbox, []]]
|
|
)
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" value="foo">`)
|
|
})
|
|
})
|
|
|
|
describe('vnode v-model dynamic', () => {
|
|
test('text', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(h('input'), [[vModelDynamic, 'hello']])
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input value="hello">`)
|
|
})
|
|
|
|
test('radio', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(
|
|
h('input', { type: 'radio', value: 'hello' }),
|
|
[[vModelDynamic, 'hello']]
|
|
)
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="radio" value="hello" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(
|
|
h('input', { type: 'radio', value: 'hello' }),
|
|
[[vModelDynamic, 'foo']]
|
|
)
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="radio" value="hello">`)
|
|
})
|
|
|
|
test('checkbox', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(h('input', { type: 'checkbox' }), [
|
|
[vModelDynamic, true]
|
|
])
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(h('input', { type: 'checkbox' }), [
|
|
[vModelDynamic, false]
|
|
])
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox">`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(
|
|
h('input', { type: 'checkbox', value: 'foo' }),
|
|
[[vModelDynamic, ['foo']]]
|
|
)
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" value="foo" checked>`)
|
|
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(
|
|
h('input', { type: 'checkbox', value: 'foo' }),
|
|
[[vModelDynamic, []]]
|
|
)
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<input type="checkbox" value="foo">`)
|
|
})
|
|
})
|
|
|
|
test('custom directive w/ getSSRProps (vdom)', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
render() {
|
|
return withDirectives(h('div'), [
|
|
[
|
|
{
|
|
getSSRProps({ value }) {
|
|
return { id: value }
|
|
}
|
|
},
|
|
'foo'
|
|
]
|
|
])
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<div id="foo"></div>`)
|
|
})
|
|
|
|
test('custom directive w/ getSSRProps (optimized)', async () => {
|
|
expect(
|
|
await renderToString(
|
|
createApp({
|
|
data() {
|
|
return {
|
|
x: 'foo'
|
|
}
|
|
},
|
|
directives: {
|
|
xxx: {
|
|
getSSRProps({ value, arg, modifiers }) {
|
|
return { id: [value, arg, modifiers.ok].join('-') }
|
|
}
|
|
}
|
|
},
|
|
ssrRender(_ctx, _push, _parent, _attrs) {
|
|
const _directive_xxx = resolveDirective('xxx')!
|
|
_push(
|
|
`<div${ssrRenderAttrs(
|
|
ssrGetDirectiveProps(_ctx, _directive_xxx, _ctx.x, 'arg', {
|
|
ok: true
|
|
})
|
|
)}></div>`
|
|
)
|
|
}
|
|
})
|
|
)
|
|
).toBe(`<div id="foo-arg-true"></div>`)
|
|
})
|
|
})
|