Files
dify/web/app/components/workflow/skill/hooks/use-file-node-view-state.spec.tsx
yyh dc213ca76c refactor(skill)!: add file node view-state flow and mode-based file data hook
- introduce resolving/ready/missing node view-state to avoid unsupported flicker

- switch useSkillFileData to explicit mode: none/content/download

- add hook tests for view-state transitions and mode query gating

BREAKING CHANGE: useSkillFileData signature changed from (appId, nodeId, isEditable) to (appId, nodeId, mode).
2026-02-06 15:39:00 +08:00

116 lines
3.1 KiB
TypeScript

import { renderHook, waitFor } from '@testing-library/react'
import { useFileNodeViewState } from './use-file-node-view-state'
type HookProps = {
fileTabId: string | null
hasCurrentFileNode: boolean
isNodeMapLoading: boolean
isNodeMapFetching: boolean
isNodeMapFetched: boolean
}
const createProps = (overrides: Partial<HookProps> = {}): HookProps => ({
fileTabId: 'file-1',
hasCurrentFileNode: false,
isNodeMapLoading: true,
isNodeMapFetching: true,
isNodeMapFetched: false,
...overrides,
})
describe('useFileNodeViewState', () => {
describe('resolution lifecycle', () => {
it('should return ready when there is no active file tab', () => {
const { result } = renderHook(() => useFileNodeViewState(createProps({
fileTabId: null,
})))
expect(result.current).toBe('ready')
})
it('should return resolving during initial node resolution', () => {
const { result } = renderHook(() => useFileNodeViewState(createProps()))
expect(result.current).toBe('resolving')
})
it('should return missing when query settles without a matching node', () => {
const { result, rerender } = renderHook(
(props: HookProps) => useFileNodeViewState(props),
{ initialProps: createProps() },
)
rerender(createProps({
isNodeMapLoading: false,
isNodeMapFetching: false,
isNodeMapFetched: true,
}))
expect(result.current).toBe('missing')
})
it('should stay missing during background refetch after missing is resolved', async () => {
const { result, rerender } = renderHook(
(props: HookProps) => useFileNodeViewState(props),
{ initialProps: createProps() },
)
rerender(createProps({
isNodeMapLoading: false,
isNodeMapFetching: false,
isNodeMapFetched: true,
}))
await waitFor(() => {
expect(result.current).toBe('missing')
})
rerender(createProps({
isNodeMapLoading: false,
isNodeMapFetching: true,
isNodeMapFetched: true,
}))
expect(result.current).toBe('missing')
})
it('should become ready once the target node appears', () => {
const { result, rerender } = renderHook(
(props: HookProps) => useFileNodeViewState(props),
{ initialProps: createProps() },
)
rerender(createProps({
hasCurrentFileNode: true,
isNodeMapLoading: false,
isNodeMapFetching: false,
isNodeMapFetched: true,
}))
expect(result.current).toBe('ready')
})
it('should reset to resolving when switching to another file tab', () => {
const { result, rerender } = renderHook(
(props: HookProps) => useFileNodeViewState(props),
{ initialProps: createProps({
isNodeMapLoading: false,
isNodeMapFetching: false,
isNodeMapFetched: true,
}) },
)
expect(result.current).toBe('missing')
rerender(createProps({
fileTabId: 'file-2',
isNodeMapLoading: false,
isNodeMapFetching: true,
isNodeMapFetched: true,
}))
expect(result.current).toBe('resolving')
})
})
})