mirror of
https://github.com/stablyai/orca.git
synced 2026-11-14 18:07:45 +00:00
test: remove low-value chat hook tests (#38474)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -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 })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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<LinearConnectionStatus>((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<LinearIssue> = {
|
||||
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 <span>{connection.loaded ? 'ready' : 'pending'}</span>
|
||||
}
|
||||
const mounted = render(
|
||||
<>
|
||||
{Array.from({ length: N }, (_, index) => (
|
||||
<Source key={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)
|
||||
}
|
||||
)
|
||||
|
||||
+2
-329
@@ -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<T>() {
|
||||
let resolve!: (value: T) => void
|
||||
const promise = new Promise<T>((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<LinearIssue[]>()
|
||||
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<LinearIssue[]>()
|
||||
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<LinearIssue[]>()
|
||||
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<LinearIssue[]>()
|
||||
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<LinearIssue[]>()
|
||||
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 })
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user