Skip to content

Commit

Permalink
test: add vue ssr e2e case
Browse files Browse the repository at this point in the history
  • Loading branch information
nonzzz committed Dec 18, 2023
1 parent f26e426 commit 8e82133
Show file tree
Hide file tree
Showing 12 changed files with 286 additions and 26 deletions.
3 changes: 2 additions & 1 deletion __tests__/plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ async function mockBuild(taskName: string, opts: BuildOptions = {}) {
...viteOptions?.build,
write: false
},
plugins: [stylexPlugin(stylex)]
plugins: [stylexPlugin(stylex)],
logLevel: 'silent'
}, viteOptions))
let css = ''
let js = ''
Expand Down
53 changes: 36 additions & 17 deletions e2e/e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
import path from 'path'
import test from 'ava'
import { createE2EServer } from './helper'
import { createSSRServer } from './fixtures/vue-ssr/server'

// FIXME
// test('fixture remix', async (t) => {
// const { page } = await createE2EServer('remix')
// await page.waitForSelector('div[role="button"]')
// const elementHandle = await page.$('div[role="button"]')
// const windowHandle = await page.evaluateHandle(() => Promise.resolve(window))
// const red = await page.evaluate(([window, el]) => {
// return (window as Window).getComputedStyle(el as Element).color
// }, [windowHandle, elementHandle])
// t.is(red, 'rgb(255, 0, 0)', 'first load spa button text color should be red')
// await elementHandle.click()
// await new Promise((resolve) => setTimeout(resolve, 2000))
// const blue = await page.evaluate(([window, el]) => {
// return (window as Window).getComputedStyle(el as Element).color
// }, [windowHandle, elementHandle])
// t.is(blue, 'rgb(0, 0, 255)', 'tap button and text color should be blue')
// })

test('fixture spa', async (t) => {
const { page } = await createE2EServer('spa')
Expand Down Expand Up @@ -35,20 +55,19 @@ test('fixture qwik', async (t) => {
t.is(blue, 'rgb(0, 0, 255)', 'tap button and text color should be blue')
})

// FIXME
// test('fixture remix', async (t) => {
// const { page } = await createE2EServer('remix')
// await page.waitForSelector('div[role="button"]')
// const elementHandle = await page.$('div[role="button"]')
// const windowHandle = await page.evaluateHandle(() => Promise.resolve(window))
// const red = await page.evaluate(([window, el]) => {
// return (window as Window).getComputedStyle(el as Element).color
// }, [windowHandle, elementHandle])
// t.is(red, 'rgb(255, 0, 0)', 'first load spa button text color should be red')
// await elementHandle.click()
// await new Promise((resolve) => setTimeout(resolve, 2000))
// const blue = await page.evaluate(([window, el]) => {
// return (window as Window).getComputedStyle(el as Element).color
// }, [windowHandle, elementHandle])
// t.is(blue, 'rgb(0, 0, 255)', 'tap button and text color should be blue')
// })
test('fixture vue ssr', async (t) => {
const { page } = await createSSRServer(path.join(__dirname, 'fixtures', 'vue-ssr', 'vite.config.mts'))
await page.waitForSelector('div[role="button"]')
const elementHandle = await page.$('div[role="button"]')
const windowHandle = await page.evaluateHandle(() => Promise.resolve(window))
const red = await page.evaluate(([window, el]) => {
return (window as Window).getComputedStyle(el as Element).color
}, [windowHandle, elementHandle])
t.is(red, 'rgb(255, 0, 0)', 'first load spa button text color should be red')
await elementHandle.click()
await new Promise((resolve) => setTimeout(resolve, 2000))
const blue = await page.evaluate(([window, el]) => {
return (window as Window).getComputedStyle(el as Element).color
}, [windowHandle, elementHandle])
t.is(blue, 'rgb(0, 0, 255)', 'tap button and text color should be blue')
})
14 changes: 14 additions & 0 deletions e2e/fixtures/vue-ssr/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue</title>
<!--app-head-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="./src/entry-client.ts"></script>
</body>
</html>
17 changes: 17 additions & 0 deletions e2e/fixtures/vue-ssr/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "vite-plugin-stylex-e2e-vue-ssr",
"scripts": {
"dev": "tsx ./server.ts"
},
"dependencies": {
"@vitejs/plugin-vue": "4.5.1",
"express": "^4.18.2",
"vite": "^5.0.6",
"vite-plugin-stylex": "workspace:*",
"vue": "^3.3.10"
},
"devDependencies": {
"@types/express": "^4.17.21",
"tsx": "^4.6.2"
}
}
36 changes: 36 additions & 0 deletions e2e/fixtures/vue-ssr/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import fs from 'fs/promises'
import path from 'path'
import express from 'express'
import { createChromeBrowser, genRandomPort } from '../../helper'

export async function createSSRServer(configFile = path.join(__dirname, 'vite.config.mts')) {
const app = express()
const { createServer } = await import('vite')

const viteServer = await createServer({ configFile, server: { middlewareMode: true }, appType: 'custom', base: '/', root: __dirname })
app.use(viteServer.middlewares)
app.use('*', async (req, res) => {
try {
const url = req.originalUrl.replace('/', '')
let template = await fs.readFile(path.join(__dirname, 'index.html'), 'utf8')
template = await viteServer.transformIndexHtml(url, template)
const { render } = await viteServer.ssrLoadModule('/src/entry-server.ts')
const rendered = await render(url)
const html = template
.replace('<!--app-head-->', rendered.head ?? '')
.replace('<!--app-html-->', rendered.html ?? '')
res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
} catch (error) {
viteServer.ssrFixStacktrace(error)
res.status(500).end(error.stack)
}
})
const port = genRandomPort()
app.listen(port)
const { page } = await createChromeBrowser(port)
return { app, page }
}

if (require.main === module) {
createSSRServer()
}
33 changes: 33 additions & 0 deletions e2e/fixtures/vue-ssr/src/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<template>
<div>
<div :class="className" role="button" @click="handleClick">Action</div>
</div>
</template>

<script>
import * as stylex from '@stylexjs/stylex'
import { computed, defineComponent, ref } from 'vue'
const styles = stylex.create({
text: { fontSize: '20px', cursor: 'pointer' },
blue: {
color: 'blue'
},
red: {
color: 'red'
}
})
export default defineComponent({
setup() {
const color = ref('red')
const className = computed(() => stylex.props(styles.text, color.value === 'red' ? styles.red : styles.blue).className)
const handleClick = () => {
color.value = color.value === 'red' ? 'blue' : 'red'
}
return { className, handleClick }
}
})
</script>
5 changes: 5 additions & 0 deletions e2e/fixtures/vue-ssr/src/entry-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createApp } from './main'

const { app } = createApp()

app.mount('#app')
15 changes: 15 additions & 0 deletions e2e/fixtures/vue-ssr/src/entry-server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { renderToString } from 'vue/server-renderer'
import { createApp } from './main'

export async function render() {
const { app } = createApp()

// passing SSR context object which will be available via useSSRContext()
// @vitejs/plugin-vue injects code into a component's setup() that registers
// itself on ctx.modules. After the render, ctx.modules would contain all the
// components that have been instantiated during this render call.
const ctx = {}
const html = await renderToString(app, ctx)

return { html }
}
10 changes: 10 additions & 0 deletions e2e/fixtures/vue-ssr/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { createSSRApp } from 'vue'
import App from './app.vue'

// SSR requires a fresh app instance per request, therefore we export a function
// that creates a fresh app instance. If using Vuex, we'd also be creating a
// fresh store here.
export function createApp() {
const app = createSSRApp(App)
return { app }
}
7 changes: 7 additions & 0 deletions e2e/fixtures/vue-ssr/vite.config.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { stylexPlugin } from 'vite-plugin-stylex'

export default defineConfig({
plugins: [vue(), stylexPlugin()]
})
11 changes: 5 additions & 6 deletions e2e/helper.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import path from 'path'
import { chromium } from 'playwright'
import type { ViteDevServer } from 'vite'

export async function createChromeBrowser(server: ViteDevServer) {
export async function createChromeBrowser(port: number) {
const browser = await chromium.launch()
const page = await browser.newPage()
const localURL = `http://localhost:${server.config.server.port}`
const localURL = `http://localhost:${port}`
page.goto(localURL)
return { page }
}

// I don't know thy vite don't accept port 0
function genRandomPort() {
// I don't know why vite don't accept port 0
export function genRandomPort() {
const minPort = 5173
const maxPort = 49151
return Math.floor(Math.random() * (maxPort - minPort + 1)) + minPort
Expand All @@ -28,6 +27,6 @@ export async function createE2EServer(taskName: string) {
root: path.join(__dirname, 'fixtures', taskName)
})
await server.listen()
const { page } = await createChromeBrowser(server)
const { page } = await createChromeBrowser(server.config.server.port)
return { page, server }
}
Loading

0 comments on commit 8e82133

Please sign in to comment.