Skip to content

feat(vitest-environment): support @vitest-environment-options#1673

Open
yamachi4416 wants to merge 1 commit intonuxt:mainfrom
yamachi4416:support-vitest-environment-options
Open

feat(vitest-environment): support @vitest-environment-options#1673
yamachi4416 wants to merge 1 commit intonuxt:mainfrom
yamachi4416:support-vitest-environment-options

Conversation

@yamachi4416
Copy link
Copy Markdown
Member

@yamachi4416 yamachi4416 commented Apr 21, 2026

🔗 Linked issue

resolves #1541

📚 Description

Added support for @vitest-environment-options, initially limited to url and domEnvironment as they are safe to change per test file.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 21, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@nuxt/test-utils@1673
npm i https://pkg.pr.new/vitest-environment-nuxt@1673

commit: f00a8e1

@yamachi4416 yamachi4416 force-pushed the support-vitest-environment-options branch 4 times, most recently from d80da26 to acf91a9 Compare April 22, 2026 11:27
@yamachi4416 yamachi4416 marked this pull request as ready for review April 22, 2026 11:33
@yamachi4416 yamachi4416 requested a review from danielroe as a code owner April 22, 2026 11:33
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

📝 Walkthrough

Walkthrough

Merges per-test @vitest-environment-options with base Nuxt Vitest environment options by introducing a SetupWindowNuxtEnvironmentOptions interface and a mergeSetupWindowEnvironmentOptions helper. The Vitest environment setup now uses merged options (including nuxt.url and nuxt.domEnvironment) and passes them into setupWindow. The plugin caches serialized options and exposes them via process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__. Documentation JSDoc for NuxtEnvironmentOptions was updated to note @vitest-environment-options overrides. Two new Vitest spec files and a test count update validate the behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main feature addition: support for @vitest-environment-options annotation in Vitest environment configuration.
Description check ✅ Passed The description is related to the changeset, mentioning issue #1541 and that support for @vitest-environment-options was added for url and domEnvironment options.
Linked Issues check ✅ Passed The PR implements the core requirement from issue #1541: merging @vitest-environment-options with config-level environmentOptions instead of replacing them.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing @vitest-environment-options support: new test files, environment merging logic, plugin hooks, and documentation updates for url and domEnvironment.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@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: 1

🧹 Nitpick comments (4)
src/runtime/shared/environment.ts (1)

79-83: Redundant optional chaining on required parameter.

environmentOptions is now required (non-optional) per the new SetupWindowNuxtEnvironmentOptions signature, so the environmentOptions?. optional chain on Line 80–81 is dead. The inner ?.nuxtRuntimeConfig?.app?.baseURL chain is still needed since nuxtRuntimeConfig is optional.

♻️ Proposed tweak
   const manifestOutputPath = joinURL(
-    environmentOptions?.nuxtRuntimeConfig?.app?.baseURL || '/',
-    environmentOptions?.nuxtRuntimeConfig?.app?.buildAssetsDir || '_nuxt',
+    environmentOptions.nuxtRuntimeConfig?.app?.baseURL || '/',
+    environmentOptions.nuxtRuntimeConfig?.app?.buildAssetsDir || '_nuxt',
     'builds',
   )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/shared/environment.ts` around lines 79 - 83, The
manifestOutputPath computation uses redundant optional chaining on the
now-required parameter environmentOptions; change the references from
environmentOptions?.nuxtRuntimeConfig to environmentOptions.nuxtRuntimeConfig
(keep the remaining ?.nuxtRuntimeConfig?.app?.baseURL and ?.app?.buildAssetsDir
chains intact) so that only the unnecessary leading ?. is removed; update the
expression that constructs manifestOutputPath (the joinURL call where
manifestOutputPath is declared) to reference environmentOptions directly while
preserving the inner optional chains.
src/module/plugins/options.ts (1)

22-28: Double JSON.stringify is correct here, but add a brief comment.

define values must be JavaScript source expressions, so the payload needs to be a string literal whose runtime value is the JSON text. JSON.stringify(serializedOptions) achieves exactly that (turning {"a":1} into "\"{\\\"a\\\":1}\""), which is then JSON.parse'd in src/environments/vitest/index.ts. This looks odd at first glance and is easy to "simplify" incorrectly — a one-line comment would prevent future regressions.

♻️ Suggested comment
     config() {
       return {
         define: {
+          // Double-stringify: `define` values must be source expressions, so we need a JS string literal
+          // whose runtime value is the JSON text (consumed via JSON.parse in the Vitest env setup).
           'process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__': JSON.stringify(serializedOptions),
         },
       }
     },

Also worth confirming the define actually reaches the Vitest environment module (src/environments/vitest/index.ts) at runtime — this depends on that file being transformed by Vite. @nuxt/test-utils is in server.deps.inline so this should hold, but it's worth a manual spot-check (e.g., log the raw env value from inside the environment) given a silent failure here would degrade to the exact bug #1541 describes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/module/plugins/options.ts` around lines 22 - 28, Add a one-line inline
comment above the define entry in the config() method (referencing define and
serializedOptions) that explains why we call JSON.stringify(serializedOptions)
twice so future readers don't remove the extra stringification (i.e., define
expects a JS source expression string which will be parsed at runtime in
src/environments/vitest/index.ts). After adding the comment, perform a quick
runtime spot-check by logging the raw
process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__ value from
src/environments/vitest/index.ts to confirm the define is being transformed and
the JSON text is present at runtime.
examples/app-vitest-full/tests/nuxt/vitest-environment-options-1.spec.ts (1)

1-17: Coverage looks good, but consider asserting jsdom-specific global to avoid UA-string false positives.

navigator.userAgent containing "jsdom" is a reasonable signal today, but a stronger assertion is the presence of a jsdom-only global/marker (e.g., window._virtualConsole or checking that happy-dom's signature is absent) to protect against happy-dom one day including the substring in its UA. Optional.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/app-vitest-full/tests/nuxt/vitest-environment-options-1.spec.ts`
around lines 1 - 17, Update the test "can override domEnvironment via
`@vitest-environment-options`" to assert a jsdom-specific global in addition to
the navigator check: keep the existing navigator.userAgent assertion and add a
second assertion that a jsdom-only marker (for example window._virtualConsole is
defined or another jsdom-specific property) exists so the test doesn't rely
solely on UA-string content; modify the test body that references
navigator.userAgent and add the additional expectation against
window._virtualConsole (or another jsdom-only global) to strengthen the
environment check.
src/config.ts (1)

373-399: Docs accurately reflect the new scope.

Calling out the @vitest-environment-options override on exactly the two supported fields (url, domEnvironment) is appropriate. Consider also noting in the interface doc (or README) that other nuxt.* options inside an annotation are currently ignored, so users don't get surprised when setting e.g. rootId via annotation has no effect.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/config.ts` around lines 373 - 399, Update the interface/doc comment
around the Nuxt test environment options (the properties url and domEnvironment)
to explicitly state that only these two fields are read from the
`@vitest-environment-options` annotation and that other nuxt.* options (for
example rootId or values under overrides/dotenv) present in the annotation will
be ignored; mention this behavior in the comment block near the url,
domEnvironment and rootId declarations so users aren’t surprised when setting
other options via the annotation has no effect.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/environments/vitest/index.ts`:
- Around line 70-90: mergeSetupWindowEnvironmentOptions currently only keeps
nuxt.url and nuxt.domEnvironment and silently drops any other keys under nuxt,
and also blindly spreads all top-level environmentOptions which lets unintended
top-level keys override base config; update mergeSetupWindowEnvironmentOptions
to (1) detect any keys present on the incoming environmentOptions.nuxt other
than "url" and "domEnvironment" and emit a single console.warn per unknown key
(include the key name and that it's ignored) to aid debugging, and (2) replace
the broad "...environmentOptions" spread with a narrow allowlist of safe
top-level keys (e.g., happyDom, jsdom, nuxtRuntimeConfig, nuxtRouteRules —
whatever the project deems safe) so only those top-level annotation keys can
override base config; reference the mergeSetupWindowEnvironmentOptions function
and the nuxt property when making these changes.

---

Nitpick comments:
In `@examples/app-vitest-full/tests/nuxt/vitest-environment-options-1.spec.ts`:
- Around line 1-17: Update the test "can override domEnvironment via
`@vitest-environment-options`" to assert a jsdom-specific global in addition to
the navigator check: keep the existing navigator.userAgent assertion and add a
second assertion that a jsdom-only marker (for example window._virtualConsole is
defined or another jsdom-specific property) exists so the test doesn't rely
solely on UA-string content; modify the test body that references
navigator.userAgent and add the additional expectation against
window._virtualConsole (or another jsdom-only global) to strengthen the
environment check.

In `@src/config.ts`:
- Around line 373-399: Update the interface/doc comment around the Nuxt test
environment options (the properties url and domEnvironment) to explicitly state
that only these two fields are read from the `@vitest-environment-options`
annotation and that other nuxt.* options (for example rootId or values under
overrides/dotenv) present in the annotation will be ignored; mention this
behavior in the comment block near the url, domEnvironment and rootId
declarations so users aren’t surprised when setting other options via the
annotation has no effect.

In `@src/module/plugins/options.ts`:
- Around line 22-28: Add a one-line inline comment above the define entry in the
config() method (referencing define and serializedOptions) that explains why we
call JSON.stringify(serializedOptions) twice so future readers don't remove the
extra stringification (i.e., define expects a JS source expression string which
will be parsed at runtime in src/environments/vitest/index.ts). After adding the
comment, perform a quick runtime spot-check by logging the raw
process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__ value from
src/environments/vitest/index.ts to confirm the define is being transformed and
the JSON text is present at runtime.

In `@src/runtime/shared/environment.ts`:
- Around line 79-83: The manifestOutputPath computation uses redundant optional
chaining on the now-required parameter environmentOptions; change the references
from environmentOptions?.nuxtRuntimeConfig to
environmentOptions.nuxtRuntimeConfig (keep the remaining
?.nuxtRuntimeConfig?.app?.baseURL and ?.app?.buildAssetsDir chains intact) so
that only the unnecessary leading ?. is removed; update the expression that
constructs manifestOutputPath (the joinURL call where manifestOutputPath is
declared) to reference environmentOptions directly while preserving the inner
optional chains.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 30713eed-6c4a-4211-9f04-49d66ebcbf86

📥 Commits

Reviewing files that changed from the base of the PR and between 16db6e0 and acf91a9.

📒 Files selected for processing (7)
  • examples/app-vitest-full/tests/nuxt/vitest-environment-options-1.spec.ts
  • examples/app-vitest-full/tests/nuxt/vitest-environment-options-2.spec.ts
  • examples/app-vitest-full/tests/resolved-files.spec.ts
  • src/config.ts
  • src/environments/vitest/index.ts
  • src/module/plugins/options.ts
  • src/runtime/shared/environment.ts

@yamachi4416 yamachi4416 force-pushed the support-vitest-environment-options branch from acf91a9 to 773442d Compare April 22, 2026 11:49
@yamachi4416 yamachi4416 marked this pull request as draft April 22, 2026 12:15
@yamachi4416 yamachi4416 force-pushed the support-vitest-environment-options branch from 773442d to f00a8e1 Compare April 22, 2026 12:15
@yamachi4416 yamachi4416 marked this pull request as ready for review April 22, 2026 13:56
Copy link
Copy Markdown

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/environments/vitest/index.ts`:
- Around line 70-87: The mergeSetupWindowEnvironmentOptions function currently
falls back to an empty object when
process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__ is missing, which loses
incoming options; change the fallback to use the already-parsed
nuxtEnvironmentOptions (from the local variable nuxtEnvironmentOptions) as the
base for defu instead of '{}', ensuring you JSON.parse the env var when present
and pass nuxt: { url, domEnvironment, ... } merged with
JSON.parse(process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__ ||
JSON.stringify({ nuxt: nuxtEnvironmentOptions })) so properties like
nuxt.rootId, nuxt.mock, nuxt.h3Version, nuxtRuntimeConfig, and nuxtRouteRules
are preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8ad164f9-5977-44e7-993c-de3ba0c329ad

📥 Commits

Reviewing files that changed from the base of the PR and between acf91a9 and f00a8e1.

📒 Files selected for processing (7)
  • examples/app-vitest-full/tests/nuxt/vitest-environment-options-1.spec.ts
  • examples/app-vitest-full/tests/nuxt/vitest-environment-options-2.spec.ts
  • examples/app-vitest-full/tests/resolved-files.spec.ts
  • src/config.ts
  • src/environments/vitest/index.ts
  • src/module/plugins/options.ts
  • src/runtime/shared/environment.ts
✅ Files skipped from review due to trivial changes (3)
  • examples/app-vitest-full/tests/resolved-files.spec.ts
  • examples/app-vitest-full/tests/nuxt/vitest-environment-options-1.spec.ts
  • src/config.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/module/plugins/options.ts
  • examples/app-vitest-full/tests/nuxt/vitest-environment-options-2.spec.ts
  • src/runtime/shared/environment.ts

Comment on lines +70 to +87
// Manually merge with base config because `@vitest-environment-options` doesn't merge by default
function mergeSetupWindowEnvironmentOptions(
environmentOptions: Record<string, unknown>,
): SetupWindowNuxtEnvironmentOptions {
const {
nuxt: nuxtEnvironmentOptions = {},
} = environmentOptions as unknown as SetupWindowNuxtEnvironmentOptions

return defu(
{
nuxt: {
url: nuxtEnvironmentOptions.url,
domEnvironment: nuxtEnvironmentOptions.domEnvironment,
},
},
JSON.parse(process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__ || '{}'),
)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Inspect Nuxt Vitest environment/plugin wiring and direct environment usages.
# Expected: every supported `environment: 'nuxt'` path should also install the options plugin;
# otherwise the helper should preserve incoming environmentOptions when the injected env var is absent.

rg -n -C3 'NuxtVitestEnvironmentOptionsPlugin|__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__|environment:\s*["'\'']nuxt["'\'']|@vitest-environment\s+nuxt'

Repository: nuxt/test-utils

Length of output: 13107


🏁 Script executed:

# Check if simple fixtures use defineVitestConfig or are standalone
cat test/fixtures/simple/env-nuxt/vitest.config.ts

Repository: nuxt/test-utils

Length of output: 199


🏁 Script executed:

# Check the vitest environment setup code to see when mergeSetupWindowEnvironmentOptions is called
cat -n src/environments/vitest/index.ts | head -100

Repository: nuxt/test-utils

Length of output: 4011


🏁 Script executed:

# Look for other environment initialization patterns
rg -n "mergeSetupWindowEnvironmentOptions|setupWindowEnvironmentOptions" src/

Repository: nuxt/test-utils

Length of output: 262


🏁 Script executed:

# Check src/config.ts to understand the plugin registration
cat -n src/config.ts | sed -n '290,360p'

Repository: nuxt/test-utils

Length of output: 2961


🏁 Script executed:

# Check for any direct environment: 'nuxt' usage that might not go through defineVitestConfig
rg "environment.*nuxt" -A 2 -B 2 | grep -v "defineVitestConfig\|snapshots\|fixtures\|examples" | head -40

Repository: nuxt/test-utils

Length of output: 1881


🏁 Script executed:

# Check the fixture with `@vitest-environment` comment
cat test/fixtures/simple/env-other-include/vitest.config.ts
cat test/fixtures/simple/env-other-include/test/test3.spec.ts

Repository: nuxt/test-utils

Length of output: 452


🏁 Script executed:

# Check if the fixture with `@vitest-environment` nuxt is actually supposed to work
# Look at the test runner to see if env-other-include is tested
rg "env-other-include|env-other" test/ --type ts --type js | grep -v ".snap\|snapshot"

Repository: nuxt/test-utils

Length of output: 392


🏁 Script executed:

# Check the resolve-config.spec.ts to understand what this test is verifying
cat -n test/unit/resolve-config.spec.ts | sed -n '1,50p'

Repository: nuxt/test-utils

Length of output: 1731


🏁 Script executed:

# Look for the specific test case for env-other-include
rg -A 20 "describe.*env-other-include" test/unit/resolve-config.spec.ts

Repository: nuxt/test-utils

Length of output: 599


🏁 Script executed:

# Search for any documentation or comments about per-file environment overrides
rg -C 5 "@vitest-environment" test/fixtures/ --type ts

Repository: nuxt/test-utils

Length of output: 1123


🏁 Script executed:

# Let me check what happens with environmentOptions when using per-file environment overrides
# Search for how Vitest passes environmentOptions for per-file overrides
rg -C 3 "environmentOptions" src/config.ts | head -60

Repository: nuxt/test-utils

Length of output: 1516


🏁 Script executed:

# Check the SetupWindowNuxtEnvironmentOptions type to see what properties might be lost
cat -n src/runtime/shared/environment.ts | head -80

Repository: nuxt/test-utils

Length of output: 3286


🏁 Script executed:

# Check if there's any documentation or examples of using nuxt environment without defineVitestConfig
rg -C 3 "vitest-environment-nuxt\|environment.*nuxt" docs/ examples/ README.md 2>/dev/null | head -40

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Search for how Vitest passes environmentOptions to per-file environment overrides
# Check if there's any test that validates per-file environment behavior
rg "test3.spec.ts" test/unit/ -A 10 -B 5

Repository: nuxt/test-utils

Length of output: 1921


🏁 Script executed:

# Check the NuxtVitestEnvironmentOptionsPlugin to understand how it injects the env var
cat -n src/module/plugins/options.ts

Repository: nuxt/test-utils

Length of output: 1085


🏁 Script executed:

# Look for Vitest documentation or behavior about per-file environment overrides and environmentOptions
# Check if environmentOptions are passed when using per-file overrides
rg -C 5 "environmentOptions.*nuxt\|nuxt.*environmentOptions" test/fixtures/simple/env-other-include/

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Check if the nuxt environment can be used as a standalone package without defineVitestConfig
# Look at the vitest-environment-nuxt stub to see how it's exported
cat stubs/vitest-environment-nuxt/package.json

Repository: nuxt/test-utils

Length of output: 439


🏁 Script executed:

# Look for any tests that actually verify per-file environment overrides with nuxt
rg "test3" test/unit/resolve-config.spec.ts -A 30 | head -50

Repository: nuxt/test-utils

Length of output: 1259


🏁 Script executed:

# Check if there are integration tests that run the per-file override tests
rg -C 5 "env-other-include\|test3.spec.ts" test/unit/ --type ts

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Check stubs/vitest-environment-nuxt/index.mjs to see if it's a standalone environment
cat stubs/vitest-environment-nuxt/index.mjs

Repository: nuxt/test-utils

Length of output: 120


🏁 Script executed:

# Verify when NuxtVitestEnvironmentOptionsPlugin is called - is it guaranteed for all nuxt environment uses?
# Check if defineVitestConfig is the only entry point
rg "export.*defineVitestConfig\|NuxtVitestEnvironmentOptionsPlugin" src/ --type ts | grep -v snap

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Check if there are any code paths that use environment: 'nuxt' without going through defineVitestConfig
rg "environment.*nuxt" src/ --type ts -C 2 | grep -v snap

Repository: nuxt/test-utils

Length of output: 5497


🏁 Script executed:

# Check what happens when per-file environment override is used - does Vitest pass environmentOptions?
# Look at how Vitest handles per-file environment overrides
rg -C 10 "test3" test/fixtures/simple/env-other-include/ --type ts

Repository: nuxt/test-utils

Length of output: 674


🏁 Script executed:

# Verify the actual behavior: when a test uses `@vitest-environment` nuxt override,
# what environmentOptions are passed to the environment setup?
# Check if there's any code that handles per-file environmentOptions
rg "environmentOptions.*undefined\|_environmentOptions" src/environments/ -C 3

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Check if there are any integration tests that actually execute test3.spec.ts to verify it works
rg "test3\|env-other" test/ --type ts -C 5 | grep -v snap | head -60

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Search for any direct vitest config without defineVitestConfig that uses nuxt environment
find . -name "vitest.config.ts" -o -name "vitest.config.js" | xargs grep -l "environment.*nuxt" | head -10

Repository: nuxt/test-utils

Length of output: 452


🏁 Script executed:

# Check if per-file overrides actually work - run a simple test to see the behavior
cat test/fixtures/simple/env-other-include/vitest.config.ts
cat test/fixtures/simple/env-other/vitest.config.ts

Repository: nuxt/test-utils

Length of output: 383


🏁 Script executed:

# Let me check if there are any tests that actually verify the per-file environment behavior
# Look for test runs that execute env-other or env-other-include
rg "globTestSpecifications\|vitest run" test/unit/resolve-config.spec.ts -C 5 | head -40

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Check if there are actual runtime tests that execute the per-file override tests
find test/unit -name "*.spec.ts" | xargs grep -l "env-other\|test3"

Repository: nuxt/test-utils

Length of output: 91


🏁 Script executed:

# Look for any documented examples or warnings about per-file environment behavior
rg "per-file\|per file\|@vitest-environment" . --type md --type mdx 2>/dev/null

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Check if the NuxtVitestEnvironmentOptionsPlugin is ALWAYS run before environment setup
# Search for all places where the plugin might not be registered
rg "plugins.*push\|NuxtVitestEnvironmentOptionsPlugin" src/ --type ts -C 2

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Check if per-file environment overrides receive environmentOptions from config
# Vitest documentation suggests per-file overrides don't pass config-level environmentOptions
# Let me verify the actual test behavior
cat test/unit/resolve-config.spec.ts | grep -A 20 "globTestSpecifications.*function"

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Check what globTestSpecifications actually does - does it run the tests?
rg -B 10 "async function globTestSpecifications" test/unit/resolve-config.spec.ts

Repository: nuxt/test-utils

Length of output: 337


🏁 Script executed:

# Understand the actual issue: check if vitest-environment-nuxt can be used standalone
# without defineVitestConfig
cat src/config.ts | grep -A 5 "defineVitestConfig\|export.*function"

Repository: nuxt/test-utils

Length of output: 1169


🏁 Script executed:

# Check if someone can install vitest-environment-nuxt and use it directly
# without the plugin being registered
rg "defineVitestConfig.*export\|export.*defineVitestConfig" src/config.ts -A 3

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# The key question: what if a user configures vitest manually like:
# { test: { environment: 'vitest-environment-nuxt', environmentOptions: {...} } }
# without using defineVitestConfig?
# Let's see if the plugin registration is guaranteed
cat -n src/config.ts | sed -n '200,250p'

Repository: nuxt/test-utils

Length of output: 2120


🏁 Script executed:

# Check if vitest-environment-nuxt can be used without `@nuxt/test-utils`
# Is it published as a separate package?
rg "vitest-environment-nuxt" src/config.ts -C 3

Repository: nuxt/test-utils

Length of output: 388


🏁 Script executed:

# Check if there's any documentation or examples of using vitest-environment-nuxt directly
cat stubs/vitest-environment-nuxt/package.json | grep -A 10 "exports\|main"

Repository: nuxt/test-utils

Length of output: 190


🏁 Script executed:

# The critical question: Can the nuxt environment be used without defineVitestConfig?
# Look for any code that might bypass the plugin registration
rg "resolveConfig\|NuxtVitestEnvironmentOptionsPlugin" src/config.ts -C 2 | head -80

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Final verification: Is there ANY supported code path where vitest-environment-nuxt 
# is used without NuxtVitestEnvironmentOptionsPlugin being registered?
# Check all the exports and entry points

cat src/config.ts | grep "^export"

Repository: nuxt/test-utils

Length of output: 385


🏁 Script executed:

# Search for any documentation that might describe unsupported usage
rg "vitest-environment-nuxt\|NuxtVitestEnvironmentOptionsPlugin" README.md docs/ examples/ 2>/dev/null | head -20

Repository: nuxt/test-utils

Length of output: 41


🏁 Script executed:

# Verify: When the per-file override test (test3.spec.ts) runs, 
# does it actually have access to the global env var set by the plugin?
# This determines if the issue is real or theoretical

# The plugin sets: process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__
# This should be available globally during the test run

# Check if there are any actual failing tests or warnings about this
rg "test3\|env-other" test/ --type ts -A 5 | grep -i "fail\|error\|warn"

Repository: nuxt/test-utils

Length of output: 41


Preserve incoming options as fallback when the serialized base config is unavailable.

Line 85 falls back to {} when process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__ is unavailable. In that path, properties from _environmentOptions like nuxt.rootId, nuxt.mock, nuxt.h3Version, nuxtRuntimeConfig, and nuxtRouteRules are lost. The incoming options should be used as the fallback base instead.

While all documented entry points (defineVitestConfig and defineVitestProject) register NuxtVitestEnvironmentOptionsPlugin to inject the env var at build time, this fallback should be defensive against scenarios where the var is unavailable.

Suggested fix
 function mergeSetupWindowEnvironmentOptions(
-  environmentOptions: Record<string, unknown>,
+  environmentOptions: Record<string, unknown> = {},
 ): SetupWindowNuxtEnvironmentOptions {
   const {
     nuxt: nuxtEnvironmentOptions = {},
   } = environmentOptions as unknown as SetupWindowNuxtEnvironmentOptions
+
+  const serializedResolvedOptions = process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__
+  const baseEnvironmentOptions = serializedResolvedOptions
+    ? JSON.parse(serializedResolvedOptions)
+    : environmentOptions
 
   return defu(
     {
       nuxt: {
         url: nuxtEnvironmentOptions.url,
         domEnvironment: nuxtEnvironmentOptions.domEnvironment,
       },
     },
-    JSON.parse(process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__ || '{}'),
+    baseEnvironmentOptions,
   )
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Manually merge with base config because `@vitest-environment-options` doesn't merge by default
function mergeSetupWindowEnvironmentOptions(
environmentOptions: Record<string, unknown>,
): SetupWindowNuxtEnvironmentOptions {
const {
nuxt: nuxtEnvironmentOptions = {},
} = environmentOptions as unknown as SetupWindowNuxtEnvironmentOptions
return defu(
{
nuxt: {
url: nuxtEnvironmentOptions.url,
domEnvironment: nuxtEnvironmentOptions.domEnvironment,
},
},
JSON.parse(process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__ || '{}'),
)
}
// Manually merge with base config because `@vitest-environment-options` doesn't merge by default
function mergeSetupWindowEnvironmentOptions(
environmentOptions: Record<string, unknown> = {},
): SetupWindowNuxtEnvironmentOptions {
const {
nuxt: nuxtEnvironmentOptions = {},
} = environmentOptions as unknown as SetupWindowNuxtEnvironmentOptions
const serializedResolvedOptions = process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__
const baseEnvironmentOptions = serializedResolvedOptions
? JSON.parse(serializedResolvedOptions)
: environmentOptions
return defu(
{
nuxt: {
url: nuxtEnvironmentOptions.url,
domEnvironment: nuxtEnvironmentOptions.domEnvironment,
},
},
baseEnvironmentOptions,
)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/environments/vitest/index.ts` around lines 70 - 87, The
mergeSetupWindowEnvironmentOptions function currently falls back to an empty
object when process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__ is missing,
which loses incoming options; change the fallback to use the already-parsed
nuxtEnvironmentOptions (from the local variable nuxtEnvironmentOptions) as the
base for defu instead of '{}', ensuring you JSON.parse the env var when present
and pass nuxt: { url, domEnvironment, ... } merged with
JSON.parse(process.env.__NUXT_VITEST_ENVIRONMENT_RESOLVED_OPTIONS__ ||
JSON.stringify({ nuxt: nuxtEnvironmentOptions })) so properties like
nuxt.rootId, nuxt.mock, nuxt.h3Version, nuxtRuntimeConfig, and nuxtRouteRules
are preserved.

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.

@vitest-environment-options is not working

1 participant