diff --git a/src/renderer/src/components/contextual-tours/contextual-tour-gate.progress.test.ts b/src/renderer/src/components/contextual-tours/contextual-tour-gate.progress.test.ts index 1a6f59e8e78..cac8e5bbf4e 100644 --- a/src/renderer/src/components/contextual-tours/contextual-tour-gate.progress.test.ts +++ b/src/renderer/src/components/contextual-tours/contextual-tour-gate.progress.test.ts @@ -1,11 +1,10 @@ import { describe, expect, it } from 'vitest' -import { getContextualTour, isContextualTourStepDone } from '../../../../shared/contextual-tours' + import type { FeatureInteractionId, FeatureInteractionState } from '../../../../shared/feature-interactions' import { isContextualTourStartBlockedByProgress } from '../../store/slices/ui/ui-slice-tour-actions' -import { getContextualTourRequestDecision } from './contextual-tour-gate' const TOUR_ID = 'workspace-agent-sessions' @@ -33,25 +32,4 @@ describe('workspace agent sessions tour after progress', () => { expect(blocked(['terminal-pane-split'])).toBe(true) expect(blocked(['tab-splits'])).toBe(true) }) - - it('continues a tour started this session at the next tip instead of rewinding to +', () => { - expect(blocked(['terminal-pane-split'], true)).toBe(false) - const featureInteractions = interactions(['terminal-pane-split']) - const decision = getContextualTourRequestDecision({ - tour: getContextualTour(TOUR_ID), - persistedUIReady: true, - autoEligible: true, - onboardingVisible: false, - seenIds: [], - progressBlocked: false, - sessionConsumed: false, - activeTourId: null, - activeModal: 'none', - blockingSurfaceVisible: false, - // Terminal tab active: the + menu, terminal split and new-workspace targets are measurable. - targetExists: (selector) => !selector.includes('chat-pane-split-target'), - isStepDone: (step) => isContextualTourStepDone(step, featureInteractions) - }) - expect(decision).toEqual({ kind: 'start', stepIndex: 3 }) - }) }) diff --git a/src/renderer/src/components/new-workspace/use-linear-source-connection.test.tsx b/src/renderer/src/components/new-workspace/use-linear-source-connection.test.tsx index 82886ec87c2..5fa4d265ef5 100644 --- a/src/renderer/src/components/new-workspace/use-linear-source-connection.test.tsx +++ b/src/renderer/src/components/new-workspace/use-linear-source-connection.test.tsx @@ -1,17 +1,12 @@ // @vitest-environment happy-dom -import { act, cleanup, render, renderHook, screen, waitFor } from '@testing-library/react' +import { act, cleanup, renderHook, waitFor } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { useStore } from 'zustand' import { createStore } from 'zustand/vanilla' import type { TaskSourceContext } from '../../../../shared/task-source-context' -import type { - LinearCollectionResult, - LinearConnectionStatus -} from '../../../../shared/linear/workspace-types' -import { openLinearIssueRead } from '@/store/slices/linear/linear-issue-publication' -import { getLinearSourceScope } from '@/store/slices/linear/linear-slice-scope' -import type { LinearIssue } from '../../../../shared/linear/issue-types' +import type { LinearConnectionStatus } from '../../../../shared/linear/workspace-types' + import { useLinearSourceConnection } from './use-linear-source-connection' const mocks = vi.hoisted(() => ({ linearStatus: vi.fn() })) @@ -70,53 +65,6 @@ describe('useLinearSourceConnection', () => { }) }) - it('reads the explicit source host independently of focused runtime status', async () => { - const source = context('runtime:source-host') - mocks.linearStatus.mockResolvedValue(status(true)) - const { result } = renderHook(() => - useLinearSourceConnection({ enabled: true, sourceContext: source }) - ) - expect(result.current).toEqual({ status: null, loaded: false, refresh: expect.any(Function) }) - await waitFor(() => expect(result.current.status?.connected).toBe(true)) - expect(result.current.loaded).toBe(true) - expect(mocks.linearStatus).toHaveBeenCalledWith(source) - }) - - it('does not add reads to existing consumers without an explicit source', async () => { - renderHook(() => useLinearSourceConnection({ enabled: true, sourceContext: null })) - renderHook(() => useLinearSourceConnection({ enabled: false, sourceContext: context('local') })) - await act(async () => {}) - expect(mocks.linearStatus).not.toHaveBeenCalled() - }) - - it('keeps equivalent source objects from refetching on every renderer update', async () => { - mocks.linearStatus.mockResolvedValue(status(true)) - const { result, rerender } = renderHook(() => - useLinearSourceConnection({ enabled: true, sourceContext: context('local') }) - ) - await waitFor(() => expect(result.current.loaded).toBe(true)) - const loaded = result.current - rerender() - expect(result.current).toBe(loaded) - expect(mocks.linearStatus).toHaveBeenCalledTimes(1) - }) - - it('keeps the loaded status when the selected repo changes on the same host', async () => { - mocks.linearStatus.mockResolvedValue(status(true)) - const { result, rerender } = renderHook( - ({ source }) => useLinearSourceConnection({ enabled: true, sourceContext: source }), - { initialProps: { source: context('runtime:host') } } - ) - await waitFor(() => expect(result.current.loaded).toBe(true)) - rerender({ source: { ...context('runtime:host'), projectId: 'project-2', repoId: 'repo-2' } }) - expect(result.current).toEqual({ - status: status(true), - loaded: true, - refresh: expect.any(Function) - }) - expect(mocks.linearStatus).toHaveBeenCalledTimes(1) - }) - it('hides old status immediately and rejects late responses after a host switch', async () => { let resolveOld: (value: LinearConnectionStatus) => void = () => {} const oldRead = new Promise((resolve) => { @@ -137,15 +85,6 @@ describe('useLinearSourceConnection', () => { expect(result.current.status?.connected).toBe(false) }) - it('settles cold failed status reads as unknown', async () => { - mocks.linearStatus.mockRejectedValue(new Error('Host unavailable')) - const { result } = renderHook(() => - useLinearSourceConnection({ enabled: true, sourceContext: context('runtime:offline') }) - ) - await waitFor(() => expect(result.current.loaded).toBe(true)) - expect(result.current.status).toBeNull() - }) - it.each(['hostContactEpoch', 'connectionGeneration'] as const)( 'retries a failed saved-host read when %s advances without changing focus', async (revision) => { @@ -185,101 +124,6 @@ describe('useLinearSourceConnection', () => { }) expect(result.current.status?.connected).toBe(true) }) - - it('refreshes matching-host workspace changes without borrowing another host status', async () => { - mocks.linearStatus.mockResolvedValue({ ...status(true), selectedWorkspaceId: 'original' }) - const { result } = renderHook(() => - useLinearSourceConnection({ enabled: true, sourceContext: context('runtime:saved-host') }) - ) - await waitFor(() => expect(result.current.loaded).toBe(true)) - act(() => { - store.setState({ - linearStatusContextKey: 'runtime:other-host#0', - linearStatus: { ...status(true), selectedWorkspaceId: 'other' }, - runtimeStatusByEnvironmentId: new Map([['other-host', { hostContactEpoch: 1 }]]) - }) - }) - expect(result.current.status?.selectedWorkspaceId).toBe('original') - expect(mocks.linearStatus).toHaveBeenCalledTimes(1) - mocks.linearStatus.mockResolvedValue({ ...status(true), selectedWorkspaceId: 'updated' }) - act(() => { - store.setState({ - linearStatusObserved: true, - linearStatusContextKey: 'runtime:saved-host#0', - linearStatus: { ...status(true), selectedWorkspaceId: 'updated' } - }) - }) - // Same-host re-read keeps the last status so the Linear tab stays selected. - expect(result.current).toMatchObject({ - loaded: true, - status: { selectedWorkspaceId: 'updated' } - }) - await waitFor(() => expect(result.current.status?.selectedWorkspaceId).toBe('updated')) - expect(mocks.linearStatus).toHaveBeenCalledTimes(1) - }) -}) - -it('retains a matching source success on outage but actual matching false wins without redundant probe', async () => { - store.setState({ - linearStatus: status(false), - linearStatusObserved: false, - linearStatusContextKey: null, - runtimeStatusByEnvironmentId: new Map() - }) - mocks.linearStatus.mockReset() - mocks.linearStatus.mockResolvedValueOnce(status(true)).mockRejectedValue(new Error('offline')) - const { result } = renderHook(() => - useLinearSourceConnection({ enabled: true, sourceContext: context('runtime:saved-host') }) - ) - await waitFor(() => expect(result.current.status?.connected).toBe(true)) - act(() => - store.setState({ - runtimeStatusByEnvironmentId: new Map([['saved-host', { hostContactEpoch: 1 }]]) - }) - ) - await waitFor(() => expect(mocks.linearStatus).toHaveBeenCalledTimes(2)) - await act(async () => {}) - expect(result.current.status?.connected).toBe(true) - const cached: LinearCollectionResult = { - items: [], - errors: [ - { - workspaceId: 'old-W', - type: 'auth', - message: 'Linear authentication expired for this workspace.' - } - ] - } - const read = openLinearIssueRead({ - scope: getLinearSourceScope(context('runtime:saved-host')), - seed: cached, - cached, - dispatch: async () => { - throw new Error('ordinary query outage') - }, - publish: () => {}, - isCurrent: () => true, - remove: () => {} - }) - const lease = read.acquire() - read.force() - const view = await lease.waitForCurrentTerminal() - expect(view).toMatchObject({ kind: 'error', data: cached }) - await act(async () => { - await result.current.refresh({ view, workspaceId: 'all', status: status(true) }) - }) - lease.release() - expect(mocks.linearStatus).toHaveBeenCalledTimes(2) - expect(result.current.status?.connected).toBe(true) - act(() => - store.setState({ - linearStatusContextKey: 'runtime:saved-host#0', - linearStatusObserved: true, - linearStatus: status(false) - }) - ) - expect(result.current.status?.connected).toBe(false) - expect(mocks.linearStatus).toHaveBeenCalledTimes(2) }) // Each update has its own act turn: upstream operation counts are separate from renders. @@ -337,46 +181,3 @@ it('retires held source requests with matching truth and isolates unrelated cons await refresh() expect(mocks.linearStatus).toHaveBeenCalledTimes(calls) }) - -it.each([2, 20])( - 'bounds actual runtime-contact status work for %i mounted source consumers', - async (N) => { - mocks.linearStatus.mockReset() - mocks.linearStatus.mockResolvedValue(status(true)) - store.setState({ - linearStatusObserved: false, - linearStatusContextKey: null, - runtimeStatusByEnvironmentId: new Map() - }) - function Source() { - const connection = useLinearSourceConnection({ - enabled: true, - sourceContext: context('runtime:scaling') - }) - return {connection.loaded ? 'ready' : 'pending'} - } - const mounted = render( - <> - {Array.from({ length: N }, (_, index) => ( - - ))} - - ) - await waitFor(() => expect(screen.getAllByText('ready')).toHaveLength(N)) - expect(mocks.linearStatus).toHaveBeenCalledTimes(N) - await act(async () => - store.setState({ - runtimeStatusByEnvironmentId: new Map([['scaling', { hostContactEpoch: 1 }]]) - }) - ) - expect(mocks.linearStatus).toHaveBeenCalledTimes(2 * N) - const calls = mocks.linearStatus.mock.calls.length - mounted.unmount() - act(() => - store.setState({ - runtimeStatusByEnvironmentId: new Map([['scaling', { hostContactEpoch: 2 }]]) - }) - ) - expect(mocks.linearStatus).toHaveBeenCalledTimes(calls) - } -) diff --git a/src/renderer/src/components/new-workspace/use-smart-workspace-name-field-foundation.source.test.tsx b/src/renderer/src/components/new-workspace/use-smart-workspace-name-field-foundation.source.test.tsx index 5ad1f8de932..fbfeb9a436c 100644 --- a/src/renderer/src/components/new-workspace/use-smart-workspace-name-field-foundation.source.test.tsx +++ b/src/renderer/src/components/new-workspace/use-smart-workspace-name-field-foundation.source.test.tsx @@ -4,17 +4,13 @@ import { linearIssueReadFixture } from '@/store/slices/linear-slice-test-harness import { act, cleanup, renderHook, waitFor } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import type { Repo } from '../../../../shared/repo-types' -import { normalizeTaskSourceContext } from '../../../../shared/task-source-context' + import type { LinearIssue } from '../../../../shared/linear/issue-types' -import type { GitLabWorkItem } from '../../../../shared/gitlab-types' + import type { TaskSourceContext } from '../../../../shared/task-source-context' import type { NormalizedWorkItemSourceSearchProps } from './smart-workspace-name-field-model' import { useWorkItemSourceSearch } from './use-work-item-source-search' import { referenceLinearIssue } from '../sidebar/workspace-card/review/workspace-reference-fixtures.test-support' -import { useWorkItemSourceFoundation } from './use-work-item-source-foundation' -import { useSmartWorkspaceSecondarySearches } from './use-smart-workspace-secondary-searches' -import { useSmartWorkspaceGitlabSearch } from './use-smart-workspace-gitlab-search' -import { useWorkItemSourcePresentation } from './use-work-item-source-presentation' const mocks = vi.hoisted(() => ({ readStatus: vi.fn(), @@ -68,16 +64,6 @@ vi.mock('../use-jira-project-inventory', () => ({ useJiraProjectInventory: () => ({ projects: [], connected: true, error: null, loading: false }) })) -const source: TaskSourceContext = { - kind: 'task-source', - provider: 'linear', - projectId: 'project-1', - hostId: 'runtime:saved-host', - repoId: null, - providerIdentity: null, - accountLabel: null -} - function props(context?: TaskSourceContext): NormalizedWorkItemSourceSearchProps { return { repos: [], @@ -94,14 +80,6 @@ function props(context?: TaskSourceContext): NormalizedWorkItemSourceSearchProps } } -function deferred() { - let resolve!: (value: T) => void - const promise = new Promise((res) => { - resolve = res - }) - return { promise, resolve } -} - describe('smart workspace explicit source connection', () => { afterEach(cleanup) @@ -117,286 +95,6 @@ describe('smart workspace explicit source connection', () => { } }) - it('uses the resolved runtime repository default when a local repository has the same ID', () => { - const localRepo: Repo = { - id: 'same-id', - path: '/local', - displayName: 'Local', - badgeColor: '', - addedAt: 0, - defaultJiraProject: { id: '10', key: 'LOC', name: 'Local', siteId: 'site-a' } - } - const selectedRepo: Repo = { - ...localRepo, - path: '/runtime', - executionHostId: 'runtime:remote', - defaultJiraProject: { id: '20', key: 'REM', name: 'Remote', siteId: 'site-b' } - } - const fieldProps = { - ...props(), - repos: [localRepo, selectedRepo], - repoId: 'same-id', - selectedRepo, - jiraSourceContext: normalizeTaskSourceContext({ - provider: 'jira', - projectId: 'repo:same-id', - hostId: 'runtime:remote' - }) - } - const { result } = renderHook(() => useWorkItemSourceFoundation(fieldProps)) - expect(result.current.selectedRepo).toBe(selectedRepo) - expect(result.current.jiraProject).toEqual(selectedRepo.defaultJiraProject) - }) - - it('exposes Linear on a connected saved host while the focused runtime is disconnected', async () => { - mocks.readStatus.mockResolvedValue({ - connected: true, - viewer: null, - selectedWorkspaceId: 'source-workspace' - }) - const fieldProps = props(source) - const { result } = renderHook(() => { - const foundation = useWorkItemSourceFoundation(fieldProps) - useSmartWorkspaceSecondarySearches({ - foundation, - shouldQueryLinear: foundation.linearAvailable, - linearQuery: 'launch', - linearUrlIntent: null, - linearUrlIntentOwnsInput: false, - shouldQueryJira: false, - jiraSearchQuery: null - }) - return foundation - }) - await waitFor(() => - expect(result.current.availableModes.some((mode) => mode.id === 'linear')).toBe(true) - ) - expect(result.current.linearSourceContext).toBe(source) - expect(result.current.linearStatus.connected).toBe(true) - expect(mocks.state.searchLinearIssues).toHaveBeenCalledWith('launch', 12, { - sourceContext: source, - workspaceId: 'source-workspace' - }) - expect(mocks.readStatus).toHaveBeenCalledWith(source) - expect(mocks.state.checkLinearConnection).not.toHaveBeenCalled() - expect(mocks.state.linearStatus.connected).toBe(false) - }) - - it('lists and searches all workspaces by default, with a composer-only override scoped to its source', async () => { - const first = referenceLinearIssue({ id: 'first', workspaceId: 'first' }) - const second = referenceLinearIssue({ id: 'second', workspaceId: 'second' }) - mocks.readStatus.mockResolvedValue({ - connected: true, - viewer: null, - selectedWorkspaceId: 'first' - }) - mocks.state.searchLinearIssues.mockImplementation(async (_query, _limit, options) => - options.workspaceId === 'all' - ? [first, second] - : [first, second].filter((issue) => issue.workspaceId === options.workspaceId) - ) - const fieldProps = props(source) - const { result, rerender, unmount } = renderHook( - ({ context, query }) => { - return useWorkItemSourceSearch({ - ...fieldProps, - linearSourceContext: context, - value: query, - defaultLinearWorkspaceId: 'all' - }) - }, - { initialProps: { context: source, query: '' } } - ) - act(() => result.current.setMode('linear')) - await waitFor(() => - expect(mocks.state.listLinearIssues).toHaveBeenCalledWith( - { kind: 'list', filter: 'assigned', limit: 12 }, - { sourceContext: source, workspaceId: 'all' } - ) - ) - rerender({ context: source, query: 'launch' }) - await waitFor(() => expect(result.current.linearIssues).toEqual([first, second])) - const pendingSecond = deferred() - mocks.state.searchLinearIssues.mockReturnValueOnce(pendingSecond.promise) - act(() => result.current.setLinearWorkspaceId('second')) - expect(result.current.linearLoading).toBe(true) - expect(result.current.searchResultRows).toEqual([]) - await act(async () => pendingSecond.resolve([second])) - expect(result.current.searchResultRows).toMatchObject([{ kind: 'linear', issue: second }]) - expect(mocks.state.searchLinearIssues).toHaveBeenLastCalledWith('launch', 12, { - sourceContext: source, - workspaceId: 'second' - }) - expect(result.current.linearStatus.selectedWorkspaceId).toBe('first') - expect(mocks.state.linearStatus.selectedWorkspaceId).toBe('focused-workspace') - - act(() => result.current.setLinearWorkspaceId('all')) - await waitFor(() => expect(result.current.linearIssues).toEqual([first, second])) - const pendingAll = deferred() - mocks.state.searchLinearIssues.mockReturnValueOnce(pendingAll.promise) - rerender({ context: source, query: 'launch later' }) - await waitFor(() => - expect(mocks.state.searchLinearIssues).toHaveBeenLastCalledWith('launch later', 12, { - sourceContext: source, - workspaceId: 'all' - }) - ) - expect(result.current.linearIssues).toEqual([first, second]) - expect(result.current.linearLoading).toBe(true) - expect(result.current.searchResultRows).toMatchObject([ - { kind: 'linear', issue: first }, - { kind: 'linear', issue: second } - ]) - act(() => result.current.setLinearWorkspaceId('first')) - await waitFor(() => expect(result.current.linearIssues).toEqual([first])) - const replacementSecond = deferred() - mocks.state.searchLinearIssues.mockReturnValueOnce(replacementSecond.promise) - act(() => result.current.setLinearWorkspaceId('second')) - expect(result.current.searchResultRows).toEqual([]) - expect(result.current.linearLoading).toBe(true) - await act(async () => replacementSecond.resolve([second])) - await act(async () => pendingAll.resolve([first, second])) - expect(result.current.searchResultRows).toMatchObject([{ kind: 'linear', issue: second }]) - expect(result.current.linearLoading).toBe(false) - const otherHost: TaskSourceContext = { ...source, hostId: 'runtime:other-host' } - const otherHostReplacement = deferred() - mocks.state.searchLinearIssues.mockReturnValue(otherHostReplacement.promise) - rerender({ context: otherHost, query: 'launch' }) - await waitFor(() => - expect(mocks.state.searchLinearIssues).toHaveBeenLastCalledWith('launch', 12, { - sourceContext: otherHost, - workspaceId: 'all' - }) - ) - expect(result.current.linearIssues).toEqual([]) - expect(result.current.searchResultRows).toEqual([]) - expect(result.current.linearLoading).toBe(true) - await act(async () => otherHostReplacement.resolve([first, second])) - expect(result.current.linearIssues).toEqual([first, second]) - expect(result.current.linearLoading).toBe(false) - const emptyReplacement = deferred() - mocks.state.searchLinearIssues.mockReturnValueOnce(emptyReplacement.promise) - rerender({ context: otherHost, query: 'nothing matches' }) - await waitFor(() => - expect(mocks.state.searchLinearIssues).toHaveBeenLastCalledWith('nothing matches', 12, { - sourceContext: otherHost, - workspaceId: 'all' - }) - ) - expect(result.current.linearLoading).toBe(true) - expect(result.current.searchResultRows).toMatchObject([ - { kind: 'linear', issue: first }, - { kind: 'linear', issue: second } - ]) - await act(async () => emptyReplacement.resolve([])) - expect(result.current.linearIssues).toEqual([]) - expect(result.current.searchResultRows).toEqual([]) - expect(result.current.linearLoading).toBe(false) - unmount() - const reopened = renderHook(() => - useWorkItemSourceFoundation({ ...props(source), defaultLinearWorkspaceId: 'all' }) - ) - expect(reopened.result.current.linearWorkspaceIdOverride).toBe('all') - }) - - it('shows GitLab workspace search rows without fetching an advertised probe page', async () => { - const repo: Repo = { - id: 'server-repo', - path: '/srv/app', - displayName: 'app', - badgeColor: '', - addedAt: 0, - executionHostId: 'runtime:remote' - } - const items: GitLabWorkItem[] = Array.from({ length: 12 }, (_, index) => ({ - id: `mr-${index + 1}`, - type: 'mr', - number: index + 1, - title: `Merge request ${index + 1}`, - state: 'opened', - url: `https://gitlab.com/group/app/-/merge_requests/${index + 1}`, - labels: [], - updatedAt: '2026-10-01T00:00:00Z', - author: null, - repoId: repo.id - })) - mocks.listGitlabWorkItems.mockResolvedValue({ - items, - page: 1, - perPage: 12, - totalCount: 0, - totalPages: 2 - }) - const fieldProps = { - ...props(), - repos: [repo], - repoId: repo.id, - repoBackedSourcesDisabled: false, - value: 'launch' - } - const { result } = renderHook(() => { - const foundation = useWorkItemSourceFoundation(fieldProps) - useSmartWorkspaceGitlabSearch({ - foundation, - sourceQueryWithinLimit: true, - shouldQueryGitlab: true - }) - return useWorkItemSourcePresentation(foundation) - }) - - await waitFor(() => expect(result.current.searchResultRows).toHaveLength(items.length)) - expect(result.current.searchResultRows).toEqual( - items.map((item) => ({ - kind: 'gitlab', - value: `gitlab-${repo.id}-mr-${item.number}`, - item - })) - ) - expect(result.current.loading).toBe(false) - expect(mocks.listGitlabWorkItems).toHaveBeenCalledTimes(1) - expect(mocks.listGitlabWorkItems).toHaveBeenCalledWith( - expect.objectContaining({ - repoPath: repo.path, - repoId: repo.id, - state: 'opened', - page: 1, - perPage: 12, - query: 'launch' - }) - ) - }) - - it('hides disconnected saved-host Linear even when the focused runtime is connected', async () => { - mocks.state.linearStatus = { ...mocks.state.linearStatus, connected: true } - mocks.readStatus.mockResolvedValue({ connected: false, viewer: null }) - const fieldProps = props(source) - const { result } = renderHook(() => useWorkItemSourceFoundation(fieldProps)) - await waitFor(() => expect(result.current.linearStatusChecked).toBe(true)) - expect(result.current.availableModes.some((mode) => mode.id === 'linear')).toBe(false) - expect(result.current.linearStatus.connected).toBe(false) - }) - - it("reads Linear on the selected repo's host, not the focused one (#32924)", async () => { - mocks.state.linearStatus = { ...mocks.state.linearStatus, connected: true } - mocks.readStatus.mockResolvedValue({ connected: false, viewer: null }) - const serverRepo: Repo = { - id: 'server-repo', - path: '/srv/app', - displayName: 'app', - badgeColor: '', - addedAt: 0, - executionHostId: 'runtime:remote' - } - const fieldProps = { ...props(), repos: [serverRepo], repoId: serverRepo.id } - const { result } = renderHook(() => useWorkItemSourceFoundation(fieldProps)) - await waitFor(() => expect(result.current.linearStatusChecked).toBe(true)) - expect(mocks.readStatus).toHaveBeenCalledWith( - expect.objectContaining({ provider: 'linear', hostId: 'runtime:remote' }) - ) - expect(result.current.availableModes.some((mode) => mode.id === 'linear')).toBe(false) - expect(mocks.state.checkLinearConnection).not.toHaveBeenCalled() - }) - it("holds a pasted Linear URL while the repo host's status is still loading", async () => { mocks.state.linearStatus = { ...mocks.state.linearStatus, connected: true } mocks.readStatus.mockReturnValue(new Promise(() => {})) @@ -419,16 +117,6 @@ describe('smart workspace explicit source connection', () => { expect(result.current.linearStatusChecked).toBe(false) expect(result.current.unresolvedLinearUrlIntent).toBe(true) }) - - it('retains focused runtime status and avoids a new status read with no selected repo', async () => { - mocks.state.linearStatus = { ...mocks.state.linearStatus, connected: true } - const fieldProps = props() - const { result } = renderHook(() => useWorkItemSourceFoundation(fieldProps)) - await act(async () => {}) - expect(result.current.availableModes.some((mode) => mode.id === 'linear')).toBe(true) - expect(result.current.linearStatus).toBe(mocks.state.linearStatus) - expect(mocks.readStatus).not.toHaveBeenCalled() - }) it('returns to Smart after losing a provider and does not resurrect its stale mode or rows', async () => { mocks.state.linearStatus = { ...mocks.state.linearStatus, connected: true } mocks.state.searchLinearIssues.mockResolvedValue([referenceLinearIssue()]) @@ -447,19 +135,4 @@ describe('smart workspace explicit source connection', () => { expect(result.current.mode).toBe('smart') expect(result.current.rows).toEqual([]) }) - - it.each([false, true])( - 'allows Jira URL resolution only while sourceSelected=%s is false', - (sourceSelected) => { - const fieldProps = { - ...props(), - sourceSelected, - value: 'https://company.atlassian.net/browse/ENG-1' - } - renderHook(() => useWorkItemSourceFoundation(fieldProps)) - expect(mocks.readJiraSource).toHaveBeenLastCalledWith( - expect.objectContaining({ enabled: !sourceSelected }) - ) - } - ) })