diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 3f44c8bd7a..9bb7424497 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -172,7 +172,7 @@ jobs: # Manual override (workflow_dispatch input) if [[ -n "${{ github.event.inputs.test_filter }}" ]]; then - TEST_INTEGRATION=1 bun x jest --coverage --maxWorkers=100% --silent ${{ github.event.inputs.test_filter }} + bun x jest --coverage --maxWorkers=100% --silent ${{ github.event.inputs.test_filter }} exit 0 fi @@ -185,11 +185,11 @@ jobs: # Backend changed: run ALL integration tests (includes tests/ui) if [[ "$BACKEND" == "true" ]]; then echo "Backend changes detected - running all integration tests" - TEST_INTEGRATION=1 bun x jest --coverage --maxWorkers=100% --silent tests/ + bun x jest --coverage --maxWorkers=100% --silent tests/ else # Browser-only changes: run tests/ui echo "Browser changes detected - running tests/ui" - TEST_INTEGRATION=1 bun x jest --coverage --maxWorkers=100% --silent tests/ui/ + bun x jest --coverage --maxWorkers=100% --silent tests/ui/ fi env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} @@ -296,7 +296,6 @@ jobs: bun x jest --silent tests/ipc/runtime/backgroundBashDirect.test.ts tests/ipc/runtime/executeBash.test.ts tests/ipc/projects/create.test.ts tests/ipc/agents/planCommands.test.ts env: BACKEND: ${{ needs.changes.outputs.backend }} - TEST_INTEGRATION: "1" smoke-server: name: Smoke / Server diff --git a/.mux/skills/tests/SKILL.md b/.mux/skills/tests/SKILL.md index 72a62e7ae5..2cdc18a340 100644 --- a/.mux/skills/tests/SKILL.md +++ b/.mux/skills/tests/SKILL.md @@ -14,12 +14,13 @@ Two types of tests are preferred: Unit tests are located colocated with the source they test as ".test.ts[x]" files. -Integration tests are located in `tests/`, with these primary harnesses: +Integration tests are located in `tests/`, organized into semantic subfolders: -- `tests/ipc` — tests that rely on the IPC and are focussed on ensuring backend behavior. -- `tests/ui` — frontend integration tests that use the real IPC and happy-dom Full App rendering. -- `tests/e2e` - end-to-end tests using Playwright which are needed to verify browser behavior that - can't be easily tested with happy-dom. +- `tests/ipc//` — backend tests via IPC, grouped by oRPC namespace: `workspace/`, `streaming/`, `runtime/`, `terminal/`, `projects/`, `agents/`, `config/`, `providers/`. +- `tests/ui//` — frontend integration tests using happy-dom Full App rendering, grouped by product area: `workspaces/`, `chat/`, `agents/`, `review/`, `tasks/`, `compaction/`, `config/`, `layout/`, `git/`, `runtime/`, `gateway/`. +- `tests/e2e/` — end-to-end tests using Playwright for behavior that can't be easily tested with happy-dom. + +Shared helpers stay at the harness root (e.g., `tests/ipc/setup.ts`, `tests/ui/helpers.ts`). Additionally, we have stories in `src/browser/stories` that are primarily used for human visual verification of UI changes. @@ -52,16 +53,16 @@ the production code, then verify the test passes. ## Test Runtime -All tests in `tests/` are run under `bun x jest` with `TEST_INTEGRATION=1` set. +All tests in `tests/` are run under `bun x jest`. Tests that live in `src/` run under `bun test` (generally these are unit tests). -Otherwise, tests that live in `src/` run under `bun test` (generally these are unit tests). +Tests that call real AI APIs set `jest.setTimeout(600_000)` at file level and use `validateApiKeys()` in a `beforeAll` to fail fast when keys are missing. No env var gating is needed — the Makefile controls which paths run. ## Runtime & Checks - Never kill the running Mux process; rely on the following for local validation: - `make typecheck` - `make static-check` (includes typecheck, lint, fmt-check, and docs link validation) - - targeted test invocations (e.g. `bun x jest tests/ipc/sendMessage.test.ts -t "pattern"`) + - targeted test invocations (e.g. `bun x jest tests/ipc/streaming/sendMessage.basic.test.ts -t "pattern"`) - Only wait on CI to pass when local, targeted checks pass. - Prefer surgical test invocations over running full suites. - Keep utils pure or parameterize external effects for easier testing. @@ -91,8 +92,8 @@ Otherwise, tests that live in `src/` run under `bun test` (generally these are u - Backend API calls are fine for setup/teardown or to avoid expensive operations. - Consider moving the test to `tests/ipc` if backend logic needs granular testing. - Never bypass the UI in these tests; e.g. do not call `updatePersistedState` to change UI state—go through the UI to trigger the desired behavior. -- These tests require `TEST_INTEGRATION=1`; use `shouldRunIntegrationTests()` guard. - Only call `validateApiKeys()` in tests that actually make AI API calls. Pure UI interaction tests (clicking buttons, selecting items) don't need API keys. +- Tests that call real AI APIs should add `jest.setTimeout(600_000)` at file level. ### Happy-dom Limitations diff --git a/Makefile b/Makefile index 22bba127fe..a753d32b6b 100644 --- a/Makefile +++ b/Makefile @@ -335,7 +335,7 @@ check-deadcode: node_modules/.installed ## Check for potential dead code (manual ## Testing test-integration: node_modules/.installed build-main ## Run all tests (unit + integration) @bun test src - @TEST_INTEGRATION=1 bun x jest tests + @bun x jest tests test-unit: node_modules/.installed build-main ## Run unit tests @bun test src diff --git a/jest.config.js b/jest.config.js index c59421582f..9707684631 100644 --- a/jest.config.js +++ b/jest.config.js @@ -41,6 +41,6 @@ module.exports = { maxWorkers: "50%", // Force exit after tests complete to avoid hanging on lingering handles forceExit: true, - // 10 minute timeout for integration tests, 10s for unit tests - testTimeout: process.env.TEST_INTEGRATION === "1" ? 600000 : 10000, + // 2 min default covers non-AI integration tests. AI tests set jest.setTimeout(600_000). + testTimeout: 120000, }; diff --git a/src/node/services/streamManager.test.ts b/src/node/services/streamManager.test.ts index d57684cbd3..71ccbc9a55 100644 --- a/src/node/services/streamManager.test.ts +++ b/src/node/services/streamManager.test.ts @@ -7,17 +7,12 @@ import { APICallError, RetryError, type ModelMessage } from "ai"; import type { HistoryService } from "./historyService"; import { createTestHistoryService } from "./testHistoryService"; import { createAnthropic } from "@ai-sdk/anthropic"; -import { shouldRunIntegrationTests, validateApiKeys } from "../../../tests/testUtils"; import { DisposableTempDir } from "@/node/services/tempDir"; import { createRuntime } from "@/node/runtime/runtimeFactory"; -// Skip integration tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -// Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} +// The "with real API" section calls Anthropic — gate on key availability +const hasAnthropicKey = Boolean(process.env.ANTHROPIC_API_KEY); +const describeWithApi = hasAnthropicKey ? describe : describe.skip; // Real HistoryService backed by a temp directory (created fresh per test) let historyService: HistoryService; @@ -266,8 +261,8 @@ describe("StreamManager - Concurrent Stream Prevention", () => { streamManager.on("error", () => undefined); }); - // Integration test - requires API key and TEST_INTEGRATION=1 - describeIntegration("with real API", () => { + // Integration test - requires ANTHROPIC_API_KEY + describeWithApi("with real API", () => { test("should prevent concurrent streams for the same workspace", async () => { const workspaceId = "test-workspace-concurrent"; const anthropic = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY }); diff --git a/tests/ipc/agents/planCommands.test.ts b/tests/ipc/agents/planCommands.test.ts index 9fd1e4a457..bee8132184 100644 --- a/tests/ipc/agents/planCommands.test.ts +++ b/tests/ipc/agents/planCommands.test.ts @@ -9,7 +9,7 @@ import * as fs from "fs/promises"; import * as path from "path"; -import { shouldRunIntegrationTests, createTestEnvironment, cleanupTestEnvironment } from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment } from "../setup"; import type { TestEnvironment } from "../setup"; import { createTempGitRepo, cleanupTempGitRepo, generateBranchName } from "../helpers"; import { detectDefaultTrunkBranch } from "../../../src/node/git"; @@ -17,10 +17,7 @@ import { getPlanFilePath } from "../../../src/common/utils/planStorage"; import { createMuxMessage } from "../../../src/common/types/message"; import { expandTilde } from "../../../src/node/runtime/tildeExpansion"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("Plan Commands Integration", () => { +describe("Plan Commands Integration", () => { let env: TestEnvironment; let repoPath: string; diff --git a/tests/ipc/compaction1MRetry.integration.test.ts b/tests/ipc/compaction1MRetry.integration.test.ts index 11a0252cf7..45ddc35323 100644 --- a/tests/ipc/compaction1MRetry.integration.test.ts +++ b/tests/ipc/compaction1MRetry.integration.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * Integration test: Compaction 1M context retry. * @@ -9,19 +11,12 @@ * the compaction should succeed rather than returning context_exceeded. */ -import { setupWorkspace, shouldRunIntegrationTests, validateApiKeys } from "./setup"; +import { setupWorkspace } from "./setup"; import { createStreamCollector, resolveOrpcClient } from "./helpers"; import { HistoryService } from "../../src/node/services/historyService"; import { createMuxMessage } from "../../src/common/types/message"; import { KNOWN_MODELS } from "../../src/common/constants/knownModels"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} - // ~1 token ≈ 4 chars in English text. To exceed 200k tokens we need ~800k chars. // Use ~260k tokens of padding to comfortably exceed the 200k default context. const TOKENS_PER_CHAR = 0.25; // conservative estimate @@ -40,7 +35,7 @@ function buildFillerText(charCount: number): string { return base.repeat(repeats).slice(0, charCount); } -describeIntegration("compaction 1M context retry", () => { +describe("compaction 1M context retry", () => { // Compaction with 1M retry can take a while — summarizing 250k+ tokens of content const TEST_TIMEOUT_MS = 120_000; diff --git a/tests/ipc/config/mcpConfig.test.ts b/tests/ipc/config/mcpConfig.test.ts index 70c3531088..7794a68fc0 100644 --- a/tests/ipc/config/mcpConfig.test.ts +++ b/tests/ipc/config/mcpConfig.test.ts @@ -1,12 +1,6 @@ import * as fs from "fs/promises"; import * as path from "path"; -import { - shouldRunIntegrationTests, - cleanupTestEnvironment, - createTestEnvironment, - setupWorkspace, - validateApiKeys, -} from "../setup"; +import { cleanupTestEnvironment, createTestEnvironment, setupWorkspace } from "../setup"; import { createTempGitRepo, cleanupTempGitRepo, @@ -19,7 +13,7 @@ import { } from "../helpers"; import type { StreamCollector } from "../streamCollector"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; +jest.setTimeout(600_000); const CHROME_DEVTOOLS_MCP_VERSION = "0.12.1"; const CHROME_DEVTOOLS_MCP_NPX = `npx -y chrome-devtools-mcp@${CHROME_DEVTOOLS_MCP_VERSION}`; @@ -31,9 +25,6 @@ const TEST_SCREENSHOT_MCP_SERVER_PATH = path.join( "mcp-screenshot-server.js" ); const TEST_SCREENSHOT_MCP_SERVER_COMMAND = `node "${TEST_SCREENSHOT_MCP_SERVER_PATH}"`; -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} // Shared types for MCP content parsing type MediaItem = { type: "media"; data: string; mediaType: string }; @@ -131,7 +122,7 @@ function assertValidScreenshotResult( return { mediaItems, textItems }; } -describeIntegration("MCP global configuration", () => { +describe("MCP global configuration", () => { test.concurrent("add, list, and remove MCP servers", async () => { const env = await createTestEnvironment(); const repoPath = await createTempGitRepo(); @@ -294,7 +285,7 @@ describeIntegration("MCP global configuration", () => { }); }); -describeIntegration("MCP server integration with model", () => { +describe("MCP server integration with model", () => { // Test matrix for image format handling const imageFormatCases = [ { diff --git a/tests/ipc/config/modelNotFound.test.ts b/tests/ipc/config/modelNotFound.test.ts index 1073d0d3f4..beb0bad74d 100644 --- a/tests/ipc/config/modelNotFound.test.ts +++ b/tests/ipc/config/modelNotFound.test.ts @@ -1,16 +1,12 @@ -import { setupWorkspace, shouldRunIntegrationTests, validateApiKeys } from "../setup"; +import { setupWorkspace } from "../setup"; import { sendMessageWithModel, createStreamCollector, modelString } from "../helpers"; import type { StreamErrorMessage } from "@/common/orpc/types"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; +jest.setTimeout(600_000); // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY", "OPENAI_API_KEY"]); -} -describeIntegration("model_not_found error handling", () => { +describe("model_not_found error handling", () => { test.concurrent( "should classify Anthropic 404 as model_not_found (not retryable)", async () => { diff --git a/tests/ipc/doubleRegister.test.ts b/tests/ipc/doubleRegister.test.ts index 960c9a6738..d786c5265f 100644 --- a/tests/ipc/doubleRegister.test.ts +++ b/tests/ipc/doubleRegister.test.ts @@ -1,9 +1,7 @@ -import { shouldRunIntegrationTests, createTestEnvironment, cleanupTestEnvironment } from "./setup"; +import { createTestEnvironment, cleanupTestEnvironment } from "./setup"; import { resolveOrpcClient } from "./helpers"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("Service double registration", () => { +describe("Service double registration", () => { test.concurrent( "should not throw when register() is called multiple times", async () => { diff --git a/tests/ipc/projects/create.test.ts b/tests/ipc/projects/create.test.ts index da4f70e8aa..da7c2d450c 100644 --- a/tests/ipc/projects/create.test.ts +++ b/tests/ipc/projects/create.test.ts @@ -12,12 +12,10 @@ import * as fs from "fs/promises"; import * as path from "path"; import { getMuxHome, getMuxProjectsDir } from "../../../src/common/constants/paths"; import * as os from "os"; -import { shouldRunIntegrationTests, createTestEnvironment, cleanupTestEnvironment } from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment } from "../setup"; import { resolveOrpcClient } from "../helpers"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("PROJECT_CREATE IPC Handler", () => { +describe("PROJECT_CREATE IPC Handler", () => { test.concurrent("should resolve bare project name to mux projects dir", async () => { const env = await createTestEnvironment(); const bareName = `mux-test-bare-${Date.now()}`; diff --git a/tests/ipc/projects/nameGeneration.test.ts b/tests/ipc/projects/nameGeneration.test.ts index df436a8345..e3a93e9ea3 100644 --- a/tests/ipc/projects/nameGeneration.test.ts +++ b/tests/ipc/projects/nameGeneration.test.ts @@ -7,13 +7,11 @@ * - Model selection fallback works correctly */ -import { shouldRunIntegrationTests } from "../../testUtils"; import { createTestEnvironment, cleanupTestEnvironment, type TestEnvironment } from "../setup"; // Skip if integration tests are disabled (requires real API keys) -const describeIfIntegration = shouldRunIntegrationTests() ? describe : describe.skip; -describeIfIntegration("Name generation with real LLM", () => { +describe("Name generation with real LLM", () => { let env: TestEnvironment; beforeAll(async () => { diff --git a/tests/ipc/projects/refactor.test.ts b/tests/ipc/projects/refactor.test.ts index 477df3ebac..d99a16432c 100644 --- a/tests/ipc/projects/refactor.test.ts +++ b/tests/ipc/projects/refactor.test.ts @@ -1,12 +1,10 @@ import * as fs from "fs/promises"; import * as path from "path"; import * as os from "os"; -import { shouldRunIntegrationTests, createTestEnvironment, cleanupTestEnvironment } from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment } from "../setup"; import { resolveOrpcClient } from "../helpers"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("ProjectService IPC Handlers", () => { +describe("ProjectService IPC Handlers", () => { test.concurrent("should list projects including the created one", async () => { const env = await createTestEnvironment(); const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-project-service-test-")); diff --git a/tests/ipc/providers/anthropicCacheStrategy.test.ts b/tests/ipc/providers/anthropicCacheStrategy.test.ts index 1a3e4662ac..d6147f5b9c 100644 --- a/tests/ipc/providers/anthropicCacheStrategy.test.ts +++ b/tests/ipc/providers/anthropicCacheStrategy.test.ts @@ -1,18 +1,19 @@ -import { setupWorkspace, shouldRunIntegrationTests } from "../setup"; +import { setupWorkspace } from "../setup"; import { sendMessageWithModel, createStreamCollector } from "../helpers"; -// Skip tests unless TEST_INTEGRATION=1 AND required API keys are present +// Skip tests unless ANTHROPIC_API_KEY is present const hasAnthropicKey = Boolean(process.env.ANTHROPIC_API_KEY); -const shouldRunSuite = shouldRunIntegrationTests() && hasAnthropicKey; -const describeIntegration = shouldRunSuite ? describe : describe.skip; +const describeSuite = hasAnthropicKey ? describe : describe.skip; const TEST_TIMEOUT_MS = 45000; // 45s total: setup + 2 messages at 15s each -if (shouldRunIntegrationTests() && !shouldRunSuite) { +if (!hasAnthropicKey) { // eslint-disable-next-line no-console console.warn("Skipping Anthropic cache strategy integration tests: missing ANTHROPIC_API_KEY"); } -describeIntegration("Anthropic cache strategy integration", () => { +jest.setTimeout(600_000); + +describeSuite("Anthropic cache strategy integration", () => { test( "should apply cache control to messages, system prompt, and tools for Anthropic models", async () => { diff --git a/tests/ipc/providers/ollama.test.ts b/tests/ipc/providers/ollama.test.ts index be28171d60..f55d28b399 100644 --- a/tests/ipc/providers/ollama.test.ts +++ b/tests/ipc/providers/ollama.test.ts @@ -1,4 +1,4 @@ -import { setupWorkspace, shouldRunIntegrationTests } from "../setup"; +import { setupWorkspace } from "../setup"; import { sendMessageWithModel, createStreamCollector, @@ -10,8 +10,10 @@ import { import { spawn } from "child_process"; import { loadTokenizerModules } from "../../../src/node/utils/main/tokenizer"; -// Skip all tests if TEST_INTEGRATION or TEST_OLLAMA is not set -const shouldRunOllamaTests = shouldRunIntegrationTests() && process.env.TEST_OLLAMA === "1"; +jest.setTimeout(600_000); + +// Skip all tests unless TEST_OLLAMA=1 (requires local Ollama service) +const shouldRunOllamaTests = process.env.TEST_OLLAMA === "1"; const describeOllama = shouldRunOllamaTests ? describe : describe.skip; // Ollama doesn't require API keys - it's a local service diff --git a/tests/ipc/providers/openaiPreviousResponseIdRecovery.test.ts b/tests/ipc/providers/openaiPreviousResponseIdRecovery.test.ts index fa1c1b49b6..da21ef7c14 100644 --- a/tests/ipc/providers/openaiPreviousResponseIdRecovery.test.ts +++ b/tests/ipc/providers/openaiPreviousResponseIdRecovery.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * OpenAI previousResponseId recovery integration test. * @@ -6,7 +8,7 @@ */ import { randomBytes } from "crypto"; -import { setupWorkspace, shouldRunIntegrationTests, validateApiKeys } from "../setup"; +import { setupWorkspace } from "../setup"; import { sendMessageWithModel, createStreamCollector, @@ -17,13 +19,7 @@ import { KNOWN_MODELS } from "../../../src/common/constants/knownModels"; import type { ToolPolicy } from "../../../src/common/utils/tools/toolPolicy"; import { createMuxMessage } from "../../../src/common/types/message"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["OPENAI_API_KEY"]); -} const OPENAI_MODEL = modelString("openai", KNOWN_MODELS.GPT.providerModelId); const DISABLE_TOOLS: ToolPolicy = [{ regex_match: ".*", action: "disable" }]; @@ -32,7 +28,7 @@ function createInvalidResponseId(): string { return `resp_${randomBytes(12).toString("hex")}`; } -describeIntegration("OpenAI previousResponseId recovery", () => { +describe("OpenAI previousResponseId recovery", () => { configureTestRetries(3); test.concurrent( diff --git a/tests/ipc/providers/openaiWebSearch.test.ts b/tests/ipc/providers/openaiWebSearch.test.ts index e64e754a13..7b03aa9d4d 100644 --- a/tests/ipc/providers/openaiWebSearch.test.ts +++ b/tests/ipc/providers/openaiWebSearch.test.ts @@ -1,4 +1,4 @@ -import { setupWorkspace, shouldRunIntegrationTests, validateApiKeys } from "../setup"; +import { setupWorkspace } from "../setup"; import { sendMessageWithModel, createStreamCollector, @@ -7,15 +7,11 @@ import { configureTestRetries, } from "../helpers"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; +jest.setTimeout(600_000); // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["OPENAI_API_KEY"]); -} -describeIntegration("OpenAI web_search integration tests", () => { +describe("OpenAI web_search integration tests", () => { // Enable retries in CI for flaky API tests configureTestRetries(3); diff --git a/tests/ipc/runtime/backgroundBash.test.ts b/tests/ipc/runtime/backgroundBash.test.ts index 9a3f9556df..cd1e95d823 100644 --- a/tests/ipc/runtime/backgroundBash.test.ts +++ b/tests/ipc/runtime/backgroundBash.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * Integration tests for background bash process execution * @@ -8,14 +10,7 @@ * is covered by unit tests in backgroundProcessManager.test.ts */ -import { - createTestEnvironment, - cleanupTestEnvironment, - shouldRunIntegrationTests, - validateApiKeys, - getApiKey, - setupProviders, -} from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment, getApiKey, setupProviders } from "../setup"; import { createTempGitRepo, cleanupTempGitRepo, @@ -123,18 +118,12 @@ function extractTerminatedTaskIds(events: WorkspaceChatMessage[]): string[] { return []; } -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} // Retry flaky tests in CI (API latency / rate limiting) configureTestRetries(3); -describeIntegration("Background Bash Execution", () => { +describe("Background Bash Execution", () => { test.concurrent( "should start a background process and list it", async () => { diff --git a/tests/ipc/runtime/executeBash.test.ts b/tests/ipc/runtime/executeBash.test.ts index c7eb715f2c..39e6b14311 100644 --- a/tests/ipc/runtime/executeBash.test.ts +++ b/tests/ipc/runtime/executeBash.test.ts @@ -1,4 +1,4 @@ -import { shouldRunIntegrationTests, createTestEnvironment, cleanupTestEnvironment } from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment } from "../setup"; import { createTempGitRepo, cleanupTempGitRepo, @@ -67,13 +67,11 @@ function expectWorkspaceCreationSuccess(result: WorkspaceCreationResult): Worksp const GIT_FETCH_TIMEOUT_SECS = process.platform === "win32" ? 15 : 5; const TEST_TIMEOUT_MS = process.platform === "win32" ? 60_000 : 15_000; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; // Retry flaky integration tests in CI (Windows shell startup / IO jitter) configureTestRetries(2); -describeIntegration("executeBash", () => { +describe("executeBash", () => { test.concurrent( "should execute bash command in workspace context", async () => { diff --git a/tests/ipc/runtime/originFetch.test.ts b/tests/ipc/runtime/originFetch.test.ts index 5e3955cf65..c98b482004 100644 --- a/tests/ipc/runtime/originFetch.test.ts +++ b/tests/ipc/runtime/originFetch.test.ts @@ -22,7 +22,7 @@ import * as path from "path"; import * as os from "os"; import { exec } from "child_process"; import { promisify } from "util"; -import { shouldRunIntegrationTests, createTestEnvironment, cleanupTestEnvironment } from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment } from "../setup"; import { generateBranchName, cleanupTempGitRepo, waitForInitComplete } from "../helpers"; import { detectDefaultTrunkBranch } from "../../../src/node/git"; import { @@ -41,8 +41,6 @@ const TEST_TIMEOUT_MS = 60000; const SSH_INIT_WAIT_MS = 15000; // SSH init includes sync + checkout, needs more time const ORIGIN_COMMIT_MARKER = "ORIGIN_ONLY_COMMIT_MARKER"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // SSH server config (shared across all SSH tests) let sshConfig: SSHServerConfig | undefined; @@ -124,11 +122,11 @@ async function cleanupTestRepos(repoPath: string, originPath: string): Promise { +describe("Origin fetch ordering during workspace creation", () => { beforeAll(async () => { if (!(await isDockerAvailable())) { throw new Error( - "Docker is required for SSH runtime tests. Please install Docker or skip tests by unsetting TEST_INTEGRATION." + "Docker is required for SSH runtime tests. Please install Docker or skip this test suite." ); } diff --git a/tests/ipc/runtime/runtimeExecuteBash.test.ts b/tests/ipc/runtime/runtimeExecuteBash.test.ts index b1f5f32a9a..43d63e6a22 100644 --- a/tests/ipc/runtime/runtimeExecuteBash.test.ts +++ b/tests/ipc/runtime/runtimeExecuteBash.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * Integration tests for bash execution across Local and SSH runtimes * @@ -6,14 +8,7 @@ * Reuses test infrastructure from runtimeFileEditing.test.ts */ -import { - createTestEnvironment, - cleanupTestEnvironment, - shouldRunIntegrationTests, - validateApiKeys, - getApiKey, - setupProviders, -} from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment, getApiKey, setupProviders } from "../setup"; import { createTempGitRepo, cleanupTempGitRepo, @@ -90,23 +85,17 @@ function getToolDuration(events: WorkspaceChatMessage[], toolName: string): numb return -1; } -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} // SSH server config (shared across all SSH tests) let sshConfig: SSHServerConfig | undefined; -describeIntegration("Runtime Bash Execution", () => { +describe("Runtime Bash Execution", () => { beforeAll(async () => { // Check if Docker is available (required for SSH tests) if (!(await isDockerAvailable())) { throw new Error( - "Docker is required for SSH runtime tests. Please install Docker or skip tests by unsetting TEST_INTEGRATION." + "Docker is required for SSH runtime tests. Please install Docker or skip this test suite." ); } diff --git a/tests/ipc/runtime/runtimeFileEditing.test.ts b/tests/ipc/runtime/runtimeFileEditing.test.ts index dd7a45456c..6c2340693d 100644 --- a/tests/ipc/runtime/runtimeFileEditing.test.ts +++ b/tests/ipc/runtime/runtimeFileEditing.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * Integration tests for file editing tools across Local and SSH runtimes * @@ -7,14 +9,7 @@ * Uses toolPolicy to restrict AI to only file tools (prevents bash circumvention). */ -import { - createTestEnvironment, - cleanupTestEnvironment, - shouldRunIntegrationTests, - validateApiKeys, - getApiKey, - setupProviders, -} from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment, getApiKey, setupProviders } from "../setup"; import { createTempGitRepo, cleanupTempGitRepo, @@ -47,13 +42,7 @@ const FILE_TOOLS_ONLY: ToolPolicy = [ { regex_match: "bash", action: "disable" }, ]; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} // Retry flaky tests in CI (API latency/rate limiting) configureTestRetries(); @@ -65,12 +54,12 @@ let sshConfig: SSHServerConfig | undefined; // Tests // ============================================================================ -describeIntegration("Runtime File Editing Tools", () => { +describe("Runtime File Editing Tools", () => { beforeAll(async () => { // Check if Docker is available (required for SSH tests) if (!(await isDockerAvailable())) { throw new Error( - "Docker is required for SSH runtime tests. Please install Docker or skip tests by unsetting TEST_INTEGRATION." + "Docker is required for SSH runtime tests. Please install Docker or skip this test suite." ); } diff --git a/tests/ipc/setup.ts b/tests/ipc/setup.ts index 31c5ae7dd7..98b7defb11 100644 --- a/tests/ipc/setup.ts +++ b/tests/ipc/setup.ts @@ -16,7 +16,7 @@ import type { OrpcSource } from "./helpers"; import type { ORPCContext } from "../../src/node/orpc/context"; import type { RuntimeConfig } from "../../src/common/types/runtime"; import { createOrpcTestClient, type OrpcTestClient } from "./orpcTestClient"; -import { shouldRunIntegrationTests, validateApiKeys, getApiKey } from "../testUtils"; +import { validateApiKeys, getApiKey } from "../testUtils"; export interface TestEnvironment { config: Config; @@ -52,19 +52,19 @@ function createMockBrowserWindow(): BrowserWindow { /** * Create a test environment with temporary config and service container */ -export async function createTestEnvironment(): Promise { +export async function createTestEnvironment(options?: { + seedDummyKeys?: boolean; +}): Promise { // Create temporary directory for test config const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-test-")); // Create config with temporary directory const config = new Config(tempDir); - // Some UI tests render ProjectPage, which now hard-blocks workspace creation when no providers - // are configured. For non-integration tests, seed a dummy provider so the UI can render. - // - // For integration tests (TEST_INTEGRATION=1), do NOT write dummy keys here (they would override - // real env-backed credentials used by tests like name generation). - if (!shouldRunIntegrationTests()) { + // UI tests render ProjectPage, which hard-blocks workspace creation when no providers + // are configured. Seed a dummy provider so the UI can render. Tests that need real + // API keys call setupProviders() afterwards, which overwrites this. + if (options?.seedDummyKeys !== false) { config.saveProvidersConfig({ anthropic: { apiKey: "test-key-for-ui-tests" }, }); @@ -180,7 +180,7 @@ export async function setupProviders( } // Re-export test utilities for backwards compatibility -export { shouldRunIntegrationTests, validateApiKeys, getApiKey }; +export { validateApiKeys, getApiKey }; /** * Preload modules that may be imported dynamically during concurrent tests. diff --git a/tests/ipc/streaming/emptyAssistantMessage.test.ts b/tests/ipc/streaming/emptyAssistantMessage.test.ts index 23733b9993..d14d9f1856 100644 --- a/tests/ipc/streaming/emptyAssistantMessage.test.ts +++ b/tests/ipc/streaming/emptyAssistantMessage.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * Test that corrupted chat history with empty assistant messages * does not brick the workspace (self-healing behavior). @@ -5,20 +7,14 @@ * Reproduction of: "messages.95: all messages must have non-empty content * except for the optional final assistant message" */ -import { setupWorkspace, shouldRunIntegrationTests, validateApiKeys } from "../setup"; +import { setupWorkspace } from "../setup"; import { sendMessageWithModel, createStreamCollector, HAIKU_MODEL } from "../helpers"; import { HistoryService } from "../../../src/node/services/historyService"; import { createMuxMessage } from "../../../src/common/types/message"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} -describeIntegration("empty assistant message self-healing", () => { +describe("empty assistant message self-healing", () => { test.concurrent( "should handle corrupted history with empty assistant parts array", async () => { diff --git a/tests/ipc/streaming/interrupt.test.ts b/tests/ipc/streaming/interrupt.test.ts index 76935b7d27..8a530baa94 100644 --- a/tests/ipc/streaming/interrupt.test.ts +++ b/tests/ipc/streaming/interrupt.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * interruptStream "starting..." integration tests. * @@ -5,14 +7,7 @@ * stream-start (e.g., while AIService is blocked on initStateManager.waitForInit). */ -import { - shouldRunIntegrationTests, - validateApiKeys, - createTestEnvironment, - cleanupTestEnvironment, - setupProviders, - getApiKey, -} from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment, setupProviders, getApiKey } from "../setup"; import { createTempGitRepo, cleanupTempGitRepo, @@ -32,13 +27,6 @@ import { promisify } from "util"; const execAsync = promisify(exec); -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} - async function addInitHook(repoPath: string, scriptBody: string): Promise { const muxDir = path.join(repoPath, ".mux"); await fs.mkdir(muxDir, { recursive: true }); @@ -52,7 +40,7 @@ async function addInitHook(repoPath: string, scriptBody: string): Promise await execAsync(`git -c commit.gpgsign=false commit -m "Add init hook"`, { cwd: repoPath }); } -describeIntegration("interruptStream during startup", () => { +describe("interruptStream during startup", () => { test("should emit stream-abort without stream-start when interrupted before stream-start", async () => { const env = await createTestEnvironment(); const repoPath = await createTempGitRepo(); diff --git a/tests/ipc/streaming/queuedMessages.test.ts b/tests/ipc/streaming/queuedMessages.test.ts index e3dd4d5b0a..a22d1430a7 100644 --- a/tests/ipc/streaming/queuedMessages.test.ts +++ b/tests/ipc/streaming/queuedMessages.test.ts @@ -1,4 +1,4 @@ -import { setupWorkspace, shouldRunIntegrationTests, validateApiKeys } from "../setup"; +import { setupWorkspace } from "../setup"; import { sendMessageWithModel, sendMessage, @@ -17,13 +17,9 @@ import type { WorkspaceChatMessage } from "@/common/orpc/types"; type QueuedMessageChangedEvent = Extract; type RestoreToInputEvent = Extract; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; +jest.setTimeout(600_000); // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} // Helper: Get queued messages from latest queued-message-changed event // If wait=true, waits for a new event first (use when expecting a change) @@ -86,7 +82,7 @@ async function waitForRestoreToInputEvent( return event; } -describeIntegration("Queued messages", () => { +describe("Queued messages", () => { // Enable retries in CI for flaky API tests configureTestRetries(3); diff --git a/tests/ipc/streaming/resume.test.ts b/tests/ipc/streaming/resume.test.ts index a8ff2d96e8..6607b1ce1d 100644 --- a/tests/ipc/streaming/resume.test.ts +++ b/tests/ipc/streaming/resume.test.ts @@ -1,4 +1,4 @@ -import { setupWorkspace, shouldRunIntegrationTests, validateApiKeys } from "../setup"; +import { setupWorkspace } from "../setup"; import { sendMessageWithModel, createStreamCollector, @@ -10,15 +10,11 @@ import { HistoryService } from "../../../src/node/services/historyService"; import { createMuxMessage } from "../../../src/common/types/message"; import type { WorkspaceChatMessage } from "@/common/orpc/types"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; +jest.setTimeout(600_000); // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} -describeIntegration("resumeStream", () => { +describe("resumeStream", () => { // Enable retries in CI for flaky API tests configureTestRetries(3); diff --git a/tests/ipc/streaming/sendMessage.basic.test.ts b/tests/ipc/streaming/sendMessage.basic.test.ts index 5fc2da3215..137e4aa3bb 100644 --- a/tests/ipc/streaming/sendMessage.basic.test.ts +++ b/tests/ipc/streaming/sendMessage.basic.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * Basic sendMessage integration tests. * @@ -8,7 +10,6 @@ * - Provider parity (OpenAI and Anthropic) */ -import { shouldRunIntegrationTests, validateApiKeys } from "../setup"; import { sendMessageWithModel, modelString, assertStreamSuccess } from "../helpers"; import { createSharedRepo, @@ -18,13 +19,7 @@ import { } from "../sendMessageTestHelpers"; import { KNOWN_MODELS } from "../../../src/common/constants/knownModels"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]); -} // Test both providers with their respective models const PROVIDER_CONFIGS: Array<[string, string]> = [ @@ -41,7 +36,7 @@ const PROVIDER_CONFIGS: Array<[string, string]> = [ beforeAll(createSharedRepo); afterAll(cleanupSharedRepo); -describeIntegration("sendMessage basic integration tests", () => { +describe("sendMessage basic integration tests", () => { configureTestRetries(3); // Run tests for each provider concurrently diff --git a/tests/ipc/streaming/sendMessage.context.test.ts b/tests/ipc/streaming/sendMessage.context.test.ts index 299d24a639..881c21ca40 100644 --- a/tests/ipc/streaming/sendMessage.context.test.ts +++ b/tests/ipc/streaming/sendMessage.context.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * sendMessage context handling integration tests. * @@ -10,7 +12,6 @@ import * as path from "path"; import * as fs from "fs/promises"; -import { shouldRunIntegrationTests, validateApiKeys } from "../setup"; import { sendMessageWithModel, modelString } from "../helpers"; import { createSharedRepo, @@ -21,13 +22,7 @@ import { } from "../sendMessageTestHelpers"; import { KNOWN_MODELS } from "../../../src/common/constants/knownModels"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]); -} // Test both providers const PROVIDER_CONFIGS: Array<[string, string]> = [ @@ -38,7 +33,7 @@ const PROVIDER_CONFIGS: Array<[string, string]> = [ beforeAll(createSharedRepo); afterAll(cleanupSharedRepo); -describeIntegration("sendMessage context handling tests", () => { +describe("sendMessage context handling tests", () => { configureTestRetries(3); describe.each(PROVIDER_CONFIGS)("%s conversation continuity", (provider, model) => { diff --git a/tests/ipc/streaming/sendMessage.errors.test.ts b/tests/ipc/streaming/sendMessage.errors.test.ts index f3a808477a..64a47ef183 100644 --- a/tests/ipc/streaming/sendMessage.errors.test.ts +++ b/tests/ipc/streaming/sendMessage.errors.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * sendMessage error handling integration tests. * @@ -8,12 +10,7 @@ * - Stream errors */ -import { - shouldRunIntegrationTests, - validateApiKeys, - createTestEnvironment, - cleanupTestEnvironment, -} from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment } from "../setup"; import { sendMessage, sendMessageWithModel, modelString, generateBranchName } from "../helpers"; import { createSharedRepo, @@ -25,18 +22,12 @@ import { import { KNOWN_MODELS } from "../../../src/common/constants/knownModels"; import { detectDefaultTrunkBranch } from "../../../src/node/git"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]); -} beforeAll(createSharedRepo); afterAll(cleanupSharedRepo); -describeIntegration("sendMessage error handling tests", () => { +describe("sendMessage error handling tests", () => { configureTestRetries(3); describe("validation errors", () => { diff --git a/tests/ipc/streaming/sendMessage.heavy.test.ts b/tests/ipc/streaming/sendMessage.heavy.test.ts index 7743d49f6c..f795ecba6c 100644 --- a/tests/ipc/streaming/sendMessage.heavy.test.ts +++ b/tests/ipc/streaming/sendMessage.heavy.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * sendMessage heavy/load integration tests. * @@ -6,7 +8,6 @@ * - Context limit error handling */ -import { shouldRunIntegrationTests, validateApiKeys } from "../setup"; import { sendMessageWithModel, modelString } from "../helpers"; import { createSharedRepo, @@ -16,18 +17,12 @@ import { } from "../sendMessageTestHelpers"; import { KNOWN_MODELS } from "../../../src/common/constants/knownModels"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]); -} beforeAll(createSharedRepo); afterAll(cleanupSharedRepo); -describeIntegration("sendMessage heavy/load tests", () => { +describe("sendMessage heavy/load tests", () => { configureTestRetries(3); describe("OpenAI context limit error (forced)", () => { diff --git a/tests/ipc/streaming/sendMessage.images.test.ts b/tests/ipc/streaming/sendMessage.images.test.ts index d62a50bbd7..c3e49020ee 100644 --- a/tests/ipc/streaming/sendMessage.images.test.ts +++ b/tests/ipc/streaming/sendMessage.images.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * sendMessage image handling integration tests. * @@ -7,7 +9,6 @@ * - Multi-modal conversation support */ -import { shouldRunIntegrationTests, validateApiKeys } from "../setup"; import { sendMessage, modelString } from "../helpers"; import { createSharedRepo, @@ -33,13 +34,7 @@ async function collectFullHistory( return messages; } -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]); -} // 4x4 pure red PNG (#FF0000) as base64 data URI // Uses 8-bit RGB color (not indexed) for reliable vision model processing @@ -71,7 +66,7 @@ const PROVIDER_CONFIGS: Array<[string, string]> = [ beforeAll(createSharedRepo); afterAll(cleanupSharedRepo); -describeIntegration("sendMessage image handling tests", () => { +describe("sendMessage image handling tests", () => { configureTestRetries(3); describe.each(PROVIDER_CONFIGS)("%s image support", (provider, model) => { diff --git a/tests/ipc/streaming/sendMessage.reasoning.test.ts b/tests/ipc/streaming/sendMessage.reasoning.test.ts index e654457af2..8c858f4545 100644 --- a/tests/ipc/streaming/sendMessage.reasoning.test.ts +++ b/tests/ipc/streaming/sendMessage.reasoning.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * Integration tests for reasoning/thinking functionality across Anthropic models. * @@ -7,7 +9,6 @@ * - Reasoning events are properly streamed */ -import { shouldRunIntegrationTests, validateApiKeys } from "../setup"; import { sendMessage } from "../helpers"; import { createSharedRepo, @@ -17,18 +18,12 @@ import { } from "../sendMessageTestHelpers"; import { KNOWN_MODELS } from "../../../src/common/constants/knownModels"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} beforeAll(createSharedRepo); afterAll(cleanupSharedRepo); -describeIntegration("Anthropic reasoning parameter tests", () => { +describe("Anthropic reasoning parameter tests", () => { configureTestRetries(3); test.concurrent( diff --git a/tests/ipc/streaming/streamErrorRecovery.test.ts b/tests/ipc/streaming/streamErrorRecovery.test.ts index bbb600fd06..cb583b7c13 100644 --- a/tests/ipc/streaming/streamErrorRecovery.test.ts +++ b/tests/ipc/streaming/streamErrorRecovery.test.ts @@ -1,3 +1,5 @@ +jest.setTimeout(600_000); + /** * Stream Error Recovery Integration Tests * @@ -16,7 +18,7 @@ * test the recovery path without relying on actual network failures. */ -import { setupWorkspace, shouldRunIntegrationTests, validateApiKeys } from "../setup"; +import { setupWorkspace } from "../setup"; import { sendMessageWithModel, createStreamCollector, @@ -27,13 +29,7 @@ import { } from "../helpers"; import type { StreamCollector } from "../streamCollector"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} // Use Haiku 4.5 for speed const PROVIDER = "anthropic"; @@ -195,8 +191,7 @@ async function collectStreamUntil( } // TODO: This test requires a debug IPC method (triggerStreamError) that is exposed via ORPC -// Using describeIntegration to enable when TEST_INTEGRATION=1 -describeIntegration("Stream Error Recovery (No Amnesia)", () => { +describe("Stream Error Recovery (No Amnesia)", () => { // Enable retries in CI for flaky API tests configureTestRetries(3); diff --git a/tests/ipc/streaming/system1BashCompaction.matrix.test.ts b/tests/ipc/streaming/system1BashCompaction.matrix.test.ts index 69bbf384e1..bfe8608b87 100644 --- a/tests/ipc/streaming/system1BashCompaction.matrix.test.ts +++ b/tests/ipc/streaming/system1BashCompaction.matrix.test.ts @@ -16,7 +16,6 @@ import { createTestEnvironment, preloadTestModules, setupProviders, - shouldRunIntegrationTests, type TestEnvironment, } from "../setup"; @@ -93,10 +92,10 @@ const configuredModels = requestedModels.filter((modelString) => { return true; }); -const shouldRunSuite = shouldRunIntegrationTests() && configuredModels.length > 0; -const describeIntegration = shouldRunSuite ? describe : describe.skip; +const shouldRunSuite = configuredModels.length > 0; +const describeSuite = shouldRunSuite ? describe : describe.skip; -if (shouldRunIntegrationTests() && !shouldRunSuite) { +if (!shouldRunSuite) { // eslint-disable-next-line no-console console.warn( "Skipping System1 bash compaction integration tests: no configured models (missing API keys)" @@ -120,7 +119,7 @@ const MAX_KEPT_LINES = 40; // This test calls real providers via runSystem1KeepRangesForBashOutput() and validates that we can // reliably obtain usable keep_ranges for bash output filtering across a model + thinking-level matrix. -describeIntegration("System1 bash output compaction (keep_ranges matrix)", () => { +describeSuite("System1 bash output compaction (keep_ranges matrix)", () => { let env: TestEnvironment; beforeAll(async () => { diff --git a/tests/ipc/streaming/truncate.test.ts b/tests/ipc/streaming/truncate.test.ts index cf484a902e..896abbc170 100644 --- a/tests/ipc/streaming/truncate.test.ts +++ b/tests/ipc/streaming/truncate.test.ts @@ -1,4 +1,4 @@ -import { setupWorkspace, shouldRunIntegrationTests, validateApiKeys } from "../setup"; +import { setupWorkspace } from "../setup"; import { sendMessageWithModel, createStreamCollector, @@ -10,15 +10,11 @@ import { HistoryService } from "../../../src/node/services/historyService"; import { createMuxMessage } from "../../../src/common/types/message"; import type { DeleteMessage } from "@/common/orpc/types"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; +jest.setTimeout(600_000); // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} -describeIntegration("truncateHistory", () => { +describe("truncateHistory", () => { test.concurrent( "should truncate 50% of chat history and verify context is updated", async () => { diff --git a/tests/ipc/streaming/usageDelta.test.ts b/tests/ipc/streaming/usageDelta.test.ts index e1add91f78..bbe1472c88 100644 --- a/tests/ipc/streaming/usageDelta.test.ts +++ b/tests/ipc/streaming/usageDelta.test.ts @@ -1,4 +1,4 @@ -import { setupWorkspace, shouldRunIntegrationTests, validateApiKeys } from "../setup"; +import { setupWorkspace } from "../setup"; import { sendMessageWithModel, createStreamCollector, @@ -9,15 +9,11 @@ import { import { isUsageDelta } from "../../../src/common/orpc/types"; import { KNOWN_MODELS } from "../../../src/common/constants/knownModels"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; +jest.setTimeout(600_000); // Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} -describeIntegration("usage-delta events", () => { +describe("usage-delta events", () => { // Enable retries in CI for flaky API tests configureTestRetries(3); diff --git a/tests/ipc/terminal/terminal.test.ts b/tests/ipc/terminal/terminal.test.ts index 9a63ec151c..d6f31d1cb1 100644 --- a/tests/ipc/terminal/terminal.test.ts +++ b/tests/ipc/terminal/terminal.test.ts @@ -1,4 +1,4 @@ -import { shouldRunIntegrationTests, createTestEnvironment, cleanupTestEnvironment } from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment } from "../setup"; import { createTempGitRepo, cleanupTempGitRepo, @@ -17,10 +17,7 @@ function expectWorkspaceCreationSuccess(result: WorkspaceCreationResult): Worksp return result.metadata; } -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("terminal PTY", () => { +describe("terminal PTY", () => { test.concurrent( "should create terminal session, send command, receive output, and close", async () => { diff --git a/tests/ipc/windowTitle.test.ts b/tests/ipc/windowTitle.test.ts index 2c9f3da578..ff899eb37f 100644 --- a/tests/ipc/windowTitle.test.ts +++ b/tests/ipc/windowTitle.test.ts @@ -1,9 +1,7 @@ -import { shouldRunIntegrationTests, createTestEnvironment, cleanupTestEnvironment } from "./setup"; +import { createTestEnvironment, cleanupTestEnvironment } from "./setup"; import { resolveOrpcClient } from "./helpers"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("Window title IPC", () => { +describe("Window title IPC", () => { test.concurrent( "should update window title via IPC", async () => { diff --git a/tests/ipc/workspace/create.test.ts b/tests/ipc/workspace/create.test.ts index 2a979a1e88..16997f98d8 100644 --- a/tests/ipc/workspace/create.test.ts +++ b/tests/ipc/workspace/create.test.ts @@ -14,7 +14,7 @@ import * as fs from "fs/promises"; import * as path from "path"; import { exec } from "child_process"; import { promisify } from "util"; -import { shouldRunIntegrationTests, createTestEnvironment, cleanupTestEnvironment } from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment } from "../setup"; import type { TestEnvironment } from "../setup"; import { createTempGitRepo, @@ -63,9 +63,6 @@ const INIT_HOOK_FILENAME = "init"; const EVENT_TYPE_INIT_OUTPUT = "init-output"; const EVENT_TYPE_INIT_END = "init-end"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // SSH server config (shared across all SSH tests) let sshConfig: SSHServerConfig | undefined; @@ -152,12 +149,12 @@ async function createWorkspaceWithCleanup( return { result, cleanup }; } -describeIntegration("WORKSPACE_CREATE with both runtimes", () => { +describe("WORKSPACE_CREATE with both runtimes", () => { beforeAll(async () => { // Check if Docker is available (required for SSH tests) if (!(await isDockerAvailable())) { throw new Error( - "Docker is required for SSH runtime tests. Please install Docker or skip tests by unsetting TEST_INTEGRATION." + "Docker is required for SSH runtime tests. Please install Docker or skip this test suite." ); } diff --git a/tests/ipc/workspace/fileChangeNotification.test.ts b/tests/ipc/workspace/fileChangeNotification.test.ts index 22bafb9e51..b837a42f6f 100644 --- a/tests/ipc/workspace/fileChangeNotification.test.ts +++ b/tests/ipc/workspace/fileChangeNotification.test.ts @@ -16,7 +16,6 @@ import { setupProviders, preloadTestModules, type TestEnvironment, - shouldRunIntegrationTests, } from "../setup"; import { createTempGitRepo, @@ -32,17 +31,11 @@ import { getPlanFilePath } from "../../../src/common/utils/planStorage"; import { log } from "../../../src/node/services/log"; import { getMuxHome } from "../../../src/common/constants/paths"; -// Skip tests if integration tests are disabled or API keys are missing -const runTests = shouldRunIntegrationTests(); +validateApiKeys(["ANTHROPIC_API_KEY"]); -// Validate API keys are available -if (runTests) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} +jest.setTimeout(600_000); -const describeIntegration = runTests ? describe : describe.skip; - -describeIntegration("File Change Notification Integration", () => { +describe("File Change Notification Integration", () => { let env: TestEnvironment; let repoPath: string; let originalLogLevel: ReturnType; diff --git a/tests/ipc/workspace/fork.test.ts b/tests/ipc/workspace/fork.test.ts index fb6599124b..d099d6fc04 100644 --- a/tests/ipc/workspace/fork.test.ts +++ b/tests/ipc/workspace/fork.test.ts @@ -1,10 +1,4 @@ -import { - shouldRunIntegrationTests, - createTestEnvironment, - cleanupTestEnvironment, - setupWorkspace, - validateApiKeys, -} from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment, setupWorkspace } from "../setup"; import { createTempGitRepo, cleanupTempGitRepo, @@ -29,6 +23,8 @@ import { HistoryService } from "../../../src/node/services/historyService"; import { createMuxMessage, type MuxMessage } from "../../../src/common/types/message"; import assert from "node:assert"; +jest.setTimeout(600_000); + /** Collect all messages via iterateFullHistory (replaces removed getFullHistory). */ async function collectFullHistory(service: HistoryService, workspaceId: string) { const messages: MuxMessage[] = []; @@ -39,25 +35,19 @@ async function collectFullHistory(service: HistoryService, workspaceId: string) return messages; } -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // Validate API keys for tests that need them -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} // SSH server config (shared across SSH runtime tests) let sshConfig: SSHServerConfig | undefined; // Retry flaky tests in CI (API latency / rate limiting) configureTestRetries(3); -describeIntegration("Workspace fork", () => { +describe("Workspace fork", () => { beforeAll(async () => { // Check if Docker is available (required for SSH tests) if (!(await isDockerAvailable())) { throw new Error( - "Docker is required for SSH runtime tests. Please install Docker or skip tests by unsetting TEST_INTEGRATION." + "Docker is required for SSH runtime tests. Please install Docker or skip this test suite." ); } diff --git a/tests/ipc/workspace/init.test.ts b/tests/ipc/workspace/init.test.ts index 8884561534..97b54afd5d 100644 --- a/tests/ipc/workspace/init.test.ts +++ b/tests/ipc/workspace/init.test.ts @@ -1,11 +1,4 @@ -import { - shouldRunIntegrationTests, - createTestEnvironment, - cleanupTestEnvironment, - validateApiKeys, - getApiKey, - setupProviders, -} from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment, getApiKey, setupProviders } from "../setup"; import { generateBranchName, createWorkspace, @@ -32,13 +25,9 @@ import type { RuntimeConfig } from "../../../src/common/types/runtime"; import { sshConnectionPool } from "../../../src/node/runtime/sshConnectionPool"; import { ssh2ConnectionPool } from "../../../src/node/runtime/SSH2ConnectionPool"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; +jest.setTimeout(600_000); // Validate API keys for AI tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} /** * Create a temp git repo with a .mux/init hook that writes to stdout/stderr and exits with a given code @@ -118,7 +107,7 @@ async function cleanupTempGitRepo(repoPath: string): Promise { console.warn(`Failed to cleanup temp git repo after ${maxRetries} attempts:`, lastError); } -describeIntegration("Workspace init hook", () => { +describe("Workspace init hook", () => { test.concurrent( "should stream init hook output and allow workspace usage on hook success", async () => { @@ -385,7 +374,7 @@ describeIntegration("Workspace init hook", () => { // TODO: This test relies on timestamp-based event capture (sentEvents with timestamps) // which isn't available in the ORPC subscription model. The test verified real-time // streaming timing behavior. Consider reimplementing with StreamCollector timestamp tracking. -describeIntegration("Init timing behavior", () => { +describe("Init timing behavior", () => { test("should receive init events with natural timing (not batched)", async () => { const env = await createTestEnvironment(); // Create a repo with an init hook that outputs lines with delays @@ -450,7 +439,7 @@ let sshConfig: SSHServerConfig | undefined; // Runtime Matrix Tests - Init Queue Behavior // ============================================================================ -describeIntegration("Init Queue - Runtime Matrix", () => { +describe("Init Queue - Runtime Matrix", () => { beforeAll(async () => { // Only start SSH server if Docker is available if (await isDockerAvailable()) { diff --git a/tests/ipc/workspace/remove.test.ts b/tests/ipc/workspace/remove.test.ts index 4dee326b5d..41e206ecee 100644 --- a/tests/ipc/workspace/remove.test.ts +++ b/tests/ipc/workspace/remove.test.ts @@ -8,12 +8,7 @@ import * as fs from "fs/promises"; import * as path from "path"; import * as os from "os"; -import { - createTestEnvironment, - cleanupTestEnvironment, - shouldRunIntegrationTests, - type TestEnvironment, -} from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment, type TestEnvironment } from "../setup"; import { createTempGitRepo, cleanupTempGitRepo, @@ -38,9 +33,6 @@ import { sshConnectionPool } from "../../../src/node/runtime/sshConnectionPool"; import { ssh2ConnectionPool } from "../../../src/node/runtime/SSH2ConnectionPool"; import { execAsync } from "../../../src/node/utils/disposableExec"; -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // SSH server config (shared across all SSH tests) let sshConfig: SSHServerConfig | undefined; @@ -164,12 +156,12 @@ async function markerFileExists( // Test Suite // ============================================================================ -describeIntegration("Workspace deletion integration tests", () => { +describe("Workspace deletion integration tests", () => { beforeAll(async () => { // Check if Docker is available (required for SSH tests) if (!(await isDockerAvailable())) { throw new Error( - "Docker is required for SSH runtime tests. Please install Docker or skip tests by unsetting TEST_INTEGRATION." + "Docker is required for SSH runtime tests. Please install Docker or skip this test suite." ); } diff --git a/tests/ipc/workspace/rename.test.ts b/tests/ipc/workspace/rename.test.ts index 8e2357eabc..90f18ed8d1 100644 --- a/tests/ipc/workspace/rename.test.ts +++ b/tests/ipc/workspace/rename.test.ts @@ -10,7 +10,7 @@ * Uses real IPC handlers, real git operations, and Docker SSH server. */ -import { shouldRunIntegrationTests, createTestEnvironment, cleanupTestEnvironment } from "../setup"; +import { createTestEnvironment, cleanupTestEnvironment } from "../setup"; import { createTempGitRepo, cleanupTempGitRepo, @@ -32,9 +32,6 @@ import { ssh2ConnectionPool } from "../../../src/node/runtime/SSH2ConnectionPool // Test constants const TEST_TIMEOUT_MS = TEST_TIMEOUT_SSH_MS; // Use SSH timeout for consistency -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // SSH server config (shared across all SSH tests) let sshConfig: SSHServerConfig | undefined; @@ -42,12 +39,12 @@ let sshConfig: SSHServerConfig | undefined; // Tests // ============================================================================ -describeIntegration("WORKSPACE_RENAME with both runtimes", () => { +describe("WORKSPACE_RENAME with both runtimes", () => { beforeAll(async () => { // Check if Docker is available (required for SSH tests) if (!(await isDockerAvailable())) { throw new Error( - "Docker is required for SSH runtime tests. Please install Docker or skip tests by unsetting TEST_INTEGRATION." + "Docker is required for SSH runtime tests. Please install Docker or skip this test suite." ); } diff --git a/tests/run/smoke.integration.test.ts b/tests/run/smoke.integration.test.ts index fd2a31e1a3..9be4dce43d 100644 --- a/tests/run/smoke.integration.test.ts +++ b/tests/run/smoke.integration.test.ts @@ -10,17 +10,13 @@ import { spawn } from "child_process"; import * as path from "path"; import * as fs from "fs/promises"; import * as os from "os"; -import { shouldRunIntegrationTests, validateApiKeys } from "../testUtils"; +import { validateApiKeys } from "../testUtils"; const RUN_PATH = path.resolve(__dirname, "../../src/cli/run.ts"); -// Skip all tests if TEST_INTEGRATION is not set -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; +validateApiKeys(["ANTHROPIC_API_KEY"]); -// Validate API keys before running tests -if (shouldRunIntegrationTests()) { - validateApiKeys(["ANTHROPIC_API_KEY"]); -} +jest.setTimeout(600_000); interface ExecResult { stdout: string; @@ -76,7 +72,7 @@ async function runMuxRun( }); } -describeIntegration("mux run smoke tests", () => { +describe("mux run smoke tests", () => { let testDir: string; let muxRoot: string; diff --git a/tests/setup.ts b/tests/setup.ts index 9ac24cc345..5c6db01b9b 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -51,17 +51,5 @@ if (typeof globalThis.File === "undefined") { }; } -// Preload tokenizer and AI SDK modules for integration tests -// This eliminates ~10s initialization delay on first use -if (process.env.TEST_INTEGRATION === "1") { - // Store promise globally to ensure it blocks subsequent test execution - (globalThis as any).__muxPreloadPromise = (async () => { - const { preloadTestModules } = await import("./ipc/setup"); - await preloadTestModules(); - })(); - - // Add a global beforeAll to block until preload completes - beforeAll(async () => { - await (globalThis as any).__muxPreloadPromise; - }, 30000); // 30s timeout for preload -} +// Tests that need AI SDK preloading call preloadTestModules() in their own +// beforeAll hook — see tests/ipc/setup.ts. No global preload needed. diff --git a/tests/testUtils.js b/tests/testUtils.js deleted file mode 100644 index 4146d5803f..0000000000 --- a/tests/testUtils.js +++ /dev/null @@ -1,86 +0,0 @@ -"use strict"; -/** - * Shared test utilities for integration tests - * - * This module handles: - * - Loading .env configuration for tests - * - Checking TEST_INTEGRATION flag - * - Validating required API keys - */ -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -exports.shouldRunIntegrationTests = shouldRunIntegrationTests; -exports.validateApiKeys = validateApiKeys; -exports.getApiKey = getApiKey; -const dotenv_1 = require("dotenv"); -const path = __importStar(require("path")); -// Load .env from project root on module import -// This runs once when the module is first imported -(0, dotenv_1.config)({ path: path.resolve(__dirname, "../.env"), quiet: true }); -/** - * Check if integration tests should run - * Tests are skipped if TEST_INTEGRATION env var is not set - */ -function shouldRunIntegrationTests() { - return process.env.TEST_INTEGRATION === "1"; -} -/** - * Validate required API keys are present - * Throws if TEST_INTEGRATION is set but API keys are missing - */ -function validateApiKeys(requiredKeys) { - if (!shouldRunIntegrationTests()) { - return; // Skip validation if not running integration tests - } - const missing = requiredKeys.filter((key) => !process.env[key]); - if (missing.length > 0) { - throw new Error(`Integration tests require the following environment variables: ${missing.join(", ")}\n` + - `Please set them or unset TEST_INTEGRATION to skip these tests.`); - } -} -/** - * Get API key from environment or throw if missing (when TEST_INTEGRATION is set) - */ -function getApiKey(keyName) { - if (!shouldRunIntegrationTests()) { - throw new Error("getApiKey should only be called when TEST_INTEGRATION is set"); - } - const value = process.env[keyName]; - if (!value) { - throw new Error(`Environment variable ${keyName} is required for integration tests`); - } - return value; -} -//# sourceMappingURL=testUtils.js.map \ No newline at end of file diff --git a/tests/testUtils.js.map b/tests/testUtils.js.map deleted file mode 100644 index 5b70e5e645..0000000000 --- a/tests/testUtils.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"testUtils.js","sourceRoot":"","sources":["testUtils.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,mCAAgC;AAChC,MAAY,IAAI,iCAAa;AAE7B,+CAA+C;AAC/C,mDAAmD;AACnD,IAAA,eAAM,EAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAElE;;;GAGG;AACH,qCAAqD;IACnD,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,GAAG,CAAC;AAAA,CAC7C;AAED;;;GAGG;AACH,yBAAgC,YAAsB,EAAQ;IAC5D,IAAI,CAAC,yBAAyB,EAAE,EAAE,CAAC;QACjC,OAAO,CAAC,mDAAmD;IAC7D,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAEhE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,kEAAkE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YACtF,gEAAgE,CACnE,CAAC;IACJ,CAAC;AAAA,CACF;AAED;;GAEG;AACH,mBAA0B,OAAe,EAAU;IACjD,IAAI,CAAC,yBAAyB,EAAE,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,wBAAwB,OAAO,oCAAoC,CAAC,CAAC;IACvF,CAAC;IAED,OAAO,KAAK,CAAC;AAAA,CACd","sourcesContent":["/**\n * Shared test utilities for integration tests\n *\n * This module handles:\n * - Loading .env configuration for tests\n * - Checking TEST_INTEGRATION flag\n * - Validating required API keys\n */\n\nimport { config } from \"dotenv\";\nimport * as path from \"path\";\n\n// Load .env from project root on module import\n// This runs once when the module is first imported\nconfig({ path: path.resolve(__dirname, \"../.env\"), quiet: true });\n\n/**\n * Check if integration tests should run\n * Tests are skipped if TEST_INTEGRATION env var is not set\n */\nexport function shouldRunIntegrationTests(): boolean {\n return process.env.TEST_INTEGRATION === \"1\";\n}\n\n/**\n * Validate required API keys are present\n * Throws if TEST_INTEGRATION is set but API keys are missing\n */\nexport function validateApiKeys(requiredKeys: string[]): void {\n if (!shouldRunIntegrationTests()) {\n return; // Skip validation if not running integration tests\n }\n\n const missing = requiredKeys.filter((key) => !process.env[key]);\n\n if (missing.length > 0) {\n throw new Error(\n `Integration tests require the following environment variables: ${missing.join(\", \")}\\n` +\n `Please set them or unset TEST_INTEGRATION to skip these tests.`\n );\n }\n}\n\n/**\n * Get API key from environment or throw if missing (when TEST_INTEGRATION is set)\n */\nexport function getApiKey(keyName: string): string {\n if (!shouldRunIntegrationTests()) {\n throw new Error(\"getApiKey should only be called when TEST_INTEGRATION is set\");\n }\n\n const value = process.env[keyName];\n if (!value) {\n throw new Error(`Environment variable ${keyName} is required for integration tests`);\n }\n\n return value;\n}\n"]} \ No newline at end of file diff --git a/tests/testUtils.ts b/tests/testUtils.ts index d8375b4fe6..d416f5d429 100644 --- a/tests/testUtils.ts +++ b/tests/testUtils.ts @@ -3,7 +3,6 @@ * * This module handles: * - Loading .env configuration for tests - * - Checking TEST_INTEGRATION flag * - Validating required API keys */ @@ -15,40 +14,24 @@ import * as path from "path"; config({ path: path.resolve(__dirname, "../.env"), quiet: true }); /** - * Check if integration tests should run - * Tests are skipped if TEST_INTEGRATION env var is not set - */ -export function shouldRunIntegrationTests(): boolean { - return process.env.TEST_INTEGRATION === "1"; -} - -/** - * Validate required API keys are present - * Throws if TEST_INTEGRATION is set but API keys are missing + * Validate required API keys are present. + * Throws if any key is missing from the environment. */ export function validateApiKeys(requiredKeys: string[]): void { - if (!shouldRunIntegrationTests()) { - return; // Skip validation if not running integration tests - } - const missing = requiredKeys.filter((key) => !process.env[key]); if (missing.length > 0) { throw new Error( - `Integration tests require the following environment variables: ${missing.join(", ")}\n` + - `Please set them or unset TEST_INTEGRATION to skip these tests.` + `Missing required environment variables: ${missing.join(", ")}\n` + + `Set them in .env or the environment to run these tests.` ); } } /** - * Get API key from environment or throw if missing (when TEST_INTEGRATION is set) + * Get API key from environment or throw if missing. */ export function getApiKey(keyName: string): string { - if (!shouldRunIntegrationTests()) { - throw new Error("getApiKey should only be called when TEST_INTEGRATION is set"); - } - const value = process.env[keyName]; if (!value) { throw new Error(`Environment variable ${keyName} is required for integration tests`); diff --git a/tests/ui/agents/creationSlashCommands.test.ts b/tests/ui/agents/creationSlashCommands.test.ts index a6338d22b3..e396e6fae2 100644 --- a/tests/ui/agents/creationSlashCommands.test.ts +++ b/tests/ui/agents/creationSlashCommands.test.ts @@ -5,7 +5,6 @@ import "../dom"; import { waitFor } from "@testing-library/react"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -27,8 +26,6 @@ import { readPersistedState } from "@/browser/hooks/usePersistedState"; import { getDraftScopeId, getModelKey, getProjectScopeId } from "@/common/constants/storage"; import { MODEL_ABBREVIATIONS } from "@/common/constants/knownModels"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - type CreationView = { env: ReturnType; projectPath: string; @@ -61,7 +58,7 @@ async function setupCreationView(): Promise { }; } -describeIntegration("Creation slash commands", () => { +describe("Creation slash commands", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/agents/picker.test.ts b/tests/ui/agents/picker.test.ts index cdd5acce67..34c4230c18 100644 --- a/tests/ui/agents/picker.test.ts +++ b/tests/ui/agents/picker.test.ts @@ -15,7 +15,6 @@ import userEvent from "@testing-library/user-event"; import * as fs from "node:fs/promises"; import * as path from "node:path"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -33,8 +32,6 @@ import { setupWorkspaceView, } from "../helpers"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // ═══════════════════════════════════════════════════════════════════════════════ // HELPER FUNCTIONS // ═══════════════════════════════════════════════════════════════════════════════ @@ -170,7 +167,7 @@ async function removeAgentFile(workspacePath: string, agentId: string): Promise< // TESTS // ═══════════════════════════════════════════════════════════════════════════════ -describeIntegration("Agent Picker (UI)", () => { +describe("Agent Picker (UI)", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/agents/thinkingPersistence.test.ts b/tests/ui/agents/thinkingPersistence.test.ts index c05fb2b7ad..984dec6023 100644 --- a/tests/ui/agents/thinkingPersistence.test.ts +++ b/tests/ui/agents/thinkingPersistence.test.ts @@ -11,11 +11,8 @@ import { getModelKey } from "@/common/constants/storage"; import { readPersistedState } from "@/browser/hooks/usePersistedState"; import { formatModelDisplayName } from "@/common/utils/ai/modelDisplay"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { createAppHarness } from "../harness"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - const OPENAI_MODEL = "openai:gpt-5.2"; // Use Sonnet 4.5 as the model that caps at HIGH (4 levels, no xhigh). // Opus 4.6 supports xhigh so it can't be used to test clamping behavior. @@ -144,7 +141,7 @@ async function expectThinkingLabel(container: HTMLElement, expected: string): Pr ); } -describeIntegration("Thinking level persistence", () => { +describe("Thinking level persistence", () => { test("keeps XHIGH preference when switching away and back", async () => { const harness = await createAppHarness({ branchPrefix: "thinking" }); diff --git a/tests/ui/agents/thinkingPolicy.test.ts b/tests/ui/agents/thinkingPolicy.test.ts index 98a1272d62..198a70a496 100644 --- a/tests/ui/agents/thinkingPolicy.test.ts +++ b/tests/ui/agents/thinkingPolicy.test.ts @@ -14,11 +14,8 @@ import { PREFERRED_SYSTEM_1_THINKING_LEVEL_KEY, } from "@/common/constants/storage"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { createAppHarness } from "../harness"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - const GEMINI_FLASH_PREVIEW = "google:gemini-3-flash-preview"; /** @@ -32,7 +29,7 @@ const GEMINI_FLASH_PREVIEW = "google:gemini-3-flash-preview"; * - UI clamps display to "high" * - Dropdown does not include "xhigh" */ -describeIntegration("System 1 reasoning policy", () => { +describe("System 1 reasoning policy", () => { test("clamps and filters unsupported thinking levels for the selected model", async () => { const harness = await createAppHarness({ branchPrefix: "system1", diff --git a/tests/ui/chat/readMore.test.ts b/tests/ui/chat/readMore.test.ts index 61def59ab5..7e8a06dd32 100644 --- a/tests/ui/chat/readMore.test.ts +++ b/tests/ui/chat/readMore.test.ts @@ -12,7 +12,6 @@ import "../dom"; import { fireEvent, waitFor } from "@testing-library/react"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -27,8 +26,6 @@ import type { APIClient } from "@/browser/contexts/API"; import { updatePersistedState } from "@/browser/hooks/usePersistedState"; import { STORAGE_KEYS } from "@/constants/workspaceDefaults"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - type ExecuteBashResult = Awaited>; type ExecuteBashSuccess = Extract; type BashToolResult = ExecuteBashSuccess["data"]; @@ -221,7 +218,7 @@ git diff HEAD -- test-readmore.ts | grep -q "MODIFIED FOR TEST"`, // READ-MORE CONTEXT EXPANSION TESTS // ═══════════════════════════════════════════════════════════════════════════════ -describeIntegration("ReadMore context expansion (UI + ORPC)", () => { +describe("ReadMore context expansion (UI + ORPC)", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/chat/sections.test.ts b/tests/ui/chat/sections.test.ts index 259fc2c26f..f0900c5b18 100644 --- a/tests/ui/chat/sections.test.ts +++ b/tests/ui/chat/sections.test.ts @@ -20,7 +20,6 @@ import "../dom"; import { act, fireEvent, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -35,8 +34,6 @@ import { renderApp } from "../renderReviewPanel"; import { cleanupView, setupWorkspaceView } from "../helpers"; import { expandProjects } from "@/browser/stories/storyHelpers"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // ═══════════════════════════════════════════════════════════════════════════════ // HELPER FUNCTIONS // ═══════════════════════════════════════════════════════════════════════════════ @@ -132,7 +129,7 @@ async function createSectionViaAPI( // TESTS // ═══════════════════════════════════════════════════════════════════════════════ -describeIntegration("Workspace Sections", () => { +describe("Workspace Sections", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/chat/shareMessage.test.ts b/tests/ui/chat/shareMessage.test.ts index daaecfa5a5..b2d7b8fc64 100644 --- a/tests/ui/chat/shareMessage.test.ts +++ b/tests/ui/chat/shareMessage.test.ts @@ -9,20 +9,17 @@ */ import "../dom"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { uploadToMuxMd, deleteFromMuxMd, getMuxMdBaseUrl } from "../../../src/common/lib/muxMd"; if (process.env.CI && typeof jest !== "undefined" && jest.retryTimes) { jest.retryTimes(2, { logErrorsBeforeRetry: true }); } -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // ═══════════════════════════════════════════════════════════════════════════════ // MUX.MD UPLOAD TESTS // ═══════════════════════════════════════════════════════════════════════════════ -describeIntegration("mux.md sharing (upload integration)", () => { +describe("mux.md sharing (upload integration)", () => { test("should upload encrypted content and return valid URL", async () => { const testContent = "# Test Message\n\nThis is a test message for sharing.\n\n```typescript\nconst x = 42;\n```"; diff --git a/tests/ui/compaction/contextExceeded.test.ts b/tests/ui/compaction/contextExceeded.test.ts index e571c41269..303e94b722 100644 --- a/tests/ui/compaction/contextExceeded.test.ts +++ b/tests/ui/compaction/contextExceeded.test.ts @@ -8,7 +8,6 @@ import "../dom"; import { waitFor } from "@testing-library/react"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -23,9 +22,7 @@ import { PREFERRED_COMPACTION_MODEL_KEY } from "@/common/constants/storage"; import { KNOWN_MODELS } from "@/common/constants/knownModels"; import { setupProviders } from "../../ipc/setup"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("Context exceeded compaction suggestion (UI)", () => { +describe("Context exceeded compaction suggestion (UI)", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/config/customModels.test.ts b/tests/ui/config/customModels.test.ts index d9063a4622..abcc22ccf7 100644 --- a/tests/ui/config/customModels.test.ts +++ b/tests/ui/config/customModels.test.ts @@ -22,7 +22,6 @@ import { cleanup, render, waitFor } from "@testing-library/react"; import { APIProvider, useAPI } from "@/browser/contexts/API"; import { useProvidersConfig } from "@/browser/hooks/useProvidersConfig"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -31,8 +30,6 @@ import { import { installDom } from "../dom"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - function AddCustomModelHarness(props: { provider: string; modelId: string; @@ -69,7 +66,7 @@ function AddCustomModelHarness(props: { return React.createElement("div", { "data-testid": "harness" }, loading ? "loading" : "ready"); } -describeIntegration("Custom Models", () => { +describe("Custom Models", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/git/initBanner.test.ts b/tests/ui/git/initBanner.test.ts index 2da022dbaf..254cb6ca4c 100644 --- a/tests/ui/git/initBanner.test.ts +++ b/tests/ui/git/initBanner.test.ts @@ -10,7 +10,6 @@ import "../dom"; import { fireEvent, waitFor } from "@testing-library/react"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { installDom } from "../dom"; import { renderApp } from "../renderReviewPanel"; import { cleanupView, openProjectCreationView } from "../helpers"; @@ -19,15 +18,13 @@ import type { ProjectConfig } from "@/node/config"; import { expandProjects } from "@/browser/stories/storyHelpers"; import { DEFAULT_RUNTIME_CONFIG } from "@/common/constants/workspace"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - /** Helper to create a project config for a path with no workspaces */ function projectWithNoWorkspaces(path: string): [string, ProjectConfig] { return [path, { workspaces: [] }]; } -describeIntegration("Git Init Banner (UI)", () => { +describe("Git Init Banner (UI)", () => { test("shows git init banner when project is not a git repository", async () => { const cleanupDom = installDom(); diff --git a/tests/ui/git/status.test.ts b/tests/ui/git/status.test.ts index 9ea71285dc..7cf634d52f 100644 --- a/tests/ui/git/status.test.ts +++ b/tests/ui/git/status.test.ts @@ -1,5 +1,4 @@ import "../dom"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -23,8 +22,6 @@ import { } from "../helpers"; import { invalidateGitStatus } from "@/browser/stores/GitStatusStore"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - /** * Trigger git status refresh directly via store invalidation. * Window focus events don't work reliably in happy-dom, so we bypass @@ -34,7 +31,7 @@ function triggerGitStatusRefresh(workspaceId: string): void { invalidateGitStatus(workspaceId); } -describeIntegration("GitStatus (UI + ORPC)", () => { +describe("GitStatus (UI + ORPC)", () => { beforeAll(async () => { await createSharedRepo(); // Add fake origin for ahead/behind status tests diff --git a/tests/ui/layout/fileTreeViewMode.test.ts b/tests/ui/layout/fileTreeViewMode.test.ts index 35a360c190..c16664757c 100644 --- a/tests/ui/layout/fileTreeViewMode.test.ts +++ b/tests/ui/layout/fileTreeViewMode.test.ts @@ -1,7 +1,6 @@ import "../dom"; import { fireEvent, waitFor, within } from "@testing-library/react"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { STORAGE_KEYS } from "@/constants/workspaceDefaults"; import { REVIEW_FILE_TREE_VIEW_MODE_KEY } from "@/common/constants/storage"; import { updatePersistedState } from "@/browser/hooks/usePersistedState"; @@ -18,9 +17,7 @@ import { cleanupView, setupWorkspaceView } from "../helpers"; configureTestRetries(2); -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("ReviewPanel FileTree view mode (UI + ORPC)", () => { +describe("ReviewPanel FileTree view mode (UI + ORPC)", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/layout/leftSidebarResize.test.ts b/tests/ui/layout/leftSidebarResize.test.ts index ea58a3ee59..4b039c44ea 100644 --- a/tests/ui/layout/leftSidebarResize.test.ts +++ b/tests/ui/layout/leftSidebarResize.test.ts @@ -5,7 +5,6 @@ import "../dom"; import { fireEvent, waitFor } from "@testing-library/react"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -18,9 +17,7 @@ import { cleanupView, setupWorkspaceView } from "../helpers"; import { LEFT_SIDEBAR_COLLAPSED_KEY, LEFT_SIDEBAR_WIDTH_KEY } from "@/common/constants/storage"; import { updatePersistedState } from "@/browser/hooks/usePersistedState"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("LeftSidebar (UI)", () => { +describe("LeftSidebar (UI)", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/layout/rightSidebar.test.ts b/tests/ui/layout/rightSidebar.test.ts index aff0114d15..0fc8e76638 100644 --- a/tests/ui/layout/rightSidebar.test.ts +++ b/tests/ui/layout/rightSidebar.test.ts @@ -13,7 +13,6 @@ import "../dom"; import { fireEvent, waitFor } from "@testing-library/react"; -import { getApiKey, shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -38,10 +37,9 @@ import { import { updatePersistedState } from "@/browser/hooks/usePersistedState"; // RightSidebarLayoutState used for initial setup via persisted-state helpers - acceptable for test fixtures import type { RightSidebarLayoutState } from "@/browser/utils/rightSidebarLayout"; +import { getApiKey } from "../../testUtils"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("RightSidebar (UI)", () => { +describe("RightSidebar (UI)", () => { let env: TestEnvironment; let workspaceId: string; let metadata: FrontendWorkspaceMetadata; diff --git a/tests/ui/review/baseSelector.test.ts b/tests/ui/review/baseSelector.test.ts index f279752bf3..093a1b52b3 100644 --- a/tests/ui/review/baseSelector.test.ts +++ b/tests/ui/review/baseSelector.test.ts @@ -8,7 +8,6 @@ import "../dom"; import { fireEvent, waitFor } from "@testing-library/react"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, configureTestRetries, @@ -23,8 +22,6 @@ import type { FrontendWorkspaceMetadata } from "@/common/types/workspace"; configureTestRetries(2); -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - // ═══════════════════════════════════════════════════════════════════════════════ // HELPER FUNCTIONS // ═══════════════════════════════════════════════════════════════════════════════ @@ -117,7 +114,7 @@ function getDisplayedBase(container: HTMLElement): string { // BASE SELECTOR TESTS // ═══════════════════════════════════════════════════════════════════════════════ -describeIntegration("ReviewPanel base selector", () => { +describe("ReviewPanel base selector", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/review/focus.test.ts b/tests/ui/review/focus.test.ts index 639c61542c..5bae1419aa 100644 --- a/tests/ui/review/focus.test.ts +++ b/tests/ui/review/focus.test.ts @@ -1,7 +1,6 @@ import "../dom"; import { fireEvent, waitFor } from "@testing-library/react"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -12,9 +11,7 @@ import { installDom } from "../dom"; import { renderReviewPanel } from "../renderReviewPanel"; import { cleanupView, setupWorkspaceView } from "../helpers"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("ReviewPanel focus (UI + ORPC)", () => { +describe("ReviewPanel focus (UI + ORPC)", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/review/refresh.test.ts b/tests/ui/review/refresh.test.ts index 16df179130..c62d33527a 100644 --- a/tests/ui/review/refresh.test.ts +++ b/tests/ui/review/refresh.test.ts @@ -1,7 +1,6 @@ import "../dom"; import { fireEvent, waitFor } from "@testing-library/react"; -import { shouldRunIntegrationTests, validateApiKeys } from "../../testUtils"; import { STORAGE_KEYS } from "@/constants/workspaceDefaults"; import { getReviewsKey } from "@/common/constants/storage"; import { @@ -26,11 +25,10 @@ import { import type { APIClient } from "@/browser/contexts/API"; import type { FrontendWorkspaceMetadata } from "@/common/types/workspace"; import { readPersistedState, updatePersistedState } from "@/browser/hooks/usePersistedState"; +import { validateApiKeys } from "../../testUtils"; configureTestRetries(2); -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - validateApiKeys(["ANTHROPIC_API_KEY"]); /** @@ -72,7 +70,7 @@ function renderReviewPanelForRefreshTests(params: { }); } -describeIntegration("ReviewPanel manual refresh (UI + ORPC)", () => { +describe("ReviewPanel manual refresh (UI + ORPC)", () => { beforeAll(async () => { await createSharedRepo(); }); @@ -278,7 +276,7 @@ describeIntegration("ReviewPanel manual refresh (UI + ORPC)", () => { // SIMULATED TOOL COMPLETION TEST (fast, no LLM) // ═══════════════════════════════════════════════════════════════════════════════ -describeIntegration("ReviewPanel simulated tool refresh (UI + ORPC, no LLM)", () => { +describe("ReviewPanel simulated tool refresh (UI + ORPC, no LLM)", () => { beforeAll(async () => { await createSharedRepo(); }); @@ -428,7 +426,7 @@ describeIntegration("ReviewPanel simulated tool refresh (UI + ORPC, no LLM)", () // AUTO REFRESH TEST (slow, requires LLM) // ═══════════════════════════════════════════════════════════════════════════════ -describeIntegration("ReviewPanel auto refresh (UI + ORPC + live LLM)", () => { +describe("ReviewPanel auto refresh (UI + ORPC + live LLM)", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/runtime/docker.test.ts b/tests/ui/runtime/docker.test.ts index 381dac0e46..b18399678e 100644 --- a/tests/ui/runtime/docker.test.ts +++ b/tests/ui/runtime/docker.test.ts @@ -10,7 +10,6 @@ import "../dom"; import { fireEvent, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { installDom } from "../dom"; import { renderApp } from "../renderReviewPanel"; import { cleanupView, openProjectCreationView } from "../helpers"; @@ -18,8 +17,6 @@ import { createMockORPCClient } from "@/browser/stories/mocks/orpc"; import { expandProjects } from "@/browser/stories/storyHelpers"; import type { ProjectConfig } from "@/node/config"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - /** Helper to create a project config for a path with no workspaces */ function projectWithNoWorkspaces(path: string): [string, ProjectConfig] { return [path, { workspaces: [] }]; @@ -38,7 +35,7 @@ function findRuntimeButton(container: HTMLElement, label: string): HTMLButtonEle return (button ?? null) as HTMLButtonElement | null; } -describeIntegration("Docker runtime selection (UI)", () => { +describe("Docker runtime selection (UI)", () => { test("selecting Docker shows image input", async () => { const cleanupDom = installDom(); diff --git a/tests/ui/workspaces/draft.test.ts b/tests/ui/workspaces/draft.test.ts index 718f64491d..b4aa1b35cf 100644 --- a/tests/ui/workspaces/draft.test.ts +++ b/tests/ui/workspaces/draft.test.ts @@ -10,7 +10,6 @@ import "../dom"; import { fireEvent, waitFor } from "@testing-library/react"; import * as path from "node:path"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -24,8 +23,6 @@ import { updatePersistedState } from "@/browser/hooks/usePersistedState"; import { WORKSPACE_DRAFTS_BY_PROJECT_KEY } from "@/common/constants/storage"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - /** Wait for a specific number of drafts to exist */ async function waitForDraftCount(projectPath: string, count: number): Promise { return await waitFor( @@ -40,7 +37,7 @@ async function waitForDraftCount(projectPath: string, count: number): Promise { +describe("Draft workspace behavior", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/workspaces/fork.test.ts b/tests/ui/workspaces/fork.test.ts index d13798e084..4c4c15205d 100644 --- a/tests/ui/workspaces/fork.test.ts +++ b/tests/ui/workspaces/fork.test.ts @@ -9,15 +9,12 @@ import "../dom"; import { waitFor } from "@testing-library/react"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { preloadTestModules } from "../../ipc/setup"; import { generateBranchName } from "../../ipc/helpers"; import { createAppHarness } from "../harness"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("Workspace Fork (UI)", () => { +describe("Workspace Fork (UI)", () => { beforeAll(async () => { await preloadTestModules(); }); diff --git a/tests/ui/workspaces/lifecycle.test.ts b/tests/ui/workspaces/lifecycle.test.ts index ba669ac1cc..08fb230915 100644 --- a/tests/ui/workspaces/lifecycle.test.ts +++ b/tests/ui/workspaces/lifecycle.test.ts @@ -13,7 +13,6 @@ import "../dom"; import { fireEvent, waitFor } from "@testing-library/react"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -28,9 +27,7 @@ import { installDom } from "../dom"; import { renderApp } from "../renderReviewPanel"; import { cleanupView, openProjectCreationView, setupWorkspaceView } from "../helpers"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("Workspace Creation (UI)", () => { +describe("Workspace Creation (UI)", () => { beforeAll(async () => { await createSharedRepo(); }); @@ -101,7 +98,7 @@ describeIntegration("Workspace Creation (UI)", () => { }, 30_000); }); -describeIntegration("Workspace Archive (UI)", () => { +describe("Workspace Archive (UI)", () => { beforeAll(async () => { await createSharedRepo(); }); @@ -307,7 +304,7 @@ describeIntegration("Workspace Archive (UI)", () => { }, 30_000); }); -describeIntegration("Workspace Archive List Reactivity (UI)", () => { +describe("Workspace Archive List Reactivity (UI)", () => { beforeAll(async () => { await createSharedRepo(); }); @@ -466,7 +463,7 @@ describeIntegration("Workspace Archive List Reactivity (UI)", () => { }, 60_000); }); -describeIntegration("Workspace Delete from Archive (UI)", () => { +describe("Workspace Delete from Archive (UI)", () => { beforeAll(async () => { await createSharedRepo(); }); diff --git a/tests/ui/workspaces/nameGeneration.test.ts b/tests/ui/workspaces/nameGeneration.test.ts index eea3536c3c..871acc6dce 100644 --- a/tests/ui/workspaces/nameGeneration.test.ts +++ b/tests/ui/workspaces/nameGeneration.test.ts @@ -12,7 +12,6 @@ import "../dom"; import { act, waitFor } from "@testing-library/react"; -import { shouldRunIntegrationTests } from "../../testUtils"; import { cleanupSharedRepo, createSharedRepo, @@ -31,9 +30,7 @@ import { waitForLatestDraftId, } from "../helpers"; -const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; - -describeIntegration("Name generation UI flow", () => { +describe("Name generation UI flow", () => { beforeAll(async () => { await createSharedRepo(); }, 30_000);