Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions e2e/react-start/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"dev": "vite dev --port 3000",
"dev:e2e": "vite dev",
"build": "vite build && tsc --noEmit",
"build:spa": "MODE=spa vite build && tsc --noEmit",
"start": "pnpx srvx --prod -s ../client dist/server/server.js",
"start:spa": "node server.js",
"test:e2e:spaMode": "rm -rf port*.txt; MODE=spa playwright test --project=chromium",
"test:e2e:ssrMode": "rm -rf port*.txt; playwright test --project=chromium",
"test:e2e": "pnpm run test:e2e:spaMode && pnpm run test:e2e:ssrMode"
Expand All @@ -16,6 +18,8 @@
"@tanstack/react-router": "workspace:^",
"@tanstack/react-router-devtools": "workspace:^",
"@tanstack/react-start": "workspace:^",
"express": "^5.1.0",
"http-proxy-middleware": "^3.0.5",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"redaxios": "^0.5.1",
Expand Down
12 changes: 9 additions & 3 deletions e2e/react-start/basic/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ import {
getDummyServerPort,
getTestServerPort,
} from '@tanstack/router-e2e-utils'
import { isSpaMode } from 'tests/utils/isSpaMode'
import { isSpaMode } from './tests/utils/isSpaMode'
import packageJson from './package.json' with { type: 'json' }

const PORT = await getTestServerPort(packageJson.name)
const PORT = await getTestServerPort(
`${packageJson.name}${isSpaMode ? '_spa' : ''}`,
)
const START_PORT = await getTestServerPort(
`${packageJson.name}${isSpaMode ? '_spa_start' : ''}`,
)
const EXTERNAL_PORT = await getDummyServerPort(packageJson.name)
const baseURL = `http://localhost:${PORT}`
const spaModeCommand = `pnpm build && pnpm dev:e2e --port=${PORT}`
const spaModeCommand = `pnpm build:spa && pnpm start:spa`
const ssrModeCommand = `pnpm build && pnpm start`

console.log('running in spa mode: ', isSpaMode.toString())
Expand Down Expand Up @@ -39,6 +44,7 @@ export default defineConfig({
VITE_NODE_ENV: 'test',
VITE_EXTERNAL_PORT: String(EXTERNAL_PORT),
VITE_SERVER_PORT: String(PORT),
START_PORT: String(START_PORT),
PORT: String(PORT),
},
},
Expand Down
67 changes: 67 additions & 0 deletions e2e/react-start/basic/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { toNodeHandler } from 'srvx/node'
import path from 'node:path'
import express from 'express'
import { createProxyMiddleware } from 'http-proxy-middleware'

const port = process.env.PORT || 3000

const startPort = process.env.START_PORT || 3001

export async function createStartServer() {
const server = (await import('./dist/server/server.js')).default
const nodeHandler = toNodeHandler(server.fetch)

const app = express()

app.use(express.static('./dist/client'))

app.use(async (req, res, next) => {
try {
await nodeHandler(req, res)
} catch (error) {
next(error)
}
})

return { app }
}

export async function createSpaServer() {
const app = express()

app.use(
'/api',
createProxyMiddleware({
target: `http://localhost:${startPort}/api`, // Replace with your target server's URL
changeOrigin: false, // Needed for virtual hosted sites,
}),
)

app.use(
'/_serverFn',
createProxyMiddleware({
target: `http://localhost:${startPort}/_serverFn`, // Replace with your target server's URL
changeOrigin: false, // Needed for virtual hosted sites,
}),
)

app.use(express.static('./dist/client'))

app.get('/{*splat}', (req, res) => {
res.sendFile(path.resolve('./dist/client/index.html'))
})

return { app }
}

createSpaServer().then(async ({ app }) =>
app.listen(port, () => {
console.info(`Client Server: http://localhost:${port}`)
}),
)

createStartServer().then(async ({ app }) =>
app.listen(startPort, () => {
console.info(`Start Server: http://localhost:${startPort}`)
}),
)
17 changes: 9 additions & 8 deletions e2e/react-start/basic/tests/navigation.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { expect } from '@playwright/test'

import { test } from '@tanstack/router-e2e-utils'
import { isSpaMode } from 'tests/utils/isSpaMode'

test.use({
whitelistErrors: [
Expand All @@ -19,14 +18,15 @@ test('Navigating to post', async ({ page }) => {

test('Navigating to user', async ({ page }) => {
await page.goto('/')

await page.waitForURL('/')
await page.getByRole('link', { name: 'Users' }).click()
await page.getByRole('link', { name: 'Leanne Graham' }).click()
await expect(page.getByRole('heading')).toContainText('Leanne Graham')
})

test('Navigating nested layouts', async ({ page }) => {
await page.goto('/')
await page.waitForURL('/')

await page.getByRole('link', { name: 'Layout', exact: true }).click()

Expand All @@ -42,24 +42,24 @@ test('Navigating nested layouts', async ({ page }) => {

test('client side navigating to a route with scripts', async ({ page }) => {
await page.goto('/')
await page.waitForURL('/')
await page.getByRole('link', { name: 'Scripts', exact: true }).click()
await expect(page.getByTestId('scripts-test-heading')).toBeInViewport()
expect(await page.evaluate('window.SCRIPT_1')).toBe(true)
expect(await page.evaluate('window.SCRIPT_2')).toBe(
isSpaMode ? true : undefined,
)
expect(await page.evaluate('window.SCRIPT_2')).toBe(undefined)
})

test('directly going to a route with scripts', async ({ page }) => {
await page.goto('/scripts')
await page.waitForURL('/scripts')
await page.waitForLoadState('networkidle')
expect(await page.evaluate('window.SCRIPT_1')).toBe(true)
expect(await page.evaluate('window.SCRIPT_2')).toBe(
isSpaMode ? true : undefined,
)
expect(await page.evaluate('window.SCRIPT_2')).toBe(undefined)
})

test('Navigating to a not-found route', async ({ page }) => {
await page.goto('/')
await page.waitForURL('/')

await page.getByRole('link', { name: 'This Route Does Not Exist' }).click()
await page.getByRole('link', { name: 'Start Over' }).click()
Expand All @@ -68,6 +68,7 @@ test('Navigating to a not-found route', async ({ page }) => {

test('Should change title on client side navigation', async ({ page }) => {
await page.goto('/')
await page.waitForURL('/')

await page.getByRole('link', { name: 'Posts' }).click()

Expand Down
4 changes: 3 additions & 1 deletion e2e/react-start/basic/tests/not-found.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { expect } from '@playwright/test'
import combinateImport from 'combinate'
import { test } from '@tanstack/router-e2e-utils'
import { isSpaMode } from '../tests/utils/isSpaMode'

// somehow playwright does not correctly import default exports
const combinate = (combinateImport as any).default as typeof combinateImport
Expand All @@ -14,7 +15,7 @@ test.describe('not-found', () => {
test(`global not found`, async ({ page }) => {
const response = await page.goto(`/this-page-does-not-exist/foo/bar`)

expect(response?.status()).toBe(404)
expect(response?.status()).toBe(isSpaMode ? 200 : 404)

await expect(
page.getByTestId('default-not-found-component'),
Expand Down Expand Up @@ -47,6 +48,7 @@ test.describe('not-found', () => {
await expect(
page.getByTestId(`via-${thrower}-notFound-component`),
).toBeInViewport()

await expect(
page.getByTestId(`via-${thrower}-route-component`),
).not.toBeInViewport()
Expand Down
14 changes: 4 additions & 10 deletions e2e/react-start/basic/tests/redirect.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import packageJson from '../package.json' with { type: 'json' }
// somehow playwright does not correctly import default exports
const combinate = (combinateImport as any).default as typeof combinateImport

const PORT = await getTestServerPort(packageJson.name)
const PORT = await getTestServerPort(
`${packageJson.name}${isSpaMode ? '_spa' : ''}`,
)

const EXTERNAL_HOST_PORT = await getDummyServerPort(packageJson.name)

test.describe('redirects', () => {
Expand Down Expand Up @@ -65,7 +68,6 @@ test.describe('redirects', () => {
await link.click()

const url = `http://localhost:${PORT}/posts`

await page.waitForURL(url)
expect(page.url()).toBe(url)
await expect(page.getByTestId('PostsIndexComponent')).toBeInViewport()
Expand All @@ -80,14 +82,6 @@ test.describe('redirects', () => {
})

internalDirectVisitTestMatrix.forEach(({ thrower, reloadDocument }) => {
if (isSpaMode) {
test.use({
whitelistErrors: [
/A tree hydrated but some attributes of the server rendered HTML/,
],
})
}

test(`internal target, direct visit: thrower: ${thrower}, reloadDocument: ${reloadDocument}`, async ({
page,
}) => {
Expand Down
4 changes: 3 additions & 1 deletion e2e/react-start/basic/tests/search-params.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ test.describe('/search-params/default', () => {
page,
}) => {
const response = await page.goto('/search-params/default')
expectRedirect(response, '/search-params/default?default=d1')
if (!isSpaMode) {
expectRedirect(response, '/search-params/default?default=d1')
}
await expect(page.getByTestId('search-default')).toContainText('d1')
await expect(page.getByTestId('context-hello')).toContainText('world')
expect(
Expand Down
4 changes: 1 addition & 3 deletions e2e/react-start/basic/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
import { isSpaMode } from './tests/utils/isSpaMode'

const spaMode = isSpaMode

const spaModeConfiguration = {
enabled: true,
prerender: {
Expand All @@ -23,7 +21,7 @@ export default defineConfig({
}),
// @ts-ignore we want to keep one test with verboseFileRoutes off even though the option is hidden
tanstackStart({
spa: spaMode ? spaModeConfiguration : undefined,
spa: isSpaMode ? spaModeConfiguration : undefined,
}),
viteReact(),
],
Expand Down
4 changes: 4 additions & 0 deletions e2e/solid-start/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"dev": "vite dev --port 3000",
"dev:e2e": "vite dev",
"build": "vite build && tsc --noEmit",
"build:spa": "MODE=spa vite build && tsc --noEmit",
"start": "pnpx srvx --prod -s ../client dist/server/server.js",
"start:spa": "node server.js",
"test:e2e:spaMode": "rm -rf port*.txt; MODE=spa playwright test --project=chromium",
"test:e2e:ssrMode": "rm -rf port*.txt; playwright test --project=chromium",
"test:e2e": "pnpm run test:e2e:spaMode && pnpm run test:e2e:ssrMode"
Expand All @@ -16,6 +18,8 @@
"@tanstack/solid-router": "workspace:^",
"@tanstack/solid-router-devtools": "workspace:^",
"@tanstack/solid-start": "workspace:^",
"express": "^5.1.0",
"http-proxy-middleware": "^3.0.5",
"redaxios": "^0.5.1",
"solid-js": "^1.9.5",
"tailwind-merge": "^2.6.0",
Expand Down
11 changes: 9 additions & 2 deletions e2e/solid-start/basic/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ import {
import packageJson from './package.json' with { type: 'json' }
import { isSpaMode } from './tests/utils/isSpaMode'

const PORT = await getTestServerPort(packageJson.name)
const PORT = await getTestServerPort(
`${packageJson.name}${isSpaMode ? '_spa' : ''}`,
)
const START_PORT = await getTestServerPort(
`${packageJson.name}${isSpaMode ? '_spa_start' : ''}`,
)
const EXTERNAL_PORT = await getDummyServerPort(packageJson.name)
const baseURL = `http://localhost:${PORT}`
const spaModeCommand = `pnpm build && pnpm dev:e2e --port=${PORT}`
const spaModeCommand = `pnpm build:spa && pnpm start:spa`
const ssrModeCommand = `pnpm build && pnpm start`

console.log('running in spa mode: ', isSpaMode.toString())
/**
* See https://playwright.dev/docs/test-configuration.
*/
Expand Down Expand Up @@ -39,6 +45,7 @@ export default defineConfig({
VITE_NODE_ENV: 'test',
VITE_EXTERNAL_PORT: String(EXTERNAL_PORT),
VITE_SERVER_PORT: String(PORT),
START_PORT: String(START_PORT),
PORT: String(PORT),
},
},
Expand Down
67 changes: 67 additions & 0 deletions e2e/solid-start/basic/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { toNodeHandler } from 'srvx/node'
import path from 'node:path'
import express from 'express'
import { createProxyMiddleware } from 'http-proxy-middleware'

const port = process.env.PORT || 3000

const startPort = process.env.START_PORT || 3001

export async function createStartServer() {
const server = (await import('./dist/server/server.js')).default
const nodeHandler = toNodeHandler(server.fetch)

const app = express()

app.use(express.static('./dist/client'))

app.use(async (req, res, next) => {
try {
await nodeHandler(req, res)
} catch (error) {
next(error)
}
})

return { app }
}

export async function createSpaServer() {
const app = express()

app.use(
'/api',
createProxyMiddleware({
target: `http://localhost:${startPort}/api`, // Replace with your target server's URL
changeOrigin: false, // Needed for virtual hosted sites,
}),
)

app.use(
'/_serverFn',
createProxyMiddleware({
target: `http://localhost:${startPort}/_serverFn`, // Replace with your target server's URL
changeOrigin: false, // Needed for virtual hosted sites,
}),
)

app.use(express.static('./dist/client'))

app.get('/{*splat}', (req, res) => {
res.sendFile(path.resolve('./dist/client/index.html'))
})

return { app }
}

createSpaServer().then(async ({ app }) =>
app.listen(port, () => {
console.info(`Client Server: http://localhost:${port}`)
}),
)

createStartServer().then(async ({ app }) =>
app.listen(startPort, () => {
console.info(`Start Server: http://localhost:${startPort}`)
}),
)
Loading
Loading