Describe the bug
With Vitest 5, clicking Start Vitest UI in the Vite+ group starts the server, the dock swaps to the iframe, and the iframe shows only this text instead of the Vitest UI:
Vitest UI requires authentication. Open the URL with the token printed in the terminal, e.g. http://localhost:51204/__vitest__/?token=...
Since Vitest 5 (vitest-dev/vitest#10583), /__vitest__/ answers 403 unless the request carries ?token=<api token> (which sets a vitest-ui-token cookie and redirects 302 to the clean URL) or already has that cookie. The token is printed by Vitest as UI started at http://localhost:<port>/__vitest__/?token=… and is stored in %LOCALAPPDATA%/vitest/.vitest-secret-token (or node_modules/.vitest/).
The launcher never obtains that token:
- The iframe URL is built as
http://localhost:${port}/__vitest__/ with no token (plugin.ts#L117) and returned from onReady as-is (#L133-L137).
waitForServer() treats any status below 500 as ready (#L192-L205), so the 403 counts as "ready" and the auth page is embedded. Accepting 403 is fine for "is the port up", but the embedded URL then can never succeed.
Possible fix: take the authenticated URL from the UI started at … line of the session's stdout (via session.getChildProcess()), use it as the iframe URL, and have the readiness probe request that URL and accept only 2xx/3xx. A fallback could read the token file, but that path is a Vitest internal.
Unverified, possibly related (not tested in a browser): the cookie is SameSite=Strict and the launcher hard-codes the localhost host. If DevTools is opened on http://127.0.0.1:<vite port>, the localhost iframe is cross-site, so the browser may not store or send the cookie even when the token is present. Building the iframe URL on the same hostname as the DevTools page would avoid that.
Related: stopping this launcher on Windows leaves the vitest process running, see devframes/devframe#402.
Reproduction
Inline steps below — needs a local Vitest 5 UI (no hosted repro possible).
- Any Vite 8 project with
vitest@5, @vitest/ui@5, @vitejs/devtools@0.7.5 and @vitejs/devtools-vitest@0.7.5, devtools: true in the Vite config. Upstream's own pnpm -C packages/core run play should show the same, since the workspace uses vitest ^5.0.1.
- Run
vite, open DevTools, Vite+ group → Vitest → Start Vitest UI.
- The iframe shows the "Vitest UI requires authentication" page.
The HTTP side without a browser (empty folder with one test file and an empty vitest.config.js; vitest 5.0.0 + @vitest/ui 5.0.0 installed):
// probe.mjs — same spawn args and probe as the launcher
import { spawn } from 'node:child_process'
const port = 43217
const cp = spawn(process.execPath, ['node_modules/vitest/vitest.mjs', '--ui', '--no-open', '--watch', '--api.port', String(port)], { stdio: 'pipe' })
let out = ''
cp.stdout.on('data', d => { out += d })
let res
for (let i = 0; i < 100 && !res; i++)
res = await fetch(`http://localhost:${port}/__vitest__/`, { redirect: 'manual' }).catch(() => new Promise(r => setTimeout(r, 300)))
console.log('bare URL ->', res.status, (await res.text()).slice(0, 60), '| launcher accepts:', res.status < 500)
await new Promise(r => setTimeout(r, 1500))
const url = out.replace(/\x1B\[[0-9;]*m/g, '').match(/UI started at (\S+)/)[1]
const r2 = await fetch(url, { redirect: 'manual' })
console.log('token URL ->', r2.status, r2.headers.get('location'), r2.headers.get('set-cookie')?.split(';').slice(1).join(';'))
cp.kill()
Output:
bare URL -> 403 Vitest UI requires authentication. Open the URL with the | launcher accepts: true
token URL -> 302 /__vitest__/ Path=/__vitest__/; HttpOnly; SameSite=Strict
Expected: the dock iframe shows the Vitest UI.
Actual: the dock iframe shows Vitest's 403 "requires authentication" page, and the launcher reports the server as ready.
System Info
OS: Windows 11 Pro 10.0.26200 (x64)
Node: 24.21.0
pnpm: 12.5.1
Browser: Chrome
@vitejs/devtools / @vitejs/devtools-kit / @vitejs/devtools-vitest: 0.7.5 (also upstream main ad2d6df)
devframe / @devframes/hub: 1.0.0
vite: 8.3.0
vitest / @vitest/ui: 5.0.0
Used Package Manager
pnpm
Validations
Describe the bug
With Vitest 5, clicking Start Vitest UI in the Vite+ group starts the server, the dock swaps to the iframe, and the iframe shows only this text instead of the Vitest UI:
Since Vitest 5 (vitest-dev/vitest#10583),
/__vitest__/answers403unless the request carries?token=<api token>(which sets avitest-ui-tokencookie and redirects302to the clean URL) or already has that cookie. The token is printed by Vitest asUI started at http://localhost:<port>/__vitest__/?token=…and is stored in%LOCALAPPDATA%/vitest/.vitest-secret-token(ornode_modules/.vitest/).The launcher never obtains that token:
http://localhost:${port}/__vitest__/with no token (plugin.ts#L117) and returned fromonReadyas-is (#L133-L137).waitForServer()treats any status below 500 as ready (#L192-L205), so the403counts as "ready" and the auth page is embedded. Accepting 403 is fine for "is the port up", but the embedded URL then can never succeed.Possible fix: take the authenticated URL from the
UI started at …line of the session's stdout (viasession.getChildProcess()), use it as the iframe URL, and have the readiness probe request that URL and accept only 2xx/3xx. A fallback could read the token file, but that path is a Vitest internal.Unverified, possibly related (not tested in a browser): the cookie is
SameSite=Strictand the launcher hard-codes thelocalhosthost. If DevTools is opened onhttp://127.0.0.1:<vite port>, thelocalhostiframe is cross-site, so the browser may not store or send the cookie even when the token is present. Building the iframe URL on the same hostname as the DevTools page would avoid that.Related: stopping this launcher on Windows leaves the
vitestprocess running, see devframes/devframe#402.Reproduction
Inline steps below — needs a local Vitest 5 UI (no hosted repro possible).
vitest@5,@vitest/ui@5,@vitejs/devtools@0.7.5and@vitejs/devtools-vitest@0.7.5,devtools: truein the Vite config. Upstream's ownpnpm -C packages/core run playshould show the same, since the workspace usesvitest ^5.0.1.vite, open DevTools, Vite+ group → Vitest → Start Vitest UI.The HTTP side without a browser (empty folder with one test file and an empty
vitest.config.js;vitest5.0.0 +@vitest/ui5.0.0 installed):Output:
Expected: the dock iframe shows the Vitest UI.
Actual: the dock iframe shows Vitest's 403 "requires authentication" page, and the launcher reports the server as ready.
System Info
Used Package Manager
pnpm
Validations