-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
chore: stabilize tests #6492
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
chore: stabilize tests #6492
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,77 @@ | ||
| import { e2eStartDummyServer } from '@tanstack/router-e2e-utils' | ||
| import { chromium } from '@playwright/test' | ||
| import { | ||
| e2eStartDummyServer, | ||
| getTestServerPort, | ||
| } from '@tanstack/router-e2e-utils' | ||
| import packageJson from '../../package.json' with { type: 'json' } | ||
|
|
||
| async function waitForServer(url: string) { | ||
| const start = Date.now() | ||
| while (Date.now() - start < 30_000) { | ||
| try { | ||
| const res = await fetch(url, { redirect: 'manual' }) | ||
| if (res.ok) return | ||
| } catch { | ||
| // ignore | ||
| } | ||
| await new Promise((r) => setTimeout(r, 250)) | ||
| } | ||
| throw new Error(`Timed out waiting for dev server at ${url}`) | ||
| } | ||
|
|
||
| async function preOptimizeDevServer(baseURL: string) { | ||
| const browser = await chromium.launch() | ||
| const context = await browser.newContext() | ||
| const page = await context.newPage() | ||
|
|
||
| try { | ||
| await page.goto(`${baseURL}/`, { waitUntil: 'domcontentloaded' }) | ||
| await page.getByTestId('global-styled').waitFor({ state: 'visible' }) | ||
| await page.waitForLoadState('networkidle') | ||
|
|
||
| await page.goto(`${baseURL}/modules`, { waitUntil: 'domcontentloaded' }) | ||
| await page.getByTestId('module-card').waitFor({ state: 'visible' }) | ||
| await page.waitForLoadState('networkidle') | ||
|
|
||
| await page.goto(`${baseURL}/sass-mixin`, { waitUntil: 'domcontentloaded' }) | ||
| await page.getByTestId('mixin-styled').waitFor({ state: 'visible' }) | ||
| await page.waitForLoadState('networkidle') | ||
|
|
||
| await page.goto(`${baseURL}/quotes`, { waitUntil: 'domcontentloaded' }) | ||
| await page.getByTestId('quote-styled').waitFor({ state: 'visible' }) | ||
| await page.getByTestId('after-quote-styled').waitFor({ state: 'visible' }) | ||
| await page.waitForLoadState('networkidle') | ||
|
|
||
| // Ensure we end in a stable state. Vite's optimize step triggers a reload; | ||
| // this waits until no further navigations happen for a short window. | ||
| for (let i = 0; i < 40; i++) { | ||
| const currentUrl = page.url() | ||
| await page.waitForTimeout(250) | ||
| if (page.url() === currentUrl) { | ||
| await page.waitForTimeout(250) | ||
| if (page.url() === currentUrl) return | ||
| } | ||
| } | ||
|
|
||
| throw new Error('Dev server did not reach a stable URL after warmup') | ||
| } finally { | ||
| await context.close() | ||
| await browser.close() | ||
| } | ||
| } | ||
|
|
||
| export default async function setup() { | ||
| await e2eStartDummyServer(packageJson.name) | ||
|
|
||
| if (process.env.MODE !== 'dev') return | ||
|
|
||
| const viteConfig = process.env.VITE_CONFIG // 'nitro' | 'basepath' | 'cloudflare' | undefined | ||
| const port = await getTestServerPort( | ||
| viteConfig ? `${packageJson.name}-${viteConfig}` : packageJson.name, | ||
| ) | ||
| const basePath = viteConfig === 'basepath' ? '/my-app' : '' | ||
| const baseURL = `http://localhost:${port}${basePath}` | ||
|
|
||
| await waitForServer(baseURL) | ||
| await preOptimizeDevServer(baseURL) | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,68 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { e2eStartDummyServer } from '@tanstack/router-e2e-utils' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { chromium } from '@playwright/test' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e2eStartDummyServer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getTestServerPort, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '@tanstack/router-e2e-utils' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import packageJson from '../../package.json' with { type: 'json' } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function waitForServer(url: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const start = Date.now() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while (Date.now() - start < 30_000) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const res = await fetch(url, { redirect: 'manual' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (res.ok) return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ignore | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await new Promise((r) => setTimeout(r, 250)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`Timed out waiting for dev server at ${url}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+8
to
+19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n e2e/solid-start/css-modules/tests/setup/global.setup.ts | sed -n '1,30p'Repository: TanStack/router Length of output: 1211 🌐 Web query:
💡 Result:
Sources: Add per-attempt timeout to prevent hanging fetch calls in With 🛠️ Suggested fix async function waitForServer(url: string) {
const start = Date.now()
while (Date.now() - start < 30_000) {
+ const controller = new AbortController()
+ const timeout = setTimeout(() => controller.abort(), 2_000)
try {
- const res = await fetch(url, { redirect: 'manual' })
+ const res = await fetch(url, {
+ redirect: 'manual',
+ signal: controller.signal,
+ })
if (res.ok) return
} catch {
// ignore
+ } finally {
+ clearTimeout(timeout)
}
await new Promise((r) => setTimeout(r, 250))
}
throw new Error(`Timed out waiting for dev server at ${url}`)
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function preOptimizeDevServer(baseURL: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const browser = await chromium.launch() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const context = await browser.newContext() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const page = await context.newPage() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.goto(`${baseURL}/`, { waitUntil: 'domcontentloaded' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.getByTestId('global-styled').waitFor({ state: 'visible' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.waitForLoadState('networkidle') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.goto(`${baseURL}/modules`, { waitUntil: 'domcontentloaded' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.getByTestId('module-card').waitFor({ state: 'visible' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.waitForLoadState('networkidle') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.goto(`${baseURL}/sass-mixin`, { waitUntil: 'domcontentloaded' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.getByTestId('mixin-styled').waitFor({ state: 'visible' }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.waitForLoadState('networkidle') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Ensure we end in a stable state. Vite's optimize step triggers a reload; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // this waits until no further navigations happen for a short window. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let i = 0; i < 40; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const currentUrl = page.url() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.waitForTimeout(250) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (page.url() === currentUrl) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await page.waitForTimeout(250) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (page.url() === currentUrl) return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error('Dev server did not reach a stable URL after warmup') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } finally { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await context.close() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await browser.close() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default async function setup() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await e2eStartDummyServer(packageJson.name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (process.env.MODE !== 'dev') return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const port = await getTestServerPort(packageJson.name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const baseURL = `http://localhost:${port}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await waitForServer(baseURL) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await preOptimizeDevServer(baseURL) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: TanStack/router
Length of output: 1451
🏁 Script executed:
Repository: TanStack/router
Length of output: 3295
🏁 Script executed:
# Check other setup files to see if there are similar patterns head -30 ./e2e/react-router/basic/tests/setup/global.setup.tsRepository: TanStack/router
Length of output: 279
🏁 Script executed:
Repository: TanStack/router
Length of output: 86
🏁 Script executed:
Repository: TanStack/router
Length of output: 3412
🏁 Script executed:
Repository: TanStack/router
Length of output: 1350
🏁 Script executed:
Repository: TanStack/router
Length of output: 188
🏁 Script executed:
Repository: TanStack/router
Length of output: 4428
🏁 Script executed:
Repository: TanStack/router
Length of output: 1858
Handle redirects and per-attempt timeouts in
waitForServer.res.okonly returns true for 2xx status codes. Withredirect: 'manual', 3xx responses (including base-path redirects) cause the check to fail. Additionally, the fetch call lacks a per-attempt timeout, allowing network hangs to stall the loop. Add an abort timeout per attempt and accept 3xx responses.Suggested fix
async function waitForServer(url: string) { const start = Date.now() while (Date.now() - start < 30_000) { + const controller = new AbortController() + const timeout = setTimeout(() => controller.abort(), 2_000) try { - const res = await fetch(url, { redirect: 'manual' }) - if (res.ok) return + const res = await fetch(url, { + redirect: 'manual', + signal: controller.signal, + }) + if (res.ok || (res.status >= 300 && res.status < 400)) return } catch { // ignore - } + } finally { + clearTimeout(timeout) + } await new Promise((r) => setTimeout(r, 250)) } throw new Error(`Timed out waiting for dev server at ${url}`) }🤖 Prompt for AI Agents