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);