FN-5849: shard dashboard quality Vitest runs

Split the dashboard quality Vitest lane into bounded heap-managed shards to avoid signal exits.

- replace the single dashboard quality test command with sequential app and API shard scripts
- add a heap wrapper plus Vitest config shard definitions for foundation, component, App, ChatView, and SettingsModal coverage
- add guard tests for the sharded dashboard test configuration and restore spinner-animation.css.test.ts to foundation-ui coverage
- update the CLI package-config test expectations for the new dashboard test script layout

Files changed:
 packages/cli/src/__tests__/package-config.test.ts  |   8 +-
 packages/dashboard/package.json                    |  18 +-
 packages/dashboard/scripts/run-vitest-with-heap.mjs     |  41 ++++
 packages/dashboard/src/__tests__/dashboard-test-config-guard.test.ts  |  77 ++++++
 packages/dashboard/vitest.config.ts                | 273 ++++++++++++++++++++-
 5 files changed, 407 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-5849

Fusion-Task-Lineage: 522f3963-4647-4a59-bb6b-a3dacfbf620e
This commit is contained in:
gsxdsm
2026-06-02 00:53:39 -07:00
parent 04e1701d90
commit e549d7af30
5 changed files with 407 additions and 10 deletions

View File

@@ -272,10 +272,14 @@ describe("Workspace bootstrap script contract", () => {
it("keeps dashboard's default test lane curated with explicit deep coverage", () => { it("keeps dashboard's default test lane curated with explicit deep coverage", () => {
const defaultTest = dashboardPkg.scripts?.test; const defaultTest = dashboardPkg.scripts?.test;
const defaultAppQuality = dashboardPkg.scripts?.["test:quality:app"];
const defaultApiQuality = dashboardPkg.scripts?.["test:quality:api"];
const deepTest = dashboardPkg.scripts?.["test:deep"]; const deepTest = dashboardPkg.scripts?.["test:deep"];
expect(hasProjectArg(defaultTest, "dashboard-app-quality")).toBe(true); expect(defaultTest).toBe("pnpm run test:quality:app && pnpm run test:quality:api");
expect(hasProjectArg(defaultTest, "dashboard-api-quality")).toBe(true); expect(defaultAppQuality).toContain("test:quality:app:foundation-api");
expect(defaultAppQuality).toContain("test:quality:app:settings");
expect(hasProjectArg(defaultApiQuality, "dashboard-api-quality")).toBe(true);
expect(hasProjectArg(defaultTest, "dashboard-app")).toBe(false); expect(hasProjectArg(defaultTest, "dashboard-app")).toBe(false);
expect(hasProjectArg(defaultTest, "dashboard-api")).toBe(false); expect(hasProjectArg(defaultTest, "dashboard-api")).toBe(false);

View File

@@ -57,7 +57,23 @@
"dev": "pnpm build && pnpm typecheck && pnpm dev:serve", "dev": "pnpm build && pnpm typecheck && pnpm dev:serve",
"dev:serve": "vite dev", "dev:serve": "vite dev",
"pretest": "node ../../scripts/ensure-test-artifacts.mjs", "pretest": "node ../../scripts/ensure-test-artifacts.mjs",
"test": "vitest run --project dashboard-app-quality --project dashboard-api-quality --silent=passed-only --reporter=dot --exclude '**/build-output.test.ts'", "test": "pnpm run test:quality:app && pnpm run test:quality:api",
"test:quality:app": "pnpm run test:quality:app:foundation-api && pnpm run test:quality:app:foundation-ui && pnpm run test:quality:app:foundation-hooks-utils && pnpm run test:quality:app:components-a && pnpm run test:quality:app:components-b && pnpm run test:quality:app:app && pnpm run test:quality:app:chat && pnpm run test:quality:app:settings",
"test:quality:app:foundation-api": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-foundation-api --silent=passed-only --reporter=dot --exclude '**/build-output.test.ts'",
"test:quality:app:foundation-ui": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-foundation-ui --silent=passed-only --reporter=dot --exclude '**/build-output.test.ts'",
"test:quality:app:foundation-hooks-utils": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-foundation-hooks-utils --silent=passed-only --reporter=dot --exclude '**/build-output.test.ts'",
"test:quality:app:components-a": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-components-a --silent=passed-only --reporter=dot --exclude '**/build-output.test.ts'",
"test:quality:app:components-b": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-components-b --silent=passed-only --reporter=dot --exclude '**/build-output.test.ts'",
"test:quality:app:app": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-app --reporter=default --silent=passed-only --exclude '**/build-output.test.ts'",
"test:quality:app:chat": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-chat --reporter=default --silent=passed-only --exclude '**/build-output.test.ts'",
"test:quality:app:settings": "pnpm run test:quality:app:settings-a1 && pnpm run test:quality:app:settings-a2 && pnpm run test:quality:app:settings-a3 && pnpm run test:quality:app:settings-b && pnpm run test:quality:app:settings-c && pnpm run test:quality:app:settings-d",
"test:quality:app:settings-a1": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-settings --reporter=default --silent=passed-only --exclude '**/build-output.test.ts' -t \"applies keyboard CSS variables|defaults to the global General section|honors an explicit initialSection override|legacy pi-extensions initialSection alias|shows a Secrets entry|renders the SecretsView|direct merge commit routing|reuse-task-worktree when the server omits|persists cwd-main through the save payload|does NOT render the warning banner|legacy cwd-main mode is selected|removes the warning banner|legacy sibling branch rename escape hatch|agent provisioning approval settings|deferred settings fetches|Global General\"",
"test:quality:app:settings-a2": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-settings --reporter=default --silent=passed-only --exclude '**/build-output.test.ts' -t \"Project General|Appearance|Project Models\"",
"test:quality:app:settings-a3": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-settings --reporter=default --silent=passed-only --exclude '**/build-output.test.ts' -t \"settings header actions|settings version display|settings export filename\"",
"test:quality:app:settings-b": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-settings --reporter=default --silent=passed-only --exclude '**/build-output.test.ts' -t \"Authentication provider icon wrappers|Droid plugin Settings integration|Plugins section navigation\"",
"test:quality:app:settings-c": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-settings --reporter=default --silent=passed-only --exclude '**/build-output.test.ts' -t \"Scheduling overlap ignore paths|Number input clearing|Worktrunk integration|Memory section|Merge section|Experimental Features section\"",
"test:quality:app:settings-d": "node scripts/run-vitest-with-heap.mjs --heap=6144 run --project dashboard-app-quality-settings --reporter=default --silent=passed-only --exclude '**/build-output.test.ts' -t \"Remote section|Notifications provider cards|scheduled eval settings section|memory backups settings|research settings sections|memory dream trigger|plugin structured contribution contract fixtures\"",
"test:quality:api": "vitest run --project dashboard-api-quality --silent=passed-only --reporter=dot --exclude '**/build-output.test.ts'",
"test:app": "vitest run --project dashboard-app --silent=passed-only --reporter=dot --exclude '**/build-output.test.ts'", "test:app": "vitest run --project dashboard-app --silent=passed-only --reporter=dot --exclude '**/build-output.test.ts'",
"test:api": "vitest run --project dashboard-api --silent=passed-only --reporter=dot", "test:api": "vitest run --project dashboard-api --silent=passed-only --reporter=dot",
"test:deep": "vitest run --project dashboard-app --project dashboard-api --silent=passed-only --reporter=dot --exclude '**/build-output.test.ts'", "test:deep": "vitest run --project dashboard-app --project dashboard-api --silent=passed-only --reporter=dot --exclude '**/build-output.test.ts'",

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env node
/* global clearInterval, console, process, setInterval */
import { spawn } from "node:child_process";
const rawArgs = process.argv.slice(2);
const heapArg = rawArgs.find((arg) => arg.startsWith("--heap="));
const heapMb = heapArg?.slice("--heap=".length) || "6144";
const vitestArgs = rawArgs.filter((arg) => !arg.startsWith("--heap="));
if (vitestArgs.length === 0) {
console.error("Usage: node scripts/run-vitest-with-heap.mjs [--heap=6144] <vitest args...>");
process.exit(1);
}
const nodeOptions = [`--max-old-space-size=${heapMb}`, process.env.NODE_OPTIONS || ""]
.join(" ")
.trim();
const child = spawn("pnpm", ["exec", "vitest", ...vitestArgs], {
stdio: "inherit",
env: { ...process.env, NODE_OPTIONS: nodeOptions },
});
const heartbeat = setInterval(() => {
console.log(`[dashboard-vitest] still running: ${vitestArgs.join(" ")}`);
}, 5_000);
const forwardSignal = (signal) => {
child.kill(signal);
};
process.on("SIGINT", () => forwardSignal("SIGINT"));
process.on("SIGTERM", () => forwardSignal("SIGTERM"));
child.on("close", (code, signal) => {
clearInterval(heartbeat);
if (signal) {
process.kill(process.pid, signal);
return;
}
process.exit(code ?? 1);
});

View File

@@ -0,0 +1,77 @@
// @vitest-environment node
import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
const __dirname = dirname(fileURLToPath(import.meta.url));
const dashboardRoot = join(__dirname, "..", "..");
const dashboardPackageJsonPath = join(dashboardRoot, "package.json");
const vitestConfigPath = join(dashboardRoot, "vitest.config.ts");
function readDashboardPackageJson(): { scripts: Record<string, string> } {
return JSON.parse(readFileSync(dashboardPackageJsonPath, "utf8"));
}
describe("dashboard test config guard", () => {
it("keeps the dashboard quality gate split into sequential sub-runs", () => {
const { scripts } = readDashboardPackageJson();
expect(scripts.test).toBe("pnpm run test:quality:app && pnpm run test:quality:api");
expect(scripts["test:quality:app"]).toContain("test:quality:app:foundation-api");
expect(scripts["test:quality:app"]).toContain("test:quality:app:foundation-ui");
expect(scripts["test:quality:app"]).toContain("test:quality:app:foundation-hooks-utils");
expect(scripts["test:quality:app"]).toContain("test:quality:app:components-a");
expect(scripts["test:quality:app"]).toContain("test:quality:app:components-b");
expect(scripts["test:quality:app"]).toContain("test:quality:app:app");
expect(scripts["test:quality:app"]).toContain("test:quality:app:chat");
expect(scripts["test:quality:app"]).toContain("test:quality:app:settings");
expect(scripts["test:quality:app"]).not.toContain("dashboard-app-quality --project dashboard-api-quality");
});
it("pins every app-quality shard to the heap wrapper and keeps split settings shards", () => {
const { scripts } = readDashboardPackageJson();
for (const key of [
"test:quality:app:foundation-api",
"test:quality:app:foundation-ui",
"test:quality:app:foundation-hooks-utils",
"test:quality:app:components-a",
"test:quality:app:components-b",
"test:quality:app:app",
"test:quality:app:chat",
"test:quality:app:settings-a1",
"test:quality:app:settings-a2",
"test:quality:app:settings-a3",
"test:quality:app:settings-b",
"test:quality:app:settings-c",
"test:quality:app:settings-d",
]) {
expect(scripts[key]).toContain("node scripts/run-vitest-with-heap.mjs --heap=6144");
}
expect(scripts["test:quality:app:settings"]).toContain("settings-a1");
expect(scripts["test:quality:app:settings"]).toContain("settings-d");
});
it("keeps the split quality projects declared in vitest config", () => {
const vitestConfig = readFileSync(vitestConfigPath, "utf8");
for (const projectName of [
"dashboard-app-quality-foundation-api",
"dashboard-app-quality-foundation-ui",
"dashboard-app-quality-foundation-hooks-utils",
"dashboard-app-quality-components-a",
"dashboard-app-quality-components-b",
"dashboard-app-quality-app",
"dashboard-app-quality-chat",
"dashboard-app-quality-settings",
"dashboard-api-quality",
]) {
expect(vitestConfig).toContain(`name: \"${projectName}\"`);
}
expect(vitestConfig).toContain('"app/__tests__/spinner-animation.css.test.ts"');
});
});

View File

@@ -5,24 +5,211 @@ import { computeMaxWorkers } from "../core/src/__test-utils__/vitest-workers";
const maxWorkers = computeMaxWorkers({ defaultCap: 3 }); const maxWorkers = computeMaxWorkers({ defaultCap: 3 });
const qualityAppTests = [ const qualityAppFoundationApiTests = [
// Top-level API-client, mobile layout, styling, auth, and shell regressions. // API-client regressions are numerous but lightweight; keep them in their
"app/__tests__/*.test.{ts,tsx}", // own shard so the jsdom heap can reset before broader UI/layout coverage.
"app/__tests__/browser-layout-smoke-fixture.test.ts", "app/__tests__/api-*.test.ts",
"app/api/**/*.test.ts", "app/api/**/*.test.ts",
// Representative workflow/component coverage. Exhaustive modal/view suites ];
// stay available in the full `dashboard-app` project.
"app/components/__tests__/{ActiveAgentsPanel,ActivityLogModal,AgentMentionPopup,AgentMetricsBar,AgentOnboardingModal,AgentReflectionsTab,AgentTokenStatsPanel,App,AuthTokenRecoveryDialog,Board,board-mobile,board-mobile-view-switch,BranchGroupCard,ChatView,ChatView.autosize,ChatView.chat-input-autosize,ChatView.default-model-icon,ChatView.draft,ChatView.hash-mention,ChatView.rooms,ChatView.scroll-to-top,ChatView.swipe-back,Column,ConfirmDialog,ConversationHistory,DashboardLoader,DevServerView.mobile,DirectoryPicker,DuplicateWarningModal,ErrorBoundary,ExecutorStatusBar,FileBrowser,FileEditor,GitHubBadge,GroupTaskModal,InlineCreateCard,LoginInstructions,MemoryView,MergeAdvanceNotice,MessageComposer,MessageComposer.autosize,MobileNavBar,NewTaskModal,NewTaskModal.shared-cache,NodeCard,NodeHealthDot,NodeStatusIndicator,PlanningModeModal.autosize,PrChecksList,PrCreateModal,PrCreateModal.layout,ProjectCard,ProjectSelector,ProviderIcon,PrPanel,PrPanel.merge,PrPanel.reviews,QuickChatFAB,QuickChatFAB.shared-cache,ReliabilityView,ResearchView,SecretsView,SecretsView.mobile,SettingsModal,SettingsModal.testMode,SettingsModal.worktrunk,StashConflictModal,StashRecoveryView,TaskCard,TaskCard.badge-height,TaskCard.badge-wrap,TaskCard.footer-wrap,TaskChangesTab,TaskComments,TaskDetailModal,TaskDetailModal.allow-resurrection,TaskDetailModal.create-pr-e2e,TestModeBanner,TaskDetailModal.create-pr-integration,TaskDetailModal.github-tracking-header,TaskDetailModal.github-tracking-stale,TaskDetailModal.rebind-banner,TaskDocumentsTab,TaskForm,TaskIdIntegrityBanner,TrackingRepoSelect,WorkflowResultsTab,WorktrunkInstallApprovalDetails}.test.tsx", const qualityAppFoundationUiTests = [
// Top-level UI, auth, shell, mobile layout, and styling regressions.
// Keep these as explicit file paths: this shard completes reliably when the
// worker starts from a concrete file list instead of the broad glob.
"app/__tests__/AgentMentionPopup.css.test.ts",
"app/__tests__/App.boot-gate.test.tsx",
"app/__tests__/App.shell-onboarding.test.tsx",
"app/__tests__/ShellContext.test.tsx",
"app/__tests__/activity-feed-theme-styling.test.ts",
"app/__tests__/activity-log-mobile-layout.test.ts",
"app/__tests__/agent-css-classes.test.ts",
"app/__tests__/agent-runs-ui.test.ts",
"app/__tests__/auth.test.ts",
"app/__tests__/board-mobile-corner-rendering.test.ts",
"app/__tests__/board-tablet-overflow.test.ts",
"app/__tests__/browser-layout-smoke-fixture.test.ts",
"app/__tests__/chat-tool-calls-mobile-layout.test.ts",
"app/__tests__/column-fixed-width.test.ts",
"app/__tests__/component-css-no-raw-rgba.test.ts",
"app/__tests__/dashboard-component-color-tokenization.test.ts",
"app/__tests__/dashboard-footer-mobile-layout.test.ts",
"app/__tests__/detail-body-mobile-overflow.test.ts",
"app/__tests__/dev-server-layout-css.test.ts",
"app/__tests__/executor-status-bar-theme.test.ts",
"app/__tests__/footer-safe-layout.test.ts",
"app/__tests__/git-manager-theme-styling.test.ts",
"app/__tests__/index-html-theme-link.test.ts",
"app/__tests__/insight-model-selector.test.tsx",
"app/__tests__/lazy-loaded-views-docs.test.ts",
"app/__tests__/mission-planning-modals-mobile.test.ts",
"app/__tests__/mobile-bottom-bars-keyboard-layout.test.ts",
"app/__tests__/mobile-feature-access-regression.test.tsx",
"app/__tests__/mobile-header-controls.test.ts",
"app/__tests__/mobile-input-font-size.test.ts",
"app/__tests__/mobile-nav-bar-css.test.ts",
"app/__tests__/mobile-planning-input-font-size.test.ts",
"app/__tests__/mobile-scripts.test.ts",
"app/__tests__/mobile-scroll-snap.test.ts",
"app/__tests__/no-legacy-public.test.ts",
"app/__tests__/onboarding-overlay-layering.test.ts",
"app/__tests__/pwa.test.ts",
"app/__tests__/quick-chat-mobile-keyboard-layout.test.ts",
"app/__tests__/quick-chat-session-dropdown.test.ts",
"app/__tests__/quick-chat-tool-calls-mobile-layout.test.ts",
"app/__tests__/quick-entry-expanded-height.test.tsx",
"app/__tests__/settings-mobile-wrap.test.ts",
"app/__tests__/setup-wizard-modal-layout.test.ts",
"app/__tests__/shell-host.test.ts",
"app/__tests__/shell-native.test.ts",
"app/__tests__/spinner-animation.css.test.ts",
"app/__tests__/sse-bus.test.ts",
"app/__tests__/status-colors-theme.test.ts",
"app/__tests__/swUpdate.test.ts",
"app/__tests__/tablet-header-controls.test.tsx",
"app/__tests__/task-detail-modal-tablet-width.test.ts",
"app/__tests__/terminal-input.test.ts",
"app/__tests__/terminal-mobile-header-row.test.ts",
"app/__tests__/terminal-mobile-keyboard-layout.test.ts",
"app/__tests__/text-token-canonicalization.test.ts",
"app/__tests__/versionCheck.test.ts",
"app/__tests__/viewport-compensation-keyboard.test.ts",
];
const qualityAppHooksAndUtilsTests = [
// Hooks and utilities are fast, user-visible state/formatting behavior. // Hooks and utilities are fast, user-visible state/formatting behavior.
"app/context/**/*.test.tsx", "app/context/**/*.test.tsx",
"app/hooks/__tests__/{useAgents,useAgentLogs,useAgentLogs.resume-instrumentation,useAppSettings,useAuthOnboarding,useConfirm,useCurrentProject,useNodes,useNodes.resume-instrumentation,useNodeSettingsSync,useProjects,useProjects.resume-instrumentation,useMeshState.resume-instrumentation,useManagedDockerNodes.resume-instrumentation,usePrChecksStream.resume-instrumentation,useDevServerLogs.resume-instrumentation,useResearch.resume-instrumentation,useBackgroundSessions.resume-instrumentation,useQuickChat,useTasks,useTasks.resume-instrumentation,useChatRooms.resume-instrumentation,useTerminalSessions,useTheme,useToast,useUsageData,useViewState,useMergeAdvanceNotice}.test.{ts,tsx}", "app/hooks/__tests__/{useAgents,useAgentLogs,useAgentLogs.resume-instrumentation,useAppSettings,useAuthOnboarding,useConfirm,useCurrentProject,useNodes,useNodes.resume-instrumentation,useNodeSettingsSync,useProjects,useProjects.resume-instrumentation,useMeshState.resume-instrumentation,useManagedDockerNodes.resume-instrumentation,usePrChecksStream.resume-instrumentation,useDevServerLogs.resume-instrumentation,useResearch.resume-instrumentation,useBackgroundSessions.resume-instrumentation,useQuickChat,useTasks,useTasks.resume-instrumentation,useChatRooms.resume-instrumentation,useTerminalSessions,useTheme,useToast,useUsageData,useViewState,useMergeAdvanceNotice}.test.{ts,tsx}",
"app/utils/**/*.test.{ts,tsx}", "app/utils/**/*.test.{ts,tsx}",
]; ];
const qualityAppComponentTests = [
"ActiveAgentsPanel",
"ActivityLogModal",
"AgentMentionPopup",
"AgentMetricsBar",
"AgentOnboardingModal",
"AgentReflectionsTab",
"AgentTokenStatsPanel",
"App",
"AuthTokenRecoveryDialog",
"Board",
"board-mobile",
"board-mobile-view-switch",
"BranchGroupCard",
"ChatView",
"ChatView.autosize",
"ChatView.chat-input-autosize",
"ChatView.default-model-icon",
"ChatView.draft",
"ChatView.hash-mention",
"ChatView.rooms",
"ChatView.scroll-to-top",
"ChatView.swipe-back",
"Column",
"ConfirmDialog",
"ConversationHistory",
"DashboardLoader",
"DevServerView.mobile",
"DirectoryPicker",
"DuplicateWarningModal",
"ErrorBoundary",
"ExecutorStatusBar",
"FileBrowser",
"FileEditor",
"GitHubBadge",
"GroupTaskModal",
"InlineCreateCard",
"LoginInstructions",
"MemoryView",
"MergeAdvanceNotice",
"MessageComposer",
"MessageComposer.autosize",
"MobileNavBar",
"NewTaskModal",
"NewTaskModal.shared-cache",
"NodeCard",
"NodeHealthDot",
"NodeStatusIndicator",
"PlanningModeModal.autosize",
"PrChecksList",
"PrCreateModal",
"PrCreateModal.layout",
"ProjectCard",
"ProjectSelector",
"ProviderIcon",
"PrPanel",
"PrPanel.merge",
"PrPanel.reviews",
"QuickChatFAB",
"QuickChatFAB.shared-cache",
"ReliabilityView",
"ResearchView",
"SecretsView",
"SecretsView.mobile",
"SettingsModal",
"SettingsModal.testMode",
"SettingsModal.worktrunk",
"StashConflictModal",
"StashRecoveryView",
"TaskCard",
"TaskCard.badge-height",
"TaskCard.badge-wrap",
"TaskCard.footer-wrap",
"TaskChangesTab",
"TaskComments",
"TaskDetailModal",
"TaskDetailModal.allow-resurrection",
"TaskDetailModal.create-pr-e2e",
"TestModeBanner",
"TaskDetailModal.create-pr-integration",
"TaskDetailModal.github-tracking-header",
"TaskDetailModal.github-tracking-stale",
"TaskDetailModal.rebind-banner",
"TaskDocumentsTab",
"TaskForm",
"TaskIdIntegrityBanner",
"TrackingRepoSelect",
"WorkflowResultsTab",
"WorktrunkInstallApprovalDetails",
] as const;
const isolatedQualityAppComponentTests = ["App", "ChatView", "SettingsModal"] as const;
const batchedQualityAppComponentTests = qualityAppComponentTests.filter(
(testName) => !isolatedQualityAppComponentTests.includes(testName),
);
const batchedQualityAppSplitIndex = Math.ceil(batchedQualityAppComponentTests.length / 2);
const batchedQualityAppComponentTestsA = batchedQualityAppComponentTests.slice(0, batchedQualityAppSplitIndex);
const batchedQualityAppComponentTestsB = batchedQualityAppComponentTests.slice(batchedQualityAppSplitIndex);
function buildComponentQualityInclude(testNames: readonly string[]): string[] {
return testNames.length > 0
? [`app/components/__tests__/{${testNames.join(",")}}.test.tsx`]
: [];
}
const qualityAppTests = [
...qualityAppFoundationApiTests,
...qualityAppFoundationUiTests,
...qualityAppHooksAndUtilsTests,
...buildComponentQualityInclude(qualityAppComponentTests),
];
const qualityAppFoundationApiShardTests = [...qualityAppFoundationApiTests];
const qualityAppFoundationUiShardTests = [...qualityAppFoundationUiTests];
const qualityAppFoundationHooksAndUtilsTests = [...qualityAppHooksAndUtilsTests];
const qualityAppComponentBatchATests = buildComponentQualityInclude(batchedQualityAppComponentTestsA);
const qualityAppComponentBatchBTests = buildComponentQualityInclude(batchedQualityAppComponentTestsB);
const qualityAppAppOnlyTests = ["app/components/__tests__/App.test.tsx"];
const qualityAppChatOnlyTests = ["app/components/__tests__/ChatView.test.tsx"];
const qualityAppSettingsOnlyTests = ["app/components/__tests__/SettingsModal.test.tsx"];
const qualityApiTests = [ const qualityApiTests = [
// Critical HTTP/server behavior: auth, task/project/settings mutation, // Critical HTTP/server behavior: auth, task/project/settings mutation,
// git/GitHub, agents, nodes, chat/files, realtime, and isolation guards. // git/GitHub, agents, nodes, chat/files, realtime, and isolation guards.
"src/__tests__/{api-error,auth-middleware,auth-middleware-integration,chat-attachment-routes,chat-routes,file-service,github,github-webhooks,initialize,planning-flow-diagnostics-guardrail,pr-routes-auto-merge,pr-routes.contract,project-routes,project-store-resolver,register-git-github.pr-options-preflight-metadata,remote-access-routes,remote-auth,routes-agent-budget,routes-agent-keys,routes-agent-permissions,routes-agent-ratings,routes-agent-runs,routes-agent-soul-memory,routes-agents,routes-automation,routes-branch-groups,routes-git,routes-github,routes-merge-advance-push-origin,routes-nodes,routes-nodes-sync-contract,routes-planning,routes-secrets-sync,routes-settings,routes-task-commit-associations,routes-tasks,routes-tasks-deterministic-dedup,routes-tasks-duplicate-check,routes-tasks-explicit-duplicate-marker,server,server-static-assets,server-webhook,server.events,setup-routes,sse,sse-buffer,test-isolation-guard,update-check-route,websocket,recover-branch-binding-route}.test.ts", "src/__tests__/{api-error,auth-middleware,auth-middleware-integration,chat-attachment-routes,chat-routes,file-service,github,github-webhooks,initialize,planning-flow-diagnostics-guardrail,pr-routes-auto-merge,pr-routes.contract,project-routes,project-store-resolver,register-git-github.pr-options-preflight-metadata,remote-access-routes,remote-auth,routes-agent-budget,routes-agent-keys,routes-agent-permissions,routes-agent-ratings,routes-agent-runs,routes-agent-soul-memory,routes-agents,routes-automation,routes-branch-groups,routes-git,routes-github,routes-merge-advance-push-origin,routes-nodes,routes-nodes-sync-contract,routes-planning,routes-secrets-sync,routes-settings,routes-task-commit-associations,routes-tasks,routes-tasks-deterministic-dedup,routes-tasks-duplicate-check,routes-tasks-explicit-duplicate-marker,server,server-static-assets,server-webhook,server.events,setup-routes,sse,sse-buffer,test-isolation-guard,update-check-route,websocket,recover-branch-binding-route}.test.ts",
"src/__tests__/dashboard-test-config-guard.test.ts",
"src/routes/__tests__/{custom-provider-routes,custom-providers,register-docker-node-routes,register-diagnostics-routes,stash-recovery-routes}.test.ts", "src/routes/__tests__/{custom-provider-routes,custom-providers,register-docker-node-routes,register-diagnostics-routes,stash-recovery-routes}.test.ts",
]; ];
@@ -92,6 +279,78 @@ export default defineConfig({
css: { include: [/app\//] }, css: { include: [/app\//] },
}, },
}, },
{
extends: true,
test: {
name: "dashboard-app-quality-foundation-api",
environment: "jsdom",
include: qualityAppFoundationApiShardTests,
css: { include: [/app\//] },
},
},
{
extends: true,
test: {
name: "dashboard-app-quality-foundation-ui",
environment: "jsdom",
include: qualityAppFoundationUiShardTests,
css: { include: [/app\//] },
},
},
{
extends: true,
test: {
name: "dashboard-app-quality-foundation-hooks-utils",
environment: "jsdom",
include: qualityAppFoundationHooksAndUtilsTests,
css: { include: [/app\//] },
},
},
{
extends: true,
test: {
name: "dashboard-app-quality-components-a",
environment: "jsdom",
include: qualityAppComponentBatchATests,
css: { include: [/app\//] },
},
},
{
extends: true,
test: {
name: "dashboard-app-quality-components-b",
environment: "jsdom",
include: qualityAppComponentBatchBTests,
css: { include: [/app\//] },
},
},
{
extends: true,
test: {
name: "dashboard-app-quality-app",
environment: "jsdom",
include: qualityAppAppOnlyTests,
css: { include: [/app\//] },
},
},
{
extends: true,
test: {
name: "dashboard-app-quality-chat",
environment: "jsdom",
include: qualityAppChatOnlyTests,
css: { include: [/app\//] },
},
},
{
extends: true,
test: {
name: "dashboard-app-quality-settings",
environment: "jsdom",
include: qualityAppSettingsOnlyTests,
css: { include: [/app\//] },
},
},
{ {
extends: true, extends: true,
test: { test: {