fix(vitest): embed the tokenized Vitest UI URL - #588
Merged
Merged
Conversation
Vitest 5 answers `/__vitest__/` with a `403` auth page unless the request carries the API token printed on startup. The launcher embedded the bare URL and its readiness probe accepted any status below 500, so the dock iframe showed the auth page. Read the token from the session output, embed the tokenized URL, and only treat a `2xx`/`3xx` as ready. Fixes vitejs#585 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
antfu
approved these changes
Sep 25, 2026
@vitejs/devtools
@vitejs/devtools-kit
@vitejs/devtools-oxc
@vitejs/devtools-rolldown
@vitejs/devtools-vite
@vitejs/devtools-vitest
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
With Vitest 5 the Vitest UI launcher embedded Vitest's
403"requires authentication" page instead of the UI. Since vitest-dev/vitest#10583,/__vitest__/needs the API token Vitest prints on startup (UI started at …/__vitest__/?token=…). The launcher embedded the bare URL, and its readiness probe accepted any status below 500, so the 403 counted as ready.This PR:
packages/vitest/src/node/ui-url.ts:resolveVitestUiUrl(url, output)reads the token from theUI started atline (ANSI stripped withnode:util'sstripVTControlCharacters) and returns the launcher's URL with?token=. It returns the URL unchanged when the printed URL has no token (Vitest < 5), orundefinedif the line hasn't been printed yet.waitForVitestUi(url, timeout, getOutput)polls the tokenized URL (plain URL until the line shows up) withredirect: 'manual', and treats only2xx/3xxas ready. Vitest answers a valid?token=with302plus the auth cookie.serve.onReadyreads the session's output (session.buffer) and returns the tokenized URL as the iframe URL, so the browser's first request sets the cookie and gets redirected to the UI.docs/errors/VTDT0002.md(cause and source) to match.Linked Issues
Fixes #585
Additional context
packages/vitest/src/node/__tests__/ui-url.test.tscovers the parser (no line yet, ANSI-colored Vitest 5 line, Vitest < 5 line without a token) and the readiness loop against a local server that behaves like Vitest 5'svitestUiAuthmiddleware. The 403-only case would have counted as ready under the oldstatus < 500check.waitForVitestUireturnedhttp://localhost:<port>/__vitest__/?token=…. Requesting it gave302+vitest-ui-tokencookie, and following the redirect with the cookie returned200with the UI HTML.SameSite=Strict, and the launcher hard-codeslocalhost. If DevTools is opened onhttp://127.0.0.1:<vite port>, the iframe is cross-site and the browser may refuse the cookie. The UI would then get a 403 on the redirected request even with the token. Using the DevTools page's hostname for the iframe would avoid that. Out of scope here.pnpm lint,pnpm typecheckandpnpm buildpass.pnpm testpasses except twopackages/uibytesToHumanSizecases ('1,5'vs'1.5'). They fail the same way on a cleanmainhere because of the machine's tr-TR locale, and are unrelated.🤖 Generated with Claude Code