diff --git a/config/scripts/ci-shard-timings.json b/config/scripts/ci-shard-timings.json index a78dd8f2ea4..00142ef9f5c 100644 --- a/config/scripts/ci-shard-timings.json +++ b/config/scripts/ci-shard-timings.json @@ -7326,7 +7326,6 @@ "src/renderer/src/components/confirmation-dialog.test.tsx": 979, "src/renderer/src/components/confirmation-skip-preference.test.ts": 141, "src/renderer/src/components/connect-dialog-outside-dismiss.test.tsx": 835, - "src/renderer/src/components/contextual-tours/ContextualTourControl.test.ts": 145, "src/renderer/src/components/contextual-tours/ContextualTourOverlay.remeasure.test.tsx": 2292, "src/renderer/src/components/contextual-tours/ContextualTourOverlay.test.tsx": 1598, "src/renderer/src/components/contextual-tours/ContextualTourOverlay.visibility.test.tsx": 1302, @@ -7349,7 +7348,6 @@ "src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-geometry.test.tsx": 1712, "src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-lifetime.test.tsx": 1564, "src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsx": 2249, - "src/renderer/src/components/dashboard-popout/DashboardHostBadge.test.tsx": 599, "src/renderer/src/components/dashboard-popout/DashboardPopoutRoot.test.tsx": 271, "src/renderer/src/components/dashboard-popout/agent-board-filtering.test.ts": 50, "src/renderer/src/components/dashboard-popout/dashboard-agent-status-patch.test.ts": 59, @@ -7464,7 +7462,6 @@ "src/renderer/src/components/editor/check-annotation-path.test.ts": 30, "src/renderer/src/components/editor/check-details-reading-viewport.test.ts": 192, "src/renderer/src/components/editor/check-job-step-status.test.ts": 31, - "src/renderer/src/components/editor/check-run-clipboard-text.test.ts": 56, "src/renderer/src/components/editor/check-run-details-fix-with-ai.test.ts": 674, "src/renderer/src/components/editor/check-run-details-tab.test.ts": 46, "src/renderer/src/components/editor/closed-editor-model-lifetime.test.ts": 7598, @@ -7492,7 +7489,6 @@ "src/renderer/src/components/editor/combined-diff/resolve-changes/combined-diff-section-cache-match.test.ts": 41, "src/renderer/src/components/editor/combined-diff/resolve-changes/combined-diff-section-scaling.test.tsx": 377, "src/renderer/src/components/editor/combined-diff/resolve-changes/use-combined-diff-section-index-map.test.tsx": 237, - "src/renderer/src/components/editor/combined-diff/review-controls/combined-diff-commit-message.test.ts": 55, "src/renderer/src/components/editor/combined-diff/review-controls/use-combined-diff-section-actions.disk-precondition.test.tsx": 1206, "src/renderer/src/components/editor/combined-diff/scroll-viewport/combined-diff-render-range.test.ts": 48, "src/renderer/src/components/editor/combined-diff/scroll-viewport/combined-diff-restore-signal-equivalence.test.tsx": 350, @@ -7639,7 +7635,6 @@ "src/renderer/src/components/editor/markdown-tokenizer-start.test.ts": 68, "src/renderer/src/components/editor/mermaid-config.test.ts": 579, "src/renderer/src/components/editor/monaco-auto-height.test.ts": 110, - "src/renderer/src/components/editor/monaco-codebase-search.test.ts": 60, "src/renderer/src/components/editor/monaco-conflict-decorations.test.ts": 41, "src/renderer/src/components/editor/monaco-content-sync.test.ts": 33, "src/renderer/src/components/editor/monaco-content-sync.undo-history.test.ts": 996, @@ -7873,7 +7868,6 @@ "src/renderer/src/components/host-picker/host-list-surfaces.large-config.test.tsx": 1713, "src/renderer/src/components/jira-attachment-image.test.tsx": 1521, "src/renderer/src/components/jira-connect-scoped-token.test.tsx": 492, - "src/renderer/src/components/jira-create-adf.test.ts": 27, "src/renderer/src/components/jira-issue-assignee-control.test.tsx": 2380, "src/renderer/src/components/jira-issue-transition-control.test.tsx": 651, "src/renderer/src/components/jira-issue-workspace-actions.test.ts": 123, @@ -8038,7 +8032,6 @@ "src/renderer/src/components/native-chat/StructuredAgentSessionStatusBridge.test.tsx": 1855, "src/renderer/src/components/native-chat/agent-session-failure-words-text.test.ts": 875, "src/renderer/src/components/native-chat/agent-session-write-notice-text.test.ts": 935, - "src/renderer/src/components/native-chat/background-task-words-text.test.ts": 151, "src/renderer/src/components/native-chat/claude-model-switch-confirmation.test.ts": 1546, "src/renderer/src/components/native-chat/claude-terminal-session-options.test.ts": 62, "src/renderer/src/components/native-chat/native-chat-active-rail-item.test.ts": 31, @@ -8069,7 +8062,6 @@ "src/renderer/src/components/native-chat/native-chat-composer-upload-completion.test.tsx": 2200, "src/renderer/src/components/native-chat/native-chat-composer-workspace-file-drop.test.tsx": 662, "src/renderer/src/components/native-chat/native-chat-context-command.test.tsx": 342, - "src/renderer/src/components/native-chat/native-chat-context-usage-summary.test.ts": 33, "src/renderer/src/components/native-chat/native-chat-diff.test.ts": 68, "src/renderer/src/components/native-chat/native-chat-dismiss-key.test.ts": 40, "src/renderer/src/components/native-chat/native-chat-draft-cache.test.ts": 153, @@ -8140,7 +8132,6 @@ "src/renderer/src/components/native-chat/native-chat-structured-session-notices.command-failure.test.tsx": 1670, "src/renderer/src/components/native-chat/native-chat-structured-session-notices.create-message.test.tsx": 1828, "src/renderer/src/components/native-chat/native-chat-subagent-delegation.test.ts": 45, - "src/renderer/src/components/native-chat/native-chat-subagent-group-words-text.test.ts": 189, "src/renderer/src/components/native-chat/native-chat-subagent-handoff-copy-budget.test.ts": 521, "src/renderer/src/components/native-chat/native-chat-subagent-section-work-runs.test.ts": 202, "src/renderer/src/components/native-chat/native-chat-subagent-sections-retention.test.ts": 609, @@ -8340,7 +8331,6 @@ "src/renderer/src/components/pet/PetOverlay.keyframes.test.tsx": 620, "src/renderer/src/components/pet/PetOverlay.pet-switch.test.tsx": 185, "src/renderer/src/components/pet/PetOverlay.pointer-interaction.test.tsx": 195, - "src/renderer/src/components/pet/PetOverlay.test.ts": 306, "src/renderer/src/components/pet/pet-blob-cache.test.ts": 55, "src/renderer/src/components/pet/pet-overlay-hit-area.test.tsx": 228, "src/renderer/src/components/pet/pet-overlay-visibility.test.ts": 46, @@ -8377,7 +8367,6 @@ "src/renderer/src/components/right-sidebar/AiVaultPanel.legacy-filter.test.tsx": 2390, "src/renderer/src/components/right-sidebar/AiVaultPanelHeader.focus.test.tsx": 386, "src/renderer/src/components/right-sidebar/AiVaultPanelSearch.test.tsx": 469, - "src/renderer/src/components/right-sidebar/AiVaultScanIssueBanners.test.tsx": 333, "src/renderer/src/components/right-sidebar/AiVaultScanProgressStrip.test.tsx": 732, "src/renderer/src/components/right-sidebar/AiVaultSearchEvidence.test.tsx": 2230, "src/renderer/src/components/right-sidebar/AiVaultSessionActionMenuItems.test.tsx": 663, @@ -8396,12 +8385,10 @@ "src/renderer/src/components/right-sidebar/CommitArea.generate.test.tsx": 1781, "src/renderer/src/components/right-sidebar/CommitArea.test.tsx": 8618, "src/renderer/src/components/right-sidebar/FileExplorerFilesTreePane.errors.test.tsx": 3001, - "src/renderer/src/components/right-sidebar/FileExplorerNameFilter.test.tsx": 197, "src/renderer/src/components/right-sidebar/FileExplorerQueryStrip.focus.test.tsx": 530, "src/renderer/src/components/right-sidebar/FileExplorerRow.actions.test.tsx": 287, "src/renderer/src/components/right-sidebar/FileExplorerScopeNotice.test.tsx": 480, "src/renderer/src/components/right-sidebar/FileExplorerToolbar.test.tsx": 1475, - "src/renderer/src/components/right-sidebar/FileExplorerViewSwitch.test.tsx": 133, "src/renderer/src/components/right-sidebar/FileExplorerVirtualRows.row-handlers.test.tsx": 2029, "src/renderer/src/components/right-sidebar/FileExplorerVirtualRowsAddProject.test.tsx": 1985, "src/renderer/src/components/right-sidebar/FolderWorkspacePrChecksPanel.test.tsx": 809, @@ -8511,7 +8498,6 @@ "src/renderer/src/components/right-sidebar/file-explorer-directory-listing.test.ts": 1367, "src/renderer/src/components/right-sidebar/file-explorer-display-root.test.ts": 1535, "src/renderer/src/components/right-sidebar/file-explorer-drag-scroll-marker.test.tsx": 2184, - "src/renderer/src/components/right-sidebar/file-explorer-entries.test.ts": 46, "src/renderer/src/components/right-sidebar/file-explorer-expanded-dirs-refresh.test.ts": 1349, "src/renderer/src/components/right-sidebar/file-explorer-inline-input-ime-enter.test.tsx": 465, "src/renderer/src/components/right-sidebar/file-explorer-inline-input-outside-click.test.tsx": 197, @@ -8557,7 +8543,6 @@ "src/renderer/src/components/right-sidebar/plugin-panel-watchdog-visibility.test.ts": 457, "src/renderer/src/components/right-sidebar/plugin-panel-watchdog.test.ts": 131, "src/renderer/src/components/right-sidebar/ports-panel-host.test.ts": 182, - "src/renderer/src/components/right-sidebar/pr-comment-ack-summary.test.ts": 36, "src/renderer/src/components/right-sidebar/pr-comment-snapshotted-thread-resolver.test.ts": 63, "src/renderer/src/components/right-sidebar/pr-comment-thread-resolution.test.ts": 29, "src/renderer/src/components/right-sidebar/pr-comments-ai-launch-ack.test.ts": 75, @@ -8566,7 +8551,6 @@ "src/renderer/src/components/right-sidebar/review-cache-entry-selection.test.ts": 24, "src/renderer/src/components/right-sidebar/right-panel-comment-composer.ime-enter.test.tsx": 273, "src/renderer/src/components/right-sidebar/right-panel-comment-focus-timers.test.ts": 82, - "src/renderer/src/components/right-sidebar/right-sidebar-activity-visibility.test.ts": 77, "src/renderer/src/components/right-sidebar/right-sidebar-effective-tab.test.ts": 34, "src/renderer/src/components/right-sidebar/right-sidebar-titlebar-drag-regions.render.test.tsx": 591, "src/renderer/src/components/right-sidebar/right-sidebar-width.test.ts": 61, @@ -8590,7 +8574,6 @@ "src/renderer/src/components/right-sidebar/source-control-entry-context-menu.test.tsx": 367, "src/renderer/src/components/right-sidebar/source-control-file-filter.test.ts": 46, "src/renderer/src/components/right-sidebar/source-control-header-toolbar-identity.test.tsx": 346, - "src/renderer/src/components/right-sidebar/source-control-header-toolbar.test.ts": 229, "src/renderer/src/components/right-sidebar/source-control-hosted-review-creation-eligibility-snapshot.test.ts": 87, "src/renderer/src/components/right-sidebar/source-control-hosted-review-push-target.test.ts": 52, "src/renderer/src/components/right-sidebar/source-control-huge-repo-warning-dismissals.test.ts": 150, @@ -8813,7 +8796,6 @@ "src/renderer/src/components/settings/TerminalAdvancedSection.test.tsx": 2069, "src/renderer/src/components/settings/TerminalAppearanceSection.ghostty.test.ts": 490, "src/renderer/src/components/settings/TerminalContrastSetting.test.tsx": 526, - "src/renderer/src/components/settings/TerminalFontSizeSetting.test.tsx": 1623, "src/renderer/src/components/settings/TerminalPane.pwsh.test.ts": 530, "src/renderer/src/components/settings/TerminalPane.section-lifetime.test.tsx": 757, "src/renderer/src/components/settings/TerminalSettingsPreview.lifecycle.test.tsx": 318, @@ -9105,7 +9087,6 @@ "src/renderer/src/components/sidebar/project-header-drag-start.test.ts": 147, "src/renderer/src/components/sidebar/project-header-drop.test.ts": 212, "src/renderer/src/components/sidebar/project-move-pause-follower.test.ts": 563, - "src/renderer/src/components/sidebar/project-order-manual-default-notice-visibility.test.ts": 34, "src/renderer/src/components/sidebar/prompt-cache-countdown-clock.test.ts": 62, "src/renderer/src/components/sidebar/remote-file-browser-drive-paths.test.ts": 47, "src/renderer/src/components/sidebar/remote-file-browser-helpers.test.ts": 174, @@ -9197,7 +9178,6 @@ "src/renderer/src/components/sidebar/worktree-card-compact-agent-row.stable-message.test.tsx": 2596, "src/renderer/src/components/sidebar/worktree-card-details-hover-state.test.tsx": 166, "src/renderer/src/components/sidebar/worktree-card-dom-events.test.ts": 115, - "src/renderer/src/components/sidebar/worktree-card-jira-issue-display.test.ts": 48, "src/renderer/src/components/sidebar/worktree-card-option-items.test.tsx": 266, "src/renderer/src/components/sidebar/worktree-card-pr-display.test.ts": 77, "src/renderer/src/components/sidebar/worktree-card-send-target-inputs.test.ts": 26, @@ -9583,7 +9563,6 @@ "src/renderer/src/components/task-page/jira/IssueAssigneeField.test.tsx": 1003, "src/renderer/src/components/task-page/jira/IssueUserField.test.tsx": 2183, "src/renderer/src/components/task-page/linear/task-page-linear-in-orca-issues.test.ts": 98, - "src/renderer/src/components/task-page/linear/task-page-linear-issue-empty-state.test.ts": 36, "src/renderer/src/components/task-page/linear/task-page-linear-issue-grouping.test.ts": 1441, "src/renderer/src/components/task-page/linear/task-page-linear-issue-request.test.ts": 57, "src/renderer/src/components/task-page/linear/task-page-linear-team-selection.test.ts": 46, @@ -10255,7 +10234,6 @@ "src/renderer/src/components/workspace-cleanup/workspace-cleanup-confirm-remove.test.tsx": 658, "src/renderer/src/components/workspace-cleanup/workspace-cleanup-confirm-stop-agents.test.tsx": 343, "src/renderer/src/components/workspace-cleanup/workspace-cleanup-deletion-phases.test.ts": 127, - "src/renderer/src/components/workspace-cleanup/workspace-cleanup-dialog-notices.test.tsx": 571, "src/renderer/src/components/workspace-cleanup/workspace-cleanup-facet-controls.test.tsx": 601, "src/renderer/src/components/workspace-cleanup/workspace-cleanup-facet-filter.test.ts": 107, "src/renderer/src/components/workspace-cleanup/workspace-cleanup-facet-sort.test.ts": 127, diff --git a/src/main/synthetic-title-spinner.test.ts b/src/main/synthetic-title-spinner.test.ts index 449d1ad0f1d..122f22652b8 100644 --- a/src/main/synthetic-title-spinner.test.ts +++ b/src/main/synthetic-title-spinner.test.ts @@ -6,26 +6,6 @@ import { } from './synthetic-title-spinner' describe('advanceSyntheticTitleSpinnerEntries', () => { - it('advances live panes in one shared tick and wraps frames', () => { - const entries = new Map>([ - ['pane-a', { frame: 1, profile: { label: 'A' } }], - ['pane-b', { frame: 2, profile: { label: 'B' } }] - ]) - - const ticks = advanceSyntheticTitleSpinnerEntries({ - entries, - frameCount: 3, - getPtyIdForPaneKey: (paneKey) => `pty-${paneKey}` - }) - - expect(ticks).toEqual([ - { paneKey: 'pane-a', ptyId: 'pty-pane-a', frame: 2, profile: { label: 'A' } }, - { paneKey: 'pane-b', ptyId: 'pty-pane-b', frame: 0, profile: { label: 'B' } } - ]) - expect(entries.get('pane-a')?.frame).toBe(2) - expect(entries.get('pane-b')?.frame).toBe(0) - }) - it('drops panes whose pty mapping disappeared', () => { const entries = new Map>([ ['live-pane', { frame: 0, profile: { label: 'live' } }], @@ -47,10 +27,6 @@ describe('advanceSyntheticTitleSpinnerEntries', () => { }) describe('getSyntheticTitleSpinnerPaneKeyToStop', () => { - it('retires the spinner of a pane-scoped clear', () => { - expect(getSyntheticTitleSpinnerPaneKeyToStop({ paneKey: 'pane-a' })).toBe('pane-a') - }) - it('keeps pane spinners running for a connection-scoped transient clear', () => { expect( getSyntheticTitleSpinnerPaneKeyToStop({ diff --git a/src/main/tray/tray-dev-badge.test.ts b/src/main/tray/tray-dev-badge.test.ts index e683c6d6b5c..7e87d0c975f 100644 --- a/src/main/tray/tray-dev-badge.test.ts +++ b/src/main/tray/tray-dev-badge.test.ts @@ -26,14 +26,6 @@ function fakeTemplate(width: number, height: number) { } describe('stampTrayDevBadge', () => { - it('returns the base unchanged when it has no pixels', () => { - createFromBitmapMock.mockClear() - const base = { getSize: () => ({ width: 0, height: 0 }), toBitmap: () => Buffer.alloc(0) } - - expect(stampTrayDevBadge(base as never)).toBe(base) - expect(createFromBitmapMock).not.toHaveBeenCalled() - }) - it('keeps the template canvas size and stamps opaque template-black pixels', () => { createFromBitmapMock.mockClear() const width = 22 diff --git a/src/main/warp-themes/manual-warp-theme-files.test.ts b/src/main/warp-themes/manual-warp-theme-files.test.ts index 097cf631723..58643cab844 100644 --- a/src/main/warp-themes/manual-warp-theme-files.test.ts +++ b/src/main/warp-themes/manual-warp-theme-files.test.ts @@ -31,17 +31,4 @@ describe('manual theme ordering', () => { vi.restoreAllMocks() } }) - - it('returns a single dialog selection without collating', () => { - const construct = vi.spyOn(Intl, 'Collator') - try { - expect(createManualWarpThemeFileCandidates([]).map((file) => file.path)).toEqual([]) - expect(createManualWarpThemeFileCandidates(['a/one.yaml']).map((file) => file.path)).toEqual([ - 'a/one.yaml' - ]) - expect(construct).not.toHaveBeenCalled() - } finally { - vi.restoreAllMocks() - } - }) }) diff --git a/src/renderer/src/components/comment-code-context-state.test.ts b/src/renderer/src/components/comment-code-context-state.test.ts index 7df60f7e4b9..3981a5b7498 100644 --- a/src/renderer/src/components/comment-code-context-state.test.ts +++ b/src/renderer/src/components/comment-code-context-state.test.ts @@ -6,23 +6,6 @@ import { } from './comment-code-context-state' describe('comment code context expansion state', () => { - it('keeps expanded context for the same comment', () => { - const expanded = updateCommentCodeContextExpansionState( - createCommentCodeContextExpansionState('comment-1'), - 'comment-1', - { - contextBefore: 5, - contextAfter: 3 - } - ) - - expect(resolveCommentCodeContextExpansionState(expanded, 'comment-1')).toEqual({ - commentId: 'comment-1', - contextBefore: 5, - contextAfter: 3 - }) - }) - it('resets expansion when a rendered row switches comments', () => { const expanded = updateCommentCodeContextExpansionState( createCommentCodeContextExpansionState('comment-1'), diff --git a/src/renderer/src/components/contextual-tours/ContextualTourControl.test.ts b/src/renderer/src/components/contextual-tours/ContextualTourControl.test.ts deleted file mode 100644 index 0b9c2fb4e2f..00000000000 --- a/src/renderer/src/components/contextual-tours/ContextualTourControl.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { describe, expect, it, vi, afterEach } from 'vitest' -import { toggleAutoRenameBranchFromWork } from './ContextualTourControl' -import { CONTEXTUAL_TOUR_ENABLE_AUTO_WORKSPACE_NAME_EVENT } from './contextual-tour-composer-events' - -describe('toggleAutoRenameBranchFromWork', () => { - it('clears the generated workspace name when enabling first-message auto-name', () => { - const updateSettings = vi.fn() - const dispatchEvent = vi.fn() - - toggleAutoRenameBranchFromWork({ - enabled: false, - updateSettings, - dispatchEvent - }) - - expect(updateSettings).toHaveBeenCalledWith({ autoRenameBranchFromWork: true }) - expect(dispatchEvent).toHaveBeenCalledTimes(1) - expect(dispatchEvent.mock.calls[0]?.[0]).toMatchObject({ - type: CONTEXTUAL_TOUR_ENABLE_AUTO_WORKSPACE_NAME_EVENT - }) - }) - - it('does not clear the workspace name when disabling first-message auto-name', () => { - const updateSettings = vi.fn() - const dispatchEvent = vi.fn() - - toggleAutoRenameBranchFromWork({ - enabled: true, - updateSettings, - dispatchEvent - }) - - expect(updateSettings).toHaveBeenCalledWith({ autoRenameBranchFromWork: false }) - expect(dispatchEvent).not.toHaveBeenCalled() - }) -}) - -const { rejectAppStoreAccess } = vi.hoisted(() => ({ - rejectAppStoreAccess: vi.fn(() => { - throw new Error('Pure helper tests must not access the app store') - }) -})) - -vi.mock('@/store', () => ({ - useAppStore: Object.assign(rejectAppStoreAccess, { - getState: rejectAppStoreAccess, - getInitialState: rejectAppStoreAccess, - setState: rejectAppStoreAccess, - subscribe: rejectAppStoreAccess - }) -})) - -afterEach(() => { - expect(rejectAppStoreAccess).not.toHaveBeenCalled() -}) diff --git a/src/renderer/src/components/dashboard-popout/DashboardHostBadge.test.tsx b/src/renderer/src/components/dashboard-popout/DashboardHostBadge.test.tsx deleted file mode 100644 index 08211439eb7..00000000000 --- a/src/renderer/src/components/dashboard-popout/DashboardHostBadge.test.tsx +++ /dev/null @@ -1,54 +0,0 @@ -// @vitest-environment happy-dom - -import '@testing-library/jest-dom/vitest' -import { cleanup, fireEvent, render, screen } from '@testing-library/react' -import { afterEach, describe, expect, it } from 'vitest' -import { TooltipProvider } from '@/components/ui/tooltip' -import { DashboardHostBadge } from './DashboardHostBadge' - -afterEach(cleanup) - -describe('DashboardHostBadge', () => { - it('names a saved SSH host in its focusable tooltip', async () => { - render( - - - - ) - - const badge = screen.getByLabelText('SSH host · openclaw') - expect(badge).toHaveAttribute('data-dashboard-host-badge', 'ssh') - expect(badge.querySelector('.lucide-server')).toBeInTheDocument() - - fireEvent.focus(badge) - expect(await screen.findByRole('tooltip')).toHaveTextContent('SSH host · openclaw') - }) - - it('distinguishes paired Orca hosts and omits local hosts', () => { - const { rerender } = render( - - - - ) - - const badge = screen.getByLabelText('Remote Orca host · Build Mac') - expect(badge).toHaveAttribute('data-dashboard-host-badge', 'remote') - expect(badge.querySelector('.lucide-server')).toBeInTheDocument() - - rerender( - - - - ) - expect(screen.queryByLabelText(/host/i)).not.toBeInTheDocument() - }) -}) diff --git a/src/renderer/src/components/dictation/dictation-audio-meter.test.ts b/src/renderer/src/components/dictation/dictation-audio-meter.test.ts index 031690af7fe..2c4e5bba937 100644 --- a/src/renderer/src/components/dictation/dictation-audio-meter.test.ts +++ b/src/renderer/src/components/dictation/dictation-audio-meter.test.ts @@ -1,8 +1,7 @@ import { describe, expect, it } from 'vitest' import { analyzeDictationAudioChunk, - createDictationMeterAnalyzerState, - toPublicDictationMeterState + createDictationMeterAnalyzerState } from './dictation-audio-meter' describe('dictation audio meter', () => { @@ -27,18 +26,4 @@ describe('dictation audio meter', () => { expect(held.isClipping).toBe(true) expect(released.isClipping).toBe(false) }) - - it('publishes only presentation-safe meter fields', () => { - const analyzed = analyzeDictationAudioChunk( - new Float32Array(128).fill(0.25), - 250, - createDictationMeterAnalyzerState() - ) - - expect(toPublicDictationMeterState(analyzed)).toEqual({ - level: Math.round(analyzed.level * 100) / 100, - isSpeaking: analyzed.isSpeaking, - isClipping: analyzed.isClipping - }) - }) }) diff --git a/src/renderer/src/components/editor/CheckRunCopyButton.test.tsx b/src/renderer/src/components/editor/CheckRunCopyButton.test.tsx index d5dcf8125e5..5fe47429db6 100644 --- a/src/renderer/src/components/editor/CheckRunCopyButton.test.tsx +++ b/src/renderer/src/components/editor/CheckRunCopyButton.test.tsx @@ -38,13 +38,4 @@ describe('CheckRunCopyButton', () => { ) expect(await screen.findByRole('button', { name: 'Copied' })).toBeDefined() }) - - it('disables the action when there is no card text', () => { - renderCopyButton('') - - const copyButton = screen.getByRole('button', { name: 'Nothing to copy' }) - expect((copyButton as HTMLButtonElement).disabled).toBe(true) - fireEvent.click(copyButton) - expect(writeClipboardText).not.toHaveBeenCalled() - }) }) diff --git a/src/renderer/src/components/editor/check-run-clipboard-text.test.ts b/src/renderer/src/components/editor/check-run-clipboard-text.test.ts deleted file mode 100644 index 1fbba66611d..00000000000 --- a/src/renderer/src/components/editor/check-run-clipboard-text.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import { normalizeCheckRunDetailsLogTails } from '@/lib/check-run-details-log-normalization' -import * as sanitation from '../../../../shared/check-job-log-excerpt' -import { - captured, - checkLogDetails, - checkLogJob -} from '@/lib/check-run-details-log-normalization-test-fixture' -import type { PRCheckAnnotation, PRCheckJob } from '../../../../shared/github/check-types' -import { - formatAnnotationsForClipboard, - formatCheckRunOutputForClipboard, - formatJobsForClipboard -} from './check-run-clipboard-text' - -describe('check run clipboard text', () => { - it('formats the already normalized captured diagnostic and stack without sanitizing again', () => { - const sanitize = vi.spyOn(sanitation, 'sanitizeCheckJobLogExcerpt') - try { - const loaded = normalizeCheckRunDetailsLogTails( - checkLogDetails([checkLogJob(captured.rawLog)]) - ) - if (!loaded) { - throw new Error('Expected details') - } - const copied = formatJobsForClipboard(loaded.jobs, 'unknown') - expect(copied).toContain('job-1: failure\nTest shard: failure\n') - expect(copied).toContain(captured.expectedDiagnostic) - expect(copied).toContain(captured.expectedStackFrame) - expect(copied).not.toContain('\x1b') - expect(sanitize).toHaveBeenCalledOnce() - } finally { - sanitize.mockRestore() - } - }) - - it('formats all output sections in display order', () => { - expect( - formatCheckRunOutputForClipboard({ - title: 'Build failed', - summary: 'One test failed.', - text: 'Run the suite locally.' - }) - ).toBe('Build failed\n\nOne test failed.\n\nRun the suite locally.') - - expect( - formatCheckRunOutputForClipboard({ title: null, summary: 'Summary only', text: null }) - ).toBe('Summary only') - }) - - it('formats annotations with localized missing-path labels and separators', () => { - const annotations: PRCheckAnnotation[] = [ - { - path: 'src/main.ts', - startLine: 10, - endLine: 10, - annotationLevel: 'failure', - title: 'Type error', - message: 'Expected string', - rawDetails: 'Actual: number' - }, - { - path: null, - startLine: null, - endLine: null, - annotationLevel: null, - title: null, - message: 'Workflow failed', - rawDetails: null - } - ] - - expect(formatAnnotationsForClipboard(annotations, 'Anotacion')).toBe( - 'src/main.ts:10\nfailure\nType error\nExpected string\nActual: number\n\nAnotacion\nWorkflow failed' - ) - }) - - it('formats jobs with localized unknown states and log excerpts', () => { - const jobs: PRCheckJob[] = [ - { - id: 1, - name: 'unit', - status: null, - conclusion: 'failure', - startedAt: null, - completedAt: null, - url: null, - logTail: 'AssertionError: expected true', - steps: [ - { - name: 'test', - status: null, - conclusion: null, - startedAt: null, - completedAt: null - } - ] - }, - { - id: 2, - name: 'deploy', - status: null, - conclusion: null, - startedAt: null, - completedAt: null, - url: null, - logTail: null, - steps: [] - } - ] - - expect(formatJobsForClipboard(jobs, 'desconocido')).toBe( - 'unit: failure\ntest: desconocido\nAssertionError: expected true\n\ndeploy: desconocido' - ) - }) -}) diff --git a/src/renderer/src/components/editor/combined-diff/review-controls/combined-diff-commit-message.test.ts b/src/renderer/src/components/editor/combined-diff/review-controls/combined-diff-commit-message.test.ts deleted file mode 100644 index 6b2907484b6..00000000000 --- a/src/renderer/src/components/editor/combined-diff/review-controls/combined-diff-commit-message.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { afterEach, describe, expect, it, vi } from 'vitest' -import { getCombinedDiffCommitMessageBody } from './combined-diff-commit-message' - -afterEach(() => { - vi.restoreAllMocks() -}) - -describe('getCombinedDiffCommitMessageBody', () => { - it('removes the commit subject from the returned body', () => { - expect(getCombinedDiffCommitMessageBody('Fix tests\n\nBody line', 'Fix tests')).toBe( - 'Body line' - ) - }) - - it('normalizes CRLF before matching the subject and body', () => { - expect(getCombinedDiffCommitMessageBody('Fix tests\r\n\r\nBody line', 'Fix tests')).toBe( - 'Body line' - ) - }) - - it('normalizes newline-heavy CRLF bodies without global replace or split', () => { - const replace = vi.spyOn(String.prototype, 'replace') - const split = vi.spyOn(String.prototype, 'split') - const message = `Fix tests\r\n\r\n${'Body line\r\n'.repeat(10_000)}` - - const result = getCombinedDiffCommitMessageBody(message, 'Fix tests') - - expect(result.startsWith('Body line\nBody line')).toBe(true) - expect(result).not.toContain('\r\n') - const usedCrlfReplace = replace.mock.calls.some( - ([pattern]) => pattern instanceof RegExp && pattern.source === '\\r\\n' - ) - expect(usedCrlfReplace).toBe(false) - expect(split).not.toHaveBeenCalled() - }) - - it('keeps messages without a matching subject and avoids splitting large bodies', () => { - const split = vi.spyOn(String.prototype, 'split') - const message = `Subject\n${'body\n'.repeat(10_000)}` - - expect(getCombinedDiffCommitMessageBody(message, 'Other subject')).toBe(message.trim()) - expect(split).not.toHaveBeenCalled() - }) -}) diff --git a/src/renderer/src/components/editor/diff-editor-line-number-options.test.ts b/src/renderer/src/components/editor/diff-editor-line-number-options.test.ts index 57d79eb8c39..1fc38b9ce5e 100644 --- a/src/renderer/src/components/editor/diff-editor-line-number-options.test.ts +++ b/src/renderer/src/components/editor/diff-editor-line-number-options.test.ts @@ -1,26 +1,7 @@ import { describe, expect, it } from 'vitest' -import { - applyDiffEditorLineNumberOptions, - buildDiffEditorLineNumberOptions -} from './diff-editor-line-number-options' +import { applyDiffEditorLineNumberOptions } from './diff-editor-line-number-options' import type { editor } from 'monaco-editor' -describe('buildDiffEditorLineNumberOptions', () => { - it('hides original line numbers in inline mode', () => { - expect(buildDiffEditorLineNumberOptions(false)).toEqual({ - original: 'off', - modified: 'on' - }) - }) - - it('shows both gutters in side-by-side mode', () => { - expect(buildDiffEditorLineNumberOptions(true)).toEqual({ - original: 'on', - modified: 'on' - }) - }) -}) - function createMockCodeEditor(initialLineNumbers: editor.LineNumbersType = 'on'): { editor: editor.ICodeEditor emitDidChangeConfiguration: () => void diff --git a/src/renderer/src/components/editor/diff-line-stats.test.ts b/src/renderer/src/components/editor/diff-line-stats.test.ts index 127c11beecd..71b74e1c4b7 100644 --- a/src/renderer/src/components/editor/diff-line-stats.test.ts +++ b/src/renderer/src/components/editor/diff-line-stats.test.ts @@ -6,36 +6,6 @@ afterEach(() => { }) describe('computeLineStats', () => { - it('keeps existing added, deleted, and modified line count behavior', () => { - expect(computeLineStats('', 'a\nb', 'added')).toEqual({ added: 2, removed: 0 }) - expect(computeLineStats('a\nb\n', '', 'deleted')).toEqual({ added: 0, removed: 3 }) - expect(computeLineStats('a\nb\nc', 'a\nc\nd', 'modified')).toEqual({ - added: 1, - removed: 1 - }) - }) - - it('counts newline-heavy added and deleted pasted content without splitting', () => { - const split = vi.spyOn(String.prototype, 'split') - const content = '\n'.repeat(100_000) - - expect(computeLineStats('', content, 'added')).toEqual({ added: 100_001, removed: 0 }) - expect(computeLineStats(content, '', 'deleted')).toEqual({ added: 0, removed: 100_001 }) - - expect(split).not.toHaveBeenCalled() - }) - - it('compares modified files without splitting either side into line arrays', () => { - const split = vi.spyOn(String.prototype, 'split') - - expect(computeLineStats('same\nold\nkept', 'same\nnew\nkept', 'modified')).toEqual({ - added: 1, - removed: 1 - }) - - expect(split).not.toHaveBeenCalled() - }) - it('keeps the existing large modified-file guard before building multisets', () => { const split = vi.spyOn(String.prototype, 'split') diff --git a/src/renderer/src/components/editor/monaco-codebase-search.test.ts b/src/renderer/src/components/editor/monaco-codebase-search.test.ts deleted file mode 100644 index 31efb2339ef..00000000000 --- a/src/renderer/src/components/editor/monaco-codebase-search.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { IPosition, IRange } from 'monaco-editor' -import { describe, expect, it, vi } from 'vitest' -import { getMonacoCodebaseSearchQuery } from './monaco-codebase-search' - -type FakeSelection = IRange & { - isEmpty: () => boolean -} - -function selection(empty: boolean): FakeSelection { - return { - startLineNumber: 1, - startColumn: 1, - endLineNumber: 1, - endColumn: 1, - isEmpty: () => empty - } -} - -function position(): IPosition { - return { lineNumber: 1, column: 5 } -} - -function model(args: { selectedText?: string; word?: string }) { - return { - getValueInRange: vi.fn((_range: IRange) => args.selectedText ?? ''), - getWordAtPosition: vi.fn((_position: IPosition) => - args.word === undefined ? null : { word: args.word } - ) - } -} - -describe('getMonacoCodebaseSearchQuery', () => { - it('prefers normalized selected text over the cursor word', () => { - const fakeModel = model({ selectedText: ' foo\r\n bar ', word: 'fallback' }) - - expect(getMonacoCodebaseSearchQuery(fakeModel, selection(false), position())).toBe('foo bar') - expect(fakeModel.getWordAtPosition).not.toHaveBeenCalled() - }) - - it('falls back to the cursor word when there is no selection', () => { - expect( - getMonacoCodebaseSearchQuery(model({ word: 'needle' }), selection(true), position()) - ).toBe('needle') - }) - - it('falls back to the cursor word when the selection normalizes to empty', () => { - expect( - getMonacoCodebaseSearchQuery( - model({ selectedText: ' \n\t ', word: 'cursorWord' }), - selection(false), - position() - ) - ).toBe('cursorWord') - }) - - it('returns null when neither selection nor cursor word yields a query', () => { - expect(getMonacoCodebaseSearchQuery(model({}), selection(true), position())).toBeNull() - expect(getMonacoCodebaseSearchQuery(null, selection(true), position())).toBeNull() - }) -}) diff --git a/src/renderer/src/components/editor/rich-markdown-context-command-routing.test.ts b/src/renderer/src/components/editor/rich-markdown-context-command-routing.test.ts index 9a90b557dc2..5a81917a907 100644 --- a/src/renderer/src/components/editor/rich-markdown-context-command-routing.test.ts +++ b/src/renderer/src/components/editor/rich-markdown-context-command-routing.test.ts @@ -4,10 +4,7 @@ import { describe, expect, it, vi } from 'vitest' import { Editor } from '@tiptap/core' import { createRichMarkdownExtensions } from './rich-markdown-extensions' import { createRichMarkdownEditorCodec } from './rich-markdown-source-transport' -import { - isRichMarkdownTableContextCommand, - runRichMarkdownContextCommand -} from './rich-markdown-context-command-routing' +import { runRichMarkdownContextCommand } from './rich-markdown-context-command-routing' const TABLE = `| A | B | | --- | --- | @@ -31,11 +28,6 @@ function textPosition(editor: Editor, text: string): number { } describe('rich markdown context command routing', () => { - it('separates table commands for the shared rich-editor table owner', () => { - expect(isRichMarkdownTableContextCommand('delete-row')).toBe(true) - expect(isRichMarkdownTableContextCommand('bold')).toBe(false) - }) - it('runs table actions against the clicked cell coordinates', () => { const editor = new Editor({ element: document.createElement('div'), diff --git a/src/renderer/src/components/editor/rich-markdown-search.test.ts b/src/renderer/src/components/editor/rich-markdown-search.test.ts index f345a1c22eb..cbc2f502f2c 100644 --- a/src/renderer/src/components/editor/rich-markdown-search.test.ts +++ b/src/renderer/src/components/editor/rich-markdown-search.test.ts @@ -25,15 +25,6 @@ describe('findRichMarkdownSearchMatches', () => { ]) }) - it('forwards match-case and whole-word options to the range finder', () => { - expect( - findRichMarkdownSearchMatches(docFromText('Beta beta betas', 10), 'beta', { - matchCase: true, - wholeWord: true - }) - ).toEqual([{ from: 15, to: 19 }]) - }) - it('does not walk the document for oversized pasted search text', () => { const doc = { descendants() { diff --git a/src/renderer/src/components/editor/rich-markdown-slash-command-filter.test.ts b/src/renderer/src/components/editor/rich-markdown-slash-command-filter.test.ts index c8b944b6cd9..ca47bd7adeb 100644 --- a/src/renderer/src/components/editor/rich-markdown-slash-command-filter.test.ts +++ b/src/renderer/src/components/editor/rich-markdown-slash-command-filter.test.ts @@ -21,17 +21,6 @@ function command(overrides: Partial): SlashCommand { } describe('filterRichMarkdownSlashCommands', () => { - it('matches labels and aliases', () => { - const commands = [ - command({ id: 'heading-1', label: 'Heading 1', aliases: ['h1', 'title'] }), - command({ id: 'table', label: 'Table', aliases: ['grid'] }) - ] - - expect(filterRichMarkdownSlashCommands(commands, 'title').map((entry) => entry.id)).toEqual([ - 'heading-1' - ]) - }) - it('returns no commands for oversized pasted queries before reading commands', () => { const unreadableCommand = command({}) Object.defineProperty(unreadableCommand, 'label', { diff --git a/src/renderer/src/components/editor/rich-markdown-table.test.ts b/src/renderer/src/components/editor/rich-markdown-table.test.ts index b3c79eee961..e7e8fc0846b 100644 --- a/src/renderer/src/components/editor/rich-markdown-table.test.ts +++ b/src/renderer/src/components/editor/rich-markdown-table.test.ts @@ -4,33 +4,6 @@ import { RichMarkdownTable } from './rich-markdown-table' afterEach(() => vi.restoreAllMocks()) -it.each([ - '', - 'prose', - '| A | B |\n| --- | :---: |\n| a | b |', - 'A | B\n--- | ---\na | b', - '| A |\nnot a separator\n', - 'one\n\n| A |\n| --- |', - '| A |\r\n| --- |\r\n', - '| A |\n| - |', - '| A |\n| : |', - `| A |\n| - |\n${'prose\n'.repeat(10_000)}` -])('matches the upstream table detector: %j', (source) => { - const base = Table.config.markdownTokenizer - const guarded = RichMarkdownTable.config.markdownTokenizer - if ( - !base || - typeof base === 'function' || - typeof base.start !== 'function' || - !guarded || - typeof guarded === 'function' || - typeof guarded.start !== 'function' - ) { - throw new Error('Table tokenizer contract changed') - } - expect(guarded.start(source)).toBe(base.start(source)) -}) - it('only passes the first two lines to the upstream detector', () => { const base = Table.config.markdownTokenizer const guarded = RichMarkdownTable.config.markdownTokenizer diff --git a/src/renderer/src/components/github/github-mention-option-filter.test.ts b/src/renderer/src/components/github/github-mention-option-filter.test.ts index 429cf51c3b2..d3e6ce2a747 100644 --- a/src/renderer/src/components/github/github-mention-option-filter.test.ts +++ b/src/renderer/src/components/github/github-mention-option-filter.test.ts @@ -10,22 +10,6 @@ function option(login: string, name: string | null = null): GitHubMentionOption } describe('github-mention-option-filter', () => { - it('filters mention options by login or display name', () => { - const options = [ - option('octocat', 'Mona'), - option('release-manager', 'Octavia'), - option('build-bot') - ] - - expect(filterGitHubMentionOptions(options, 'oct')).toEqual([options[0], options[1]]) - }) - - it('caps mention options at the provided limit', () => { - const options = [option('one'), option('two'), option('three')] - - expect(filterGitHubMentionOptions(options, '', 2)).toEqual([options[0], options[1]]) - }) - it('enforces the query budget by UTF-8 byte length', () => { const query = 'é'.repeat(GITHUB_MENTION_QUERY_MAX_BYTES) diff --git a/src/renderer/src/components/github/github-pr-reviewer-candidate-filter.test.ts b/src/renderer/src/components/github/github-pr-reviewer-candidate-filter.test.ts index 713934e7d3a..bb119398faa 100644 --- a/src/renderer/src/components/github/github-pr-reviewer-candidate-filter.test.ts +++ b/src/renderer/src/components/github/github-pr-reviewer-candidate-filter.test.ts @@ -11,28 +11,6 @@ function user(login: string, name: string | null = null): GitHubAssignableUser { } describe('github-pr-reviewer-candidate-filter', () => { - it('normalizes typed reviewer queries with optional at-prefixes', () => { - expect(getGitHubPRReviewerQueryState(' @OctoCat ')).toEqual({ - query: 'octocat', - isTooLarge: false - }) - }) - - it('filters reviewer candidates by login or display name and prioritizes login prefixes', () => { - const candidates = [ - user('zebra-reviewer', 'Release Manager'), - user('alice', 'Feature Reviewer'), - user('review-bot', 'Automation') - ] - - expect( - filterGitHubPRReviewerCandidates({ - candidates, - queryState: getGitHubPRReviewerQueryState('review') - }).map((candidate) => candidate.login) - ).toEqual(['review-bot', 'alice', 'zebra-reviewer']) - }) - it('enforces the query budget by UTF-8 byte length', () => { const query = 'é'.repeat(GITHUB_PR_REVIEWER_QUERY_MAX_BYTES) diff --git a/src/renderer/src/components/jira-create-adf.test.ts b/src/renderer/src/components/jira-create-adf.test.ts deleted file mode 100644 index 8fb44adc7b4..00000000000 --- a/src/renderer/src/components/jira-create-adf.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { afterEach, describe, expect, it, vi } from 'vitest' -import { buildJiraCreateTextAdf } from './jira-create-adf' - -afterEach(() => { - vi.restoreAllMocks() -}) - -describe('buildJiraCreateTextAdf', () => { - it('converts plain and empty lines to Jira ADF paragraphs', () => { - expect(buildJiraCreateTextAdf('one\n\ntwo')).toEqual({ - type: 'doc', - version: 1, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'one' }] }, - { type: 'paragraph', content: [] }, - { type: 'paragraph', content: [{ type: 'text', text: 'two' }] } - ] - }) - }) - - it('normalizes CRLF line boundaries and preserves trailing blank paragraphs', () => { - expect(buildJiraCreateTextAdf('one\r\ntwo\r\n')).toEqual({ - type: 'doc', - version: 1, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'one' }] }, - { type: 'paragraph', content: [{ type: 'text', text: 'two' }] }, - { type: 'paragraph', content: [] } - ] - }) - }) - - it('builds newline-heavy ADF without splitting the full textarea value', () => { - const split = vi.spyOn(String.prototype, 'split') - const text = Array.from({ length: 5_000 }, (_, index) => `line ${index + 1}`).join('\n') - - const adf = buildJiraCreateTextAdf(text) - - expect(adf.content).toHaveLength(5_000) - expect(adf.content[0]).toEqual({ - type: 'paragraph', - content: [{ type: 'text', text: 'line 1' }] - }) - expect(adf.content.at(-1)).toEqual({ - type: 'paragraph', - content: [{ type: 'text', text: 'line 5000' }] - }) - expect(split).not.toHaveBeenCalled() - }) -}) diff --git a/src/renderer/src/components/jira-project-picker-filter.test.ts b/src/renderer/src/components/jira-project-picker-filter.test.ts index 765c5f434ef..1c39a9dd341 100644 --- a/src/renderer/src/components/jira-project-picker-filter.test.ts +++ b/src/renderer/src/components/jira-project-picker-filter.test.ts @@ -2,8 +2,7 @@ import { describe, expect, it } from 'vitest' import type { JiraProject } from '../../../shared/jira/jira-types' import { JIRA_PROJECT_PICKER_QUERY_MAX_BYTES, - filterJiraProjectPickerProjects, - getJiraProjectPickerDisplayLabel + filterJiraProjectPickerProjects } from './jira-project-picker-filter' function project(overrides: Partial = {}): JiraProject { @@ -18,37 +17,6 @@ function project(overrides: Partial = {}): JiraProject { } describe('jira-project-picker-filter', () => { - it('formats project labels with optional site names', () => { - const candidate = project() - - expect(getJiraProjectPickerDisplayLabel(candidate, true)).toBe( - 'Engineering · Application (APP)' - ) - expect(getJiraProjectPickerDisplayLabel(candidate, false)).toBe('Application (APP)') - }) - - it('matches project labels, keys, names, and site names', () => { - const projects = [ - project({ id: '1', key: 'APP', name: 'Application', siteName: 'Engineering' }), - project({ id: '2', key: 'OPS', name: 'Operations', siteName: 'Support' }) - ] - - expect( - filterJiraProjectPickerProjects({ - projects, - query: 'ops', - includeSiteName: true - }) - ).toEqual([projects[1]]) - expect( - filterJiraProjectPickerProjects({ - projects, - query: 'engineering', - includeSiteName: true - }) - ).toEqual([projects[0]]) - }) - it('enforces the query budget by UTF-8 byte length', () => { const query = 'é'.repeat(JIRA_PROJECT_PICKER_QUERY_MAX_BYTES) diff --git a/src/renderer/src/components/jira-prompt-templates.test.ts b/src/renderer/src/components/jira-prompt-templates.test.ts index 29f48f819e7..36e881ecabd 100644 --- a/src/renderer/src/components/jira-prompt-templates.test.ts +++ b/src/renderer/src/components/jira-prompt-templates.test.ts @@ -1,10 +1,6 @@ import { describe, expect, it } from 'vitest' import type { JiraIssue } from '../../../shared/jira/jira-types' -import { - renderJiraPromptTemplate, - getJiraPromptTemplates, - buildJiraIssuePrompt -} from './jira-prompt-templates' +import { renderJiraPromptTemplate, buildJiraIssuePrompt } from './jira-prompt-templates' const issue: JiraIssue = { id: '1', key: 'APP-1', @@ -33,14 +29,4 @@ describe('Jira prompt templates', () => { renderJiraPromptTemplate('$other-prompt $other-prompt $unknown $jira-issues', issue, 'note') ).toBe('note note $unknown $jira-issues') }) - it('includes key, title, URL, description and the chosen goal in all built-in prompts', () => { - for (const template of getJiraPromptTemplates()) { - const prompt = renderJiraPromptTemplate(template.text, issue, 'Run integration checks.') - expect(prompt).toContain(issue.key) - expect(prompt).toContain(issue.title) - expect(prompt).toContain(issue.url) - expect(prompt).toContain(issue.description) - expect(prompt).toContain('Run integration checks.') - } - }) }) diff --git a/src/renderer/src/components/linear-issue-text-draft-state.test.ts b/src/renderer/src/components/linear-issue-text-draft-state.test.ts index 1ba75a7dcf2..f30f2c10320 100644 --- a/src/renderer/src/components/linear-issue-text-draft-state.test.ts +++ b/src/renderer/src/components/linear-issue-text-draft-state.test.ts @@ -5,22 +5,6 @@ import { } from './linear-issue-text-draft-state' describe('linear issue text draft state', () => { - it('creates drafts from the issue source values', () => { - expect( - createLinearIssueTextDraftState({ - description: undefined, - id: 'issue-1', - title: 'Initial title' - }) - ).toEqual({ - description: '', - issueId: 'issue-1', - sourceDescription: '', - sourceTitle: 'Initial title', - title: 'Initial title' - }) - }) - it('resets both drafts when the issue changes', () => { const state = createLinearIssueTextDraftState({ description: 'Old body', diff --git a/src/renderer/src/components/native-chat/background-task-words-text.test.ts b/src/renderer/src/components/native-chat/background-task-words-text.test.ts deleted file mode 100644 index c8210fadbb4..00000000000 --- a/src/renderer/src/components/native-chat/background-task-words-text.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import { translate } from '@/i18n/i18n' -import type * as I18nModule from '@/i18n/i18n' -import en from '@/i18n/locales/en.json' -import { - BACKGROUND_TASK_COPY, - sayBackgroundTaskEnglish, - type BackgroundTaskCopyId -} from '../../../../shared/background-task-copy' -import { sayBackgroundTaskTranslated } from './background-task-words-text' - -vi.mock('@/i18n/i18n', async (importOriginal) => { - const actual = await importOriginal() - return { ...actual, translate: vi.fn(actual.translate) } -}) - -const IDS = Object.keys(BACKGROUND_TASK_COPY).filter( - (id): id is BackgroundTaskCopyId => id in BACKGROUND_TASK_COPY -) -const VALUES = { value0: '2 agents' } - -describe('desktop words for the background-tasks strip', () => { - it('says every piece as the phone does, in English', () => { - for (const id of IDS) { - expect([id, sayBackgroundTaskTranslated(id, VALUES)]).toEqual([ - id, - sayBackgroundTaskEnglish(id, VALUES) - ]) - } - }) - - // The catalog answers first in English, so read the default each key is given directly. - it('keeps each existing key, with the shared piece as its English default', () => { - for (const id of IDS) { - vi.mocked(translate).mockClear() - sayBackgroundTaskTranslated(id, VALUES) - expect(vi.mocked(translate).mock.calls.map(([key, fallback]) => [key, fallback])).toEqual([ - [`components.native-chat.backgroundTasks.${id}`, BACKGROUND_TASK_COPY[id]] - ]) - } - }) - - it('keeps the English catalog in step with the shared copy', () => { - const catalog: Record = en.components['native-chat'].backgroundTasks - for (const id of IDS) { - expect([id, catalog[id]]).toEqual([id, BACKGROUND_TASK_COPY[id]]) - } - }) -}) diff --git a/src/renderer/src/components/native-chat/native-chat-context-usage-summary.test.ts b/src/renderer/src/components/native-chat/native-chat-context-usage-summary.test.ts deleted file mode 100644 index bd4c3d4c649..00000000000 --- a/src/renderer/src/components/native-chat/native-chat-context-usage-summary.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { formatContextTokenCount, summarizeContextUsage } from './native-chat-context-usage-summary' - -describe('summarizeContextUsage', () => { - it('lists every non-empty CLI category, deferred ones included, largest first', () => { - const summary = summarizeContextUsage({ - usedTokens: 29_400, - windowTokens: 200_000, - percentage: 15, - estimated: false, - categories: [ - { name: 'Messages', tokens: 10_200 }, - { name: 'System tools (deferred)', tokens: 17_600, deferred: true }, - { name: 'Skills', tokens: 0 }, - { name: 'Free space', tokens: 170_600 }, - { name: 'System prompt', tokens: 3_800 } - ] - }) - expect(summary.rows).toEqual([ - { name: 'Free space', tokens: 170_600, percentage: 85.3 }, - { name: 'System tools (deferred)', tokens: 17_600, percentage: 8.8 }, - { name: 'Messages', tokens: 10_200, percentage: 5.1 }, - { name: 'System prompt', tokens: 3_800, percentage: 1.9 } - ]) - expect(summary.estimated).toBe(false) - }) -}) - -describe('formatContextTokenCount', () => { - it('keeps k for thousands and writes millions with a capital M', () => { - expect(formatContextTokenCount(10)).toBe('10') - expect(formatContextTokenCount(18_600)).toBe('18.6k') - expect(formatContextTokenCount(200_000)).toBe('200k') - expect(formatContextTokenCount(981_400)).toBe('981.4k') - expect(formatContextTokenCount(999_960)).toBe('1M') - expect(formatContextTokenCount(1_000_000)).toBe('1M') - expect(formatContextTokenCount(1_500_000)).toBe('1.5M') - expect(formatContextTokenCount(-5)).toBe('0') - }) -}) diff --git a/src/renderer/src/components/native-chat/native-chat-message-grouping.test.ts b/src/renderer/src/components/native-chat/native-chat-message-grouping.test.ts index 30eec4279fe..37a62706477 100644 --- a/src/renderer/src/components/native-chat/native-chat-message-grouping.test.ts +++ b/src/renderer/src/components/native-chat/native-chat-message-grouping.test.ts @@ -16,23 +16,6 @@ function msg( } describe('orderNativeChatMessages', () => { - it('orders by ascending timestamp, null first', () => { - const ordered = orderNativeChatMessages([ - msg({ id: 'b', timestamp: 20 }), - msg({ id: 'a', timestamp: 10 }), - msg({ id: 'n', timestamp: null }) - ]) - expect(ordered.map((m) => m.id)).toEqual(['n', 'a', 'b']) - }) - - it('breaks timestamp ties by id deterministically', () => { - const ordered = orderNativeChatMessages([ - msg({ id: 'z', timestamp: 5 }), - msg({ id: 'a', timestamp: 5 }) - ]) - expect(ordered.map((m) => m.id)).toEqual(['a', 'z']) - }) - it('sorts the streaming preview after real content but before optimistic echoes', () => { const ordered = orderNativeChatMessages([ msg({ id: 'pending:abc', role: 'user', timestamp: 20, source: 'scrape' }), diff --git a/src/renderer/src/components/native-chat/native-chat-subagent-group-words-text.test.ts b/src/renderer/src/components/native-chat/native-chat-subagent-group-words-text.test.ts deleted file mode 100644 index 216c0159403..00000000000 --- a/src/renderer/src/components/native-chat/native-chat-subagent-group-words-text.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import { translate } from '@/i18n/i18n' -import type * as I18nModule from '@/i18n/i18n' -import en from '@/i18n/locales/en.json' -import { - NATIVE_CHAT_SUBAGENT_GROUP_COPY, - sayNativeChatSubagentGroupEnglish, - type NativeChatSubagentGroupCopyId -} from '../../../../shared/native-chat-subagent-group-header' -import { sayNativeChatSubagentGroupTranslated } from './native-chat-subagent-group-words-text' - -vi.mock('@/i18n/i18n', async (importOriginal) => { - const actual = await importOriginal() - return { ...actual, translate: vi.fn(actual.translate) } -}) - -const IDS = Object.keys(NATIVE_CHAT_SUBAGENT_GROUP_COPY).filter( - (id): id is NativeChatSubagentGroupCopyId => id in NATIVE_CHAT_SUBAGENT_GROUP_COPY -) -const VALUES = { value0: 3 } - -function isCatalogObject(value: unknown): value is Record { - return typeof value === 'object' && value !== null && !Array.isArray(value) -} - -function catalogEntry(key: string): unknown { - return key - .split('.') - .reduce((node, part) => (isCatalogObject(node) ? node[part] : undefined), en) -} - -describe('desktop words for a transcript roster row', () => { - it('says every piece as the phone does, in English', () => { - for (const id of IDS) { - expect([id, sayNativeChatSubagentGroupTranslated(id, VALUES)]).toEqual([ - id, - sayNativeChatSubagentGroupEnglish(id, VALUES) - ]) - } - }) - - it('gives each key the shared piece as its English default, and the catalog agrees', () => { - for (const id of IDS) { - vi.mocked(translate).mockClear() - sayNativeChatSubagentGroupTranslated(id, VALUES) - const calls = vi.mocked(translate).mock.calls - expect(calls).toHaveLength(1) - const [key, fallback] = calls[0]! - expect([id, fallback]).toEqual([id, NATIVE_CHAT_SUBAGENT_GROUP_COPY[id]]) - expect(key.startsWith('components.native-chat.subagents.')).toBe(true) - expect([key, catalogEntry(key)]).toEqual([key, NATIVE_CHAT_SUBAGENT_GROUP_COPY[id]]) - } - }) -}) diff --git a/src/renderer/src/components/pet/PetOverlay.test.ts b/src/renderer/src/components/pet/PetOverlay.test.ts deleted file mode 100644 index 2c53663d555..00000000000 --- a/src/renderer/src/components/pet/PetOverlay.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { describe, expect, it, afterEach, vi } from 'vitest' - -import { clampPositionToViewport } from './PetOverlay' - -describe('clampPositionToViewport', () => { - it('keeps positions inside the viewport minus pet size', () => { - expect( - clampPositionToViewport({ x: 480, y: 390 }, 120, { - width: 500, - height: 400 - }) - ).toEqual({ x: 380, y: 280 }) - }) - - it('clamps negative positions to the origin', () => { - expect( - clampPositionToViewport({ x: -25, y: -40 }, 120, { - width: 500, - height: 400 - }) - ).toEqual({ x: 0, y: 0 }) - }) - - it('keeps the overlay inside the viewport bounds', () => { - expect( - clampPositionToViewport({ x: 900, y: -20 }, 180, { - width: 800, - height: 600 - }) - ).toEqual({ x: 620, y: 0 }) - }) - - it('pins to the origin when the overlay is larger than the viewport', () => { - expect( - clampPositionToViewport({ x: 80, y: 40 }, 500, { - width: 320, - height: 240 - }) - ).toEqual({ x: 0, y: 0 }) - }) -}) - -const { rejectAppStoreAccess } = vi.hoisted(() => ({ - rejectAppStoreAccess: vi.fn(() => { - throw new Error('Pure helper tests must not access the app store') - }) -})) - -vi.mock('@/store', () => ({ - useAppStore: Object.assign(rejectAppStoreAccess, { - getState: rejectAppStoreAccess, - getInitialState: rejectAppStoreAccess, - setState: rejectAppStoreAccess, - subscribe: rejectAppStoreAccess - }) -})) - -afterEach(() => { - expect(rejectAppStoreAccess).not.toHaveBeenCalled() -}) diff --git a/src/renderer/src/components/pr-check-counts.test.ts b/src/renderer/src/components/pr-check-counts.test.ts index 357068d6160..9f4e0f3c0f5 100644 --- a/src/renderer/src/components/pr-check-counts.test.ts +++ b/src/renderer/src/components/pr-check-counts.test.ts @@ -45,22 +45,6 @@ describe('getCheckCounts', () => { expect(getChecksSummaryLabel([check('action_required')])).toBe('1 check needs action') }) - it('buckets neutral and still-running checks apart', () => { - const checks: PRCheckDetail[] = [ - check('neutral'), - { name: 'ci', status: 'in_progress', conclusion: null, url: null } - ] - - expect(getCheckCounts(checks)).toEqual({ - passing: 0, - failing: 0, - needsAction: 0, - pending: 1, - neutral: 1 - }) - expect(getChecksSummaryLabel(checks)).toBe('1 check pending') - }) - it('keeps a completed check without a conclusion unresolved', () => { const checks: PRCheckDetail[] = [ { name: 'external', status: 'completed', conclusion: null, url: null } @@ -75,8 +59,4 @@ describe('getCheckCounts', () => { }) expect(getChecksSummaryLabel(checks)).toBe('0 of 1 checks passing') }) - - it('reports no checks for an empty list', () => { - expect(getChecksSummaryLabel([])).toBe('No checks found') - }) }) diff --git a/src/renderer/src/components/pull-request-page/mentions/options.test.ts b/src/renderer/src/components/pull-request-page/mentions/options.test.ts index 579f5e468c9..acd3162d348 100644 --- a/src/renderer/src/components/pull-request-page/mentions/options.test.ts +++ b/src/renderer/src/components/pull-request-page/mentions/options.test.ts @@ -18,25 +18,6 @@ function user(login: string, extras: Partial = {}): GitHub } describe('buildMentionOptions', () => { - it('includes the item author, commenters, participants, and assignable users', () => { - const options = buildMentionOptions({ - item, - comments: [comment('reviewer', 'https://avatars/reviewer')], - participants: [user('helper', { name: 'Helper' })], - assignableUsers: [user('teammate')] - }) - - expect(options.map((option) => option.login)).toEqual([ - 'octocat', - 'reviewer', - 'helper', - 'teammate' - ]) - expect(options[0]?.source).toBe('PR author') - expect(options[1]?.avatarUrl).toBe('https://avatars/reviewer') - expect(options[2]?.name).toBe('Helper') - }) - it('skips ghost and fills missing avatar/name on a later case-insensitive duplicate login', () => { const options = buildMentionOptions({ item, diff --git a/src/renderer/src/components/right-sidebar/AiVaultScanIssueBanners.test.tsx b/src/renderer/src/components/right-sidebar/AiVaultScanIssueBanners.test.tsx deleted file mode 100644 index df15ba89029..00000000000 --- a/src/renderer/src/components/right-sidebar/AiVaultScanIssueBanners.test.tsx +++ /dev/null @@ -1,42 +0,0 @@ -// @vitest-environment happy-dom -import { cleanup, render, screen } from '@testing-library/react' -import { afterEach, expect, it } from 'vitest' -import type { AiVaultListResult, AiVaultSession } from '../../../../shared/ai-vault-types' -import { AiVaultScanIssueBanners } from './AiVaultScanIssueBanners' - -afterEach(() => { - cleanup() -}) - -it('keeps many partial-read notices in a bounded scroll area above the session list', () => { - const notices = Array.from({ length: 40 }, (_, index) => ({ - executionHostId: 'ssh:box' as const, - agent: 'codex' as const, - kind: 'notice' as const, - path: `/home/u/.codex/sessions/rollout-${index}.jsonl`, - message: `Skipped 1 oversized transcript record over the 10.0 MiB limit (12.0 MiB at byte ${index}). The rest of the session was read.` - })) - const scanResult: AiVaultListResult = { - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: banners only read the session count. - sessions: [{} as AiVaultSession], - issues: [...notices, { agent: 'codex', path: '/broken.jsonl', message: 'Unreadable' }], - scannedAt: '2026-10-15T00:00:00.000Z' - } - - render() - - const region = screen.getByTestId('ai-vault-scan-notices') - expect(region.className).toContain('max-h-24') - expect(region.className).toContain('overflow-y-auto') - expect(region.children).toHaveLength(42) - expect(region.textContent).toContain('1 transcript skipped') -}) - -it('renders no notice area for a clean scan', () => { - render( - - ) - expect(screen.queryByTestId('ai-vault-scan-notices')).toBeNull() -}) diff --git a/src/renderer/src/components/right-sidebar/FileExplorerNameFilter.test.tsx b/src/renderer/src/components/right-sidebar/FileExplorerNameFilter.test.tsx deleted file mode 100644 index cc13cef3b9e..00000000000 --- a/src/renderer/src/components/right-sidebar/FileExplorerNameFilter.test.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import { Button } from '@/components/ui/button' -import { FileExplorerNameFilter } from './FileExplorerNameFilter' -import { visit, type ReactElementLike } from './file-explorer-element-tree-test-harness' - -function findInputByAriaLabel(node: unknown, ariaLabel: string): ReactElementLike { - let found: ReactElementLike | null = null - visit(node, (entry) => { - if (entry.type === 'input' && entry.props['aria-label'] === ariaLabel) { - found = entry - } - }) - if (!found) { - throw new Error(`${ariaLabel} input not found`) - } - return found -} - -function findButtonByAriaLabel(node: unknown, ariaLabel: string): ReactElementLike { - let found: ReactElementLike | null = null - visit(node, (entry) => { - if ( - entry.props['aria-label'] === ariaLabel && - (entry.type === Button || entry.type === 'button') - ) { - found = entry - } - }) - if (!found) { - throw new Error(`${ariaLabel} button not found`) - } - return found -} - -describe('FileExplorerNameFilter', () => { - it('reports text changes and shows the compact file filter input', () => { - const onQueryChange = vi.fn() - const element = FileExplorerNameFilter({ - query: '', - onQueryChange, - onClear: vi.fn() - }) - - const input = findInputByAriaLabel(element, 'Find files') - ;(input.props.onChange as (event: { currentTarget: { value: string } }) => void)({ - currentTarget: { value: 'FileExplorer' } - }) - - expect(input.props.placeholder).toBe('Find files') - expect(onQueryChange).toHaveBeenCalledWith('FileExplorer') - }) - - it('clears the current file filter from the clear button', () => { - const onClear = vi.fn() - const element = FileExplorerNameFilter({ - query: 'FileExplorer', - onQueryChange: vi.fn(), - onClear - }) - - const button = findButtonByAriaLabel(element, 'Clear file filter') - ;(button.props.onClick as () => void)() - - expect(onClear).toHaveBeenCalledTimes(1) - }) -}) - -it('names the visible folder in the filter prompt', () => { - const element = FileExplorerNameFilter({ - query: '', - scopeLabel: 'apps/web', - onQueryChange: vi.fn(), - onClear: vi.fn() - }) - expect(findInputByAriaLabel(element, 'Find files').props.placeholder).toBe('Find in apps/web') -}) diff --git a/src/renderer/src/components/right-sidebar/FileExplorerViewSwitch.test.tsx b/src/renderer/src/components/right-sidebar/FileExplorerViewSwitch.test.tsx deleted file mode 100644 index 5fe8f77a8c5..00000000000 --- a/src/renderer/src/components/right-sidebar/FileExplorerViewSwitch.test.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import { FileExplorerViewSwitch } from './FileExplorerViewSwitch' -import { visit, type ReactElementLike } from './file-explorer-element-tree-test-harness' - -function findElementByAriaLabel(node: unknown, ariaLabel: string): ReactElementLike { - let found: ReactElementLike | null = null - visit(node, (entry) => { - if (entry.props['aria-label'] === ariaLabel) { - found = entry - } - }) - if (!found) { - throw new Error(`${ariaLabel} element not found`) - } - return found -} - -describe('FileExplorerViewSwitch', () => { - it('switches between files and search views', () => { - const onSelectView = vi.fn() - const element = FileExplorerViewSwitch({ - view: 'files', - onSelectView - }) - - const switchRoot = findElementByAriaLabel(element, 'Explorer search mode') - ;(switchRoot.props.onValueChange as (value: string) => void)('search') - - expect(onSelectView).toHaveBeenCalledWith('search') - }) - - it('renders names and contents labels', () => { - const element = FileExplorerViewSwitch({ - view: 'search', - onSelectView: vi.fn() - }) - - const contentsTab = findElementByAriaLabel(element, 'Search file contents') - const namesTab = findElementByAriaLabel(element, 'Filter files by name') - const switchRoot = findElementByAriaLabel(element, 'Explorer search mode') - - expect(switchRoot.props.value).toBe('search') - expect(contentsTab.props.value).toBe('search') - expect(namesTab.props.value).toBe('files') - expect(JSON.stringify(contentsTab.props.children)).toContain('Contents') - expect(JSON.stringify(namesTab.props.children)).toContain('Names') - }) -}) diff --git a/src/renderer/src/components/right-sidebar/file-explorer-entries.test.ts b/src/renderer/src/components/right-sidebar/file-explorer-entries.test.ts deleted file mode 100644 index 999861c32c2..00000000000 --- a/src/renderer/src/components/right-sidebar/file-explorer-entries.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { isDotfileRelativePath, shouldIncludeFileExplorerEntry } from './file-explorer-entries' - -describe('shouldIncludeFileExplorerEntry', () => { - it('keeps dotfiles loadable so visibility can be toggled client-side', () => { - expect( - shouldIncludeFileExplorerEntry({ - name: '.env', - isDirectory: false, - isSymlink: false - }) - ).toBe(true) - - expect( - shouldIncludeFileExplorerEntry({ - name: '.config', - isDirectory: true, - isSymlink: false - }) - ).toBe(true) - }) - - it('still excludes internal and bulky directories', () => { - expect( - shouldIncludeFileExplorerEntry({ - name: '.git', - isDirectory: true, - isSymlink: false - }) - ).toBe(false) - - expect( - shouldIncludeFileExplorerEntry({ - name: 'node_modules', - isDirectory: true, - isSymlink: false - }) - ).toBe(false) - }) -}) - -describe('isDotfileRelativePath', () => { - it('matches dotfiles and descendants of dot folders across path separators', () => { - expect(isDotfileRelativePath('.env')).toBe(true) - expect(isDotfileRelativePath('.config/settings.json')).toBe(true) - expect(isDotfileRelativePath('src/.cache/result.json')).toBe(true) - expect(isDotfileRelativePath('src\\.cache\\result.json')).toBe(true) - }) - - it('does not match ordinary paths', () => { - expect(isDotfileRelativePath('src/index.ts')).toBe(false) - expect(isDotfileRelativePath('config/settings.json')).toBe(false) - }) -}) diff --git a/src/renderer/src/components/right-sidebar/plugin-panel-activity-items.test.ts b/src/renderer/src/components/right-sidebar/plugin-panel-activity-items.test.ts index 0ae15de1cf6..3d140bc0a8b 100644 --- a/src/renderer/src/components/right-sidebar/plugin-panel-activity-items.test.ts +++ b/src/renderer/src/components/right-sidebar/plugin-panel-activity-items.test.ts @@ -1,4 +1,4 @@ -import { FileText, Plug } from 'lucide-react' +import { Plug } from 'lucide-react' import { describe, expect, it } from 'vitest' import type { ActivePluginPanel } from '@/store/plugin-panels' import { getPluginPanelActivityItems, resolvePluginPanelIcon } from './plugin-panel-activity-items' @@ -12,13 +12,6 @@ const panel: ActivePluginPanel = { } describe('resolvePluginPanelIcon', () => { - it('resolves a curated icon name in both lucide naming styles', () => { - const dashed = resolvePluginPanelIcon('file-text') - // Without this, the equality below also passes when both sides fall back. - expect(dashed).toBe(FileText) - expect(resolvePluginPanelIcon('FileText')).toBe(dashed) - }) - it.each(['constructor', '__proto__', 'toString', 'hasOwnProperty'])( 'falls back to Plug for the prototype member %s', (iconName) => { @@ -33,16 +26,3 @@ describe('resolvePluginPanelIcon', () => { expect(item.icon).toBe(Plug) }) }) - -describe('getPluginPanelActivityItems', () => { - it('projects watchdog failure into host-owned activity chrome', () => { - expect( - getPluginPanelActivityItems([panel], { - 'plugin:orca-samples.demo/dashboard': true - })[0] - ).toMatchObject({ - id: panel.tabKey, - statusIndicator: 'failure' - }) - }) -}) diff --git a/src/renderer/src/components/right-sidebar/pr-comment-ack-summary.test.ts b/src/renderer/src/components/right-sidebar/pr-comment-ack-summary.test.ts deleted file mode 100644 index c4b2f83ac83..00000000000 --- a/src/renderer/src/components/right-sidebar/pr-comment-ack-summary.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { afterEach, describe, expect, it, vi } from 'vitest' -import type { PRComment } from '../../../../shared/github/comment-types' -import { describePRCommentAckTarget } from './pr-comment-fixing-reply-body' - -const comment = (body: string): PRComment => ({ - id: 1, - author: 'alice', - authorAvatarUrl: '', - body, - createdAt: '', - url: '' -}) -function originalSummary(body: string): string { - const line = body - .replace(//g, ' ') - .split('\n') - .map((line) => - line - .replace(/^[\s>#*\-_`]+/, '') - .replace(/\s+/g, ' ') - .trim() - ) - .find((line) => line.length > 0) - if (!line) { - return 'comment' - } - return `comment — ${line.length > 72 ? `${line.slice(0, 71).trimEnd()}…` : line}` -} -afterEach(() => vi.restoreAllMocks()) - -describe('review acknowledgement summary', () => { - it.each([ - '', - '\n\r\n\t', - '# > ** _ - `\n\nReadable', - '\n## Hello\r\nignored', - 'onetwo\nignored', - 'visible -->', - 'a\rb\nc', - '\u00a0##\u2028Hello\u2029world', - 'a'.repeat(71), - 'a'.repeat(72), - 'a'.repeat(73), - `${'a'.repeat(70)} b`, - `${'a'.repeat(70)}😀tail`, - '\n\n', - 'first\n\nlast' - ])('preserves the existing label for %j', (body) => { - expect(describePRCommentAckTarget(comment(body))).toBe(originalSummary(body)) - }) - - it('skips tail normalization and full-document line splitting', () => { - const input = comment(`## Heading\n${'tail with whitespace\n'.repeat(10_000)}`) - const replace = vi.spyOn(String.prototype, 'replace') - const split = vi.spyOn(String.prototype, 'split') - const actual = describePRCommentAckTarget(input) - const replaces = replace.mock.calls.length - const splits = split.mock.calls.length - expect(actual).toBe('comment — Heading') - expect(replaces).toBe(3) - expect(splits).toBe(0) - }) -}) diff --git a/src/renderer/src/components/right-sidebar/right-sidebar-activity-visibility.test.ts b/src/renderer/src/components/right-sidebar/right-sidebar-activity-visibility.test.ts deleted file mode 100644 index 90517dddb0b..00000000000 --- a/src/renderer/src/components/right-sidebar/right-sidebar-activity-visibility.test.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { Files } from 'lucide-react' -import type { ActivityBarItem } from './activity-bar-buttons' -import { getVisibleRightSidebarActivityItems } from './right-sidebar-activity-visibility' - -const items: ActivityBarItem[] = [ - { id: 'explorer', icon: Files, title: 'Explorer', shortcut: '' }, - { - id: 'workspaces', - icon: Files, - title: 'Workspaces', - shortcut: '', - folderOnly: true - }, - { - id: 'pr-checks', - icon: Files, - title: 'PR Checks', - shortcut: '', - folderOnly: true - }, - { - id: 'source-control', - icon: Files, - title: 'Source Control', - shortcut: '', - gitOnly: true - }, - { id: 'ports', icon: Files, title: 'Ports', shortcut: '', sshOnly: true }, - // Plugin panels carry no visibility flags, so they show in every context. - { - id: 'plugin:orca-samples.my-plugin/dashboard', - icon: Files, - title: 'Dashboard', - shortcut: '' - } -] - -describe('getVisibleRightSidebarActivityItems', () => { - it('shows ports only for workspaces on an SSH host', () => { - expect( - getVisibleRightSidebarActivityItems(items, { - isFolder: false, - isFolderWorkspace: false, - hasSshHost: false - }).map((item) => item.id) - ).toEqual(['explorer', 'source-control', 'plugin:orca-samples.my-plugin/dashboard']) - - expect( - getVisibleRightSidebarActivityItems(items, { - isFolder: false, - isFolderWorkspace: false, - hasSshHost: true - }).map((item) => item.id) - ).toEqual(['explorer', 'source-control', 'ports', 'plugin:orca-samples.my-plugin/dashboard']) - }) - - it('shows Workspaces only for folder workspaces and hides git tabs for all folder scopes', () => { - expect( - getVisibleRightSidebarActivityItems(items, { - isFolder: true, - isFolderWorkspace: true, - hasSshHost: true - }).map((item) => item.id) - ).toEqual([ - 'explorer', - 'workspaces', - 'pr-checks', - 'ports', - 'plugin:orca-samples.my-plugin/dashboard' - ]) - - expect( - getVisibleRightSidebarActivityItems(items, { - isFolder: true, - isFolderWorkspace: false, - hasSshHost: true - }).map((item) => item.id) - ).toEqual(['explorer', 'ports', 'plugin:orca-samples.my-plugin/dashboard']) - }) -}) diff --git a/src/renderer/src/components/right-sidebar/source-control-file-filter.test.ts b/src/renderer/src/components/right-sidebar/source-control-file-filter.test.ts index e6920100856..db265acdee5 100644 --- a/src/renderer/src/components/right-sidebar/source-control-file-filter.test.ts +++ b/src/renderer/src/components/right-sidebar/source-control-file-filter.test.ts @@ -8,26 +8,6 @@ import { } from './source-control/listing/file-filter' describe('source-control-file-filter', () => { - it('normalizes bounded queries and filters entries by path', () => { - const filter = getSourceControlFileFilterState(' SRC/button ') - - expect(filter).toEqual({ normalizedFilter: 'src/button', tooLarge: false }) - expect( - filterSourceControlPathEntries( - [{ path: 'src/Button.tsx' }, { path: 'docs/Button.md' }], - filter - ) - ).toEqual([{ path: 'src/Button.tsx' }]) - }) - - it('returns the original entries for empty filters', () => { - const entries = [{ path: 'src/a.ts' }] - - expect(filterSourceControlPathEntries(entries, getSourceControlFileFilterState(' '))).toBe( - entries - ) - }) - it('rejects oversized filters before reading entry paths', () => { const oversizedQuery = 'secret-source-control'.repeat( SOURCE_CONTROL_FILE_FILTER_QUERY_MAX_BYTES diff --git a/src/renderer/src/components/right-sidebar/source-control-header-toolbar.test.ts b/src/renderer/src/components/right-sidebar/source-control-header-toolbar.test.ts deleted file mode 100644 index d552b18e506..00000000000 --- a/src/renderer/src/components/right-sidebar/source-control-header-toolbar.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - getNextSourceControlViewMode, - shouldShowSourceControlCompareUnavailableCard -} from './source-control/panel/header-toolbar' -import type { GitBranchCompareSummary } from '../../../../shared/git-diff-compare-types' - -const readySummary: GitBranchCompareSummary = { - baseRef: 'origin/main', - baseOid: 'base', - compareRef: 'feature', - headOid: 'head', - mergeBase: 'base', - changedFiles: 2, - commitsAhead: 1, - status: 'ready' -} - -describe('source-control header toolbar helpers', () => { - it('toggles list and tree view modes', () => { - expect(getNextSourceControlViewMode('list')).toBe('tree') - expect(getNextSourceControlViewMode('tree')).toBe('list') - }) - - it('shows the compare-unavailable card only when compare failed and the body is empty', () => { - expect( - shouldShowSourceControlCompareUnavailableCard( - { ...readySummary, status: 'error', errorMessage: 'nope' }, - false, - false, - false - ) - ).toBe(true) - - expect( - shouldShowSourceControlCompareUnavailableCard( - { ...readySummary, status: 'error', errorMessage: 'nope' }, - true, - false, - false - ) - ).toBe(false) - - expect( - shouldShowSourceControlCompareUnavailableCard( - { ...readySummary, status: 'error', errorMessage: 'nope' }, - false, - true, - false - ) - ).toBe(false) - - expect(shouldShowSourceControlCompareUnavailableCard(readySummary, false, false, false)).toBe( - false - ) - - expect( - shouldShowSourceControlCompareUnavailableCard( - { ...readySummary, status: 'loading' }, - false, - false, - false - ) - ).toBe(false) - }) -}) diff --git a/src/renderer/src/components/right-sidebar/source-control/listing/section-action-buttons.test.tsx b/src/renderer/src/components/right-sidebar/source-control/listing/section-action-buttons.test.tsx index 92c8ccd202f..3701cd4d9f3 100644 --- a/src/renderer/src/components/right-sidebar/source-control/listing/section-action-buttons.test.tsx +++ b/src/renderer/src/components/right-sidebar/source-control/listing/section-action-buttons.test.tsx @@ -76,15 +76,6 @@ function renderUncommittedSections({ } describe('source control section header actions', () => { - it('routes the Changes header Stage all through the section handler', () => { - const handleStageSectionPaths = vi.fn(async () => {}) - renderUncommittedSections({ handleStageSectionPaths }) - - fireEvent.click(screen.getByRole('button', { name: 'Stage all' })) - - expect(handleStageSectionPaths).toHaveBeenCalledWith('unstaged', ['src/app.ts']) - }) - it('includes untracked files in the Changes header Stage all', () => { const handleStageSectionPaths = vi.fn(async () => {}) const changes: SourceControlDisplaySection = { diff --git a/src/renderer/src/components/right-sidebar/use-file-explorer-name-filter.test.ts b/src/renderer/src/components/right-sidebar/use-file-explorer-name-filter.test.ts index f0394973e53..55108a14777 100644 --- a/src/renderer/src/components/right-sidebar/use-file-explorer-name-filter.test.ts +++ b/src/renderer/src/components/right-sidebar/use-file-explorer-name-filter.test.ts @@ -28,22 +28,6 @@ describe('useFileExplorerNameFilter', () => { cleanup() }) - it('passes the active filename query to the runtime path search', () => { - const { result } = renderHook(() => - useFileExplorerNameFilter({ isFilesViewActive: true, activeWorktreeId: 'worktree-1' }) - ) - - act(() => result.current.setNameFilterQuery('AppDelegate.swift')) - - expect(useRuntimeFileListForWorktreeMock).toHaveBeenLastCalledWith({ - enabled: true, - worktreeId: 'worktree-1', - query: 'AppDelegate.swift', - hostFilterWhenCapped: true - }) - expect(result.current.nameFilterSource?.query).toBe('AppDelegate.swift') - }) - it('reports an unsettled source while the listing loads', () => { useRuntimeFileListForWorktreeMock.mockReturnValue({ files: [], diff --git a/src/renderer/src/components/settings/TerminalFontSizeSetting.test.tsx b/src/renderer/src/components/settings/TerminalFontSizeSetting.test.tsx deleted file mode 100644 index 949dffbb6a7..00000000000 --- a/src/renderer/src/components/settings/TerminalFontSizeSetting.test.tsx +++ /dev/null @@ -1,89 +0,0 @@ -// @vitest-environment happy-dom - -import { act } from 'react' -import { createRoot, type Root } from 'react-dom/client' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import type { GlobalSettings } from '../../../../shared/global-settings-types' -import { TerminalFontSizeSetting } from './TerminalFontSizeSetting' - -vi.mock('@/i18n/i18n', () => ({ - translate: (_key: string, defaultValue: string) => defaultValue -})) - -describe('TerminalFontSizeSetting', () => { - let container: HTMLDivElement - let root: Root - - beforeEach(() => { - globalThis.IS_REACT_ACT_ENVIRONMENT = true - container = document.createElement('div') - document.body.appendChild(container) - root = createRoot(container) - }) - - afterEach(() => { - act(() => root.unmount()) - document.body.replaceChildren() - }) - - function renderSetting(terminalFontSize: number, updateSettings = vi.fn()): void { - act(() => { - root.render( - - ) - }) - } - - function getInput(): HTMLInputElement { - const input = container.querySelector('input[type="number"]') - if (!input) { - throw new Error('font size input not found') - } - return input - } - - function getStepperButtons(): { decrement: HTMLButtonElement; increment: HTMLButtonElement } { - const [decrement, increment] = Array.from( - container.querySelectorAll('button') - ) - if (!decrement || !increment) { - throw new Error('stepper buttons not found') - } - return { decrement, increment } - } - - it('keeps the two-digit input compact without native spin buttons', () => { - renderSetting(15) - - expect(Array.from(getInput().classList)).toEqual( - expect.arrayContaining(['number-input-clean', 'w-14']) - ) - }) - - it('steps the font size within the supported range', () => { - const updateSettings = vi.fn() - renderSetting(15, updateSettings) - - const { decrement, increment } = getStepperButtons() - - act(() => increment.click()) - expect(updateSettings).toHaveBeenCalledWith({ terminalFontSize: 16 }) - - act(() => decrement.click()) - expect(updateSettings).toHaveBeenCalledWith({ terminalFontSize: 14 }) - }) - - it('disables the steppers at the range bounds', () => { - renderSetting(10) - expect(getStepperButtons().decrement.disabled).toBe(true) - expect(getStepperButtons().increment.disabled).toBe(false) - - renderSetting(24) - expect(getStepperButtons().decrement.disabled).toBe(false) - expect(getStepperButtons().increment.disabled).toBe(true) - }) -}) diff --git a/src/renderer/src/components/settings/worktree-symlink-path-filter.test.ts b/src/renderer/src/components/settings/worktree-symlink-path-filter.test.ts index beb10fd26e9..460343d006f 100644 --- a/src/renderer/src/components/settings/worktree-symlink-path-filter.test.ts +++ b/src/renderer/src/components/settings/worktree-symlink-path-filter.test.ts @@ -6,39 +6,6 @@ import { } from './worktree-symlink-path-filter' describe('worktree-symlink-path-filter', () => { - it('filters suggestions by normalized path text and caps visible results', () => { - const suggestions = [ - { name: 'node_modules', isDirectory: true }, - { name: 'packages/app', isDirectory: true }, - { name: 'packages/api', isDirectory: true }, - { name: '.env', isDirectory: false } - ] - - expect( - getWorktreeSymlinkPathFilterState({ - query: '/packages', - suggestions, - existingPaths: [], - maxSuggestions: 1 - }) - ).toEqual({ - queryTrimmed: 'packages', - filtered: [{ name: 'packages/app', isDirectory: true }], - showLiteralItem: true, - isQueryTooLarge: false - }) - }) - - it('hides the literal item when the query already exists', () => { - expect( - getWorktreeSymlinkPathFilterState({ - query: 'node_modules', - suggestions: [{ name: 'node_modules', isDirectory: true }], - existingPaths: ['node_modules'] - }).showLiteralItem - ).toBe(false) - }) - it('enforces the query budget by UTF-8 byte length', () => { const query = 'é'.repeat(WORKTREE_SYMLINK_PATH_QUERY_MAX_BYTES) diff --git a/src/renderer/src/components/sidebar/AddRepoDialogChrome.test.tsx b/src/renderer/src/components/sidebar/AddRepoDialogChrome.test.tsx index 81ad68756ae..6edef4bdfa9 100644 --- a/src/renderer/src/components/sidebar/AddRepoDialogChrome.test.tsx +++ b/src/renderer/src/components/sidebar/AddRepoDialogChrome.test.tsx @@ -55,17 +55,6 @@ describe('AddRepoDialogChrome dismissal', () => { expect(screen.queryByRole('dialog', { name: 'Clone from URL' })).not.toBeNull() }) - it('allows backdrop dismissal when no clone is running', async () => { - const user = userEvent.setup() - const onOpenChange = vi.fn() - render() - - await user.click(backdrop()) - - expect(onOpenChange).toHaveBeenCalledWith(false) - expect(screen.queryByRole('dialog', { name: 'Clone from URL' })).toBeNull() - }) - it('allows backdrop dismissal after the clone settles', async () => { const user = userEvent.setup() const onOpenChange = vi.fn() diff --git a/src/renderer/src/components/sidebar/project-order-manual-default-notice-visibility.test.ts b/src/renderer/src/components/sidebar/project-order-manual-default-notice-visibility.test.ts deleted file mode 100644 index ee3a3715d5b..00000000000 --- a/src/renderer/src/components/sidebar/project-order-manual-default-notice-visibility.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { resolveProjectOrderManualDefaultNoticeDismissed } from '../../../../shared/project-order-manual-default-notice' -import { shouldShowProjectOrderManualDefaultNotice } from './project-order-manual-default-notice-visibility' - -describe('resolveProjectOrderManualDefaultNoticeDismissed', () => { - it('keeps an explicit dismissal', () => { - expect( - resolveProjectOrderManualDefaultNoticeDismissed({ - rawDismissed: true, - rawProjectOrderBy: undefined, - isExistingProfile: true - }) - ).toBe(true) - }) - - it('hides the notice for brand-new profiles', () => { - expect( - resolveProjectOrderManualDefaultNoticeDismissed({ - rawDismissed: undefined, - rawProjectOrderBy: undefined, - isExistingProfile: false - }) - ).toBe(true) - }) - - it('hides the notice when recent ordering was already explicit', () => { - expect( - resolveProjectOrderManualDefaultNoticeDismissed({ - rawDismissed: undefined, - rawProjectOrderBy: 'recent', - isExistingProfile: true - }) - ).toBe(true) - }) - - it('shows the notice for upgraded profiles without an explicit project order', () => { - expect( - resolveProjectOrderManualDefaultNoticeDismissed({ - rawDismissed: undefined, - rawProjectOrderBy: undefined, - isExistingProfile: true - }) - ).toBe(false) - }) -}) - -describe('shouldShowProjectOrderManualDefaultNotice', () => { - it('shows only when project grouping is active and repos exist', () => { - expect( - shouldShowProjectOrderManualDefaultNotice({ - persistedUIReady: true, - projectOrderManualDefaultNoticeDismissed: false, - groupBy: 'repo', - projectOrderBy: 'manual', - repoCount: 2 - }) - ).toBe(true) - expect( - shouldShowProjectOrderManualDefaultNotice({ - persistedUIReady: true, - projectOrderManualDefaultNoticeDismissed: false, - groupBy: 'none', - projectOrderBy: 'manual', - repoCount: 2 - }) - ).toBe(false) - expect( - shouldShowProjectOrderManualDefaultNotice({ - persistedUIReady: true, - projectOrderManualDefaultNoticeDismissed: false, - groupBy: 'repo', - projectOrderBy: 'manual', - repoCount: 0 - }) - ).toBe(false) - - expect( - shouldShowProjectOrderManualDefaultNotice({ - persistedUIReady: true, - projectOrderManualDefaultNoticeDismissed: false, - groupBy: 'repo', - projectOrderBy: 'recent', - repoCount: 2 - }) - ).toBe(false) - }) -}) diff --git a/src/renderer/src/components/sidebar/worktree-card-jira-issue-display.test.ts b/src/renderer/src/components/sidebar/worktree-card-jira-issue-display.test.ts deleted file mode 100644 index 7b20053c3b6..00000000000 --- a/src/renderer/src/components/sidebar/worktree-card-jira-issue-display.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - getConfiguredWorktreeCardJiraIssueDisplay, - getWorktreeCardJiraIssueDisplay -} from './worktree-card-jira-issue-display' - -describe('getWorktreeCardJiraIssueDisplay', () => { - it('projects persisted Jira linked-item metadata for the workspace card', () => { - expect( - getWorktreeCardJiraIssueDisplay({ - linkedWorkItem: { - provider: 'jira', - type: 'issue', - number: 1, - jiraIdentifier: 'KAN-1', - title: 'KAN-1 Test Jira card icon', - url: 'https://company.atlassian.net/browse/KAN-1' - } - }) - ).toEqual({ - identifier: 'KAN-1', - title: 'Test Jira card icon', - url: 'https://company.atlassian.net/browse/KAN-1' - }) - }) - - it('does not infer Jira from another provider', () => { - expect( - getWorktreeCardJiraIssueDisplay({ - linkedWorkItem: { - provider: 'linear', - type: 'issue', - number: 1, - linearIdentifier: 'ENG-1', - title: 'Linear issue', - url: 'https://linear.app/acme/issue/ENG-1' - } - }) - ).toBeNull() - }) - - it('shows persisted Jira metadata only when the Jira display property is enabled', () => { - const worktree = { - linkedWorkItem: { - provider: 'jira' as const, - type: 'issue' as const, - number: 1, - jiraIdentifier: 'KAN-1', - title: 'Test Jira card preference', - url: 'https://company.atlassian.net/browse/KAN-1' - } - } - - expect(getConfiguredWorktreeCardJiraIssueDisplay(worktree, [])).toBeNull() - expect(getConfiguredWorktreeCardJiraIssueDisplay(worktree, ['jira-issue'])).toMatchObject({ - identifier: 'KAN-1', - title: 'Test Jira card preference' - }) - }) -}) diff --git a/src/renderer/src/components/skills/skill-bundle-retry-selection.test.ts b/src/renderer/src/components/skills/skill-bundle-retry-selection.test.ts index bdfffb6516b..69b57bf60b8 100644 --- a/src/renderer/src/components/skills/skill-bundle-retry-selection.test.ts +++ b/src/renderer/src/components/skills/skill-bundle-retry-selection.test.ts @@ -39,19 +39,4 @@ describe('bundle retry selection', () => { it('includes skills whose provider placement is incomplete', () => { expect([...retryableSkillIds(result())]).toEqual(['partial-placement']) }) - - it('includes a skill whose top-level result failed', () => { - const failedResult = result() - failedResult.skills = [ - { - skillId: 'failed-skill', - name: 'failed-skill', - digest: 'd'.repeat(64), - status: 'failed', - placements: [] - } - ] - - expect([...retryableSkillIds(failedResult)]).toEqual(['failed-skill']) - }) }) diff --git a/src/renderer/src/components/skills/skill-share-preview-summary.test.ts b/src/renderer/src/components/skills/skill-share-preview-summary.test.ts index 75b96490749..c16289a38f3 100644 --- a/src/renderer/src/components/skills/skill-share-preview-summary.test.ts +++ b/src/renderer/src/components/skills/skill-share-preview-summary.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' import type { SkillSharePreview } from '../../../../shared/skill-sharing-contract' -import { sensitiveShareFiles, summarizeShareRisk } from './skill-share-preview-summary' +import { sensitiveShareFiles } from './skill-share-preview-summary' function preview(overrides: Partial = {}): SkillSharePreview { return { @@ -21,26 +21,6 @@ function preview(overrides: Partial = {}): SkillSharePreview } } -describe('summarizeShareRisk', () => { - it('reports the absence once instead of two zero counts', () => { - expect(summarizeShareRisk(preview())).toEqual({ - risky: false, - label: 'No scripts or executables' - }) - }) - - it('counts only the kinds that are present, with matching plurals', () => { - expect(summarizeShareRisk(preview({ scriptPaths: ['scripts/a.sh'] })).label).toBe('1 script') - expect( - summarizeShareRisk(preview({ scriptPaths: ['scripts/a.sh', 'scripts/b.sh'] })).label - ).toBe('2 scripts') - expect( - summarizeShareRisk(preview({ scriptPaths: ['scripts/a.sh'], executablePaths: ['bin/x'] })) - .label - ).toBe('1 script, 1 executable') - }) -}) - describe('sensitiveShareFiles', () => { it('lists a file that is both script and executable once', () => { const files = sensitiveShareFiles( @@ -48,11 +28,4 @@ describe('sensitiveShareFiles', () => { ) expect(files).toEqual([{ path: 'scripts/setup.sh', script: true, executable: true }]) }) - - it('sorts paths so the same package always reviews in the same order', () => { - const files = sensitiveShareFiles( - preview({ scriptPaths: ['scripts/b.sh', 'scripts/a.sh'], executablePaths: ['bin/tool'] }) - ) - expect(files.map((file) => file.path)).toEqual(['bin/tool', 'scripts/a.sh', 'scripts/b.sh']) - }) }) diff --git a/src/renderer/src/components/skills/skills-filter.test.ts b/src/renderer/src/components/skills/skills-filter.test.ts index ddfa0631e1c..3a7ebf18283 100644 --- a/src/renderer/src/components/skills/skills-filter.test.ts +++ b/src/renderer/src/components/skills/skills-filter.test.ts @@ -2,7 +2,6 @@ import { describe, expect, it } from 'vitest' import type { DiscoveredSkill } from '../../../../shared/skills' import { SKILLS_FILTER_QUERY_MAX_BYTES, - countSkillsBySource, filterSkills, isSkillsFilterQueryTooLarge } from './skills-filter' @@ -79,14 +78,4 @@ describe('skills filtering', () => { }) ).toEqual([]) }) - - it('counts skills by source kind', () => { - expect( - countSkillsBySource([ - skill({ sourceKind: 'home' }), - skill({ id: 'repo', sourceKind: 'repo' }), - skill({ id: 'plugin', sourceKind: 'plugin' }) - ]) - ).toEqual({ home: 1, repo: 1, bundled: 0, plugin: 1 }) - }) }) diff --git a/src/renderer/src/components/status-bar/provider-account-sync-key.test.ts b/src/renderer/src/components/status-bar/provider-account-sync-key.test.ts index 7931bb1598b..9a9aedc80a4 100644 --- a/src/renderer/src/components/status-bar/provider-account-sync-key.test.ts +++ b/src/renderer/src/components/status-bar/provider-account-sync-key.test.ts @@ -19,16 +19,6 @@ describe.each([ ['claude', getClaudeAccountSyncKey], ['codex', getCodexAccountSyncKey] ])('%s account sync key', (_provider, getSyncKey) => { - it('returns the same string for the same settings identity', () => { - const settings = makeSettings() - expect(getSyncKey(settings)).toBe(getSyncKey(settings)) - }) - - it('answers no-settings when settings are absent', () => { - expect(getSyncKey(null)).toBe('no-settings') - expect(getSyncKey(undefined)).toBe('no-settings') - }) - it('recomputes for a new settings identity', () => { const first = getSyncKey(makeSettings()) const second = getSyncKey( diff --git a/src/renderer/src/components/task-page-jira-text-fallback-notice.test.tsx b/src/renderer/src/components/task-page-jira-text-fallback-notice.test.tsx index dcb05878bf4..328d949b81c 100644 --- a/src/renderer/src/components/task-page-jira-text-fallback-notice.test.tsx +++ b/src/renderer/src/components/task-page-jira-text-fallback-notice.test.tsx @@ -1,6 +1,6 @@ // @vitest-environment happy-dom import { afterEach, describe, expect, it } from 'vitest' -import { cleanup, fireEvent, render, screen } from '@testing-library/react' +import { cleanup, render, screen } from '@testing-library/react' import { TaskPageJiraTextFallbackNotice } from './task-page-jira-text-fallback-notice' afterEach(cleanup) @@ -9,27 +9,6 @@ const REASON = "Field 'login' does not exist or you do not have permission to vi const PROSE = { reason: REASON, likelyTypo: false } describe('TaskPageJiraTextFallbackNotice', () => { - it("keeps Jira's reason behind Details", () => { - render() - expect(screen.getByText(/Showing text matches/)).toBeTruthy() - expect(screen.getByRole('status').textContent).toContain('Showing text matches') - expect(screen.queryByText(REASON)).toBeNull() - - fireEvent.click(screen.getByRole('button', { name: 'Details' })) - expect(screen.getByText(REASON)).toBeTruthy() - }) - - it("shows Jira's reason straight away for a likely JQL typo", () => { - render() - expect(screen.getByText(REASON)).toBeTruthy() - }) - - it('omits Details when Jira gave no reason', () => { - render() - expect(screen.getByText(/Showing text matches/)).toBeTruthy() - expect(screen.queryByRole('button', { name: 'Details' })).toBeNull() - }) - it('updates one mounted live region instead of inserting a new one', () => { const { rerender } = render() const region = screen.getByRole('status') diff --git a/src/renderer/src/components/task-page/linear/task-page-linear-issue-empty-state.test.ts b/src/renderer/src/components/task-page/linear/task-page-linear-issue-empty-state.test.ts deleted file mode 100644 index 78b2bd79446..00000000000 --- a/src/renderer/src/components/task-page/linear/task-page-linear-issue-empty-state.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - resolveLinearIssueEmptyKind, - shouldOfferLinearIssueFetchMore -} from './task-page-linear-issue-empty-state' -import { emptyLinearIssueAttributeFilter } from '../../../../../shared/linear/issue-attribute-filter' - -describe('task-page-linear-issue-empty-state', () => { - it('prefers context, then search, then server filter, then client team, then unfiltered', () => { - expect( - resolveLinearIssueEmptyKind({ - hasContextLabel: true, - searchActive: true, - attributeFilter: emptyLinearIssueAttributeFilter(), - serverIssueCount: 0, - filteredIssueCount: 0 - }) - ).toBe('context') - - expect( - resolveLinearIssueEmptyKind({ - hasContextLabel: false, - searchActive: true, - attributeFilter: { - stateIds: ['s'], - priorities: [], - assignee: null, - labelIds: [] - }, - serverIssueCount: 0, - filteredIssueCount: 0 - }) - ).toBe('search') - - expect( - resolveLinearIssueEmptyKind({ - hasContextLabel: false, - searchActive: false, - attributeFilter: { - stateIds: ['s'], - priorities: [], - assignee: null, - labelIds: [] - }, - serverIssueCount: 0, - filteredIssueCount: 0 - }) - ).toBe('server-attribute-filter') - - expect( - resolveLinearIssueEmptyKind({ - hasContextLabel: false, - searchActive: false, - attributeFilter: emptyLinearIssueAttributeFilter(), - serverIssueCount: 3, - filteredIssueCount: 0 - }) - ).toBe('client-team') - - expect( - resolveLinearIssueEmptyKind({ - hasContextLabel: false, - searchActive: false, - attributeFilter: emptyLinearIssueAttributeFilter(), - serverIssueCount: 0, - filteredIssueCount: 0 - }) - ).toBe('unfiltered-scope') - }) - - it('offers fetch more only for client-team thinning with server hasMore', () => { - expect(shouldOfferLinearIssueFetchMore({ emptyKind: 'client-team', serverHasMore: true })).toBe( - true - ) - expect( - shouldOfferLinearIssueFetchMore({ - emptyKind: 'server-attribute-filter', - serverHasMore: true - }) - ).toBe(false) - }) -}) diff --git a/src/renderer/src/components/task-page/task-page-list-chrome-visibility.test.ts b/src/renderer/src/components/task-page/task-page-list-chrome-visibility.test.ts index 2591564a36a..f0fde7d94c2 100644 --- a/src/renderer/src/components/task-page/task-page-list-chrome-visibility.test.ts +++ b/src/renderer/src/components/task-page/task-page-list-chrome-visibility.test.ts @@ -16,37 +16,6 @@ const baseState: TaskPageListChromeVisibilityState = { } describe('shouldHideTaskPageListChrome', () => { - it('hides chrome for the active provider detail context', () => { - expect( - shouldHideTaskPageListChrome({ - ...baseState, - taskSource: 'github', - hasGitHubDetail: true - }) - ).toBe(true) - expect( - shouldHideTaskPageListChrome({ - ...baseState, - taskSource: 'gitlab', - hasGitLabDetail: true - }) - ).toBe(true) - expect( - shouldHideTaskPageListChrome({ - ...baseState, - taskSource: 'jira', - hasJiraDetail: true - }) - ).toBe(true) - expect( - shouldHideTaskPageListChrome({ - ...baseState, - taskSource: 'linear', - hasLinearProjectContext: true - }) - ).toBe(true) - }) - it('keeps chrome visible when only another provider has stale detail state', () => { expect( shouldHideTaskPageListChrome({ diff --git a/src/renderer/src/components/terminal-pane/terminal-spawn-error-display.test.ts b/src/renderer/src/components/terminal-pane/terminal-spawn-error-display.test.ts index 087886a9d52..e61504a2d71 100644 --- a/src/renderer/src/components/terminal-pane/terminal-spawn-error-display.test.ts +++ b/src/renderer/src/components/terminal-pane/terminal-spawn-error-display.test.ts @@ -2,9 +2,7 @@ import { describe, expect, it, vi } from 'vitest' import { LEGACY_PTY_ALLOCATION_HINT, LEGACY_TERMINAL_PROCESS_LIMIT_HINT, - PTY_ALLOCATION_HINT, - TERMINAL_HOST_CAP_HINT, - TERMINAL_PROCESS_LIMIT_HINT + PTY_ALLOCATION_HINT } from '../../../../shared/terminal-spawn-error-copy' // Why a locale stand-in: English fallbacks equal the host copy, so only a translation shows the swap. @@ -34,10 +32,6 @@ describe('localizeTerminalSpawnHints', () => { ) }) - it('translates the terminal process limit hint', () => { - expect(localizeTerminalSpawnHints(TERMINAL_PROCESS_LIMIT_HINT)).toBe('系统无法再启动终端进程。') - }) - it('translates the multi-line hints an older host publishes', () => { expect(localizeTerminalSpawnHints(`${LEGACY_PTY_ALLOCATION_HINT} ${RAW}`)).toBe( `系统无法再分配 pty 设备。 ${RAW}` @@ -46,29 +40,9 @@ describe('localizeTerminalSpawnHints', () => { '系统无法再启动终端进程。' ) }) - - it('translates the host terminal cap refusal', () => { - expect(localizeTerminalSpawnHints(TERMINAL_HOST_CAP_HINT)).toBe('主机终端已达上限。') - }) - - it('leaves unrelated errors untouched', () => { - expect(localizeTerminalSpawnHints('Paste failed.')).toBe('Paste failed.') - }) }) describe('withoutTerminalSpawnIssueRequest', () => { - it('drops the host issue request and keeps the diagnostic', () => { - expect(withoutTerminalSpawnIssueRequest(RAW)).toBe( - 'Failed to spawn shell "/bin/zsh": node-pty: open_slave failed: EMFILE (errno 24, Too many open files) (shell: /bin/zsh).' - ) - }) - - it('drops the request from an error before another pane error', () => { - expect(withoutTerminalSpawnIssueRequest(`${RAW}\nPaste failed.`)).toBe( - 'Failed to spawn shell "/bin/zsh": node-pty: open_slave failed: EMFILE (errno 24, Too many open files) (shell: /bin/zsh).\nPaste failed.' - ) - }) - it('keeps the same words when they are part of the diagnostic', () => { const error = `Command printed: If this persists, please file an issue.\nMore detail follows.` expect(withoutTerminalSpawnIssueRequest(error)).toBe(error) diff --git a/src/renderer/src/components/workspace-cleanup/workspace-cleanup-dialog-notices.test.tsx b/src/renderer/src/components/workspace-cleanup/workspace-cleanup-dialog-notices.test.tsx deleted file mode 100644 index 8544d8eb415..00000000000 --- a/src/renderer/src/components/workspace-cleanup/workspace-cleanup-dialog-notices.test.tsx +++ /dev/null @@ -1,58 +0,0 @@ -// @vitest-environment happy-dom -import { cleanup, render, screen } from '@testing-library/react' -import { afterEach, describe, expect, it, vi } from 'vitest' -import { - WorkspaceCleanupInitialScanBanner, - WorkspaceCleanupSizeScanBanner -} from './workspace-cleanup-dialog-notices' - -afterEach(cleanup) - -describe('WorkspaceCleanupInitialScanBanner', () => { - it('puts determinate progress in the title with matching typography', () => { - render( - - ) - - expect(screen.getByText('Scanning workspaces (23/3048)')).toBeTruthy() - expect(screen.queryByText('Checked workspaces so far: 23')).toBeNull() - }) -}) - -describe('WorkspaceCleanupSizeScanBanner', () => { - it('explains why scanning is useful and exposes the action', () => { - render( - - ) - - expect(screen.getByText('Scan workspace sizes')).toBeTruthy() - expect( - screen.getByText('Scan disk usage to compare, sort, and filter workspaces by size.') - ).toBeTruthy() - expect(screen.getByRole('button', { name: 'Scan' })).toBeTruthy() - }) - - it('shows determinate progress and disables duplicate runs', () => { - render( - - ) - - expect( - (screen.getByRole('button', { name: 'Scanning 23/100' }) as HTMLButtonElement).disabled - ).toBe(true) - }) -}) diff --git a/src/renderer/src/lib/new-workspace-create-gates.test.ts b/src/renderer/src/lib/new-workspace-create-gates.test.ts index 59770f886c0..858630fc2a1 100644 --- a/src/renderer/src/lib/new-workspace-create-gates.test.ts +++ b/src/renderer/src/lib/new-workspace-create-gates.test.ts @@ -15,28 +15,6 @@ const readyInput: ComposerCreateGateInput = { } describe('new workspace create gates', () => { - it('keeps quick create clickable when no repo is selected so submit can validate inline', () => { - expect(getQuickComposerCreateDisabled({ ...readyInput, repoId: '' })).toBe(false) - }) - - it('still blocks quick create for other missing form state and explicit setup choices', () => { - expect(getQuickComposerCreateDisabled({ ...readyInput, workspaceSeedName: '' })).toBe(true) - expect(getQuickComposerCreateDisabled({ ...readyInput, creating: true })).toBe(true) - expect( - getQuickComposerCreateDisabled({ ...readyInput, selectedRepoRequiresConnection: true }) - ).toBe(true) - expect( - getQuickComposerCreateDisabled({ - ...readyInput, - requiresExplicitSetupChoice: true, - hasSetupDecision: false - }) - ).toBe(true) - expect(getQuickComposerCreateDisabled({ ...readyInput, sparseError: 'Bad sparse path' })).toBe( - true - ) - }) - it('blocks quick create synchronously for unresolved source intent', () => { const blocked = { ...readyInput, sourceIntentBlocksCreate: true } diff --git a/src/renderer/src/lib/renderer-app-platform.test.ts b/src/renderer/src/lib/renderer-app-platform.test.ts index ff247e8b362..5a46beb2888 100644 --- a/src/renderer/src/lib/renderer-app-platform.test.ts +++ b/src/renderer/src/lib/renderer-app-platform.test.ts @@ -30,15 +30,6 @@ describe('getRendererAppPlatform', () => { expect(get).toHaveBeenCalledTimes(1) }) - it.each(['darwin', 'win32', 'linux'] as const)( - 'reports the preload platform verbatim on %s', - (platform) => { - stubPlatformApi(() => ({ platform })) - - expect(getRendererAppPlatform()).toBe(platform) - } - ) - // The web platform bridge arrives after boot; early user-agent guesses must not become session-long cache entries. it('does not cache the user-agent fallback', () => { // 'freebsd' is never a user-agent fallback answer, so the swap is unambiguous. diff --git a/src/renderer/src/lib/skill-freshness-display-status.test.ts b/src/renderer/src/lib/skill-freshness-display-status.test.ts index 48dae48bfa8..03d51f1eab9 100644 --- a/src/renderer/src/lib/skill-freshness-display-status.test.ts +++ b/src/renderer/src/lib/skill-freshness-display-status.test.ts @@ -7,8 +7,7 @@ import { } from '../components/skills/bundled-skill-plan-fixtures.test-support' import { getSkillFreshnessDisplayStatus, - hasSkillCopyNeedingAttention, - skillPlanHasDetails + hasSkillCopyNeedingAttention } from './skill-freshness-display-status' const SKILL_NAME = 'orca-cli' @@ -20,31 +19,6 @@ function planWith(...ops: BundledSkillOp[]) { } describe('getSkillFreshnessDisplayStatus', () => { - it('reports presence only without a plan or without a copy of Orca’s', () => { - expect(getSkillFreshnessDisplayStatus(null, SKILL_NAME)).toBe('installed') - expect(getSkillFreshnessDisplayStatus(planOf([]), SKILL_NAME)).toBe('installed') - expect(skillPlanHasDetails(null, SKILL_NAME)).toBe(false) - }) - - it('is up to date when every location is kept', () => { - const plan = planWith(planOp('keep', SHARED), planOp('keep', CLAUDE)) - expect(getSkillFreshnessDisplayStatus(plan, SKILL_NAME)).toBe('up-to-date') - expect(skillPlanHasDetails(plan, SKILL_NAME)).toBe(false) - }) - - it('offers an update when a released copy would be rewritten', () => { - const plan = planWith(planOp('update', SHARED), planOp('keep', CLAUDE)) - expect(getSkillFreshnessDisplayStatus(plan, SKILL_NAME)).toBe('update-available') - expect(hasSkillCopyNeedingAttention(plan, SKILL_NAME)).toBe(false) - expect(skillPlanHasDetails(plan, SKILL_NAME)).toBe(true) - }) - - it('treats link-only work as up to date but still offers details', () => { - const plan = planWith(planOp('keep', SHARED), planOp('link', CLAUDE)) - expect(getSkillFreshnessDisplayStatus(plan, SKILL_NAME)).toBe('up-to-date') - expect(skillPlanHasDetails(plan, SKILL_NAME)).toBe(true) - }) - it('flags an edited copy left alone, and an interrupted update to repair', () => { const edited = planWith( planOp('keep', SHARED), diff --git a/src/renderer/src/lib/worktree-display-name-order.test.ts b/src/renderer/src/lib/worktree-display-name-order.test.ts index c01d3d90148..4f402f03279 100644 --- a/src/renderer/src/lib/worktree-display-name-order.test.ts +++ b/src/renderer/src/lib/worktree-display-name-order.test.ts @@ -34,14 +34,4 @@ describe('compareWorktreeDisplayName', () => { expect(compareWorktreeDisplayName(a, b)).toBeLessThan(0) expect(compareWorktreeDisplayName(b, a)).toBeGreaterThan(0) }) - - it('treats two undefined names as equal without throwing', () => { - expect(compareWorktreeDisplayName(worktree('a', undefined), worktree('b', undefined))).toBe(0) - }) - - it('orders defined names lexicographically', () => { - expect( - compareWorktreeDisplayName(worktree('a', 'Apple'), worktree('b', 'Banana')) - ).toBeLessThan(0) - }) }) diff --git a/src/renderer/src/runtime/sync-runtime-graph/mobile-terminal-theme.test.ts b/src/renderer/src/runtime/sync-runtime-graph/mobile-terminal-theme.test.ts index ed840b37f43..d6f81137e9d 100644 --- a/src/renderer/src/runtime/sync-runtime-graph/mobile-terminal-theme.test.ts +++ b/src/renderer/src/runtime/sync-runtime-graph/mobile-terminal-theme.test.ts @@ -15,11 +15,6 @@ const BASE = { // Explicit contrast floor must travel with theme or mobile renders the same session differently (#10754). describe('resolveMobileTerminalTheme contrast floor', () => { - it('omits the floor when the user has not set one', () => { - const theme = resolveMobileTerminalTheme(stateWith(BASE), true) - expect(theme?.minimumContrastRatio).toBeUndefined() - }) - it('publishes the user floor so the phone stops lifting low-contrast output', () => { const theme = resolveMobileTerminalTheme( stateWith({ ...BASE, terminalMinimumContrastRatio: 1 }), @@ -40,8 +35,4 @@ describe('resolveMobileTerminalTheme contrast floor', () => { )?.minimumContrastRatio ).toBeUndefined() }) - - it('returns nothing without settings', () => { - expect(resolveMobileTerminalTheme(stateWith(null), true)).toBeUndefined() - }) })