From b1a36226b1703b3c7c1a8b8c6aaa1a9b6f22b517 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 28 Apr 2026 04:09:36 +0100 Subject: [PATCH] test: stabilize faster unit lanes --- .../src/host/remote-http.test.ts | 65 +++++-------- .../memory-host-sdk/src/host/remote-http.ts | 10 +- scripts/test-live-shard.mjs | 2 +- src/crestodian/overview.test.ts | 93 +++++++++---------- src/crestodian/overview.ts | 43 +++++++-- src/memory-host-sdk/host/remote-http.test.ts | 65 +++++-------- src/memory-host-sdk/host/remote-http.ts | 10 +- test/scripts/test-live-shard.test.ts | 17 +++- test/vitest/vitest.unit-fast-paths.mjs | 6 +- test/vitest/vitest.unit-support.config.ts | 1 + test/vitest/vitest.unit.config.ts | 3 +- 11 files changed, 157 insertions(+), 158 deletions(-) diff --git a/packages/memory-host-sdk/src/host/remote-http.test.ts b/packages/memory-host-sdk/src/host/remote-http.test.ts index a7a7b0bb1f4..7559f0165df 100644 --- a/packages/memory-host-sdk/src/host/remote-http.test.ts +++ b/packages/memory-host-sdk/src/host/remote-http.test.ts @@ -1,53 +1,34 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; - -const { fetchWithSsrFGuardMock, shouldUseEnvHttpProxyForUrlMock } = vi.hoisted(() => ({ - fetchWithSsrFGuardMock: vi.fn(), - shouldUseEnvHttpProxyForUrlMock: vi.fn(() => false), -})); - -vi.mock("../../../../src/infra/net/fetch-guard.js", async () => { - const actual = await vi.importActual( - "../../../../src/infra/net/fetch-guard.js", - ); - return { - ...actual, - fetchWithSsrFGuard: fetchWithSsrFGuardMock, - }; -}); - -vi.mock("../../../../src/infra/net/proxy-env.js", async () => { - const actual = await vi.importActual( - "../../../../src/infra/net/proxy-env.js", - ); - return { - ...actual, - shouldUseEnvHttpProxyForUrl: shouldUseEnvHttpProxyForUrlMock, - }; -}); - +import { describe, expect, it } from "vitest"; import { GUARDED_FETCH_MODE } from "../../../../src/infra/net/fetch-guard.js"; import { withRemoteHttpResponse } from "./remote-http.js"; describe("package withRemoteHttpResponse", () => { - beforeEach(() => { - vi.clearAllMocks(); - shouldUseEnvHttpProxyForUrlMock.mockReturnValue(false); - fetchWithSsrFGuardMock.mockResolvedValue({ - response: new Response("ok", { status: 200 }), - finalUrl: "https://memory.example/v1", - release: vi.fn(async () => {}), - }); - }); + function makeFetchDeps({ useEnvProxy = false }: { useEnvProxy?: boolean } = {}) { + const calls: unknown[] = []; + return { + calls, + fetchWithSsrFGuardImpl: async (params: unknown) => { + calls.push(params); + return { + response: new Response("ok", { status: 200 }), + finalUrl: "https://memory.example/v1", + release: async () => {}, + }; + }, + shouldUseEnvHttpProxyForUrlImpl: () => useEnvProxy, + }; + } it("uses trusted env proxy mode when the target will use EnvHttpProxyAgent", async () => { - shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true); + const deps = makeFetchDeps({ useEnvProxy: true }); await withRemoteHttpResponse({ url: "https://memory.example/v1/embeddings", onResponse: async () => undefined, + ...deps, }); - expect(fetchWithSsrFGuardMock).toHaveBeenCalledWith( + expect(deps.calls[0]).toEqual( expect.objectContaining({ url: "https://memory.example/v1/embeddings", mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY, @@ -56,13 +37,15 @@ describe("package withRemoteHttpResponse", () => { }); it("keeps strict guarded fetch mode when proxy env would not proxy the target", async () => { + const deps = makeFetchDeps(); + await withRemoteHttpResponse({ url: "https://internal.corp.example/v1/embeddings", onResponse: async () => undefined, + ...deps, }); - const call = fetchWithSsrFGuardMock.mock.calls[0]?.[0]; - expect(call).toBeDefined(); - expect(call).not.toHaveProperty("mode"); + expect(deps.calls[0]).toBeDefined(); + expect(deps.calls[0]).not.toHaveProperty("mode"); }); }); diff --git a/packages/memory-host-sdk/src/host/remote-http.ts b/packages/memory-host-sdk/src/host/remote-http.ts index 919e4aa7815..6676a70db8e 100644 --- a/packages/memory-host-sdk/src/host/remote-http.ts +++ b/packages/memory-host-sdk/src/host/remote-http.ts @@ -24,17 +24,19 @@ export async function withRemoteHttpResponse(params: { url: string; init?: RequestInit; ssrfPolicy?: SsrFPolicy; + fetchWithSsrFGuardImpl?: typeof fetchWithSsrFGuard; + shouldUseEnvHttpProxyForUrlImpl?: typeof shouldUseEnvHttpProxyForUrl; auditContext?: string; onResponse: (response: Response) => Promise; }): Promise { - const { response, release } = await fetchWithSsrFGuard({ + const guardedFetch = params.fetchWithSsrFGuardImpl ?? fetchWithSsrFGuard; + const shouldUseEnvProxy = params.shouldUseEnvHttpProxyForUrlImpl ?? shouldUseEnvHttpProxyForUrl; + const { response, release } = await guardedFetch({ url: params.url, init: params.init, policy: params.ssrfPolicy, auditContext: params.auditContext ?? "memory-remote", - ...(shouldUseEnvHttpProxyForUrl(params.url) - ? { mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY } - : {}), + ...(shouldUseEnvProxy(params.url) ? { mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY } : {}), }); try { return await params.onResponse(response); diff --git a/scripts/test-live-shard.mjs b/scripts/test-live-shard.mjs index aadb60d5658..c8e3c408e07 100644 --- a/scripts/test-live-shard.mjs +++ b/scripts/test-live-shard.mjs @@ -18,7 +18,6 @@ export const RELEASE_LIVE_TEST_SHARDS = Object.freeze([ "native-live-extensions-o-z-other", "native-live-extensions-xai", "native-live-extensions-media-audio", - "native-live-extensions-media-music", "native-live-extensions-media-music-google", "native-live-extensions-media-music-minimax", "native-live-extensions-media-video", @@ -28,6 +27,7 @@ export const LIVE_TEST_SHARDS = Object.freeze([ ...RELEASE_LIVE_TEST_SHARDS, "native-live-extensions-o-z", "native-live-extensions-media", + "native-live-extensions-media-music", ]); function walkFiles(rootDir) { diff --git a/src/crestodian/overview.test.ts b/src/crestodian/overview.test.ts index 06a685d8f29..ab37aa2729d 100644 --- a/src/crestodian/overview.test.ts +++ b/src/crestodian/overview.test.ts @@ -1,22 +1,14 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; +import { describe, expect, it } from "vitest"; +import type { ConfigFileSnapshot, OpenClawConfig } from "../config/config.js"; +import { + formatCrestodianOverview, + formatCrestodianStartupMessage, + loadCrestodianOverview, +} from "./overview.js"; -vi.mock("./probes.js", () => ({ - probeLocalCommand: vi.fn(async (command: string) => ({ - command, - found: command === "codex", - version: command === "codex" ? "codex 1.0.0" : undefined, - })), - probeGatewayUrl: vi.fn(async (url: string) => ({ reachable: false, url, error: "offline" })), -})); - -vi.mock("../config/config.js", () => ({ - readConfigFileSnapshot: vi.fn(async () => ({ - path: "/tmp/openclaw.json", - exists: true, - valid: true, - issues: [], - hash: "test-hash", - runtimeConfig: { +describe("loadCrestodianOverview", () => { + it("summarizes config, agents, model, tools, and gateway", async () => { + const runtimeConfig: OpenClawConfig = { agents: { defaults: { model: { primary: "openai/gpt-5.2" } }, list: [ @@ -25,37 +17,40 @@ vi.mock("../config/config.js", () => ({ ], }, gateway: { port: 19001 }, - }, - sourceConfig: undefined, - })), - resolveConfigPath: vi.fn(() => "/tmp/openclaw.json"), - resolveGatewayPort: vi.fn((cfg: { gateway?: { port?: number } }) => cfg.gateway?.port ?? 8765), -})); - -vi.mock("../gateway/call.js", () => ({ - buildGatewayConnectionDetails: vi.fn((input: { config: { gateway?: { port?: number } } }) => ({ - url: `ws://127.0.0.1:${input.config.gateway?.port ?? 8765}`, - urlSource: "local loopback", - })), -})); - -describe("loadCrestodianOverview", () => { - const previousTestFast = process.env.OPENCLAW_TEST_FAST; - - afterEach(() => { - if (previousTestFast === undefined) { - delete process.env.OPENCLAW_TEST_FAST; - } else { - process.env.OPENCLAW_TEST_FAST = previousTestFast; - } - }); - - it("summarizes config, agents, model, tools, and gateway", async () => { - vi.stubEnv("OPENCLAW_TEST_FAST", "1"); - - const { formatCrestodianOverview, formatCrestodianStartupMessage, loadCrestodianOverview } = - await import("./overview.js"); - const overview = await loadCrestodianOverview(); + }; + const snapshot: ConfigFileSnapshot = { + path: "/tmp/openclaw.json", + exists: true, + raw: "{}", + parsed: runtimeConfig, + sourceConfig: runtimeConfig, + resolved: runtimeConfig, + valid: true, + runtimeConfig, + config: runtimeConfig, + hash: "test-hash", + issues: [], + warnings: [], + legacyIssues: [], + }; + const overview = await loadCrestodianOverview({ + env: { OPENCLAW_TEST_FAST: "1" }, + deps: { + readConfigFileSnapshot: async () => snapshot, + resolveConfigPath: () => "/tmp/openclaw.json", + resolveGatewayPort: (cfg) => cfg?.gateway?.port ?? 8765, + buildGatewayConnectionDetails: (input) => ({ + url: `ws://127.0.0.1:${input.config.gateway?.port ?? 8765}`, + urlSource: "local loopback", + }), + probeLocalCommand: async (command) => ({ + command, + found: command === "codex", + version: command === "codex" ? "codex 1.0.0" : undefined, + }), + probeGatewayUrl: async (url) => ({ reachable: false, url, error: "offline" }), + }, + }); expect(overview.config).toMatchObject({ exists: true, diff --git a/src/crestodian/overview.ts b/src/crestodian/overview.ts index a5f17f2ba09..86911e53326 100644 --- a/src/crestodian/overview.ts +++ b/src/crestodian/overview.ts @@ -62,6 +62,25 @@ export type CrestodianOverview = { type OpenClawReferencePaths = Awaited>; +type GatewayConnectionDetails = { + url: string; + urlSource: string; + remoteFallbackNote?: string; +}; + +type CrestodianOverviewDependencies = { + readConfigFileSnapshot?: typeof readConfigFileSnapshot; + resolveConfigPath?: typeof resolveConfigPath; + resolveGatewayPort?: typeof resolveGatewayPort; + buildGatewayConnectionDetails?: (input: { + config: OpenClawConfig; + configPath: string; + }) => GatewayConnectionDetails; + probeLocalCommand?: typeof probeLocalCommand; + probeGatewayUrl?: typeof probeGatewayUrl; + resolveOpenClawReferencePaths?: typeof resolveOpenClawReferencePaths; +}; + function issueMessages(snapshot: ConfigFileSnapshot): string[] { return snapshot.issues.map((issue) => { const path = issue.path ? `${issue.path}: ` : ""; @@ -120,21 +139,25 @@ function resolveFastTestReferences(env: NodeJS.ProcessEnv): OpenClawReferencePat } export async function loadCrestodianOverview( - opts: { env?: NodeJS.ProcessEnv } = {}, + opts: { env?: NodeJS.ProcessEnv; deps?: CrestodianOverviewDependencies } = {}, ): Promise { const env = opts.env ?? process.env; - const snapshot = await readConfigFileSnapshot(); + const deps = opts.deps ?? {}; + const readSnapshot = deps.readConfigFileSnapshot ?? readConfigFileSnapshot; + const snapshot = await readSnapshot(); const cfg = snapshot.runtimeConfig ?? snapshot.sourceConfig ?? {}; const defaultAgentId = resolveDefaultAgentId(cfg); const defaultModel = resolveAgentEffectiveModelPrimary(cfg, defaultAgentId) ?? resolveAgentModelPrimaryValue(cfg.agents?.defaults?.model); - const configPath = snapshot.path || resolveConfigPath(env); - let gatewayUrl = `ws://127.0.0.1:${resolveGatewayPort(cfg, env)}`; + const configPath = snapshot.path || (deps.resolveConfigPath ?? resolveConfigPath)(env); + let gatewayUrl = `ws://127.0.0.1:${(deps.resolveGatewayPort ?? resolveGatewayPort)(cfg, env)}`; let gatewaySource = "local loopback"; let gatewayError: string | undefined; try { - const { buildGatewayConnectionDetails } = await import("../gateway/call.js"); + const buildGatewayConnectionDetails = + deps.buildGatewayConnectionDetails ?? + (await import("../gateway/call.js")).buildGatewayConnectionDetails; const details = buildGatewayConnectionDetails({ config: cfg, configPath }); gatewayUrl = details.url; gatewaySource = details.urlSource; @@ -142,12 +165,14 @@ export async function loadCrestodianOverview( } catch (err) { gatewayError = err instanceof Error ? err.message : String(err); } + const resolveReferences = deps.resolveOpenClawReferencePaths ?? resolveOpenClawReferencePaths; + const commandProbe = deps.probeLocalCommand ?? probeLocalCommand; const [codex, claude, gateway, references] = await Promise.all([ - probeLocalCommand("codex"), - probeLocalCommand("claude"), - probeGatewayUrl(gatewayUrl), + commandProbe("codex"), + commandProbe("claude"), + (deps.probeGatewayUrl ?? probeGatewayUrl)(gatewayUrl), resolveFastTestReferences(env) ?? - resolveOpenClawReferencePaths({ + resolveReferences({ argv1: process.argv[1], cwd: process.cwd(), moduleUrl: import.meta.url, diff --git a/src/memory-host-sdk/host/remote-http.test.ts b/src/memory-host-sdk/host/remote-http.test.ts index 4f7ae2febfb..675e74c3fe2 100644 --- a/src/memory-host-sdk/host/remote-http.test.ts +++ b/src/memory-host-sdk/host/remote-http.test.ts @@ -1,53 +1,34 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; - -const { fetchWithSsrFGuardMock, shouldUseEnvHttpProxyForUrlMock } = vi.hoisted(() => ({ - fetchWithSsrFGuardMock: vi.fn(), - shouldUseEnvHttpProxyForUrlMock: vi.fn(() => false), -})); - -vi.mock("../../infra/net/fetch-guard.js", async () => { - const actual = await vi.importActual( - "../../infra/net/fetch-guard.js", - ); - return { - ...actual, - fetchWithSsrFGuard: fetchWithSsrFGuardMock, - }; -}); - -vi.mock("../../infra/net/proxy-env.js", async () => { - const actual = await vi.importActual( - "../../infra/net/proxy-env.js", - ); - return { - ...actual, - shouldUseEnvHttpProxyForUrl: shouldUseEnvHttpProxyForUrlMock, - }; -}); - +import { describe, expect, it } from "vitest"; import { GUARDED_FETCH_MODE } from "../../infra/net/fetch-guard.js"; import { withRemoteHttpResponse } from "./remote-http.js"; describe("withRemoteHttpResponse", () => { - beforeEach(() => { - vi.clearAllMocks(); - shouldUseEnvHttpProxyForUrlMock.mockReturnValue(false); - fetchWithSsrFGuardMock.mockResolvedValue({ - response: new Response("ok", { status: 200 }), - finalUrl: "https://memory.example/v1", - release: vi.fn(async () => {}), - }); - }); + function makeFetchDeps({ useEnvProxy = false }: { useEnvProxy?: boolean } = {}) { + const calls: unknown[] = []; + return { + calls, + fetchWithSsrFGuardImpl: async (params: unknown) => { + calls.push(params); + return { + response: new Response("ok", { status: 200 }), + finalUrl: "https://memory.example/v1", + release: async () => {}, + }; + }, + shouldUseEnvHttpProxyForUrlImpl: () => useEnvProxy, + }; + } it("uses trusted env proxy mode when the target will use EnvHttpProxyAgent", async () => { - shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true); + const deps = makeFetchDeps({ useEnvProxy: true }); await withRemoteHttpResponse({ url: "https://memory.example/v1/embeddings", onResponse: async () => undefined, + ...deps, }); - expect(fetchWithSsrFGuardMock).toHaveBeenCalledWith( + expect(deps.calls[0]).toEqual( expect.objectContaining({ url: "https://memory.example/v1/embeddings", mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY, @@ -56,13 +37,15 @@ describe("withRemoteHttpResponse", () => { }); it("keeps strict guarded fetch mode when proxy env would not proxy the target", async () => { + const deps = makeFetchDeps(); + await withRemoteHttpResponse({ url: "https://internal.corp.example/v1/embeddings", onResponse: async () => undefined, + ...deps, }); - const call = fetchWithSsrFGuardMock.mock.calls[0]?.[0]; - expect(call).toBeDefined(); - expect(call).not.toHaveProperty("mode"); + expect(deps.calls[0]).toBeDefined(); + expect(deps.calls[0]).not.toHaveProperty("mode"); }); }); diff --git a/src/memory-host-sdk/host/remote-http.ts b/src/memory-host-sdk/host/remote-http.ts index cf5f91643ed..187af8afa6d 100644 --- a/src/memory-host-sdk/host/remote-http.ts +++ b/src/memory-host-sdk/host/remote-http.ts @@ -9,18 +9,20 @@ export async function withRemoteHttpResponse(params: { init?: RequestInit; ssrfPolicy?: SsrFPolicy; fetchImpl?: typeof fetch; + fetchWithSsrFGuardImpl?: typeof fetchWithSsrFGuard; + shouldUseEnvHttpProxyForUrlImpl?: typeof shouldUseEnvHttpProxyForUrl; auditContext?: string; onResponse: (response: Response) => Promise; }): Promise { - const { response, release } = await fetchWithSsrFGuard({ + const guardedFetch = params.fetchWithSsrFGuardImpl ?? fetchWithSsrFGuard; + const shouldUseEnvProxy = params.shouldUseEnvHttpProxyForUrlImpl ?? shouldUseEnvHttpProxyForUrl; + const { response, release } = await guardedFetch({ url: params.url, fetchImpl: params.fetchImpl, init: params.init, policy: params.ssrfPolicy, auditContext: params.auditContext ?? "memory-remote", - ...(shouldUseEnvHttpProxyForUrl(params.url) - ? { mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY } - : {}), + ...(shouldUseEnvProxy(params.url) ? { mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY } : {}), }); try { return await params.onResponse(response); diff --git a/test/scripts/test-live-shard.test.ts b/test/scripts/test-live-shard.test.ts index 8f503801ff0..b1fed43a8ad 100644 --- a/test/scripts/test-live-shard.test.ts +++ b/test/scripts/test-live-shard.test.ts @@ -9,15 +9,26 @@ import { describe("scripts/test-live-shard", () => { const allFiles = collectAllLiveTestFiles(); - it("partitions every native live test into exactly one release shard", () => { + it("covers every native live test and tracks provider-filtered release fanout", () => { const selected = RELEASE_LIVE_TEST_SHARDS.flatMap((shard) => selectLiveShardFiles(shard, allFiles).map((file) => ({ file, shard })), ); const selectedFiles = selected.map(({ file }) => file); + const duplicateFiles = selectedFiles.filter( + (file, index) => selectedFiles.indexOf(file) !== index, + ); + const musicProviderFanout = selected + .filter(({ file }) => file === "extensions/music-generation-providers.live.test.ts") + .map(({ shard }) => shard) + .toSorted(); expect(allFiles.length).toBeGreaterThan(0); - expect(selectedFiles.toSorted()).toEqual(allFiles); - expect(new Set(selectedFiles).size).toBe(selectedFiles.length); + expect([...new Set(selectedFiles)].toSorted()).toEqual(allFiles); + expect(duplicateFiles).toEqual(["extensions/music-generation-providers.live.test.ts"]); + expect(musicProviderFanout).toEqual([ + "native-live-extensions-media-music-google", + "native-live-extensions-media-music-minimax", + ]); }); it("keeps aggregate shard aliases available outside the release partition", () => { diff --git a/test/vitest/vitest.unit-fast-paths.mjs b/test/vitest/vitest.unit-fast-paths.mjs index 0fac68677bb..17f10e272c0 100644 --- a/test/vitest/vitest.unit-fast-paths.mjs +++ b/test/vitest/vitest.unit-fast-paths.mjs @@ -65,7 +65,6 @@ export const forcedUnitFastTestFiles = [ "src/acp/translator.prompt-prefix.test.ts", "src/acp/translator.cancel-scoping.test.ts", "src/acp/translator.stop-reason.test.ts", - "src/acp/persistent-bindings.lifecycle.test.ts", "src/acp/persistent-bindings.test.ts", "src/acp/server.startup.test.ts", "src/acp/translator.session-rate-limit.test.ts", @@ -87,7 +86,6 @@ export const forcedUnitFastTestFiles = [ "src/dockerfile.test.ts", "src/entry.compile-cache.test.ts", "src/entry.test.ts", - "src/image-generation/runtime.test.ts", "src/i18n/registry.test.ts", "src/install-sh-version.test.ts", "src/logger.test.ts", @@ -106,10 +104,10 @@ export const forcedUnitFastTestFiles = [ "src/pairing/setup-code.test.ts", "src/plugin-activation-boundary.test.ts", "src/plugin-sdk/memory-host-events.test.ts", - "src/proxy-capture/runtime.test.ts", "src/proxy-capture/store.sqlite.test.ts", "src/security/audit-exec-surface.test.ts", "src/security/audit-extra.async.test.ts", + "src/security/audit-trust-model.test.ts", "src/security/dm-policy-shared.test.ts", "src/security/audit-plugins-trust.test.ts", "src/security/audit-workspace-skill-escape.test.ts", @@ -118,7 +116,6 @@ export const forcedUnitFastTestFiles = [ "src/security/scan-paths.test.ts", "src/security/skill-scanner.test.ts", "src/security/audit-config-include-perms.test.ts", - "src/security/windows-acl.test.ts", "src/realtime-transcription/websocket-session.test.ts", "src/routing/resolve-route.test.ts", "src/trajectory/cleanup.test.ts", @@ -135,7 +132,6 @@ export const forcedUnitFastTestFiles = [ "src/test-utils/env.test.ts", "src/test-utils/temp-home.test.ts", "src/utils.test.ts", - "src/video-generation/runtime.test.ts", "src/version.test.ts", ]; const forcedUnitFastTestFileSet = new Set(forcedUnitFastTestFiles); diff --git a/test/vitest/vitest.unit-support.config.ts b/test/vitest/vitest.unit-support.config.ts index 4c813127311..524b54383d7 100644 --- a/test/vitest/vitest.unit-support.config.ts +++ b/test/vitest/vitest.unit-support.config.ts @@ -3,4 +3,5 @@ import { createUnitVitestConfigWithOptions } from "./vitest.unit.config.ts"; export default createUnitVitestConfigWithOptions(process.env, { name: "unit-support", includePatterns: ["packages/**/*.test.ts"], + passWithNoTests: true, }); diff --git a/test/vitest/vitest.unit.config.ts b/test/vitest/vitest.unit.config.ts index 583d7129972..94cca1afdb7 100644 --- a/test/vitest/vitest.unit.config.ts +++ b/test/vitest/vitest.unit.config.ts @@ -35,6 +35,7 @@ export function createUnitVitestConfigWithOptions( extraExcludePatterns?: string[]; name?: string; argv?: string[]; + passWithNoTests?: boolean; } = {}, ) { const isolate = resolveVitestIsolation(env); @@ -85,7 +86,7 @@ export function createUnitVitestConfigWithOptions( ]), ], }, - ...(cliIncludePatterns !== null ? { passWithNoTests: true } : {}), + ...(options.passWithNoTests || cliIncludePatterns !== null ? { passWithNoTests: true } : {}), }, }); }