diff --git a/config/scripts/ci-shard-timings.json b/config/scripts/ci-shard-timings.json
index ceb5f9b3a7b..b3f13546cde 100644
--- a/config/scripts/ci-shard-timings.json
+++ b/config/scripts/ci-shard-timings.json
@@ -8772,12 +8772,10 @@
"src/renderer/src/components/settings/agent-permission-conversion-persistence.test.tsx": 8787,
"src/renderer/src/components/settings/bitbucket-integration-card.test.tsx": 421,
"src/renderer/src/components/settings/browser-session-host-selection.test.ts": 43,
- "src/renderer/src/components/settings/bundled-skill-setup-labels.test.tsx": 3388,
"src/renderer/src/components/settings/bundled-skill-setup-result-copy.test.ts": 304,
"src/renderer/src/components/settings/chat-naming-persistence.test.tsx": 3654,
"src/renderer/src/components/settings/chat-settings-unsaved-guard.test.tsx": 1560,
"src/renderer/src/components/settings/cli-install-failure.test.ts": 34,
- "src/renderer/src/components/settings/cli-source-control-integration-cards.test.tsx": 695,
"src/renderer/src/components/settings/codex-config-sync-warning.test.ts": 34,
"src/renderer/src/components/settings/codex-session-source-home-control.test.tsx": 154,
"src/renderer/src/components/settings/developer-permissions-search.test.ts": 178,
@@ -9241,8 +9239,6 @@
"src/renderer/src/components/skills/skill-install-progress-state.test.tsx": 258,
"src/renderer/src/components/skills/skill-install-provider-groups.test.ts": 32,
"src/renderer/src/components/skills/skill-install-workspace-choices.test.ts": 55,
- "src/renderer/src/components/skills/skill-package-checklist-items.test.ts": 123,
- "src/renderer/src/components/skills/skill-package-install-risk.test.ts": 73,
"src/renderer/src/components/skills/skill-share-link.test.ts": 38,
"src/renderer/src/components/skills/skill-share-package-selection.test.ts": 48,
"src/renderer/src/components/skills/skill-share-preview-summary.test.ts": 149,
diff --git a/src/renderer/src/components/settings/bundled-skill-setup-labels.test.tsx b/src/renderer/src/components/settings/bundled-skill-setup-labels.test.tsx
deleted file mode 100644
index 4cc636175b0..00000000000
--- a/src/renderer/src/components/settings/bundled-skill-setup-labels.test.tsx
+++ /dev/null
@@ -1,219 +0,0 @@
-// @vitest-environment happy-dom
-
-import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'
-import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import type { BundledSkillOp } from '../../../../shared/bundled-skill-plan'
-import {
- doneResult,
- planEntry,
- planOf,
- planOp
-} from '../skills/bundled-skill-plan-fixtures.test-support'
-import { AgentSkillSetupPanel } from './AgentSkillSetupPanel'
-import { LinearAgentSkillInstallCta } from './linear-agent-skill-install-cta'
-
-const mocks = vi.hoisted(() => ({ plan: vi.fn(), execute: vi.fn(), refresh: vi.fn() }))
-const TARGET = { kind: 'environment', environmentId: 'agents-host' } as const
-
-vi.mock('@/hooks/useActiveProjectSkillRuntime', () => ({
- useActiveProjectSkillRuntime: () => ({ bundledSkillTarget: TARGET })
-}))
-vi.mock('@/hooks/installed-agent-skill-discovery', async (importOriginal) => ({
- ...(await importOriginal()),
- notifyInstalledAgentSkillsChanged: vi.fn()
-}))
-vi.mock('@/hooks/useInstalledAgentSkills', async (importOriginal) => ({
- ...(await importOriginal()),
- GLOBAL_AGENT_SKILL_SOURCE_KINDS: ['home'],
- notifyInstalledAgentSkillsRefreshed: vi.fn(),
- useInstalledAgentSkillNames: () => ({
- installed: true,
- loading: false,
- error: null,
- skills: [],
- refresh: mocks.refresh
- })
-}))
-vi.mock('@/hooks/useSkillFreshness', () => ({ refreshSkillFreshness: vi.fn() }))
-vi.mock('@/runtime/runtime-bundled-skills-client', () => ({
- planBundledSkillsOnTarget: mocks.plan,
- executeBundledSkillsOnTarget: mocks.execute
-}))
-
-function operations(
- name: string,
- update: boolean,
- agents: string[],
- edited = false
-): BundledSkillOp[] {
- return [
- planOp(update ? 'update' : 'keep', `/home/u/.agents/skills/${name}`),
- planOp('keep', `/home/u/.claude/skills/${name}`, {
- observed: { kind: 'link', target: `/home/u/.agents/skills/${name}` }
- }),
- ...agents.map((agent) =>
- planOp('link', `/home/u/.${agent}/skills/${name}`, {
- agents: agent === 'cursor' ? ['cursor'] : ['gemini']
- })
- ),
- ...(edited
- ? [
- planOp('leave', `/home/u/.factory/skills/${name}`, {
- reason: 'edited',
- agents: ['droid'],
- replaceable: true
- })
- ]
- : [])
- ]
-}
-
-beforeEach(() => {
- mocks.plan.mockReset()
- mocks.execute.mockReset()
- mocks.refresh.mockReset()
-})
-afterEach(cleanup)
-
-for (const surface of ['panel', 'linear'] as const) {
- describe(`${surface} setup plan labels`, () => {
- it.each([
- {
- update: false,
- agents: ['cursor'],
- button: 'Install for Cursor',
- result: 'Installed for Cursor'
- },
- {
- update: false,
- agents: ['cursor', 'gemini'],
- button: 'Install for 2 more agents',
- result: 'Installed for 2 more agents'
- },
- { update: true, agents: [], button: 'Update', result: 'Updated' },
- {
- update: true,
- agents: ['cursor'],
- button: 'Update',
- result: 'Updated · Installed for Cursor'
- },
- {
- update: true,
- agents: ['cursor', 'gemini'],
- button: 'Update',
- result: 'Updated · Installed for 2 more agents'
- }
- ])('labels $button and reports $result', async ({ update, agents, button, result }) => {
- const name = surface === 'panel' ? 'orca-cli' : 'orca-linear'
- const plan = planOf([planEntry(name, operations(name, update, agents))])
- mocks.plan.mockResolvedValue({ kind: 'plan', plan })
- mocks.execute.mockResolvedValue(doneResult(plan))
- render(
- surface === 'panel' ? (
-
- ) : (
-
- )
- )
- fireEvent.click(await screen.findByRole('button', { name: button }))
- expect(await screen.findByText(result, { exact: true })).toBeDefined()
- expect(mocks.plan).toHaveBeenCalledWith(TARGET, { names: [name] })
- expect(mocks.execute).toHaveBeenCalledWith(TARGET, plan.planDigest, { names: [name] })
- })
-
- it('shows the current verdict without an install button when every copy is current', async () => {
- const name = surface === 'panel' ? 'orca-cli' : 'orca-linear'
- mocks.plan.mockResolvedValue({
- kind: 'plan',
- plan: planOf([planEntry(name, operations(name, false, []))])
- })
- render(
- surface === 'panel' ? (
-
- ) : (
-
- )
- )
- await waitFor(() =>
- expect(screen.queryByRole('button', { name: /^(Install|Update)/ })).toBeNull()
- )
- expect(
- await screen.findByText(surface === 'panel' ? 'Up to date' : 'Installed', { exact: true })
- ).toBeDefined()
- expect(mocks.execute).not.toHaveBeenCalled()
- })
- })
-}
-
-it('keeps the edited-copy suffix after the mixed result', async () => {
- const plan = planOf([planEntry('orca-cli', operations('orca-cli', true, ['cursor'], true))])
- mocks.plan.mockResolvedValue({ kind: 'plan', plan })
- mocks.execute.mockResolvedValue(doneResult(plan))
- render(
-
- )
- fireEvent.click(await screen.findByRole('button', { name: 'Update' }))
- expect(
- await screen.findByText(
- 'Updated · Installed for Cursor · Update skipped in Droid: Skill edited outside Orca'
- )
- ).toBeDefined()
-})
-
-it.each([
- { agents: ['cursor'], result: 'Installed for Cursor' },
- { agents: ['cursor', 'gemini'], result: 'Installed for 2 agents' }
-])('uses first-install wording for $result', async ({ agents, result }) => {
- const plan = planOf([
- planEntry('orca-cli', [
- planOp('write', '/home/u/.agents/skills/orca-cli'),
- ...agents.map((agent) =>
- planOp('link', `/home/u/.${agent}/skills/orca-cli`, {
- agents: agent === 'cursor' ? ['cursor'] : ['gemini']
- })
- )
- ])
- ])
- mocks.plan.mockResolvedValue({ kind: 'plan', plan })
- mocks.execute.mockResolvedValue(doneResult(plan))
- render(
-
- )
- await waitFor(() =>
- expect(screen.getByRole('button', { name: 'Install' }).hasAttribute('disabled')).toBe(false)
- )
- fireEvent.click(screen.getByRole('button', { name: 'Install' }))
- expect(await screen.findByText(result, { exact: true })).toBeDefined()
-})
diff --git a/src/renderer/src/components/settings/cli-source-control-integration-cards.test.tsx b/src/renderer/src/components/settings/cli-source-control-integration-cards.test.tsx
deleted file mode 100644
index dad12f297b0..00000000000
--- a/src/renderer/src/components/settings/cli-source-control-integration-cards.test.tsx
+++ /dev/null
@@ -1,129 +0,0 @@
-// @vitest-environment happy-dom
-
-import { act } from 'react'
-import { createRoot, type Root } from 'react-dom/client'
-import { afterEach, describe, expect, it, vi } from 'vitest'
-import { getExecutionHostLabel } from '../../../../shared/execution-host'
-import {
- GitHubIntegrationCard,
- GitLabIntegrationCard
-} from './cli-source-control-integration-cards'
-
-const LOCAL_HOST_LABEL = getExecutionHostLabel('local')
-
-type StoreState = {
- settings: { activeRuntimeEnvironmentId: string | null }
- openSettingsPage: () => void
- openSettingsTarget: (target: { pane: string; repoId: string | null }) => void
-}
-
-const mocks = vi.hoisted(() => ({
- store: { current: null as StoreState | null },
- preflight: {
- statuses: {
- ghStatus: 'connected',
- glabStatus: 'connected',
- bitbucketStatus: 'not-configured',
- azureDevOpsStatus: 'not-configured',
- giteaStatus: 'not-configured',
- bitbucketAccount: null,
- azureDevOpsAccount: null,
- giteaAccount: null
- },
- unavailable: false,
- refresh: vi.fn()
- }
-}))
-
-vi.mock('@/store', () => ({
- useAppStore: (selector: (state: StoreState) => unknown) => {
- if (!mocks.store.current) {
- throw new Error('Store state was not installed')
- }
- return selector(mocks.store.current)
- }
-}))
-
-vi.mock('./source-control-preflight-card-status', () => ({
- usePreflightCardStatuses: () => mocks.preflight
-}))
-
-let root: Root | null = null
-let container: HTMLDivElement | null = null
-
-async function renderCard(card: React.ReactNode): Promise {
- container = document.createElement('div')
- document.body.appendChild(container)
- root = createRoot(container)
- await act(async () => {
- root?.render(card)
- })
- return container
-}
-
-describe('CLI source-control integration card account scope', () => {
- afterEach(async () => {
- if (root) {
- await act(async () => {
- root?.unmount()
- })
- }
- root = null
- container?.remove()
- container = null
- mocks.store.current = null
- mocks.preflight.statuses.ghStatus = 'connected'
- mocks.preflight.statuses.glabStatus = 'connected'
- mocks.preflight.unavailable = false
- mocks.preflight.refresh.mockClear()
- })
-
- it('shows local-client ownership for connected GitHub CLI credentials', async () => {
- const openSettingsPage = vi.fn()
- const openSettingsTarget = vi.fn()
- mocks.store.current = {
- settings: { activeRuntimeEnvironmentId: null },
- openSettingsPage,
- openSettingsTarget
- }
-
- const rendered = await renderCard()
-
- expect(rendered.textContent).toContain('GitHub')
- expect(rendered.textContent).toContain('Connected')
- expect(rendered.textContent).toContain(`Account scope: ${LOCAL_HOST_LABEL}`)
- expect(rendered.textContent).toContain(
- 'Credentials and account checks for this provider are owned by this desktop client. To use a server, change Settings > Remote Orca Servers > New projects open on.'
- )
- await act(async () => {
- Array.from(rendered.querySelectorAll('button'))
- .find((button) => button.textContent === 'Open Remote Servers')
- ?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
- })
-
- expect(openSettingsPage).toHaveBeenCalledTimes(1)
- expect(openSettingsTarget).toHaveBeenCalledWith({
- pane: 'servers',
- repoId: null,
- sectionId: 'default-runtime'
- })
- })
-
- it('shows remote-server ownership for GitLab CLI credential checks', async () => {
- mocks.store.current = {
- settings: { activeRuntimeEnvironmentId: 'runtime-1' },
- openSettingsPage: vi.fn(),
- openSettingsTarget: vi.fn()
- }
- mocks.preflight.statuses.glabStatus = 'not-authenticated'
-
- const rendered = await renderCard()
-
- expect(rendered.textContent).toContain('GitLab')
- expect(rendered.textContent).toContain('Account scope: Remote server: runtime-1')
- expect(rendered.textContent).toContain(
- 'Credentials and account checks for this provider are owned by this remote server. To use another host, change Settings > Remote Orca Servers > New projects open on.'
- )
- expect(rendered.textContent).toContain('glab auth login')
- })
-})
diff --git a/src/renderer/src/components/settings/linear-agent-skill-install-cta.test.tsx b/src/renderer/src/components/settings/linear-agent-skill-install-cta.test.tsx
index d5018106c33..1c3ad44e0ad 100644
--- a/src/renderer/src/components/settings/linear-agent-skill-install-cta.test.tsx
+++ b/src/renderer/src/components/settings/linear-agent-skill-install-cta.test.tsx
@@ -108,43 +108,6 @@ describe('LinearAgentSkillInstallCta', () => {
container = null
})
- it('offers Install and the explanation when the skill is missing', async () => {
- const rendered = await renderCta()
-
- expect(rendered.textContent).toContain('Agent skill:')
- expect(rendered.textContent).toContain('orca-linear')
- expect(rendered.textContent).toContain('Not installed')
- expect(rendered.textContent).toContain(
- 'Full guided setup (connect + skill + visibility) is under Settings → Task Sources.'
- )
- expect(rendered.textContent).toContain('Install skill')
- expect(rendered.textContent).not.toContain('Copy command')
- })
-
- it("installs the skill directly on the agents' host", async () => {
- const rendered = await renderCta()
-
- await act(async () => {
- Array.from(rendered.querySelectorAll('button'))
- .find((button) => button.textContent === 'Install skill')
- ?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
- })
-
- expect(mocks.plan).toHaveBeenCalledWith({ kind: 'local' }, { names: ['orca-linear'] })
- expect(rendered.textContent).toContain('Update Orca on the server to install its skills.')
- })
-
- it('shows a subtle confirmation and Update when installed', async () => {
- mocks.skillState.installed = true
- mocks.skillState.skills = [discoveredSkill({ name: 'orca-linear' })]
-
- const rendered = await renderCta()
-
- expect(rendered.textContent).toContain('Installed')
- expect(rendered.textContent).toContain('Update')
- expect(rendered.textContent).not.toContain('Not installed')
- })
-
it('updates through the legacy skill name when only linear-tickets is installed', async () => {
mocks.skillState.installed = true
mocks.skillState.skills = [
@@ -166,16 +129,6 @@ describe('LinearAgentSkillInstallCta', () => {
expect(mocks.plan).toHaveBeenCalledWith({ kind: 'local' }, { names: ['linear-tickets'] })
})
- it('notes that remote agent environments need their own setup', async () => {
- const rendered = await renderCta({
- settings: { activeRuntimeEnvironmentId: 'runtime-1', terminalWindowsShell: '' }
- })
-
- expect(rendered.textContent).toContain(
- 'This installs host setup; remote agent environments may need separate setup.'
- )
- })
-
it('keeps the resolved WSL project on the old command flow', async () => {
mocks.agentRuntime = { runtime: 'wsl', wslDistro: 'Debian', label: 'WSL Debian' }
const rendered = await renderCta()
@@ -189,31 +142,4 @@ describe('LinearAgentSkillInstallCta', () => {
expect.objectContaining({ discoveryTarget: { runtime: 'wsl', wslDistro: 'Debian' } })
)
})
-
- it('uses project host discovery even when legacy global settings still prefer WSL', async () => {
- mocks.agentRuntime = { runtime: 'host', label: 'Windows' }
- await renderCta({
- settings: {
- localAgentRuntime: 'wsl',
- localAgentWslDistro: 'Ubuntu',
- terminalWindowsShell: 'wsl.exe'
- }
- })
- expect(mocks.useInstalledAgentSkillNames).toHaveBeenCalledWith(
- expect.anything(),
- expect.objectContaining({ discoveryTarget: undefined })
- )
- })
-
- it('re-checks the skill scan on demand', async () => {
- const rendered = await renderCta()
-
- await act(async () => {
- Array.from(rendered.querySelectorAll('button'))
- .find((button) => button.textContent?.includes('Re-check'))
- ?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
- })
-
- expect(mocks.skillState.refresh).toHaveBeenCalledTimes(1)
- })
})
diff --git a/src/renderer/src/components/settings/repository/source-control/RepositorySourceControlAiSection.test.ts b/src/renderer/src/components/settings/repository/source-control/RepositorySourceControlAiSection.test.ts
index 874412263e2..236b88b79be 100644
--- a/src/renderer/src/components/settings/repository/source-control/RepositorySourceControlAiSection.test.ts
+++ b/src/renderer/src/components/settings/repository/source-control/RepositorySourceControlAiSection.test.ts
@@ -4,17 +4,9 @@ import { act, render, cleanup, fireEvent } from '@testing-library/react'
import '../../__fixtures__/settings-persistence-test-fixture'
import React from 'react'
import type { TuiAgent } from '../../../../../../shared/tui-agent'
-import { renderToStaticMarkup } from 'react-dom/server'
import { normalizeRepoSourceControlAiOverrides } from '../../../../../../shared/source-control-ai-repo-settings'
-import type {
- RepoSourceControlAiOverrides,
- SourceControlAiSettings
-} from '../../../../../../shared/source-control-ai-types'
-import {
- SOURCE_CONTROL_ACTION_IDS,
- setSourceControlActionAgentDefault,
- type SourceControlActionId
-} from '../../../../../../shared/source-control-ai-actions'
+import type { RepoSourceControlAiOverrides } from '../../../../../../shared/source-control-ai-types'
+import { setSourceControlActionAgentDefault } from '../../../../../../shared/source-control-ai-actions'
import {
computeActionDirtyById,
dropRepoLegacyInstructionForAction,
@@ -29,7 +21,6 @@ import {
import { sourceControlActionRecipeMatchesTarget } from '../../../right-sidebar/source-control-action-recipe-match'
import { SourceControlActionAgentPicker } from '../../SourceControlActionAgentPicker'
import { RepositorySourceControlAiActionRows } from './RepositorySourceControlAiActionRows'
-import { RepositorySourceControlAiEnablement } from './RepositorySourceControlAiEnablement'
import { SourceControlAiActionRecipeDefaults } from '../../SourceControlAiActionRecipeDefaults'
import { useAppStore } from '../../../../store/index'
import { TooltipProvider } from '../../../ui/tooltip'
@@ -103,24 +94,6 @@ describe('saved chat-or-CLI pick', () => {
})
})
-describe('RepositorySourceControlAiEnablement', () => {
- it('describes repo enablement as Source Control AI action visibility', () => {
- const markup = renderToStaticMarkup(
- React.createElement(RepositorySourceControlAiEnablement, {
- value: false,
- source: { enabled: true } as SourceControlAiSettings,
- onChange: () => {}
- })
- )
-
- expect(markup).toContain('Show Source Control AI actions')
- expect(markup).toContain('Controls whether Source Control AI buttons are shown')
- expect(markup).toContain('separate features follows those features' settings')
- expect(markup).toContain('Show')
- expect(markup).not.toContain('Source Control AI enabled')
- })
-})
-
describe('RepositorySourceControlAiActionRows', () => {
it.each([
{ agent: 'codex', detected: ['codex'], surface: undefined },
@@ -270,67 +243,6 @@ describe('RepositorySourceControlAiActionRows', () => {
expect(onEdit).not.toHaveBeenCalled()
}
)
-
- it.each([undefined, null, '', '--repo'])(
- 'renders save controls and argument ownership for %s',
- (repoAgentArgs) => {
- const actionDirtyById = Object.fromEntries(
- SOURCE_CONTROL_ACTION_IDS.map((actionId) => [actionId, actionId === 'fixCommitFailure'])
- ) as Record
- const source: SourceControlAiSettings = {
- enabled: true,
- agentId: null,
- selectedModelByAgent: {},
- selectedThinkingByModel: {},
- customAgentCommand: '',
- instructionsByOperation: {},
- actions: { fixCommitFailure: { agentId: null, agentArgs: '--global' } }
- }
-
- const rows = React.createElement(RepositorySourceControlAiActionRows, {
- repoId: 'repo-1',
- repoAi: {
- actionOverrides: {
- fixCommitFailure: {
- agentId: null,
- commandInputTemplate: '{basePrompt}\n\nrepo',
- ...(repoAgentArgs !== undefined ? { agentArgs: repoAgentArgs } : {})
- }
- }
- },
- source,
- defaultTuiAgent: 'codex',
- savingActionIds: {},
- actionDirtyById,
- onActionModeChange: () => {},
- onActionAgentChange: () => {},
- onActionLaunchPreferencesChange: () => {},
- onActionTemplateChange: () => {},
- onActionAgentArgsChange: () => {},
- onAppendVariable: () => {},
- onActionDiscard: () => {},
- onActionSave: () => {}
- })
- const markup = renderToStaticMarkup(React.createElement(TooltipProvider, null, rows))
-
- expect(markup).toContain('Commit failure fixes')
- expect(markup).toContain('Push failure fixes')
- expect(markup).toContain('Unsaved changes')
- expect(markup).toContain('Discard')
- expect(markup).toContain('Save')
- expect(markup).toContain('repo-repo-1-source-control-ai-fixCommitFailure')
- const card = new DOMParser()
- .parseFromString(markup, 'text/html')
- .getElementById('repo-repo-1-source-control-ai-fixCommitFailure')
- expect(card?.textContent).toContain(
- repoAgentArgs === undefined
- ? 'Global custom args'
- : repoAgentArgs
- ? 'Repository custom args'
- : 'No args'
- )
- }
- )
})
describe('dropRepoLegacyInstructionForAction', () => {
@@ -353,17 +265,6 @@ describe('dropRepoLegacyInstructionForAction', () => {
commandInputTemplate: '{basePrompt}\n\nUse PR style.'
})
})
-
- it('leaves launch action recipes alone because they have no legacy instruction key', () => {
- const value = {
- instructionsByOperation: { commitMessage: 'Use repo style.' },
- actionOverrides: {
- fixChecks: { commandInputTemplate: '{basePrompt}' }
- }
- }
-
- expect(dropRepoLegacyInstructionForAction(value, 'fixChecks')).toBe(value)
- })
})
it.each(['', '--model raw'])(
diff --git a/src/renderer/src/components/settings/repository/source-control/repository-source-control-ai-global-ux.test.ts b/src/renderer/src/components/settings/repository/source-control/repository-source-control-ai-global-ux.test.ts
index ce83937c83a..4d2216e5648 100644
--- a/src/renderer/src/components/settings/repository/source-control/repository-source-control-ai-global-ux.test.ts
+++ b/src/renderer/src/components/settings/repository/source-control/repository-source-control-ai-global-ux.test.ts
@@ -443,19 +443,6 @@ describe('editing one repository action', () => {
expect(set().launchPreferences).toBeUndefined()
})
- it('makes the copied model owned by the action, so it outranks the raw model it yielded to', () => {
- const legacy = { actionOverrides: { fixCommitFailure: { agentArgs: '--model gpt-5.6-sol' } } }
- const stored = {
- settings,
- repo: { sourceControlAi: legacy },
- actionId: 'fixCommitFailure'
- } as const
- expect(resolveSourceControlActionRecipe(stored).launchPreferencesYieldToAgentArgs).toBe(true)
- const edited = reload(editPrompt(legacy, 'fixCommitFailure'), 'fixCommitFailure')
- expect(edited).toMatchObject({ commandInputTemplate: 'mine', launchPreferences: terra })
- expect(edited.launchPreferencesYieldToAgentArgs).toBeUndefined()
- })
-
it('saves a prompt edit without authoring args the user never typed or touching a sibling', async () => {
const sibling = { agentArgs: '--repo' }
const cleared = {
diff --git a/src/renderer/src/components/settings/repository/source-control/repository-source-control-ai-persist-queue.test.ts b/src/renderer/src/components/settings/repository/source-control/repository-source-control-ai-persist-queue.test.ts
index 8fffe2ab71c..2e8b73b7d9d 100644
--- a/src/renderer/src/components/settings/repository/source-control/repository-source-control-ai-persist-queue.test.ts
+++ b/src/renderer/src/components/settings/repository/source-control/repository-source-control-ai-persist-queue.test.ts
@@ -38,14 +38,6 @@ describe('createRepoAiPersistQueue', () => {
h = makeQueue()
})
- it('persists a changed value and stores the normalized saved result', async () => {
- h.updateRepo.mockResolvedValue(true)
- const ok = await h.queue.persistTransform((base) => ({ ...base, enabled: true }))
- expect(ok).toBe(true)
- expect(h.updateRepo).toHaveBeenCalledTimes(1)
- expect(h.getPersisted()).toMatchObject({ enabled: true })
- })
-
it('skips the backend write when the transform is a no-op', async () => {
h.updateRepo.mockResolvedValue(true)
const ok = await h.queue.persistTransform((base) => base)
@@ -128,20 +120,4 @@ describe('createRepoAiPersistQueue', () => {
// Completing a stale write must not seed the new repo's local persisted base.
expect(h.setPersisted).not.toHaveBeenCalled()
})
-
- it('does not apply setPersisted when the repo switches during an in-flight updateRepo', async () => {
- let release: (ok: boolean) => void = () => {}
- h.updateRepo.mockImplementation(
- () =>
- new Promise((resolve) => {
- release = resolve
- })
- )
- const pending = h.queue.persistTransform((base) => ({ ...base, enabled: true }))
- h.setRepoId('repo-2')
- release(true)
- await expect(pending).resolves.toBe(true)
- expect(h.setPersisted).not.toHaveBeenCalled()
- expect(h.onError).not.toHaveBeenCalled()
- })
})
diff --git a/src/renderer/src/components/settings/settings-host-scope.test.ts b/src/renderer/src/components/settings/settings-host-scope.test.ts
index c6b6aab4008..693bfe235cc 100644
--- a/src/renderer/src/components/settings/settings-host-scope.test.ts
+++ b/src/renderer/src/components/settings/settings-host-scope.test.ts
@@ -4,36 +4,6 @@ import { resolveSettingsHostScope } from './settings-host-scope'
const saved = ['env-a', 'env-b']
describe('resolveSettingsHostScope', () => {
- it('starts on the default host setting until the user picks one', () => {
- expect(
- resolveSettingsHostScope({
- choice: null,
- defaultEnvironmentId: ' env-a ',
- savedEnvironmentIds: saved,
- catalogHydrated: true
- })
- ).toEqual({ target: { kind: 'environment', environmentId: 'env-a' }, available: true })
- })
-
- it('keeps the picked host when the default host setting changes', () => {
- expect(
- resolveSettingsHostScope({
- choice: { kind: 'local' },
- defaultEnvironmentId: 'env-a',
- savedEnvironmentIds: saved,
- catalogHydrated: true
- })
- ).toEqual({ target: { kind: 'local' }, available: true })
- expect(
- resolveSettingsHostScope({
- choice: { kind: 'environment', environmentId: 'env-b' },
- defaultEnvironmentId: null,
- savedEnvironmentIds: saved,
- catalogHydrated: true
- })
- ).toEqual({ target: { kind: 'environment', environmentId: 'env-b' }, available: true })
- })
-
it('marks a removed server unavailable instead of falling back to this computer', () => {
expect(
resolveSettingsHostScope({
diff --git a/src/renderer/src/components/settings/shortcut-groups.test.ts b/src/renderer/src/components/settings/shortcut-groups.test.ts
index af69731d932..3f7aa7d95f7 100644
--- a/src/renderer/src/components/settings/shortcut-groups.test.ts
+++ b/src/renderer/src/components/settings/shortcut-groups.test.ts
@@ -1,44 +1,8 @@
import { describe, expect, it } from 'vitest'
-import type { KeybindingDefinition } from '../../../../shared/keybindings'
import type { ActivePluginCommand } from '@/store/plugin-panels'
import { buildShortcutDefinitionCatalog } from './shortcut-definition-catalog'
-import { groupDefinitions } from './shortcut-groups'
-
-const pluginDefinition: KeybindingDefinition = {
- id: 'plugin:orca-samples.tasks/open',
- title: 'Open Tasks — Tasks',
- group: 'Plugins',
- scope: 'global',
- searchKeywords: ['plugin', 'tasks'],
- defaultBindings: {
- darwin: ['Mod+Alt+T'],
- linux: ['Mod+Alt+T'],
- win32: ['Mod+Alt+T']
- }
-}
describe('shortcut groups', () => {
- it('includes dynamic plugin command definitions in Settings', () => {
- expect(groupDefinitions([], [pluginDefinition])).toEqual(
- expect.arrayContaining([
- expect.objectContaining({
- title: 'Plugins',
- items: [pluginDefinition]
- })
- ])
- )
- })
-
- it('exposes the agent dashboard toggle as a customizable Global row', () => {
- const global = groupDefinitions([]).find((group) => group.title === 'Global')
-
- expect(global?.items).toEqual(
- expect.arrayContaining([
- expect.objectContaining({ id: 'dashboard.toggle', title: 'Toggle Agent Dashboard' })
- ])
- )
- })
-
it('reports a plugin default that shadows a built-in shortcut', () => {
const command: ActivePluginCommand = {
pluginKey: 'orca-samples.tasks',
diff --git a/src/renderer/src/components/settings/skill-setup-blocked-plan.test.tsx b/src/renderer/src/components/settings/skill-setup-blocked-plan.test.tsx
index e9057032eb6..32b440f8b11 100644
--- a/src/renderer/src/components/settings/skill-setup-blocked-plan.test.tsx
+++ b/src/renderer/src/components/settings/skill-setup-blocked-plan.test.tsx
@@ -115,36 +115,6 @@ function renderSurface(
)
}
-for (const surface of ['panel', 'guided-panel', 'linear', 'browser', 'capabilities'] as const) {
- describe(`${surface} blocked setup`, () => {
- describe.each([
- [
- 'update-server',
- 'Update Orca on the server to install its skills.',
- 'Update Orca on the server'
- ],
- ['connect-host', 'Connect to this SSH host to install its skills.', 'Connect the SSH host']
- ] as const)('%s', (reason, message, pill) => {
- it.each(surface === 'browser' || surface === 'capabilities' ? [false] : [false, true])(
- 'explains the prerequisite before any click (installed: %s)',
- async (installed) => {
- mocks.installed = installed
- mocks.plan.mockResolvedValue({ kind: 'unsupported', reason })
- renderSurface(surface)
-
- expect(await screen.findByText(message)).toBeDefined()
- expect(screen.queryByRole('button', { name: /^(Install|Update|Replace)/ })).toBeNull()
- expect(screen.queryByText('Check failed')).toBeNull()
- if (surface === 'panel' || surface === 'guided-panel' || surface === 'linear') {
- expect(screen.getByText(pill, { exact: true })).toBeDefined()
- }
- expect(mocks.execute).not.toHaveBeenCalled()
- }
- )
- })
- })
-}
-
for (const surface of ['panel', 'linear', 'browser', 'capabilities'] as const) {
describe(`${surface} blocked setup`, () => {
it.each([false, true])(
diff --git a/src/renderer/src/components/settings/source-control-action-card-layout.test.tsx b/src/renderer/src/components/settings/source-control-action-card-layout.test.tsx
index 238685e0faa..adbfbd8b184 100644
--- a/src/renderer/src/components/settings/source-control-action-card-layout.test.tsx
+++ b/src/renderer/src/components/settings/source-control-action-card-layout.test.tsx
@@ -17,7 +17,6 @@ import {
} from '@/runtime/host-structured-agents'
import { TooltipProvider } from '../ui/tooltip'
import { SourceControlActionRecipeRow } from './SourceControlActionRecipeRow'
-import { shouldShowSourceControlActionArguments } from './source-control-action-arguments-visibility'
vi.mock('@/runtime/runtime-rpc-client', () => ({
callRuntimeRpc: vi.fn(async () => ({ agents: [{ agent: 'grok', capabilities: {} }] }))
@@ -67,27 +66,6 @@ beforeEach(() => {
})
afterEach(resetHostStructuredAgentsForTests)
-it.each([
- ['chat on', 'claude', true, undefined, false],
- ['chat off', 'claude', false, undefined, true],
- ['provider off', 'claude', true, { claude: false }, true],
- ['no chat support', 'goose', true, undefined, true]
-] as const)('%s: shows Arguments only for the CLI', (_name, agent, chat, providers, visible) => {
- configure({ experimentalNativeChat: chat, nativeChatProviders: providers })
- render(
)
- expect(Boolean(screen.queryByRole('textbox', { name: 'Arguments' }))).toBe(visible)
- expect(screen.getByText('Command template')).toBeDefined()
-})
-
-it('hides an unresolved launch even with chat off, but always shows text action Arguments', () => {
- configure({ experimentalNativeChat: false })
- useAppStore.setState({ localDetectedAgentIdsByContext: {} })
- const view = render(
)
- expect(screen.queryByRole('textbox', { name: 'Arguments' })).toBeNull()
- view.rerender(
)
- expect(screen.getByDisplayValue('--saved')).toBeDefined()
-})
-
it('keeps the draft and chip while Model/Effort controls stay hidden', () => {
configure({ experimentalNativeChat: false })
render(
)
@@ -124,22 +102,3 @@ it('reacts to the real host registry when another agent gains chat support', asy
)
expect(screen.queryByRole('textbox', { name: 'Arguments' })).toBeNull()
})
-
-it('honors an explicit future surface only after an agent resolves', () => {
- const input = {
- agent: 'claude',
- settings: { experimentalNativeChat: true },
- chatAgents: ['claude']
- } as const
- expect(shouldShowSourceControlActionArguments({ ...input, launchKind: 'terminal' })).toBe(true)
- expect(
- shouldShowSourceControlActionArguments({
- ...input,
- settings: { experimentalNativeChat: false },
- launchKind: 'chat'
- })
- ).toBe(false)
- expect(
- shouldShowSourceControlActionArguments({ ...input, agent: null, launchKind: 'terminal' })
- ).toBe(false)
-})
diff --git a/src/renderer/src/components/sidebar/linear-agent-skill-setup-reminders.test.ts b/src/renderer/src/components/sidebar/linear-agent-skill-setup-reminders.test.ts
index 37f87a905fb..9072854977f 100644
--- a/src/renderer/src/components/sidebar/linear-agent-skill-setup-reminders.test.ts
+++ b/src/renderer/src/components/sidebar/linear-agent-skill-setup-reminders.test.ts
@@ -1,7 +1,6 @@
import { afterEach, describe, expect, it } from 'vitest'
import {
MAX_LINEAR_AGENT_SKILL_SETUP_REMINDER_RUNTIME_KEYS,
- createLinearAgentSkillSetupActivationId,
getExistingLinearAgentSkillSetupReminderState,
getLinearAgentSkillSetupReminderState,
getLinearAgentSkillSetupReminderStateCountForTests,
@@ -77,13 +76,4 @@ describe('linear agent skill setup reminders', () => {
expect(getExistingLinearAgentSkillSetupReminderState('missing')).toBeUndefined()
expect(getLinearAgentSkillSetupReminderStateCountForTests()).toBe(0)
})
-
- it('resets activation ids with reminder state for tests', () => {
- expect(createLinearAgentSkillSetupActivationId()).toBe('linear-agent-skill-setup-0')
- expect(createLinearAgentSkillSetupActivationId()).toBe('linear-agent-skill-setup-1')
-
- resetLinearAgentSkillSetupReminderState()
-
- expect(createLinearAgentSkillSetupActivationId()).toBe('linear-agent-skill-setup-0')
- })
})
diff --git a/src/renderer/src/components/skills/skill-delete-copy.test.ts b/src/renderer/src/components/skills/skill-delete-copy.test.ts
index e9a7d540874..6b9e0a31c36 100644
--- a/src/renderer/src/components/skills/skill-delete-copy.test.ts
+++ b/src/renderer/src/components/skills/skill-delete-copy.test.ts
@@ -1,148 +1,11 @@
-import { describe, expect, it, vi } from 'vitest'
+import { expect, it, vi } from 'vitest'
import type { SkillDeletePlan } from '../../../../shared/skill-delete-contract'
-import {
- skillDeleteBlockedLines,
- skillDeletePlacementSummary,
- skillDeleteResultLines,
- skillDeleteRetainedSourceLines
-} from './skill-delete-copy'
+import { skillDeletePlacementSummary } from './skill-delete-copy'
function plan(skills: SkillDeletePlan['skills']): SkillDeletePlan {
return { operationId: 'op', skills }
}
-describe('skillDeletePlacementSummary', () => {
- it('summarizes folders, links, and the roots they sit in', () => {
- const summary = skillDeletePlacementSummary(
- plan([
- {
- id: 'a',
- name: 'demo',
- canonicalPath: '/root/demo/SKILL.md',
- placements: [
- {
- path: '/home/.agents/skills/demo',
- kind: 'canonical',
- rootLabel: 'Agent skills home'
- },
- { path: '/home/.claude/skills/demo', kind: 'alias-dir', rootLabel: 'Claude Code home' }
- ]
- }
- ])
- )
- expect(summary).toContain('1')
- expect(summary).toContain('Agent skills home')
- expect(summary).toContain('Claude Code home')
- })
-
- it('drops the zero half so a link-only delete never reads "0 folders"', () => {
- const summary = skillDeletePlacementSummary(
- plan([
- {
- id: 'a',
- name: 'demo',
- canonicalPath: '/home/.local/share/devex/skills/demo/SKILL.md',
- placements: [
- { path: '/repo/.agents/skills/demo', kind: 'alias-dir', rootLabel: 'Repo app .agents' }
- ]
- }
- ])
- )
- expect(summary).not.toContain('0')
- expect(summary).toContain('link')
- expect(summary).not.toContain('folder')
- })
-
- it('is null when the plan removes nothing', () => {
- expect(
- skillDeletePlacementSummary(
- plan([
- {
- id: 'a',
- name: 'demo',
- canonicalPath: '/elsewhere/demo/SKILL.md',
- placements: [],
- blocked: 'unowned'
- }
- ])
- )
- ).toBeNull()
- })
-})
-
-describe('skillDeleteRetainedSourceLines', () => {
- it('says where the content stays when only links are removed', () => {
- const lines = skillDeleteRetainedSourceLines(
- plan([
- {
- id: 'a',
- name: 'demo',
- canonicalPath: '/home/.local/share/devex/skills/demo/SKILL.md',
- placements: [
- { path: '/repo/.agents/skills/demo', kind: 'alias-dir', rootLabel: 'Repo app .agents' }
- ]
- }
- ])
- )
- expect(lines).toHaveLength(1)
- expect(lines[0]).toContain('/home/.local/share/devex/skills/demo')
- })
-
- it('stays silent when a real folder is being removed', () => {
- expect(
- skillDeleteRetainedSourceLines(
- plan([
- {
- id: 'a',
- name: 'demo',
- canonicalPath: '/home/.agents/skills/demo/SKILL.md',
- placements: [
- {
- path: '/home/.agents/skills/demo',
- kind: 'canonical',
- rootLabel: 'Agent skills home'
- }
- ]
- }
- ])
- )
- ).toEqual([])
- })
-})
-
-describe('skillDeleteBlockedLines', () => {
- it('groups by typed reason rather than one merged skipped line', () => {
- const lines = skillDeleteBlockedLines(
- plan([
- { id: 'a', name: 'a', canonicalPath: '/p', placements: [], blocked: 'bundled' },
- { id: 'b', name: 'b', canonicalPath: '/p', placements: [], blocked: 'bundled' },
- { id: 'c', name: 'c', canonicalPath: '/p', placements: [], blocked: 'plugin' }
- ])
- )
- expect(lines).toHaveLength(2)
- expect(lines.some((line) => line.includes('2') && line.includes('Bundled'))).toBe(true)
- })
-})
-
-describe('skillDeleteResultLines', () => {
- it('omits deleted rows and keeps one line per distinct outcome', () => {
- const lines = skillDeleteResultLines([
- { id: 'a', name: 'a', status: 'deleted', removedPaths: ['/x'] },
- { id: 'b', name: 'b', status: 'skipped', blocked: 'unowned', removedPaths: [] },
- { id: 'c', name: 'c', status: 'skipped', blocked: 'unowned', removedPaths: [] },
- { id: 'd', name: 'd', status: 'busy', removedPaths: [] }
- ])
- expect(lines.map((line) => line.key)).toEqual(['skipped:unowned', 'busy'])
- expect(lines[0].label).toContain('2')
- })
-
- it('renders nothing when every skill was deleted', () => {
- expect(
- skillDeleteResultLines([{ id: 'a', name: 'a', status: 'deleted', removedPaths: ['/x'] }])
- ).toEqual([])
- })
-})
-
it('sorts deletion roots once with unchanged case, accent, and number ordering', () => {
const labels = ['éclair', 'Eclair', 'item2', 'item10', 'Ångström', 'zebra', 'İstanbul']
const expected = [...labels].sort((a, b) =>
diff --git a/src/renderer/src/components/skills/skill-package-checklist-items.test.ts b/src/renderer/src/components/skills/skill-package-checklist-items.test.ts
deleted file mode 100644
index 55df248633a..00000000000
--- a/src/renderer/src/components/skills/skill-package-checklist-items.test.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import { describe, expect, it } from 'vitest'
-import type { SkillCloudVersion } from '../../../../shared/skill-cloud-contract'
-import { checklistItemSummary, checklistItemsFromVersion } from './skill-package-checklist-items'
-
-type ManifestFile = {
- path: string
- size: number
- executable: boolean
- classification: 'binary' | 'text'
- sha256: string
- identitySha256: string
-}
-
-function file(path: string, executable = false): ManifestFile {
- return {
- path,
- size: 1024,
- executable,
- classification: 'text' as const,
- sha256: 'a'.repeat(64),
- identitySha256: 'a'.repeat(64)
- }
-}
-
-function singleVersion(): SkillCloudVersion {
- return {
- packageId: 'pkg_1',
- versionId: 'ver_1',
- name: 'published-name',
- description: 'Published description',
- packageDigest: 'a'.repeat(64),
- archiveSha256: 'b'.repeat(64),
- compressedBytes: 128,
- createdAt: '2026-08-11T00:00:00.000Z',
- releaseNotes: '',
- manifest: {
- schemaVersion: 1,
- packageId: 'pkg_1',
- versionId: 'ver_1',
- name: 'manifest-name',
- description: 'Manifest description',
- createdAt: '2026-08-11T00:00:00.000Z',
- files: [file('SKILL.md')],
- packageDigest: 'a'.repeat(64)
- }
- }
-}
-
-describe('checklistItemsFromVersion', () => {
- it('turns a single-skill package into a one-row checklist', () => {
- expect(checklistItemsFromVersion(singleVersion())).toEqual([
- {
- id: 'manifest-name',
- name: 'published-name',
- description: 'Published description',
- files: [file('SKILL.md')]
- }
- ])
- })
-
- it('keeps each bundled skill as its own row', () => {
- const bundled = {
- ...singleVersion(),
- manifest: {
- schemaVersion: 1 as const,
- packageId: 'pkg_1',
- versionId: 'ver_1',
- bundleName: 'shared-skills',
- description: 'Synthetic bundle description',
- createdAt: '2026-08-11T00:00:00.000Z',
- bundleDigest: 'c'.repeat(64),
- skills: [
- {
- id: 'a',
- name: 'alpha',
- description: 'Alpha',
- digest: 'd'.repeat(64),
- files: [file('SKILL.md')]
- },
- {
- id: 'b',
- name: 'beta',
- description: 'Beta',
- digest: 'e'.repeat(64),
- files: [file('SKILL.md')]
- }
- ]
- }
- } as unknown as SkillCloudVersion
- expect(checklistItemsFromVersion(bundled).map((item) => item.name)).toEqual(['alpha', 'beta'])
- })
-})
-
-describe('checklistItemSummary', () => {
- it('keeps instruction-only and supporting-file summaries simple', () => {
- expect(checklistItemSummary([file('SKILL.md')])).toEqual({
- label: '1 file'
- })
- expect(checklistItemSummary([file('SKILL.md'), file('references/guide.md')])).toEqual({
- label: '2 files'
- })
- })
-
- it('keeps runnable and binary classifications out of the row summary', () => {
- expect(checklistItemSummary([file('SKILL.md'), file('scripts/setup.sh')])).toEqual({
- label: '2 files'
- })
- expect(checklistItemSummary([file('bin/tool', true)])).toEqual({ label: '1 file' })
- const binary = { ...file('assets/logo.png'), classification: 'binary' as const }
- expect(checklistItemSummary([file('SKILL.md'), binary])).toEqual({
- label: '2 files'
- })
- })
-})
diff --git a/src/renderer/src/components/skills/skill-package-install-risk.test.ts b/src/renderer/src/components/skills/skill-package-install-risk.test.ts
deleted file mode 100644
index 9208811d631..00000000000
--- a/src/renderer/src/components/skills/skill-package-install-risk.test.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import { describe, expect, it } from 'vitest'
-import {
- isSkillRunnableFile,
- summarizeSkillInstallRisk,
- type SkillInstallRiskFile
-} from './skill-package-install-risk'
-
-function file(
- path: string,
- options: { classification?: 'text' | 'binary'; executable?: boolean } = {}
-): SkillInstallRiskFile {
- return {
- path,
- classification: options.classification ?? 'text',
- executable: options.executable ?? false
- }
-}
-
-describe('isSkillRunnableFile', () => {
- it('recognizes scripts outside the scripts folder and executable files without extensions', () => {
- expect(isSkillRunnableFile(file('release.py'))).toBe(true)
- expect(isSkillRunnableFile(file('tools/setup.PS1'))).toBe(true)
- expect(isSkillRunnableFile(file('bin/team-tool'))).toBe(true)
- expect(isSkillRunnableFile(file('references/guide.md', { executable: true }))).toBe(true)
- })
-
- it('does not label ordinary supporting files as runnable', () => {
- expect(isSkillRunnableFile(file('references/guide.md'))).toBe(false)
- expect(isSkillRunnableFile(file('assets/logo.png', { classification: 'binary' }))).toBe(false)
- })
-})
-
-describe('summarizeSkillInstallRisk', () => {
- const items = [
- { id: 'plain', name: 'plain', files: [file('SKILL.md')] },
- {
- id: 'docs',
- name: 'docs',
- files: [file('SKILL.md'), file('references/guide.md')]
- },
- {
- id: 'tools',
- name: 'tools',
- files: [
- file('SKILL.md'),
- file('release.py'),
- file('bin/tool', { classification: 'binary', executable: true })
- ]
- }
- ]
-
- it('separates supporting files from content that needs acknowledgement', () => {
- expect(summarizeSkillInstallRisk(items, new Set(['docs']))).toMatchObject({
- selectedSkillCount: 1,
- additionalFileCount: 1,
- runnableFileCount: 0,
- binaryFileCount: 0,
- cautionFileCount: 0,
- requiresAcknowledgement: false
- })
- })
-
- it('counts a runnable binary once for the acknowledgement gate', () => {
- expect(summarizeSkillInstallRisk(items, new Set(['tools']))).toEqual({
- selectedSkillCount: 1,
- additionalFileCount: 2,
- runnableFileCount: 2,
- binaryFileCount: 1,
- cautionFileCount: 2,
- cautionSkillNames: ['tools'],
- requiresAcknowledgement: true
- })
- })
-})
diff --git a/src/renderer/src/components/status-bar/workspace-space-presentation.test.ts b/src/renderer/src/components/status-bar/workspace-space-presentation.test.ts
index 8e5b7df9d21..e78e3facffa 100644
--- a/src/renderer/src/components/status-bar/workspace-space-presentation.test.ts
+++ b/src/renderer/src/components/status-bar/workspace-space-presentation.test.ts
@@ -15,8 +15,7 @@ import {
isWorkspaceSpaceRowReadyToDelete,
pruneWorkspaceSpaceSelectedIds,
resolveWorkspaceSpaceInspectedWorktreeId,
- resolveWorkspaceSpaceTreemapZoomWorktreeId,
- sortWorkspaceSpaceRows
+ resolveWorkspaceSpaceTreemapZoomWorktreeId
} from './workspace-space-presentation'
import { getWorkspaceSpaceGitStatusRefreshCandidates } from './workspace-space-git-status-order'
import { getWorkspaceDecisionDetails } from './workspace-space-decision-details'
@@ -228,37 +227,6 @@ describe('workspace space presentation helpers', () => {
expect(isWorkspaceSpaceRowReadyToDelete(sshRow, ssh)).toBe(false)
})
- it('sorts rows by the selected key and direction', () => {
- const rows = [
- row({ worktreeId: 'small', displayName: 'Small', sizeBytes: 10 }),
- row({ worktreeId: 'large', displayName: 'Large', sizeBytes: 100 }),
- row({ worktreeId: 'mid', displayName: 'Mid', sizeBytes: 50 })
- ]
-
- expect(sortWorkspaceSpaceRows(rows, 'size', 'desc').map((item) => item.worktreeId)).toEqual([
- 'large',
- 'mid',
- 'small'
- ])
- expect(sortWorkspaceSpaceRows(rows, 'name', 'asc').map((item) => item.worktreeId)).toEqual([
- 'large',
- 'mid',
- 'small'
- ])
- })
-
- it('filters by search text and deletable status', () => {
- const rows = [
- row({ worktreeId: 'a', displayName: 'Frontend Cache', repoDisplayName: 'app' }),
- row({ worktreeId: 'b', displayName: 'Main', repoDisplayName: 'api', canDelete: false })
- ]
-
- expect(filterWorkspaceSpaceRows(rows, 'cache', false).map((item) => item.worktreeId)).toEqual([
- 'a'
- ])
- expect(filterWorkspaceSpaceRows(rows, '', true).map((item) => item.worktreeId)).toEqual(['a'])
- })
-
it('rejects oversized pasted filters before reading workspace rows', () => {
const oversizedQuery = 'secret-workspace-space'.repeat(WORKSPACE_SPACE_FILTER_QUERY_MAX_BYTES)
const rows = [
@@ -456,117 +424,6 @@ describe('workspace space presentation helpers', () => {
expect(details.reviewLabel).toBeNull()
})
- it('hides only a matching suppressed GitHub review from workspace decisions', () => {
- const matching = getWorkspaceDecisionDetails(
- row({ branch: 'refs/heads/feature/local' }),
- decisionInputs({
- hostedReviewCache: {
- 'local::repo::feature/local': {
- data: {
- provider: 'github',
- number: 12,
- state: 'open',
- status: 'success',
- title: 'Suppressed PR'
- }
- }
- },
- worktreeMap: new Map([
- [
- 'wt',
- worktreeRecord({
- branch: 'refs/heads/feature/local',
- linkedPR: null,
- suppressedGitHubPR: 12
- })
- ]
- ])
- })
- )
- const different = getWorkspaceDecisionDetails(
- row({ branch: 'refs/heads/feature/local' }),
- decisionInputs({
- hostedReviewCache: {
- 'local::repo::feature/local': {
- data: {
- provider: 'github',
- number: 13,
- state: 'open',
- status: 'success',
- title: 'Different PR'
- }
- }
- },
- worktreeMap: new Map([
- [
- 'wt',
- worktreeRecord({
- branch: 'refs/heads/feature/local',
- linkedPR: null,
- suppressedGitHubPR: 12
- })
- ]
- ])
- })
- )
-
- expect(matching.reviewLabel).toBeNull()
- expect(different.reviewLabel).toBe('PR #13 Open, success')
- })
-
- it('preserves explicit links and non-GitHub reviews in workspace decisions', () => {
- const cachedReview = {
- number: 12,
- state: 'open',
- status: 'success',
- title: 'Review'
- }
- const explicit = getWorkspaceDecisionDetails(
- row({ branch: 'refs/heads/feature/local' }),
- decisionInputs({
- hostedReviewCache: {
- 'local::repo::feature/local': {
- data: { ...cachedReview, provider: 'github' }
- }
- },
- worktreeMap: new Map([
- [
- 'wt',
- worktreeRecord({
- branch: 'refs/heads/feature/local',
- linkedPR: 12,
- suppressedGitHubPR: 12
- })
- ]
- ])
- })
- )
- const gitLab = getWorkspaceDecisionDetails(
- row({ branch: 'refs/heads/feature/local' }),
- decisionInputs({
- hostedReviewCache: {
- 'local::repo::feature/local': {
- data: { ...cachedReview, provider: 'gitlab' }
- }
- },
- worktreeMap: new Map([
- [
- 'wt',
- worktreeRecord({
- branch: 'refs/heads/feature/local',
- linkedPR: null,
- suppressedGitHubPR: 12,
- linkedGitLabMR: 12
- })
- ]
- ])
- })
- )
-
- expect(explicit.reviewLabel).toBe('PR #12 Open, success')
- expect(gitLab.reviewLabel).toBe('MR !12 Open, success')
- })
-
it('counts migration-unsupported agent entries by worktree id', () => {
const count = countWorkspaceSpaceActiveAgents({
worktreeId: 'wt',
diff --git a/src/renderer/src/components/workspace-cleanup/workspace-cleanup-candidate-row-data.test.ts b/src/renderer/src/components/workspace-cleanup/workspace-cleanup-candidate-row-data.test.ts
index 256646080bf..f4a3bcf984d 100644
--- a/src/renderer/src/components/workspace-cleanup/workspace-cleanup-candidate-row-data.test.ts
+++ b/src/renderer/src/components/workspace-cleanup/workspace-cleanup-candidate-row-data.test.ts
@@ -1,61 +1,8 @@
import { describe, expect, it } from 'vitest'
-import {
- getCandidateFactStatuses,
- getDirtyGitLabel,
- shouldShowGitMetadataChip
-} from './workspace-cleanup-candidate-row-data'
+import { getCandidateFactStatuses } from './workspace-cleanup-candidate-row-data'
import { makeCandidate } from './workspace-cleanup-presentation-fixtures'
describe('workspace cleanup candidate row data', () => {
- it('shows facts instead of cleanup policy tiers', () => {
- expect(getCandidateFactStatuses(makeCandidate({ tier: 'ready' }))).toEqual([])
- expect(getCandidateFactStatuses(makeCandidate({ tier: 'review' }))).toEqual([])
- expect(getCandidateFactStatuses(makeCandidate({ reasons: ['archived'] }))).toContainEqual(
- expect.objectContaining({ label: 'Archived' })
- )
- })
-
- it('does not duplicate git status blockers as a separate git icon label', () => {
- const gitStatusError = makeCandidate({
- blockers: ['git-status-error'],
- git: {
- clean: null,
- upstreamAhead: null,
- upstreamBehind: null,
- checkedAt: null
- }
- })
- const unknownBase = makeCandidate({
- blockers: ['unknown-base'],
- git: {
- clean: true,
- upstreamAhead: null,
- upstreamBehind: null,
- checkedAt: 1
- }
- })
-
- expect(getDirtyGitLabel(gitStatusError)).toBe('Git status check failed')
- expect(shouldShowGitMetadataChip(gitStatusError)).toBe(false)
- expect(getDirtyGitLabel(unknownBase)).toBe('Git status could not be verified')
- expect(shouldShowGitMetadataChip(unknownBase)).toBe(false)
- })
-
- it('keeps the git metadata chip for ordinary clean rows', () => {
- expect(
- shouldShowGitMetadataChip(
- makeCandidate({
- git: {
- clean: true,
- upstreamAhead: 0,
- upstreamBehind: 0,
- checkedAt: 1
- }
- })
- )
- ).toBe(true)
- })
-
it('keeps unpushed risk visible for archived rows', () => {
expect(
getCandidateFactStatuses(
@@ -72,59 +19,4 @@ describe('workspace cleanup candidate row data', () => {
)
).toContainEqual(expect.objectContaining({ label: 'Unpushed commits' }))
})
-
- it('renders every blocker fact instead of only the first', () => {
- expect(
- getCandidateFactStatuses(makeCandidate({ blockers: ['pinned', 'git-status-error'] }))
- ).toEqual([
- expect.objectContaining({ label: 'Pinned' }),
- expect.objectContaining({
- label: 'Git status unavailable',
- tone: 'destructive'
- })
- ])
- })
-
- it('suppresses the git metadata chip when the status pill already names git risk', () => {
- expect(
- shouldShowGitMetadataChip(
- makeCandidate({
- blockers: ['unpushed-commits'],
- git: {
- clean: true,
- upstreamAhead: 2,
- upstreamBehind: 0,
- checkedAt: 1
- }
- })
- )
- ).toBe(false)
- expect(
- shouldShowGitMetadataChip(
- makeCandidate({
- tier: 'review',
- blockers: [],
- git: {
- clean: true,
- upstreamAhead: 2,
- upstreamBehind: 0,
- checkedAt: 1
- }
- })
- )
- ).toBe(false)
- expect(
- shouldShowGitMetadataChip(
- makeCandidate({
- blockers: ['dirty-files'],
- git: {
- clean: false,
- upstreamAhead: 0,
- upstreamBehind: 0,
- checkedAt: 1
- }
- })
- )
- ).toBe(false)
- })
})
diff --git a/src/renderer/src/components/workspace-cleanup/workspace-cleanup-candidate-row.test.tsx b/src/renderer/src/components/workspace-cleanup/workspace-cleanup-candidate-row.test.tsx
index 9d4ee5a6e2f..1e6fd782243 100644
--- a/src/renderer/src/components/workspace-cleanup/workspace-cleanup-candidate-row.test.tsx
+++ b/src/renderer/src/components/workspace-cleanup/workspace-cleanup-candidate-row.test.tsx
@@ -33,108 +33,6 @@ describe('CandidateRow', () => {
container = null
})
- it('does not present cleanup policy tiers as workspace facts', () => {
- const candidate = makeCandidate({ tier: 'ready' })
-
- act(() => {
- root?.render(
-
- )
- })
-
- expect(container?.textContent).not.toContain('Ready')
- expect(container?.textContent).not.toContain('Status unavailable')
- })
-
- it('shows factual status, disk size, activity, and git state before expansion', () => {
- const candidate = makeCandidate({ tier: 'ready' })
-
- act(() => {
- root?.render(
-
- )
- })
-
- expect(container?.textContent).toContain('In progress')
- expect(container?.textContent).toContain('4.00 MB')
- expect(container?.textContent).toContain('1d')
- expect(container?.textContent).toContain('Clean')
- })
-
- it('uses an external-link action to open the workspace', () => {
- const candidate = makeCandidate()
-
- act(() => {
- root?.render(
-
- )
- })
-
- const openButton = container?.querySelector(
- `[aria-label="Open ${getWorkspaceCleanupCandidateAccessibleName(candidate)}"]`
- )
- expect(openButton?.querySelector('.lucide-external-link')).not.toBeNull()
- })
-
it('hides selection and remove controls while the workspace is already deleting', () => {
const candidate = makeCandidate()
@@ -169,43 +67,6 @@ describe('CandidateRow', () => {
expect(container?.querySelector(`[aria-label="Remove ${accessibleName}"]`)).toBeNull()
})
- it.each([
- ['deleting' as const, 'Deleting…'],
- ['queued' as const, 'Queued for deletion']
- ])('replaces the status pill with the %s state', (deletionPhase, label) => {
- const candidate = makeCandidate()
-
- act(() => {
- root?.render(
-
- )
- })
-
- expect(container?.textContent).toContain(label)
- expect(container?.textContent).not.toContain('Ready')
- })
-
it('visibly and accessibly distinguishes colliding local and SSH rows', () => {
const local = makeCandidate({ executionHostId: 'local' })
const remote = makeCandidate({ connectionId: 'builder', executionHostId: 'ssh:builder' })
@@ -247,78 +108,4 @@ describe('CandidateRow', () => {
expect(container?.querySelector(`[aria-label="Select ${remoteName}"]`)).not.toBeNull()
expect(container?.querySelector(`[aria-label="Host: builder"]`)).not.toBeNull()
})
-
- it('colors the review pill by state the way the PR page and item dialog do', () => {
- const states = [
- { state: 'merged' as const, label: 'PR #1', hue: 'purple' },
- { state: 'closed' as const, label: 'PR #2', hue: 'rose' },
- { state: 'open' as const, label: 'PR #3', hue: 'emerald' },
- { state: 'draft' as const, label: 'PR #4', hue: 'slate' }
- ]
-
- for (const { state, label, hue } of states) {
- const candidate = makeCandidate()
-
- act(() => {
- root?.render(
-
- )
- })
-
- const pill = container?.querySelector(`[aria-label*="${label}"]`)
- expect(pill?.className).toContain(`text-${hue}-`)
- expect(pill?.className).not.toContain('text-muted-foreground')
- }
- })
-
- it('leaves a review with an unfetched state neutral', () => {
- const candidate = makeCandidate()
-
- act(() => {
- root?.render(
-
- )
- })
-
- const pill = container?.querySelector('[aria-label*="PR #9"]')
- expect(pill?.className).toContain('text-muted-foreground')
- })
})
diff --git a/src/renderer/src/components/workspace-cleanup/workspace-cleanup-presentation.test.ts b/src/renderer/src/components/workspace-cleanup/workspace-cleanup-presentation.test.ts
index cb9cff663cf..293ff0c169f 100644
--- a/src/renderer/src/components/workspace-cleanup/workspace-cleanup-presentation.test.ts
+++ b/src/renderer/src/components/workspace-cleanup/workspace-cleanup-presentation.test.ts
@@ -3,11 +3,7 @@ import { getHostedReviewCacheKey } from '@/store/slices/hosted-review-cache-iden
import {
filterWorkspaceCleanupCandidates,
getWorkspaceCleanupGitLabel,
- getWorkspaceCleanupReviewInfo,
- getWorkspaceCleanupSearchText,
- hasWorkspaceCleanupLocalContext,
- sortWorkspaceCleanupCandidates,
- type WorkspaceCleanupReviewInfo
+ getWorkspaceCleanupReviewInfo
} from './workspace-cleanup-presentation'
import {
DEFAULT_FILTERS,
@@ -19,22 +15,6 @@ import {
import type { Repo } from '../../../../shared/repo-types'
describe('workspace cleanup presentation', () => {
- it('finds hosted review details from renderer state', () => {
- const cacheKey = getHostedReviewCacheKey('/repo', 'alpha', {}, 'repo-1', undefined)
- const state = makeState({
- hostedReviewCache: {
- [cacheKey]: { data: makeReview(), fetchedAt: NOW }
- }
- })
-
- expect(getWorkspaceCleanupReviewInfo(makeCandidate(), state)).toMatchObject({
- hasReview: true,
- label: 'PR #42',
- state: 'open',
- title: 'Review alpha cleanup'
- })
- })
-
it('hides only the matching suppressed GitHub review', () => {
const cacheKey = getHostedReviewCacheKey('/repo', 'alpha', {}, 'repo-1', undefined)
const matching = makeState({
@@ -65,48 +45,6 @@ describe('workspace cleanup presentation', () => {
})
})
- it('preserves explicit GitHub links and non-GitHub reviews despite stale suppression', () => {
- const cacheKey = getHostedReviewCacheKey('/repo', 'alpha', {}, 'repo-1', undefined)
- const explicit = makeState({
- worktreesByRepo: {
- 'repo-1': [
- {
- ...makeState().worktreesByRepo['repo-1']![0]!,
- linkedPR: 42,
- suppressedGitHubPR: 42
- }
- ]
- },
- hostedReviewCache: {
- [cacheKey]: { data: makeReview({ number: 42 }), fetchedAt: NOW }
- }
- })
- const gitLab = makeState({
- worktreesByRepo: {
- 'repo-1': [
- {
- ...makeState().worktreesByRepo['repo-1']![0]!,
- linkedPR: null,
- suppressedGitHubPR: 42,
- linkedGitLabMR: 42
- }
- ]
- },
- hostedReviewCache: {
- [cacheKey]: {
- data: makeReview({ provider: 'gitlab', number: 42 }),
- fetchedAt: NOW
- }
- }
- })
-
- expect(getWorkspaceCleanupReviewInfo(makeCandidate(), explicit).hasReview).toBe(true)
- expect(getWorkspaceCleanupReviewInfo(makeCandidate(), gitLab)).toMatchObject({
- hasReview: true,
- provider: 'gitlab'
- })
- })
-
it('host-qualifies same-id repo, worktree, and review cache joins', () => {
const base = makeState()
const localRepo = { ...base.repos[0]!, executionHostId: 'local' as const }
@@ -177,66 +115,6 @@ describe('workspace cleanup presentation', () => {
expect(getWorkspaceCleanupReviewInfo(makeCandidate(), state).hasReview).toBe(false)
})
- it('filters by time, review, git, and context', () => {
- const openReview: WorkspaceCleanupReviewInfo = {
- hasReview: true,
- label: 'PR #7',
- state: 'open',
- provider: 'github',
- title: 'Review row'
- }
- const rows = [
- makeCandidate({ worktreeId: 'repo-1::/repo/clean', displayName: 'clean' }),
- makeCandidate({
- worktreeId: 'repo-1::/repo/dirty-review',
- displayName: 'dirty-review',
- git: { clean: false, upstreamAhead: 0, upstreamBehind: 0, checkedAt: NOW },
- lastActivityAt: NOW - 100 * 24 * 60 * 60 * 1000,
- localContext: {
- terminalTabCount: 1,
- cleanEditorTabCount: 0,
- browserTabCount: 0,
- diffCommentCount: 0,
- newestDiffCommentAt: null,
- retainedDoneAgentCount: 0
- }
- }),
- makeCandidate({
- worktreeId: 'repo-1::/repo/unknown',
- displayName: 'unknown',
- git: { clean: null, upstreamAhead: null, upstreamBehind: null, checkedAt: null },
- blockers: ['git-status-error']
- })
- ]
- const reviewInfo = new Map([
- ['repo-1::/repo/dirty-review', openReview]
- ])
-
- expect(
- filterWorkspaceCleanupCandidates(
- rows,
- {
- ...DEFAULT_FILTERS,
- time: '90d',
- review: 'open-review',
- git: 'dirty',
- context: 'has-context'
- },
- reviewInfo,
- NOW
- ).map((row) => row.displayName)
- ).toEqual(['dirty-review'])
-
- expect(
- filterWorkspaceCleanupCandidates(
- rows,
- { ...DEFAULT_FILTERS, git: 'unknown' },
- reviewInfo,
- NOW
- ).map((row) => row.displayName)
- ).toEqual(['unknown'])
- })
-
it('treats unknown-base clean rows as unknown git risk', () => {
const candidate = makeCandidate({
git: { clean: true, upstreamAhead: null, upstreamBehind: null, checkedAt: NOW },
@@ -261,111 +139,4 @@ describe('workspace cleanup presentation', () => {
)
).toEqual([candidate])
})
-
- it('search includes repo, branch, path, review, git, and context labels', () => {
- const candidate = makeCandidate({
- repoName: 'Search Repo',
- branch: 'feature/search',
- path: '/repo/search-target',
- git: { clean: null, upstreamAhead: null, upstreamBehind: null, checkedAt: null },
- localContext: {
- terminalTabCount: 0,
- cleanEditorTabCount: 0,
- browserTabCount: 1,
- diffCommentCount: 0,
- newestDiffCommentAt: null,
- retainedDoneAgentCount: 0
- }
- })
- const reviewInfo: WorkspaceCleanupReviewInfo = {
- hasReview: true,
- label: 'MR #9',
- state: 'closed',
- provider: 'gitlab',
- title: 'Searchable review'
- }
- const text = getWorkspaceCleanupSearchText(candidate, reviewInfo)
-
- expect(text).toContain('search repo')
- expect(text).toContain('feature/search')
- expect(text).toContain('/repo/search-target')
- expect(text).toContain('mr #9')
- expect(text).toContain('unknown')
- expect(text).toContain('has context')
- })
-
- it('sorts by activity, name, repo, review, and git', () => {
- const rows = [
- makeCandidate({
- worktreeId: 'repo-1::/repo/bravo',
- displayName: 'bravo',
- repoName: 'Repo B',
- lastActivityAt: NOW - 5,
- git: { clean: false, upstreamAhead: 0, upstreamBehind: 0, checkedAt: NOW }
- }),
- makeCandidate({
- worktreeId: 'repo-1::/repo/alpha',
- displayName: 'alpha',
- repoName: 'Repo A',
- lastActivityAt: NOW - 10,
- git: { clean: true, upstreamAhead: 0, upstreamBehind: 0, checkedAt: NOW }
- }),
- makeCandidate({
- worktreeId: 'repo-1::/repo/charlie',
- displayName: 'charlie',
- repoName: 'Repo C',
- lastActivityAt: NOW - 1,
- git: { clean: true, upstreamAhead: 2, upstreamBehind: 0, checkedAt: NOW },
- blockers: ['unpushed-commits']
- })
- ]
- const reviewInfo = new Map([
- [
- 'repo-1::/repo/charlie',
- {
- hasReview: true,
- label: 'PR #3',
- state: 'open',
- provider: 'github',
- title: null
- }
- ]
- ])
-
- expect(
- sortWorkspaceCleanupCandidates(rows, 'activity', 'asc').map((row) => row.displayName)
- ).toEqual(['alpha', 'bravo', 'charlie'])
- expect(
- sortWorkspaceCleanupCandidates(rows, 'name', 'asc').map((row) => row.displayName)
- ).toEqual(['alpha', 'bravo', 'charlie'])
- expect(
- sortWorkspaceCleanupCandidates(rows, 'repo', 'asc').map((row) => row.displayName)
- ).toEqual(['alpha', 'bravo', 'charlie'])
- expect(
- sortWorkspaceCleanupCandidates(rows, 'review', 'desc', reviewInfo).map(
- (row) => row.displayName
- )
- ).toEqual(['charlie', 'alpha', 'bravo'])
- expect(
- sortWorkspaceCleanupCandidates(rows, 'git', 'desc').map((row) => row.displayName)
- ).toEqual(['charlie', 'bravo', 'alpha'])
- })
-
- it('detects local context', () => {
- expect(hasWorkspaceCleanupLocalContext(makeCandidate())).toBe(false)
- expect(
- hasWorkspaceCleanupLocalContext(
- makeCandidate({
- localContext: {
- terminalTabCount: 0,
- cleanEditorTabCount: 1,
- browserTabCount: 0,
- diffCommentCount: 0,
- newestDiffCommentAt: null,
- retainedDoneAgentCount: 0
- }
- })
- )
- ).toBe(true)
- })
})
diff --git a/src/renderer/src/components/workspace-cleanup/workspace-cleanup-sort-header.test.tsx b/src/renderer/src/components/workspace-cleanup/workspace-cleanup-sort-header.test.tsx
index 151df522781..c666381078a 100644
--- a/src/renderer/src/components/workspace-cleanup/workspace-cleanup-sort-header.test.tsx
+++ b/src/renderer/src/components/workspace-cleanup/workspace-cleanup-sort-header.test.tsx
@@ -35,12 +35,6 @@ function render(sort: WorkspaceCleanupSortState, handlers: Record('[data-sort-option]') ?? [])].find(
- (button) => button.textContent?.trim() === label
- )
-}
-
describe('WorkspaceCleanupSortHeader', () => {
beforeEach(() => {
container = document.createElement('div')
@@ -57,34 +51,6 @@ describe('WorkspaceCleanupSortHeader', () => {
container = null
})
- it('shows the active sort in one menu trigger', () => {
- render({ field: 'size', direction: 'desc' })
-
- expect(container?.querySelector('[aria-label="Sort by Size"]')?.textContent).toContain(
- 'Sort by Size'
- )
- })
-
- it('routes a menu choice through the sort toggle', () => {
- const onToggleSortField = vi.fn()
- render({ field: 'last-activity', direction: 'asc' }, { onToggleSortField })
-
- act(() => sortOption('Repository')?.click())
-
- expect(onToggleSortField).toHaveBeenCalledWith('repo')
- })
-
- it('select-all reads the query result rather than the rendered page', () => {
- const onToggleSelectAll = vi.fn()
- render({ field: 'name', direction: 'asc' }, { onToggleSelectAll })
-
- const checkbox = container?.querySelector('[role="checkbox"]')
- expect(checkbox?.getAttribute('aria-checked')).toBe('false')
- act(() => checkbox?.click())
-
- expect(onToggleSelectAll).toHaveBeenCalledWith(true)
- })
-
it('exposes a partial selection as mixed', () => {
render({ field: 'name', direction: 'asc' }, { selectableCount: 3, selectedCount: 1 })
@@ -92,29 +58,4 @@ describe('WorkspaceCleanupSortHeader', () => {
container?.querySelector('[role="checkbox"]')?.getAttribute('aria-checked')
).toBe('mixed')
})
- it('states how many workspaces select-all would take', () => {
- render({ field: 'name', direction: 'asc' }, { selectableCount: 12 })
-
- expect(container?.textContent).toContain('Select all 12 safety-checked workspaces')
- })
-
- it('uses singular copy for one safety-checked workspace', () => {
- render({ field: 'name', direction: 'asc' }, { selectableCount: 1 })
-
- expect(container?.textContent).toContain('Select 1 safety-checked workspace')
- })
-
- it('does not report all-selected when the selected rows are not the selectable ones', () => {
- const onToggleSelectAll = vi.fn()
- render(
- { field: 'name', direction: 'asc' },
- { selectableCount: 3, selectedCount: 0, onToggleSelectAll }
- )
-
- const checkbox = container?.querySelector('[role="checkbox"]')
- expect(checkbox?.getAttribute('aria-checked')).toBe('false')
-
- act(() => (checkbox as HTMLElement | null)?.click())
- expect(onToggleSelectAll).toHaveBeenCalledWith(true)
- })
})