2023-12-19 12:21:29 +00:00
import { describe , expect , it , vi } from 'vitest'
2023-09-14 21:44:18 +00:00
import type { Plugin } from 'vite'
import type { Component } from '@nuxt/schema'
2023-12-19 12:21:29 +00:00
import type { UnpluginOptions } from 'unplugin'
2024-09-25 22:59:59 +00:00
import { IslandsTransformPlugin } from '../src/components/plugins/islands-transform'
2023-09-14 21:44:18 +00:00
import { normalizeLineEndings } from './utils'
const getComponents = ( ) = > [ {
filePath : '/root/hello.server.vue' ,
mode : 'server' ,
pascalName : 'HelloWorld' ,
island : true ,
kebabName : 'hello-world' ,
chunkName : 'components/hello-world' ,
export : 'default' ,
shortPath : '' ,
prefetch : false ,
2024-04-05 18:08:32 +00:00
preload : false ,
2023-09-14 21:44:18 +00:00
} ] as Component [ ]
2024-09-25 22:59:59 +00:00
const pluginWebpack = IslandsTransformPlugin ( {
2023-12-19 12:21:29 +00:00
getComponents ,
2024-04-05 18:08:32 +00:00
selectiveClient : true ,
2024-09-25 22:59:59 +00:00
} ) . raw ( { } , { framework : 'webpack' , webpack : { compiler : { } as any } } )
2023-09-14 21:44:18 +00:00
2024-05-07 20:55:54 +00:00
const viteTransform = async ( source : string , id : string , selectiveClient = false ) = > {
2024-09-25 22:59:59 +00:00
const vitePlugin = IslandsTransformPlugin ( {
2023-12-19 12:21:29 +00:00
getComponents ,
2024-04-05 18:08:32 +00:00
selectiveClient ,
2024-09-25 22:59:59 +00:00
} ) . raw ( { } , { framework : 'vite' } ) as Plugin
2023-12-19 12:21:29 +00:00
2024-08-05 15:33:27 +00:00
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
2023-12-19 12:21:29 +00:00
const result = await ( vitePlugin . transform ! as Function ) ( source , id )
return typeof result === 'string' ? result : result?.code
}
const webpackTransform = async ( source : string , id : string ) = > {
2024-08-05 15:33:27 +00:00
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
2023-12-19 12:21:29 +00:00
const result = await ( ( pluginWebpack as UnpluginOptions ) . transform ! as Function ) ( source , id )
2023-09-14 21:44:18 +00:00
return typeof result === 'string' ? result : result?.code
}
describe ( 'islandTransform - server and island components' , ( ) = > {
describe ( 'slots' , ( ) = > {
it ( 'expect slot transform to match inline snapshot' , async ( ) = > {
const result = await viteTransform ( ` <template>
< div >
< slot / >
< slot name = "named" : some - data = "someData" / >
2023-11-09 13:45:45 +00:00
< slot
name = "other"
: some - data = "someData"
/ >
2023-09-14 21:44:18 +00:00
< / div >
< / template >
< script setup lang = "ts" >
const someData = 'some data'
2023-11-09 13:45:45 +00:00
2023-09-14 21:44:18 +00:00
< / script > `
2024-03-09 06:48:15 +00:00
, 'hello.server.vue' )
2023-09-14 21:44:18 +00:00
expect ( normalizeLineEndings ( result ) ) . toMatchInlineSnapshot ( `
" < template >
< div >
2024-01-16 13:22:50 +00:00
< NuxtTeleportSsrSlot name = "default" : props = "undefined" > < slot / > < / NuxtTeleportSsrSlot >
2023-09-14 21:44:18 +00:00
2024-03-25 10:19:02 +00:00
< NuxtTeleportSsrSlot name = "named" : props = "[{ [\`some-data\`]: someData }]" > < slot name = "named" : some - data = "someData" / > < / NuxtTeleportSsrSlot >
< NuxtTeleportSsrSlot name = "other" : props = "[{ [\`some-data\`]: someData }]" > < slot
2024-01-16 13:22:50 +00:00
name = "other"
: some - data = "someData"
/ > < / N u x t T e l e p o r t S s r S l o t >
2023-09-14 21:44:18 +00:00
< / div >
< / template >
2023-12-11 18:20:11 +00:00
< script setup lang = "ts" >
2024-06-15 11:15:54 +00:00
import { mergeProps as __mergeProps } from 'vue'
2023-09-14 21:44:18 +00:00
import { vforToArray as __vforToArray } from '#app/components/utils'
2024-01-16 16:33:45 +00:00
import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'
2024-01-16 13:22:50 +00:00
import NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot'
2023-09-14 21:44:18 +00:00
const someData = 'some data'
2023-11-09 13:45:45 +00:00
2023-09-14 21:44:18 +00:00
< / script > "
` )
} )
2024-06-15 11:15:54 +00:00
it ( 'generates bindings when props are needed to be merged' , async ( ) = > {
const result = await viteTransform ( ` <script setup lang="ts">
withDefaults ( defineProps < { things? : any [ ] ; somethingElse? : string } > ( ) , {
t hings : ( ) = > [ ] ,
somethingElse : "yay" ,
} ) ;
< / script >
< template >
< template v - for = "thing in things" >
< slot name = "thing" v - bind = "thing" / >
< / template >
< / template >
` , 'hello.server.vue')
expect ( normalizeLineEndings ( result ) ) . toMatchInlineSnapshot ( `
"<script setup lang=" ts " >
import { mergeProps as __mergeProps } from 'vue'
import { vforToArray as __vforToArray } from '#app/components/utils'
import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'
import NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot'
withDefaults ( defineProps < { things? : any [ ] ; somethingElse? : string } > ( ) , {
things : ( ) = > [ ] ,
somethingElse : "yay" ,
} ) ;
< / script >
< template >
< template v - for = "thing in things" >
< NuxtTeleportSsrSlot name = "thing" : props = "[__mergeProps(thing, { })]" > < slot name = "thing" v - bind = "thing" / > < / NuxtTeleportSsrSlot >
< / template >
< / template >
"
` )
} )
2023-09-14 21:44:18 +00:00
it ( 'expect slot fallback transform to match inline snapshot' , async ( ) = > {
const result = await viteTransform ( ` <template>
< div >
< slot : some - data = "someData" >
< div > fallback < / div >
< / slot >
< / div >
< / template >
< script setup lang = "ts" >
const someData = 'some data'
2023-11-09 13:45:45 +00:00
2023-09-14 21:44:18 +00:00
< / script > `
2024-03-09 06:48:15 +00:00
, 'hello.server.vue' )
2023-09-14 21:44:18 +00:00
expect ( normalizeLineEndings ( result ) ) . toMatchInlineSnapshot ( `
" < template >
< div >
2024-03-25 10:19:02 +00:00
< NuxtTeleportSsrSlot name = "default" : props = "[{ [\`some-data\`]: someData }]" > < slot : some - data = "someData" / > < template # fallback >
2023-09-14 21:44:18 +00:00
< div > fallback < / div >
2024-01-16 13:22:50 +00:00
< / template > < / NuxtTeleportSsrSlot >
2023-09-14 21:44:18 +00:00
< / div >
< / template >
2023-12-11 18:20:11 +00:00
< script setup lang = "ts" >
2024-06-15 11:15:54 +00:00
import { mergeProps as __mergeProps } from 'vue'
2023-09-14 21:44:18 +00:00
import { vforToArray as __vforToArray } from '#app/components/utils'
2024-01-16 16:33:45 +00:00
import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'
2024-01-16 13:22:50 +00:00
import NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot'
2023-09-14 21:44:18 +00:00
const someData = 'some data'
2023-11-09 13:45:45 +00:00
2023-09-14 21:44:18 +00:00
< / script > "
` )
} )
it ( 'expect slot transform with fallback and no name to match inline snapshot #23209' , async ( ) = > {
const result = await viteTransform ( ` <template>
< div >
< UCard >
< template # header >
< h3 > Partial Hydration Example - Server - { { count } } < / h3 >
< / template >
< template # default >
< p > message : { { message } } < / p >
< p > Below is the slot I want to be hydrated on the client < / p >
< div >
< slot >
This is the default content of the slot , I should not see this after
the client loading has completed .
< / slot >
< / div >
< p > Above is the slot I want to be hydrated on the client < / p >
< / template >
< / UCard >
< / div >
< / template >
2023-11-09 13:45:45 +00:00
2023-09-14 21:44:18 +00:00
< script setup lang = "ts" >
export interface Props {
count? : number ;
}
const props = withDefaults ( defineProps < Props > ( ) , { count : 0 } ) ;
2023-11-09 13:45:45 +00:00
2023-09-14 21:44:18 +00:00
const message = "Hello World" ;
< / script >
`
2024-03-09 06:48:15 +00:00
, 'hello.server.vue' )
2023-09-14 21:44:18 +00:00
expect ( normalizeLineEndings ( result ) ) . toMatchInlineSnapshot ( `
" < template >
< div >
< UCard >
< template # header >
< h3 > Partial Hydration Example - Server - { { count } } < / h3 >
< / template >
< template # default >
< p > message : { { message } } < / p >
< p > Below is the slot I want to be hydrated on the client < / p >
< div >
2024-03-25 10:19:02 +00:00
< NuxtTeleportSsrSlot name = "default" : props = "undefined" > < slot / > < template # fallback >
2023-09-14 21:44:18 +00:00
This is the default content of the slot , I should not see this after
the client loading has completed .
2024-01-16 13:22:50 +00:00
< / template > < / NuxtTeleportSsrSlot >
2023-09-14 21:44:18 +00:00
< / div >
< p > Above is the slot I want to be hydrated on the client < / p >
< / template >
< / UCard >
< / div >
< / template >
2023-11-09 13:45:45 +00:00
2023-12-11 18:20:11 +00:00
< script setup lang = "ts" >
2024-06-15 11:15:54 +00:00
import { mergeProps as __mergeProps } from 'vue'
2023-09-14 21:44:18 +00:00
import { vforToArray as __vforToArray } from '#app/components/utils'
2024-01-16 16:33:45 +00:00
import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'
2024-01-16 13:22:50 +00:00
import NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot'
2023-09-14 21:44:18 +00:00
export interface Props {
count? : number ;
}
const props = withDefaults ( defineProps < Props > ( ) , { count : 0 } ) ;
2023-11-09 13:45:45 +00:00
2023-12-11 18:20:11 +00:00
const message = "Hello World" ;
2023-09-14 21:44:18 +00:00
< / script >
"
` )
} )
2024-03-25 10:19:02 +00:00
it ( 'expect v-if/v-else/v-else-if to be set in teleport component wrapper' , async ( ) = > {
const result = await viteTransform ( ` <script setup lang="ts">
const foo = true ;
< / script >
< template >
< slot v - if = "foo" / >
< slot v - else - if = "test" / >
< slot v - else / >
< / template >
2024-05-07 20:55:54 +00:00
` , 'WithVif.vue', true)
2024-03-25 10:19:02 +00:00
expect ( normalizeLineEndings ( result ) ) . toMatchInlineSnapshot ( `
"<script setup lang=" ts " >
2024-06-15 11:15:54 +00:00
import { mergeProps as __mergeProps } from 'vue'
2024-03-25 10:19:02 +00:00
import { vforToArray as __vforToArray } from '#app/components/utils'
import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'
import NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot'
const foo = true ;
< / script >
< template >
< NuxtTeleportSsrSlot v - if = "foo" name = "default" : props = "undefined" > < slot / > < / NuxtTeleportSsrSlot >
< NuxtTeleportSsrSlot v - else - if = "test" name = "default" : props = "undefined" > < slot / > < / NuxtTeleportSsrSlot >
< NuxtTeleportSsrSlot v - else name = "default" : props = "undefined" > < slot / > < / NuxtTeleportSsrSlot >
< / template >
"
` )
} )
2023-09-14 21:44:18 +00:00
} )
2023-12-19 12:21:29 +00:00
describe ( 'nuxt-client' , ( ) = > {
describe ( 'vite' , ( ) = > {
2024-05-07 20:55:54 +00:00
it ( 'test transform with vite' , async ( ) = > {
2023-12-19 12:21:29 +00:00
const result = await viteTransform ( ` <template>
< div >
< HelloWorld / >
< HelloWorld nuxt - client / >
< / div >
< / template >
2024-01-16 16:33:45 +00:00
2023-12-19 12:21:29 +00:00
< script setup lang = "ts" >
import HelloWorld from './HelloWorld.vue'
< / script >
2024-05-07 20:55:54 +00:00
` , 'hello.server.vue', true)
2023-12-19 12:21:29 +00:00
expect ( normalizeLineEndings ( result ) ) . toMatchInlineSnapshot ( `
" < template >
< div >
< HelloWorld / >
2024-05-07 20:55:54 +00:00
< NuxtTeleportIslandComponent to = "HelloWorld-CyH3UXLuYA" : nuxt - client = "true" > < HelloWorld / > < / NuxtTeleportIslandComponent >
2023-12-19 12:21:29 +00:00
< / div >
< / template >
2024-01-16 16:33:45 +00:00
2023-12-19 20:03:09 +00:00
< script setup lang = "ts" >
2024-06-15 11:15:54 +00:00
import { mergeProps as __mergeProps } from 'vue'
2023-12-19 12:21:29 +00:00
import { vforToArray as __vforToArray } from '#app/components/utils'
2024-01-16 16:33:45 +00:00
import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'
2024-01-16 13:22:50 +00:00
import NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot'
2023-12-19 12:21:29 +00:00
import HelloWorld from './HelloWorld.vue'
< / script >
"
` )
} )
it ( 'test dynamic nuxt-client' , async ( ) = > {
const result = await viteTransform ( ` <template>
< div >
< HelloWorld / >
< HelloWorld : nuxt - client = "nuxtClient" / >
< / div >
< / template >
2024-01-16 16:33:45 +00:00
2023-12-19 12:21:29 +00:00
< script setup lang = "ts" >
import HelloWorld from './HelloWorld.vue'
const nuxtClient = false
< / script >
2024-05-07 20:55:54 +00:00
` , 'hello.server.vue', true)
2023-12-19 12:21:29 +00:00
expect ( normalizeLineEndings ( result ) ) . toMatchInlineSnapshot ( `
" < template >
< div >
< HelloWorld / >
2024-05-07 20:55:54 +00:00
< NuxtTeleportIslandComponent to = "HelloWorld-eo0XycWCUV" : nuxt - client = "nuxtClient" > < HelloWorld / > < / NuxtTeleportIslandComponent >
2023-12-19 12:21:29 +00:00
< / div >
< / template >
2024-01-16 16:33:45 +00:00
2023-12-19 20:03:09 +00:00
< script setup lang = "ts" >
2024-06-15 11:15:54 +00:00
import { mergeProps as __mergeProps } from 'vue'
2023-12-19 12:21:29 +00:00
import { vforToArray as __vforToArray } from '#app/components/utils'
2024-01-16 16:33:45 +00:00
import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'
2024-01-16 13:22:50 +00:00
import NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot'
2023-12-19 12:21:29 +00:00
import HelloWorld from './HelloWorld.vue'
const nuxtClient = false
< / script >
"
` )
} )
it ( 'should not transform if disabled' , async ( ) = > {
const result = await viteTransform ( ` <template>
< div >
< HelloWorld / >
< HelloWorld : nuxt - client = "nuxtClient" / >
< / div >
< / template >
2024-01-16 16:33:45 +00:00
2023-12-19 12:21:29 +00:00
< script setup lang = "ts" >
import HelloWorld from './HelloWorld.vue'
const nuxtClient = false
< / script >
2024-05-07 20:55:54 +00:00
` , 'hello.server.vue', false)
2023-12-19 12:21:29 +00:00
expect ( normalizeLineEndings ( result ) ) . toMatchInlineSnapshot ( `
" < template >
< div >
< HelloWorld / >
2023-12-19 20:03:09 +00:00
< HelloWorld : nuxt - client = "nuxtClient" / >
2023-12-19 12:21:29 +00:00
< / div >
< / template >
2024-01-16 16:33:45 +00:00
2023-12-19 20:03:09 +00:00
< script setup lang = "ts" >
2024-06-15 11:15:54 +00:00
import { mergeProps as __mergeProps } from 'vue'
2023-12-19 12:21:29 +00:00
import { vforToArray as __vforToArray } from '#app/components/utils'
2024-01-16 16:33:45 +00:00
import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'
2024-01-16 13:22:50 +00:00
import NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot'
2023-12-19 12:21:29 +00:00
import HelloWorld from './HelloWorld.vue'
const nuxtClient = false
< / script >
"
` )
} )
2024-01-11 14:40:02 +00:00
it ( 'should add import if there is no scripts in the SFC' , async ( ) = > {
const result = await viteTransform ( ` <template>
< div >
< HelloWorld / >
< HelloWorld nuxt - client / >
< / div >
< / template >
2024-01-16 16:33:45 +00:00
2024-05-07 20:55:54 +00:00
` , 'hello.server.vue', true)
2024-01-11 14:40:02 +00:00
2024-01-16 16:33:45 +00:00
expect ( result ) . toMatchInlineSnapshot ( `
2024-05-07 20:55:54 +00:00
" < script setup >
2024-06-15 11:15:54 +00:00
import { mergeProps as __mergeProps } from 'vue'
2024-05-07 20:55:54 +00:00
import { vforToArray as __vforToArray } from '#app/components/utils'
import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'
import NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot' < / script > < template >
< div >
< HelloWorld / >
< NuxtTeleportIslandComponent to = "HelloWorld-CyH3UXLuYA" : nuxt - client = "true" > < HelloWorld / > < / NuxtTeleportIslandComponent >
< / div >
< / template >
2024-01-16 16:33:45 +00:00
2024-05-07 20:55:54 +00:00
"
` )
2024-03-09 06:48:15 +00:00
expect ( result ) . toContain ( 'import NuxtTeleportIslandComponent from \'#app/components/nuxt-teleport-island-component\'' )
2024-01-11 14:40:02 +00:00
} )
2024-03-26 13:47:40 +00:00
it ( 'should move v-if to the wrapper component' , async ( ) = > {
const result = await viteTransform ( ` <template>
< div >
< HelloWorld v - if = "false" nuxt - client / >
< HelloWorld v - else - if = "true" nuxt - client / >
< HelloWorld v - else nuxt - client / >
< / div >
< / template >
2024-05-07 20:55:54 +00:00
` , 'hello.server.vue', true)
2024-03-26 13:47:40 +00:00
expect ( result ) . toMatchInlineSnapshot ( `
" < script setup >
2024-06-15 11:15:54 +00:00
import { mergeProps as __mergeProps } from 'vue'
2024-03-26 13:47:40 +00:00
import { vforToArray as __vforToArray } from '#app/components/utils'
import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'
import NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot' < / script > < template >
< div >
2024-05-07 20:55:54 +00:00
< NuxtTeleportIslandComponent v - if = "false" to = "HelloWorld-D9uaHyzL7X" : nuxt - client = "true" > < HelloWorld / > < / NuxtTeleportIslandComponent >
< NuxtTeleportIslandComponent v - else - if = "true" to = "HelloWorld-o4RZMtArnE" : nuxt - client = "true" > < HelloWorld / > < / NuxtTeleportIslandComponent >
< NuxtTeleportIslandComponent v - else to = "HelloWorld-m1IbXHdd8O" : nuxt - client = "true" > < HelloWorld / > < / NuxtTeleportIslandComponent >
2024-03-26 13:47:40 +00:00
< / div >
< / template >
"
` )
} )
2023-12-19 12:21:29 +00:00
} )
describe ( 'webpack' , ( ) = > {
it ( 'test transform with webpack' , async ( ) = > {
const spyOnWarn = vi . spyOn ( console , 'warn' )
const result = await webpackTransform ( ` <template>
< div >
2024-01-16 16:33:45 +00:00
<!-- should not be wrapped by NuxtTeleportIslandComponent -- >
2023-12-19 12:21:29 +00:00
< HelloWorld / >
2024-01-16 16:33:45 +00:00
<!-- should be not wrapped by NuxtTeleportIslandComponent for now -- >
2023-12-19 12:21:29 +00:00
< HelloWorld nuxt - client / >
< / div >
< / template >
2024-01-16 16:33:45 +00:00
2023-12-19 12:21:29 +00:00
< script setup lang = "ts" >
import HelloWorld from './HelloWorld.vue'
2024-01-16 16:33:45 +00:00
2023-12-19 12:21:29 +00:00
const someData = 'some data'
< / script >
` , 'hello.server.vue')
expect ( normalizeLineEndings ( result ) ) . toMatchInlineSnapshot ( `
" < template >
< div >
2024-01-16 16:33:45 +00:00
<!-- should not be wrapped by NuxtTeleportIslandComponent -- >
2023-12-19 12:21:29 +00:00
< HelloWorld / >
2024-01-16 16:33:45 +00:00
<!-- should be not wrapped by NuxtTeleportIslandComponent for now -- >
2023-12-19 12:21:29 +00:00
< HelloWorld nuxt - client / >
< / div >
< / template >
2024-01-16 16:33:45 +00:00
2023-12-19 20:03:09 +00:00
< script setup lang = "ts" >
2024-06-15 11:15:54 +00:00
import { mergeProps as __mergeProps } from 'vue'
2023-12-19 12:21:29 +00:00
import { vforToArray as __vforToArray } from '#app/components/utils'
2024-01-16 16:33:45 +00:00
import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'
2024-01-16 13:22:50 +00:00
import NuxtTeleportSsrSlot from '#app/components/nuxt-teleport-island-slot'
2023-12-19 12:21:29 +00:00
import HelloWorld from './HelloWorld.vue'
2024-01-16 16:33:45 +00:00
2023-12-19 12:21:29 +00:00
const someData = 'some data'
< / script >
"
` )
2024-09-25 22:59:59 +00:00
expect ( spyOnWarn ) . toHaveBeenCalledWith ( 'The `nuxt-client` attribute and client components within islands are only supported with Vite. file: hello.server.vue' )
2023-12-19 12:21:29 +00:00
} )
} )
} )
2023-09-14 21:44:18 +00:00
} )