| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623 |
- import { renderToString } from '../src/renderToString'
- import {
- createApp,
- h,
- mergeProps,
- ref,
- resolveDirective,
- unref,
- vModelCheckbox,
- vModelDynamic,
- vModelRadio,
- vModelText,
- vShow,
- withDirectives,
- } 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('select', async () => {
- expect(
- await renderToString(
- createApp({
- data: () => ({ model: 1 }),
- template: `<select v-model="model"><option value="0"></option><option value="1"></option></select>`,
- }),
- ),
- ).toBe(
- `<select><option value="0"></option><option value="1" selected></option></select>`,
- )
- expect(
- await renderToString(
- createApp({
- data: () => ({ model: [0, 1] }),
- template: `<select multiple v-model="model"><option value="0"></option><option value="1"></option></select>`,
- }),
- ),
- ).toBe(
- `<select multiple><option value="0" selected></option><option value="1" selected></option></select>`,
- )
- })
- 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('template with v-text / v-html', () => {
- test('element with v-html', async () => {
- expect(
- await renderToString(
- createApp({
- data: () => ({ foo: 'hello' }),
- template: `<span v-html="foo"/>`,
- }),
- ),
- ).toBe(`<span>hello</span>`)
- })
- test('textarea with v-text', async () => {
- expect(
- await renderToString(
- createApp({
- data: () => ({ foo: 'hello' }),
- template: `<textarea v-text="foo"/>`,
- }),
- ),
- ).toBe(`<textarea>hello</textarea>`)
- })
- test('textarea with v-html', async () => {
- expect(
- await renderToString(
- createApp({
- data: () => ({ foo: 'hello' }),
- template: `<textarea v-html="foo"/>`,
- }),
- ),
- ).toBe(`<textarea>hello</textarea>`)
- })
- })
- 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>`)
- })
- // #7499
- test('custom directive w/ getSSRProps (expose)', async () => {
- let exposeVars: null | string | undefined = null
- const useTestDirective = () => ({
- vTest: {
- getSSRProps({ instance }: any) {
- if (instance) {
- exposeVars = instance.x
- }
- return { id: exposeVars }
- },
- },
- })
- const { vTest } = useTestDirective()
- const renderString = await renderToString(
- createApp({
- setup(props, { expose }) {
- const x = ref('foo')
- expose({ x })
- const __returned__ = { useTestDirective, vTest, ref, x }
- Object.defineProperty(__returned__, '__isScriptSetup', {
- enumerable: false,
- value: true,
- })
- return __returned__
- },
- ssrRender(_ctx, _push, _parent, _attrs) {
- _push(
- `<div${ssrRenderAttrs(
- mergeProps(_attrs!, ssrGetDirectiveProps(_ctx, unref(vTest))),
- )}></div>`,
- )
- },
- }),
- )
- expect(renderString).toBe(`<div id="foo"></div>`)
- expect(exposeVars).toBe('foo')
- })
- })
|