mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 10:27:33 +00:00
test: remove low-value markdown fold and invalidation cases (#42361)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -449,7 +449,7 @@
|
||||
4 test-no-wall-clock:src/main/pty/process-retirement/windows-live-tree-kill.win32.test.ts
|
||||
5 test-no-wall-clock:src/main/rate-limits/service/service-account-target-selection.test.ts
|
||||
1 test-no-wall-clock:src/main/rate-limits/service/service-cursor-usage.test.ts
|
||||
3 test-no-wall-clock:src/main/rate-limits/service/service-minimax-usage.test.ts
|
||||
1 test-no-wall-clock:src/main/rate-limits/service/service-minimax-usage.test.ts
|
||||
3 test-no-wall-clock:src/main/rate-limits/service/service-zcode-usage.test.ts
|
||||
1 test-no-wall-clock:src/main/runtime/agent-session/lifecycle/structured-codex-child-work-runtime.test.ts
|
||||
2 test-no-wall-clock:src/main/runtime/agent-session/structured-agent-session-held-signal.test.ts
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
// Folding a foldable while its host-area page shows a session must keep that session, not drop to the list beneath.
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const harness = await vi.hoisted(async () => await import('./mobile-web-shell-screen-test-harness'))
|
||||
const dependencies = vi.hoisted(() => harness.createScreenDependencies())
|
||||
const { screenModuleMocks } = await vi.hoisted(
|
||||
async () => await import('./mobile-web-shell-screen-test-mocks')
|
||||
)
|
||||
const mocks = vi.hoisted(() => screenModuleMocks(dependencies))
|
||||
const device = vi.hoisted(() => ({ width: 951, height: 669 }))
|
||||
|
||||
vi.mock('react-native', () => ({
|
||||
...mocks['react-native'](),
|
||||
useWindowDimensions: () => ({ width: device.width, height: device.height })
|
||||
}))
|
||||
vi.mock('expo-router', mocks['expo-router'])
|
||||
vi.mock('expo-clipboard', mocks['expo-clipboard'])
|
||||
vi.mock('expo-haptics', mocks['expo-haptics'])
|
||||
vi.mock('expo-document-picker', mocks['expo-document-picker'])
|
||||
vi.mock('@orca/expo-two-way-audio', mocks['@orca/expo-two-way-audio'])
|
||||
vi.mock('expo-keep-awake', mocks['expo-keep-awake'])
|
||||
vi.mock('expo-image-picker', mocks['expo-image-picker'])
|
||||
vi.mock('expo-file-system', mocks['expo-file-system'])
|
||||
vi.mock('../device-store/device-store', mocks['../device-store/device-store'])
|
||||
vi.mock('lucide-react-native', mocks['lucide-react-native'])
|
||||
vi.mock('react-native-safe-area-context', mocks['react-native-safe-area-context'])
|
||||
vi.mock('../../modules/orca-mobile-web-shell/src', mocks['../../modules/orca-mobile-web-shell/src'])
|
||||
vi.mock('../app-update/use-wall-app-update', mocks['../app-update/use-wall-app-update'])
|
||||
vi.mock(
|
||||
'../transport/connection/host-client-hooks',
|
||||
mocks['../transport/connection/host-client-hooks']
|
||||
)
|
||||
vi.mock('./use-page-host-snapshot', mocks['./use-page-host-snapshot'])
|
||||
vi.mock('./use-mobile-web-shell-session', mocks['./use-mobile-web-shell-session'])
|
||||
|
||||
import { createElement } from 'react'
|
||||
import { act, create, type ReactTestRenderer } from 'react-test-renderer'
|
||||
import { clientFrame, createFakeRpcClient } from './bridge-host-test-fakes'
|
||||
import { MobileWebShellScreen } from './MobileWebShellScreen'
|
||||
|
||||
const HOST = '/h/host-1'
|
||||
const DETAIL = '/h/host-1/session/wt-1'
|
||||
const UNFOLDED = { width: 951, height: 669 }
|
||||
const COVER = { width: 466, height: 678 }
|
||||
|
||||
const hostEntry = { key: 'entry-0', name: '[hostId]/index', params: { hostId: 'host-1' } }
|
||||
const sessionEntry = {
|
||||
key: 'entry-1',
|
||||
name: '[hostId]/session/[worktreeId]',
|
||||
params: { hostId: 'host-1', worktreeId: 'wt-1' }
|
||||
}
|
||||
|
||||
function stackOf(routes: readonly (typeof hostEntry | typeof sessionEntry)[]) {
|
||||
const hostStack = { key: 'host-stack', index: routes.length - 1, routes: [...routes] }
|
||||
return { key: 'root-stack', index: 0, routes: [{ key: 'h', name: 'h', state: hostStack }] }
|
||||
}
|
||||
|
||||
async function foldAfterPageShows(location: string | null, focused = true): Promise<void> {
|
||||
Object.assign(device, UNFOLDED)
|
||||
dependencies.ownsHostArea = true
|
||||
dependencies.screenFocused = focused
|
||||
// Unfocused means a native session was pushed over this host-route shell.
|
||||
dependencies.rootState = focused ? stackOf([hostEntry]) : stackOf([hostEntry, sessionEntry])
|
||||
dependencies.client = createFakeRpcClient()
|
||||
dependencies.state = harness.readyState('session-one')
|
||||
dependencies.pageRoutes = ['/h/[hostId]', '/h/[hostId]/session/[worktreeId]']
|
||||
const screen = () =>
|
||||
createElement(MobileWebShellScreen, { hostId: 'host-1', route: { pathname: HOST } })
|
||||
const mounted: { tree: ReactTestRenderer | null } = { tree: null }
|
||||
await act(async () => {
|
||||
mounted.tree = create(screen())
|
||||
})
|
||||
const view = mounted.tree?.root.findAll((node) => String(node.type) === 'ShellViewProbe')[0]
|
||||
await act(async () => {
|
||||
view?.props.onBridgeMessage({ nativeEvent: { json: clientFrame({ type: 'ready' }) } })
|
||||
if (location !== null) {
|
||||
view?.props.onBridgeMessage({
|
||||
nativeEvent: { json: clientFrame({ type: 'notify', name: 'location', href: location }) }
|
||||
})
|
||||
}
|
||||
})
|
||||
Object.assign(device, COVER)
|
||||
dependencies.ownsHostArea = false
|
||||
await act(async () => {
|
||||
mounted.tree?.update(screen())
|
||||
})
|
||||
act(() => mounted.tree?.unmount())
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
harness.resetScreenDependencies(dependencies)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('folding while the host-area page shows a session', () => {
|
||||
it('reopens that session natively on the cover screen', async () => {
|
||||
await foldAfterPageShows(DETAIL)
|
||||
expect(dependencies.push.mock.calls).toEqual([[DETAIL]])
|
||||
})
|
||||
|
||||
it('leaves the stack alone from a host-route shell covered by a pushed session', async () => {
|
||||
await foldAfterPageShows(HOST, false)
|
||||
expect(dependencies.push).not.toHaveBeenCalled()
|
||||
expect(dependencies.dispatch).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -7,13 +7,11 @@ import {
|
||||
const {
|
||||
handleMock,
|
||||
setMainUiLanguageMock,
|
||||
rebuildSystemTrayMenuMock,
|
||||
applyElectronProxySettingsMock,
|
||||
applyAgentStatusHooksEnabledMock
|
||||
} = vi.hoisted(() => ({
|
||||
handleMock: vi.fn(),
|
||||
setMainUiLanguageMock: vi.fn(),
|
||||
rebuildSystemTrayMenuMock: vi.fn(),
|
||||
applyElectronProxySettingsMock: vi.fn(),
|
||||
applyAgentStatusHooksEnabledMock: vi.fn()
|
||||
}))
|
||||
@@ -54,7 +52,7 @@ vi.mock('../workspaces/creation/worktree-root-preparation', () => ({
|
||||
prepareLocalWorktreeRootsForRepos: vi.fn().mockResolvedValue(undefined)
|
||||
}))
|
||||
vi.mock('../menu/register-app-menu', () => ({ rebuildAppMenu: vi.fn() }))
|
||||
vi.mock('../tray/system-tray', () => ({ rebuildSystemTrayMenu: rebuildSystemTrayMenuMock }))
|
||||
vi.mock('../tray/system-tray', () => ({ rebuildSystemTrayMenu: vi.fn() }))
|
||||
vi.mock('../i18n/main-i18n', () => ({ setMainUiLanguage: setMainUiLanguageMock }))
|
||||
|
||||
import { registerSettingsHandlers } from './settings'
|
||||
@@ -62,7 +60,6 @@ import { registerSettingsHandlers } from './settings'
|
||||
beforeEach(() => {
|
||||
handleMock.mockClear()
|
||||
setMainUiLanguageMock.mockReset().mockResolvedValue('en')
|
||||
rebuildSystemTrayMenuMock.mockClear()
|
||||
applyElectronProxySettingsMock.mockReset().mockResolvedValue({ source: 'settings' })
|
||||
applyAgentStatusHooksEnabledMock.mockReset().mockResolvedValue([])
|
||||
})
|
||||
@@ -93,11 +90,9 @@ it('returns current settings when a language change finishes after a newer theme
|
||||
|
||||
const first = write(event, { theme: 'dark', uiLanguage: 'ko' })
|
||||
await started.promise
|
||||
expect(rebuildSystemTrayMenuMock).not.toHaveBeenCalled()
|
||||
await write(event, { theme: 'light' })
|
||||
release.resolve()
|
||||
const reply = await first
|
||||
expect(rebuildSystemTrayMenuMock).toHaveBeenCalledOnce()
|
||||
await store.flushPendingOrThrowAsync()
|
||||
|
||||
expect(store.getSettings().theme).toBe('light')
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { ProviderRateLimits } from '../../../shared/rate-limit-types'
|
||||
import { RateLimitService } from './rate-limit-service'
|
||||
import { fetchActiveClaudeRateLimits } from '../providers/claude/claude-active-usage-fetch'
|
||||
import { fetchCodexRateLimits } from '../providers/codex/codex-fetcher'
|
||||
import { fetchMiniMaxRateLimits } from '../providers/minimax/minimax-fetcher'
|
||||
import {
|
||||
deferred,
|
||||
okProvider,
|
||||
resetRateLimitProviderMocks
|
||||
} from './rate-limit-service-test-harness'
|
||||
import { okProvider, resetRateLimitProviderMocks } from './rate-limit-service-test-harness'
|
||||
|
||||
vi.mock('../providers/claude/claude-active-usage-fetch', () => ({
|
||||
fetchActiveClaudeRateLimits: vi.fn()
|
||||
@@ -108,42 +103,4 @@ describe('RateLimitService', () => {
|
||||
expect.objectContaining({ apiKey: 'sk-account-b' })
|
||||
)
|
||||
})
|
||||
|
||||
it('does not apply an in-flight MiniMax result after credential invalidation', async () => {
|
||||
const service = new RateLimitService()
|
||||
const firstMiniMax = deferred<ProviderRateLimits>()
|
||||
const secondMiniMax = deferred<ProviderRateLimits>()
|
||||
service.setMiniMaxConfigResolver(() => ({
|
||||
sessionCookie: '_token=abc',
|
||||
groupId: '',
|
||||
models: 'general',
|
||||
endpoint: 'overseas',
|
||||
apiKey: ''
|
||||
}))
|
||||
vi.mocked(fetchMiniMaxRateLimits)
|
||||
.mockImplementationOnce(() => firstMiniMax.promise)
|
||||
.mockImplementationOnce(() => secondMiniMax.promise)
|
||||
|
||||
const firstRefresh = service.refresh()
|
||||
await Promise.resolve()
|
||||
|
||||
service.invalidateMiniMaxCredentialState()
|
||||
const queuedRefresh = service.refresh()
|
||||
await Promise.resolve()
|
||||
|
||||
firstMiniMax.resolve(okProvider('minimax', 50, Date.now()))
|
||||
await Promise.resolve()
|
||||
await Promise.resolve()
|
||||
|
||||
expect(service.getState().minimax?.status).toBe('fetching')
|
||||
expect(service.getState().minimax?.session).toBeNull()
|
||||
|
||||
secondMiniMax.resolve(okProvider('minimax', 10, Date.now()))
|
||||
await firstRefresh
|
||||
await queuedRefresh
|
||||
|
||||
const state = service.getState()
|
||||
expect(fetchMiniMaxRateLimits).toHaveBeenCalledTimes(2)
|
||||
expect(state.minimax?.session?.usedPercent).toBe(10)
|
||||
})
|
||||
})
|
||||
|
||||
+6
-151
@@ -1,99 +1,25 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import type { Nodes, RootContent } from 'hast'
|
||||
import { createElement } from 'react'
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import Markdown from 'react-markdown'
|
||||
import {
|
||||
MARKDOWN_REMARK_PLUGINS,
|
||||
MARKDOWN_REHYPE_PLUGINS
|
||||
} from '../render-tree/markdown-preview-plugins'
|
||||
import { renderMarkdownPreviewTree } from '../render-tree/markdown-preview-render-tree'
|
||||
import { markdownPreviewUrlTransform } from '../links/markdown-preview-url-transform'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { Nodes } from 'hast'
|
||||
import { MarkdownPreviewDocumentEngine } from './markdown-preview-document-engine'
|
||||
import {
|
||||
parseMarkdownPreviewDocument,
|
||||
renderMarkdownPreviewBlock
|
||||
} from './markdown-preview-document-tree'
|
||||
import { countMarkdownPreviewNodes } from '../render-tree/markdown-preview-tree-content'
|
||||
import {
|
||||
MARKDOWN_PREVIEW_BLOCK_MAX_NODES,
|
||||
MARKDOWN_PREVIEW_DOCUMENT_MAX_NODES,
|
||||
MARKDOWN_PREVIEW_MAX_SEARCH_MATCHES,
|
||||
MARKDOWN_PREVIEW_VIEWPORT_MAX_NODES
|
||||
} from './markdown-preview-document-types'
|
||||
import { parseMarkdownPreviewDocument } from './markdown-preview-document-tree'
|
||||
|
||||
function elements(node: Nodes): Nodes[] {
|
||||
return [node, ...('children' in node ? node.children.flatMap(elements) : [])]
|
||||
}
|
||||
|
||||
describe('large Markdown preview documents', () => {
|
||||
it('rejects atomic blocks before allocating a copy of their trees', () => {
|
||||
const { tree } = parseMarkdownPreviewDocument(`\`\`\`text\n${'x'.repeat(32_769)}\n\`\`\``)
|
||||
const broadBlock: RootContent = {
|
||||
type: 'element',
|
||||
tagName: 'div',
|
||||
properties: {},
|
||||
children: Array.from({ length: MARKDOWN_PREVIEW_BLOCK_MAX_NODES }, () => ({
|
||||
type: 'text',
|
||||
value: 'x'
|
||||
}))
|
||||
}
|
||||
const clone = vi.spyOn(globalThis, 'structuredClone')
|
||||
try {
|
||||
expect(renderMarkdownPreviewBlock(tree.children[0], 0).oversized).toBe(true)
|
||||
expect(renderMarkdownPreviewBlock(broadBlock, 1).oversized).toBe(true)
|
||||
expect(clone).not.toHaveBeenCalled()
|
||||
} finally {
|
||||
clone.mockRestore()
|
||||
}
|
||||
})
|
||||
|
||||
it('renders the same safe HTML as the ordinary preview pipeline', () => {
|
||||
const content =
|
||||
'# Repeat\n\n[Global][end] **bold** ~~deleted~~\n\n# Repeat\n\n' +
|
||||
'| a | b |\n| --- | --- |\n| x | y |\n\n' +
|
||||
'```javascript\nconst value = 42\n```\n\n$x^2$\n\n' +
|
||||
'<details open><summary>Read</summary>\n\nNested **content**\n\n</details>\n\n' +
|
||||
'Note[^n].\n\n[^n]: A footnote\n\n[end]: https://example.com\n'
|
||||
const engine = new MarkdownPreviewDocumentEngine()
|
||||
const document = engine.load(content)
|
||||
const actual = engine
|
||||
.blocks(document.blocks.map((block) => block.index))
|
||||
.map((block) => renderToStaticMarkup(renderMarkdownPreviewTree(block.tree, {})))
|
||||
.join('')
|
||||
const ordinary = renderToStaticMarkup(
|
||||
createElement(
|
||||
Markdown,
|
||||
{
|
||||
remarkPlugins: MARKDOWN_REMARK_PLUGINS,
|
||||
rehypePlugins: MARKDOWN_REHYPE_PLUGINS,
|
||||
urlTransform: markdownPreviewUrlTransform
|
||||
},
|
||||
content
|
||||
)
|
||||
)
|
||||
expect(actual.replace(/>\n+</g, '><')).toBe(ordinary.replace(/>\n+</g, '><'))
|
||||
})
|
||||
|
||||
it('evicts compiled blocks and invalidates searches on document replacement', async () => {
|
||||
it('invalidates searches on document replacement', async () => {
|
||||
const engine = new MarkdownPreviewDocumentEngine()
|
||||
engine.load('needle\n\n'.repeat(100))
|
||||
const first = engine.blocks([0])[0]
|
||||
expect(engine.blocks([0])[0]).toBe(first)
|
||||
engine.blocks(Array.from({ length: 40 }, (_, index) => index + 1))
|
||||
engine.blocks(Array.from({ length: 40 }, (_, index) => index + 41))
|
||||
expect(engine.blocks([0])[0]).not.toBe(first)
|
||||
const pending = engine.search('needle')
|
||||
engine.load('# Replacement')
|
||||
expect(await pending).toBeNull()
|
||||
expect(await engine.search('needle')).toEqual({ matches: [], truncated: false })
|
||||
expect(() => engine.load('x'.repeat(8 * 1024 * 1024 + 1))).toThrow('size limit')
|
||||
expect(() => engine.blocks([0])).toThrow('Invalid preview viewport')
|
||||
})
|
||||
|
||||
it('preserves raw HTML nesting across Markdown blocks and sanitizes executable HTML', () => {
|
||||
const { tree } = parseMarkdownPreviewDocument(
|
||||
'<details open>\n<summary>Read</summary>\n\n**Nested**\n\n</details>\n\n<script>alert(1)</script>\n\n<img src="javascript:alert(1)" onerror="alert(1)">'
|
||||
'<details open>\n<summary>Read</summary>\n\n**Nested**\n\n</details>\n\n<script>alert(1)</script>'
|
||||
)
|
||||
const nodes = elements(tree)
|
||||
expect(nodes.some((node) => node.type === 'element' && node.tagName === 'script')).toBe(false)
|
||||
@@ -102,63 +28,9 @@ describe('large Markdown preview documents', () => {
|
||||
properties: { open: true },
|
||||
children: expect.arrayContaining([expect.objectContaining({ tagName: 'p' })])
|
||||
})
|
||||
expect(nodes.find((node) => node.type === 'element' && node.tagName === 'img')).toMatchObject({
|
||||
properties: {}
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps code searchable when syntax expansion alone exceeds the node budget', async () => {
|
||||
const engine = new MarkdownPreviewDocumentEngine()
|
||||
engine.load(`\`\`\`javascript\n${'const needle = 42;\n'.repeat(900)}\`\`\``)
|
||||
const block = engine.blocks([0])[0]
|
||||
expect(block.oversized).toBe(false)
|
||||
expect(countMarkdownPreviewNodes(block.tree, MARKDOWN_PREVIEW_BLOCK_MAX_NODES)).toBeLessThan(
|
||||
MARKDOWN_PREVIEW_BLOCK_MAX_NODES
|
||||
)
|
||||
expect((await engine.search('const needle'))?.matches).toHaveLength(900)
|
||||
})
|
||||
|
||||
it('rejects giant atomic blocks and excessive input without attempting a full DOM', () => {
|
||||
const engine = new MarkdownPreviewDocumentEngine()
|
||||
engine.load(`\`\`\`javascript\n${'const value = 3;\n'.repeat(10_000)}\`\`\``)
|
||||
expect(engine.blocks([0])).toEqual([
|
||||
{ index: 0, oversized: true, tree: { type: 'root', children: [] } }
|
||||
])
|
||||
expect(() => engine.load('x'.repeat(8 * 1024 * 1024 + 1))).toThrow('size limit')
|
||||
expect(() => engine.load('🙂'.repeat(3 * 1024 * 1024))).toThrow('size limit')
|
||||
expect(() => engine.blocks([-1])).toThrow('Invalid preview viewport')
|
||||
expect(() => engine.blocks(Array.from({ length: 41 }, (_, index) => index))).toThrow(
|
||||
'Invalid preview viewport'
|
||||
)
|
||||
})
|
||||
|
||||
it('bounds document and viewport complexity independently of source bytes', () => {
|
||||
const child = { type: 'text', value: 'x' }
|
||||
expect(
|
||||
countMarkdownPreviewNodes(
|
||||
{ children: Array.from({ length: MARKDOWN_PREVIEW_DOCUMENT_MAX_NODES }, () => child) },
|
||||
MARKDOWN_PREVIEW_DOCUMENT_MAX_NODES
|
||||
)
|
||||
).toBe(MARKDOWN_PREVIEW_DOCUMENT_MAX_NODES + 1)
|
||||
const engine = new MarkdownPreviewDocumentEngine()
|
||||
engine.load(
|
||||
Array.from(
|
||||
{ length: 40 },
|
||||
() => `| a | b |\n| --- | --- |\n${'| a | b |\n'.repeat(100)}`
|
||||
).join('\n\n')
|
||||
)
|
||||
const blocks = engine.blocks(Array.from({ length: 40 }, (_, index) => index))
|
||||
expect(
|
||||
blocks.reduce(
|
||||
(sum, block) =>
|
||||
sum + countMarkdownPreviewNodes(block.tree, MARKDOWN_PREVIEW_BLOCK_MAX_NODES),
|
||||
0
|
||||
)
|
||||
).toBeLessThanOrEqual(MARKDOWN_PREVIEW_VIEWPORT_MAX_NODES + 40)
|
||||
expect(blocks.some((block) => block.oversized)).toBe(true)
|
||||
})
|
||||
|
||||
it('finds rendered text beyond the first viewport, including highlighted code and footnotes', async () => {
|
||||
it('finds code and footnote text in later document blocks', async () => {
|
||||
const engine = new MarkdownPreviewDocumentEngine()
|
||||
engine.load(
|
||||
`# Start\n\n${'Ordinary paragraph.\n\n'.repeat(
|
||||
@@ -168,22 +40,5 @@ describe('large Markdown preview documents', () => {
|
||||
const result = await engine.search('needle')
|
||||
expect(result?.matches).toHaveLength(3)
|
||||
expect(result?.matches.every((match) => match.block > 90)).toBe(true)
|
||||
expect(await engine.search('missing')).toEqual({ matches: [], truncated: false })
|
||||
expect(await engine.search('x'.repeat(2049))).toEqual({ matches: [], truncated: false })
|
||||
})
|
||||
|
||||
it('bounds search results and supersedes work when the query changes', async () => {
|
||||
const engine = new MarkdownPreviewDocumentEngine()
|
||||
engine.load(`${'needle '.repeat(MARKDOWN_PREVIEW_MAX_SEARCH_MATCHES)}\n\nend needle\n`)
|
||||
// One oversized paragraph is explicitly unavailable in the rendered preview.
|
||||
expect((await engine.search('needle'))?.matches).toHaveLength(1)
|
||||
engine.load(`${'needle '.repeat(100)}\n\n${`${'needle '.repeat(100)}\n\n`.repeat(110)}`)
|
||||
const pending = engine.search('needle')
|
||||
const latest = engine.search('absent')
|
||||
expect(await pending).toBeNull()
|
||||
expect(await latest).toEqual({ matches: [], truncated: false })
|
||||
const capped = await engine.search('needle')
|
||||
expect(capped?.matches).toHaveLength(MARKDOWN_PREVIEW_MAX_SEARCH_MATCHES)
|
||||
expect(capped?.truncated).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
import { useContext } from 'react'
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import { expect, it, vi } from 'vitest'
|
||||
import type { FolderWorkspace } from '../../../../../../shared/folder-workspaces/folder-workspace-types'
|
||||
import {
|
||||
resolveNativeChatFileLinkContextForOwner,
|
||||
type NativeChatFileLinkState
|
||||
} from '../actions/native-chat-file-link-context'
|
||||
import {
|
||||
NativeChatLinkPeekContext,
|
||||
NativeChatLinkPeekProvider
|
||||
} from './native-chat-link-peek-context'
|
||||
|
||||
const mocks = vi.hoisted((): { state: NativeChatFileLinkState | null } => ({ state: null }))
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: (select: (state: NativeChatFileLinkState) => unknown) => select(mocks.state!)
|
||||
}))
|
||||
|
||||
function RoutingHost() {
|
||||
return useContext(NativeChatLinkPeekContext).githubRoutingAuthorityKey
|
||||
}
|
||||
|
||||
it.each([
|
||||
{ owner: {}, runtimeEnvironmentId: null, expectedHost: 'local' },
|
||||
{ owner: { connectionId: 'box' }, runtimeEnvironmentId: null, expectedHost: 'ssh:box' },
|
||||
{
|
||||
owner: { executionHostId: 'runtime:env' as const },
|
||||
runtimeEnvironmentId: 'env',
|
||||
expectedHost: 'runtime:env'
|
||||
},
|
||||
{
|
||||
owner: { executionHostId: 'runtime:env' as const, connectionId: 'T' },
|
||||
runtimeEnvironmentId: 'env',
|
||||
expectedHost: 'nested:env/T'
|
||||
}
|
||||
])(
|
||||
'routes a folder chat preview through $expectedHost',
|
||||
({ owner, runtimeEnvironmentId, expectedHost }) => {
|
||||
const folder: FolderWorkspace = {
|
||||
id: 'chat',
|
||||
projectGroupId: 'group',
|
||||
name: 'Chat',
|
||||
folderPath: '/workspace',
|
||||
linkedTask: null,
|
||||
comment: '',
|
||||
isArchived: false,
|
||||
isUnread: false,
|
||||
isPinned: false,
|
||||
sortOrder: 0,
|
||||
lastActivityAt: 0,
|
||||
createdAt: 0,
|
||||
updatedAt: 0,
|
||||
...owner
|
||||
}
|
||||
mocks.state = {
|
||||
repos: [],
|
||||
projectGroups: [],
|
||||
folderWorkspaces: [folder],
|
||||
settings: null,
|
||||
worktreesByRepo: {},
|
||||
detectedWorktreesByRepo: {},
|
||||
tabsByWorktree: {},
|
||||
floatingWorkspacePath: null
|
||||
}
|
||||
const context = resolveNativeChatFileLinkContextForOwner(mocks.state, 'tab', 'folder:chat')
|
||||
expect(context?.runtimeEnvironmentId).toBe(runtimeEnvironmentId)
|
||||
expect(
|
||||
renderToStaticMarkup(
|
||||
<NativeChatLinkPeekProvider fileLinkContext={context}>
|
||||
<RoutingHost />
|
||||
</NativeChatLinkPeekProvider>
|
||||
)
|
||||
).toBe(expectedHost)
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user