Skip to content

Conversation

@nlynzaad
Copy link
Contributor

@nlynzaad nlynzaad commented Sep 28, 2025

This PR follows on #5262 and adds a custom server implementation to serve the spa mode production build for e2e tests on react-start-basic and solid-start-basic

Summary by CodeRabbit

  • New Features

    • SPA mode added with dedicated build/start workflows and paired servers to serve the SPA and proxy API/server requests on separate ports.
  • Tests

    • Improved e2e reliability with explicit URL and network-idle waits; updated expectations to be SPA-aware (redirects, not-found, script presence).
  • Chores

    • Added express and http-proxy-middleware dependencies; updated test/config setup to expose SPA-specific ports and enable SPA build/runtime options.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 28, 2025

Walkthrough

Adds SPA-mode workflows to e2e React and Solid start examples: new Express-based servers with proxying, SPA build/start scripts and dependencies, Playwright config updates with START_PORT/env, Vite SPA configuration changes, and test adjustments (URL waits, conditional expectations) across navigation, not-found, redirect, and search-params specs.

Changes

Cohort / File(s) Summary
SPA scripts & deps
e2e/react-start/basic/package.json, e2e/solid-start/basic/package.json
Add build:spa and start:spa scripts; add express and http-proxy-middleware dependencies.
Playwright config SPA ports/env
e2e/react-start/basic/playwright.config.ts, e2e/solid-start/basic/playwright.config.ts
Introduce START_PORT (SPA-aware suffix), update PORT naming for SPA, add START_PORT to webServer.env, and switch SPA command to build:spa + start:spa (Solid adds a spa-mode console log).
Servers: start + SPA proxy
e2e/react-start/basic/server.js, e2e/solid-start/basic/server.js
New exports createStartServer() and createSpaServer(). Start server loads dist/server and wraps fetch via toNodeHandler; SPA server (Express) serves dist/client, proxies /api and /_serverFn to the start server, and serves index.html for client routes. Both servers launched on PORT and START_PORT.
Navigation tests stabilization
e2e/react-start/basic/tests/navigation.spec.ts, e2e/solid-start/basic/tests/navigation.spec.ts
Insert waitForURL steps and network-idle waits to stabilize navigation; remove isSpaMode-based conditional for SCRIPT_2 (now always undefined).
Not Found tests
e2e/react-start/basic/tests/not-found.spec.ts, e2e/solid-start/basic/tests/not-found.spec.ts
Import isSpaMode; adjust not-found expectations to 200 when SPA mode, else 404.
Redirect tests
e2e/react-start/basic/tests/redirect.spec.ts, e2e/solid-start/basic/tests/redirect.spec.ts
Compute SPA-suffixed PORT; remove SPA-specific error-whitelist block (React); minor whitespace tweaks.
Search params tests
e2e/react-start/basic/tests/search-params.spec.ts, e2e/solid-start/basic/tests/search-params.spec.ts
Wrap redirect assertions to run only in non-SPA mode (if (!isSpaMode) guards).
Vite SPA configuration
e2e/react-start/basic/vite.config.ts, e2e/solid-start/basic/vite.config.ts
React: use isSpaMode inline. Solid: add spa option to tanstackStart({ spa: ... }), import isSpaMode, and include TS-ignore for hidden option.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User (Browser)
  participant SPA as SPA Server (Express) #f6f6ff
  participant PROXY as Proxy Middleware #fff6f6
  participant START as Start Server (Node handler) #f6fff6
  participant STATIC as dist/client (Static)

  U->>SPA: GET /any-route
  alt Static asset
    SPA-->>STATIC: Serve /assets/* from dist/client
    STATIC-->>U: 200 Static file
  else API or server-fn
    SPA->>PROXY: /api/* or /_serverFn/*
    PROXY->>START: Proxy request to START_PORT
    START-->>PROXY: Response
    PROXY-->>U: Proxied response
  else Client route
    SPA-->>U: 200 index.html
  end
Loading
sequenceDiagram
  autonumber
  participant PW as Playwright
  participant WS as Web Server Runner
  participant SPA as SPA Server : PORT
  participant START as Start Server : START_PORT

  PW->>WS: Start servers (SPA mode)
  WS->>START: load dist/server, toNodeHandler, listen START_PORT
  WS->>SPA: start Express: static + proxy -> START_PORT, listen PORT
  PW->>SPA: run tests against PORT
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

package: react-start, package: solid-start

Suggested reviewers

  • schiller-manuel

Poem

I built two burrows, ports side-by-side,
One serves the carrots, one serves the guide.
Proxies nibble paths where APIs run,
Static leaves rustle, routes fall to one.
Tests hop and wait—URL in sight—SPA moon rising, all is byte. 🥕🐇

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the primary intent of the pull request—updating the SPA mode end-to-end tests to use the production build—without unnecessary detail or noise, making it clear to reviewers what the main change is about.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch e2e-basic-spa

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42b217a and 090b0c7.

📒 Files selected for processing (1)
  • e2e/react-start/basic/playwright.config.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • e2e/react-start/basic/playwright.config.ts
e2e/**

📄 CodeRabbit inference engine (AGENTS.md)

Store end-to-end tests under the e2e/ directory

Files:

  • e2e/react-start/basic/playwright.config.ts
🧬 Code graph analysis (1)
e2e/react-start/basic/playwright.config.ts (4)
e2e/react-start/server-functions/playwright.config.ts (1)
  • PORT (5-5)
e2e/solid-start/server-functions/playwright.config.ts (1)
  • PORT (5-5)
e2e/e2e-utils/src/derivePort.ts (2)
  • getTestServerPort (25-27)
  • getDummyServerPort (21-23)
e2e/react-start/basic/tests/utils/isSpaMode.ts (1)
  • isSpaMode (1-1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Preview
  • GitHub Check: Test

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link

nx-cloud bot commented Sep 28, 2025

View your CI Pipeline Execution ↗ for commit 090b0c7

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 4m 21s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 15s View ↗

☁️ Nx Cloud last updated this comment at 2025-09-28 21:48:14 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Sep 28, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@5284

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@5284

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@5284

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@5284

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@5284

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@5284

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@5284

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@5284

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@5284

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@5284

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@5284

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@5284

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@5284

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@5284

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@5284

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@5284

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@5284

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@5284

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@5284

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@5284

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@5284

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@5284

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@5284

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@5284

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@5284

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@5284

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@5284

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@5284

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@5284

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@5284

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@5284

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@5284

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@5284

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@5284

commit: 090b0c7

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (14)
e2e/react-start/basic/tests/not-found.spec.ts (1)

4-4: Align import path with local tests convention

Use a simpler relative path for consistency with other files under tests/.

-import { isSpaMode } from '../tests/utils/isSpaMode'
+import { isSpaMode } from './utils/isSpaMode'
e2e/react-start/basic/tests/redirect.spec.ts (2)

48-53: Avoid hardcoded localhost in request predicate

Bind to the current page origin to work in environments that resolve to 127.0.0.1 or custom hosts.

-          const requestPromise = new Promise<void>((resolve) => {
+          const origin = new URL(page.url()).origin
+          const requestPromise = new Promise<void>((resolve) => {
             page.on('request', (request) => {
-              if (
-                request.url().startsWith(`http://localhost:${PORT}/_serverFn/`)
-              ) {
+              if (request.url().startsWith(`${origin}/_serverFn/`)) {
                 requestHappened = true
                 resolve()
               }
             })
           })

91-95: Wait for the redirect URL to settle to reduce flakiness

Direct-visit flow can race; explicitly wait for the expected URL before asserting.

-        const url = `http://localhost:${PORT}/posts`
-
-        expect(page.url()).toBe(url)
+        const url = `http://localhost:${PORT}/posts`
+        await page.waitForURL(url)
+        expect(page.url()).toBe(url)
e2e/react-start/basic/vite.config.ts (1)

5-5: Decouple build config from tests util

Read process.env.MODE directly in the config to avoid importing from tests and reduce coupling.

-import { isSpaMode } from './tests/utils/isSpaMode'
+const isSpa = process.env.MODE === 'spa'
@@
-    tanstackStart({
-      spa: isSpaMode ? spaModeConfiguration : undefined,
-    }),
+    tanstackStart({
+      spa: isSpa ? spaModeConfiguration : undefined,
+    }),

Also applies to: 24-25

e2e/solid-start/basic/vite.config.ts (1)

5-12: Optional: inline env check instead of importing from tests

Keep config self-contained by reading process.env.MODE here.

-import { isSpaMode } from './tests/utils/isSpaMode'
+const isSpa = process.env.MODE === 'spa'
@@
-    tanstackStart({
-      spa: isSpaMode ? spaModeConfiguration : undefined,
-    }),
+    tanstackStart({
+      spa: isSpa ? spaModeConfiguration : undefined,
+    }),

Also applies to: 22-25

e2e/solid-start/basic/package.json (1)

10-10: Cross‑platform env var for MODE

On Windows shells, MODE=spa won’t work. Consider cross-env for portability.

-    "build:spa": "MODE=spa vite build && tsc --noEmit",
+    "build:spa": "cross-env MODE=spa vite build && tsc --noEmit"

Add to devDependencies:

+    "cross-env": "^7.0.3"
e2e/solid-start/basic/playwright.config.ts (2)

9-14: Ports/env look correct for SPA; consider scoping START_PORT to SPA only

Deriving distinct PORT/START_PORT keys per mode is good. Minor: in non‑SPA runs START_PORT equals PORT and isn’t used—omit it from env when !isSpaMode to reduce noise.

   webServer: {
     command: isSpaMode ? spaModeCommand : ssrModeCommand,
     url: baseURL,
     reuseExistingServer: !process.env.CI,
     stdout: 'pipe',
     env: {
       MODE: process.env.MODE || '',
       VITE_NODE_ENV: 'test',
       VITE_EXTERNAL_PORT: String(EXTERNAL_PORT),
       VITE_SERVER_PORT: String(PORT),
-      START_PORT: String(START_PORT),
+      ...(isSpaMode ? { START_PORT: String(START_PORT) } : {}),
       PORT: String(PORT),
     },
   },

Also applies to: 48-48


20-20: Gate the config log behind a flag

Console noise can bloat Playwright output. Suggest logging only when DEBUG or CI is set.

-console.log('running in spa mode: ', isSpaMode.toString())
+if (process.env.DEBUG) console.log('running in spa mode:', isSpaMode)
e2e/solid-start/basic/tests/navigation.spec.ts (1)

60-64: Assert page readiness before script globals

To avoid evaluating globals before DOM is painted, mirror the client‑nav test by asserting the heading first.

 await page.goto('/scripts')
 await page.waitForURL('/scripts')
 await page.waitForLoadState('networkidle')
+await expect(page.getByTestId('scripts-test-heading')).toBeVisible()
 expect(await page.evaluate('window.SCRIPT_1')).toBe(true)
e2e/react-start/basic/tests/navigation.spec.ts (2)

45-50: Mirror direct‑nav readiness check

As in Solid, add a heading visibility assertion before reading script globals for deterministic timing.

 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(undefined)

And for direct navigation:

 await page.goto('/scripts')
 await page.waitForURL('/scripts')
 await page.waitForLoadState('networkidle')
+await expect(page.getByTestId('scripts-test-heading')).toBeVisible()
 expect(await page.evaluate('window.SCRIPT_1')).toBe(true)
 expect(await page.evaluate('window.SCRIPT_2')).toBe(undefined)

Also applies to: 54-57


21-21: Consider adding the same initial wait in the first test

For consistency, add await page.waitForURL('/') after the first goto('/') in “Navigating to post”.

e2e/react-start/basic/server.js (3)

2-2: Harden file system paths (avoid CWD dependency in CI/Playwright)

Relative paths to ./dist/... can break when the process CWD differs. Resolve from this file’s directory.

Apply this diff:

 import path from 'node:path'
+import { fileURLToPath } from 'node:url'
@@
-const startPort = process.env.START_PORT || 3001
+const startPort = process.env.START_PORT || 3001
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url))
+const CLIENT_DIR = path.resolve(__dirname, 'dist/client')
+const SERVER_ENTRY = path.resolve(__dirname, 'dist/server/server.js')
@@
-  const server = (await import('./dist/server/server.js')).default
+  const server = (await import(SERVER_ENTRY)).default
@@
-  app.use(express.static('./dist/client'))
+  app.use(express.static(CLIENT_DIR))
@@
-  app.use(express.static('./dist/client'))
+  app.use(express.static(CLIENT_DIR))
@@
-    res.sendFile(path.resolve('./dist/client/index.html'))
+    res.sendFile(path.join(CLIENT_DIR, 'index.html'))

Also applies to: 11-11, 16-16, 48-49, 51-51


57-67: Reduce startup race: ensure Start server is listening before SPA proxies to it

Currently both servers start concurrently; the SPA may proxy to a port that isn’t listening yet. Start the Start server first, then the SPA.

Apply this diff (ESM with top‑level await):

-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}`)
-  }),
-)
+const start = await createStartServer()
+await new Promise((resolve) =>
+  start.app.listen(startPort, () => {
+    console.info(`Start Server: http://localhost:${startPort}`)
+    resolve()
+  }),
+)
+const spa = await createSpaServer()
+spa.app.listen(port, () => {
+  console.info(`Client Server: http://localhost:${port}`)
+})

14-15: Minor hardening: hide Express fingerprint

Disable the X-Powered-By header.

Apply this diff:

   const app = express()
+  app.disable('x-powered-by')
@@
   const app = express()
+  app.disable('x-powered-by')

Also applies to: 30-31

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d363dca and 42b217a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • e2e/react-start/basic/package.json (2 hunks)
  • e2e/react-start/basic/playwright.config.ts (2 hunks)
  • e2e/react-start/basic/server.js (1 hunks)
  • e2e/react-start/basic/tests/navigation.spec.ts (3 hunks)
  • e2e/react-start/basic/tests/not-found.spec.ts (3 hunks)
  • e2e/react-start/basic/tests/redirect.spec.ts (1 hunks)
  • e2e/react-start/basic/tests/search-params.spec.ts (1 hunks)
  • e2e/react-start/basic/vite.config.ts (1 hunks)
  • e2e/solid-start/basic/package.json (2 hunks)
  • e2e/solid-start/basic/playwright.config.ts (2 hunks)
  • e2e/solid-start/basic/server.js (1 hunks)
  • e2e/solid-start/basic/tests/navigation.spec.ts (5 hunks)
  • e2e/solid-start/basic/tests/not-found.spec.ts (2 hunks)
  • e2e/solid-start/basic/tests/redirect.spec.ts (1 hunks)
  • e2e/solid-start/basic/tests/search-params.spec.ts (3 hunks)
  • e2e/solid-start/basic/vite.config.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • e2e/react-start/basic/tests/not-found.spec.ts
  • e2e/solid-start/basic/tests/redirect.spec.ts
  • e2e/react-start/basic/tests/search-params.spec.ts
  • e2e/react-start/basic/tests/redirect.spec.ts
  • e2e/solid-start/basic/tests/search-params.spec.ts
  • e2e/solid-start/basic/tests/not-found.spec.ts
  • e2e/react-start/basic/tests/navigation.spec.ts
  • e2e/solid-start/basic/vite.config.ts
  • e2e/solid-start/basic/tests/navigation.spec.ts
  • e2e/react-start/basic/playwright.config.ts
  • e2e/react-start/basic/vite.config.ts
  • e2e/solid-start/basic/playwright.config.ts
e2e/**

📄 CodeRabbit inference engine (AGENTS.md)

Store end-to-end tests under the e2e/ directory

Files:

  • e2e/react-start/basic/tests/not-found.spec.ts
  • e2e/solid-start/basic/tests/redirect.spec.ts
  • e2e/react-start/basic/tests/search-params.spec.ts
  • e2e/react-start/basic/tests/redirect.spec.ts
  • e2e/solid-start/basic/tests/search-params.spec.ts
  • e2e/solid-start/basic/tests/not-found.spec.ts
  • e2e/solid-start/basic/package.json
  • e2e/solid-start/basic/server.js
  • e2e/react-start/basic/package.json
  • e2e/react-start/basic/tests/navigation.spec.ts
  • e2e/solid-start/basic/vite.config.ts
  • e2e/solid-start/basic/tests/navigation.spec.ts
  • e2e/react-start/basic/server.js
  • e2e/react-start/basic/playwright.config.ts
  • e2e/react-start/basic/vite.config.ts
  • e2e/solid-start/basic/playwright.config.ts
**/package.json

📄 CodeRabbit inference engine (AGENTS.md)

Use workspace:* protocol for internal dependencies in package.json files

Files:

  • e2e/solid-start/basic/package.json
  • e2e/react-start/basic/package.json
🧬 Code graph analysis (7)
e2e/solid-start/basic/tests/redirect.spec.ts (3)
e2e/react-start/server-functions/playwright.config.ts (1)
  • PORT (5-5)
e2e/solid-start/server-functions/playwright.config.ts (1)
  • PORT (5-5)
e2e/e2e-utils/src/derivePort.ts (1)
  • getTestServerPort (25-27)
e2e/react-start/basic/tests/search-params.spec.ts (1)
e2e/react-start/basic/tests/utils/isSpaMode.ts (1)
  • isSpaMode (1-1)
e2e/react-start/basic/tests/redirect.spec.ts (2)
e2e/e2e-utils/src/derivePort.ts (1)
  • getTestServerPort (25-27)
e2e/react-start/basic/tests/utils/isSpaMode.ts (1)
  • isSpaMode (1-1)
e2e/solid-start/basic/server.js (1)
e2e/react-start/basic/server.js (8)
  • port (6-6)
  • startPort (8-8)
  • createStartServer (10-27)
  • server (11-11)
  • nodeHandler (12-12)
  • app (14-14)
  • app (30-30)
  • createSpaServer (29-55)
e2e/react-start/basic/playwright.config.ts (5)
e2e/react-start/server-functions/playwright.config.ts (1)
  • PORT (5-5)
e2e/solid-start/server-functions/playwright.config.ts (1)
  • PORT (5-5)
e2e/e2e-utils/src/derivePort.ts (2)
  • getTestServerPort (25-27)
  • getDummyServerPort (21-23)
e2e/solid-start/basic/tests/utils/isSpaMode.ts (1)
  • isSpaMode (1-1)
e2e/react-start/basic/tests/utils/isSpaMode.ts (1)
  • isSpaMode (1-1)
e2e/react-start/basic/vite.config.ts (1)
e2e/react-start/basic/tests/utils/isSpaMode.ts (1)
  • isSpaMode (1-1)
e2e/solid-start/basic/playwright.config.ts (2)
e2e/e2e-utils/src/derivePort.ts (2)
  • getTestServerPort (25-27)
  • getDummyServerPort (21-23)
e2e/solid-start/basic/tests/utils/isSpaMode.ts (1)
  • isSpaMode (1-1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test
  • GitHub Check: Preview
🔇 Additional comments (28)
e2e/react-start/basic/package.json (3)

10-10: LGTM! SPA build script follows the pattern.

The build:spa script correctly sets MODE=spa and follows the existing build process.


12-12: LGTM! SPA start script references the custom server.

The start:spa script correctly points to the custom server implementation.


21-22: Dependencies are secure and appropriately versioned.

Both express@5.1.0 and http-proxy-middleware@3.0.5 are secure versions. The http-proxy-middleware version includes fixes for CVE-2025-32997 and CVE-2024-21536.

As per coding guidelines

e2e/solid-start/basic/tests/redirect.spec.ts (2)

10-10: LGTM! Consistent import pattern across test files.

The import follows the established pattern for accessing SPA mode state in tests.


15-17: LGTM! SPA-aware port selection ensures correct test server.

The conditional port naming ensures tests connect to the appropriate server instance (SPA vs SSR).

e2e/solid-start/basic/tests/not-found.spec.ts (2)

4-4: LGTM! Consistent import pattern.

The import follows the established pattern for accessing SPA mode state.


18-18: LGTM! Correct status code handling for SPA vs SSR modes.

In SPA mode, the server returns 200 for all routes since client-side routing handles not-found scenarios. This is the expected behavioral difference.

e2e/react-start/basic/tests/search-params.spec.ts (2)

30-32: LGTM! Correct handling of SPA mode redirect behavior.

In SPA mode, redirects are handled client-side, so server redirect responses won't occur. The conditional logic correctly skips these assertions for SPA tests.


55-57: LGTM! Consistent redirect handling pattern.

The conditional logic maintains consistency with the redirect behavior handling for SPA mode.

e2e/solid-start/basic/tests/search-params.spec.ts (2)

3-3: LGTM! Consistent import pattern.

The import follows the established pattern for accessing SPA mode state in tests.


29-31: LGTM! Appropriate conditional logic for SPA mode.

The conditional logic correctly handles the behavioral difference between SPA and SSR modes. In SPA mode, redirects are handled client-side, so server redirect responses won't occur.

Also applies to: 53-55

e2e/react-start/basic/tests/not-found.spec.ts (1)

18-18: Good: not-found status accounts for SPA fallback

200 vs 404 based on SPA mode mirrors real server behavior. LGTM.

e2e/react-start/basic/tests/redirect.spec.ts (2)

15-17: LGTM: spa-aware PORT avoids collisions across modes

Suffixing the derive key with _spa yields a distinct port. Nice.


10-10: Type check for JSON import assertion

Ensure tsconfig for these tests has resolveJsonModule: true and a compatible module resolution (e.g., "moduleResolution": "bundler" or "nodeNext") so with { type: 'json' } compiles cleanly under tsc.

Would you confirm tsconfig settings for the e2e React Start project?

e2e/react-start/basic/vite.config.ts (1)

24-25: LGTM: SPA wiring into tanstackStart

Passing spa configuration via isSpaMode is correct.

e2e/solid-start/basic/vite.config.ts (1)

22-26: LGTM: SPA mode correctly plumbed into Solid Start plugin

Configuration matches the intended SPA build behavior.

e2e/solid-start/basic/package.json (2)

18-27: Deps look appropriate for SPA proxy server

express@^5 and http-proxy-middleware@^3 are suitable for the custom SPA server. No further changes.


12-12: server.js already uses ESM imports—no changes required
All imports use import syntax and no require() calls were found.

e2e/solid-start/basic/tests/navigation.spec.ts (2)

12-13: Good stability improvements with URL/load waits

The added waitForURL/networkidle points should reduce flakiness across SPA/SSR.

Also applies to: 23-24, 33-34, 50-55, 60-64, 69-70, 79-80


54-55: No change needed—SSR omits script2.js, so window.SCRIPT_2 being undefined is correct
In scripts.tsx, isProd is true during the production build that SSR uses, causing the isProd ? undefined : { src: 'script2.js' } branch to drop script2.js entirely. Hence in SSR mode window.SCRIPT_2 is undefined as the tests assert.

e2e/react-start/basic/playwright.config.ts (2)

9-14: Ports/env wiring LGTM

Distinct PORT/START_PORT derivation and env exposure look good for SPA orchestration.

Also applies to: 47-48


17-17: Confirmed SPA scripts exist

e2e/react-start/basic/tests/navigation.spec.ts (2)

21-21: Stability waits look good

The added waitForURL and networkidle syncs should reduce flakes across runs.

Also applies to: 29-29, 45-45, 54-55, 57-57, 62-62, 71-71


49-50: Sanity-check SSR mode Confirm that your SSR setup does not include public/script2.js (so window.SCRIPT_2 remains undefined).

e2e/solid-start/basic/server.js (2)

32-46: Proxy targets/path joining

Using app.use('/api', proxy({ target: http://localhost:${startPort}/api })) is valid in Express (mount strips /api). No change required; just noting the intent is correct.


1-1: Import path correct: All e2e examples import toNodeHandler from 'srvx/node' consistently; no change required.

Likely an incorrect or invalid review comment.

e2e/solid-start/basic/playwright.config.ts (1)

17-17: Scripts and port bindings are correctly defined
build:spa and start:spa are present in package.json, and Playwright’s webServer env passes PORT and START_PORT into server.js, which listens on both ports.

e2e/react-start/basic/server.js (1)

1-1: Verify toNodeHandler import path
Ensure your installed srvx version actually exports toNodeHandler from srvx/node (e.g. check its package.json > exports or inspect the package files). If that subpath isn’t available, switch to the known adapter in vinxi/http:

-import { toNodeHandler } from 'srvx/node'
+import { toNodeHandler } from 'vinxi/http'

@nlynzaad nlynzaad merged commit 58e8a94 into main Sep 28, 2025
6 checks passed
@nlynzaad nlynzaad deleted the e2e-basic-spa branch September 28, 2025 21:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant