mirror of
https://github.com/langgenius/dify.git
synced 2026-05-14 19:00:33 -04:00
175 lines
5.5 KiB
TypeScript
175 lines
5.5 KiB
TypeScript
import { act, waitFor } from '@testing-library/react'
|
|
import { renderHookWithNuqs } from '@/test/nuqs-testing'
|
|
import { APP_LIST_SEARCH_DEBOUNCE_MS } from '../../constants'
|
|
import { useAppsQueryState } from '../use-apps-query-state'
|
|
|
|
const renderWithAdapter = (searchParams = '') => {
|
|
return renderHookWithNuqs(() => useAppsQueryState(), { searchParams })
|
|
}
|
|
|
|
describe('useAppsQueryState', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
it('should expose app list query state actions', () => {
|
|
const { result } = renderWithAdapter()
|
|
|
|
expect(result.current.query).toEqual({
|
|
tagIDs: [],
|
|
creatorIDs: [],
|
|
keywords: '',
|
|
isCreatedByMe: false,
|
|
})
|
|
expect(typeof result.current.setKeywords).toBe('function')
|
|
expect(typeof result.current.setTagIDs).toBe('function')
|
|
expect(typeof result.current.setCreatorIDs).toBe('function')
|
|
expect(typeof result.current.setIsCreatedByMe).toBe('function')
|
|
})
|
|
|
|
it('should parse app list filters from URL', () => {
|
|
const { result } = renderWithAdapter(
|
|
'?tagIDs=tag1;tag2&creatorIDs=user-1;user-2&keywords=search+term&isCreatedByMe=true',
|
|
)
|
|
|
|
expect(result.current.query).toEqual({
|
|
tagIDs: ['tag1', 'tag2'],
|
|
creatorIDs: ['user-1', 'user-2'],
|
|
keywords: 'search term',
|
|
isCreatedByMe: true,
|
|
})
|
|
})
|
|
|
|
it('should update keywords state immediately while debouncing URL writes', async () => {
|
|
vi.useFakeTimers()
|
|
try {
|
|
const { result, onUrlUpdate } = renderWithAdapter()
|
|
|
|
act(() => {
|
|
result.current.setKeywords('search')
|
|
})
|
|
|
|
expect(result.current.query.keywords).toBe('search')
|
|
expect(onUrlUpdate).not.toHaveBeenCalled()
|
|
|
|
await act(async () => {
|
|
await vi.advanceTimersByTimeAsync(APP_LIST_SEARCH_DEBOUNCE_MS + 100)
|
|
})
|
|
|
|
expect(onUrlUpdate).toHaveBeenCalled()
|
|
const update = onUrlUpdate.mock.calls.at(-1)![0]
|
|
expect(update.searchParams.get('keywords')).toBe('search')
|
|
expect(update.options.history).toBe('replace')
|
|
expect(update.options.shallow).toBe(false)
|
|
}
|
|
finally {
|
|
vi.useRealTimers()
|
|
}
|
|
})
|
|
|
|
it('should remove keywords from URL when cleared', async () => {
|
|
vi.useFakeTimers()
|
|
try {
|
|
const { result, onUrlUpdate } = renderWithAdapter('?keywords=existing')
|
|
|
|
act(() => {
|
|
result.current.setKeywords('')
|
|
})
|
|
|
|
expect(result.current.query.keywords).toBe('')
|
|
|
|
await act(async () => {
|
|
await vi.advanceTimersByTimeAsync(APP_LIST_SEARCH_DEBOUNCE_MS + 100)
|
|
})
|
|
|
|
expect(onUrlUpdate).toHaveBeenCalled()
|
|
const update = onUrlUpdate.mock.calls.at(-1)![0]
|
|
expect(update.searchParams.has('keywords')).toBe(false)
|
|
}
|
|
finally {
|
|
vi.useRealTimers()
|
|
}
|
|
})
|
|
|
|
it('should update tag filter URL state', async () => {
|
|
const { result, onUrlUpdate } = renderWithAdapter()
|
|
|
|
act(() => {
|
|
result.current.setTagIDs(['tag1', 'tag2'])
|
|
})
|
|
|
|
await waitFor(() => expect(onUrlUpdate).toHaveBeenCalled())
|
|
const update = onUrlUpdate.mock.calls.at(-1)![0]
|
|
expect(result.current.query.tagIDs).toEqual(['tag1', 'tag2'])
|
|
expect(update.searchParams.get('tagIDs')).toBe('tag1;tag2')
|
|
expect(update.options.history).toBe('push')
|
|
})
|
|
|
|
it('should remove tagIDs from URL when empty', async () => {
|
|
const { result, onUrlUpdate } = renderWithAdapter('?tagIDs=tag1;tag2')
|
|
|
|
act(() => {
|
|
result.current.setTagIDs([])
|
|
})
|
|
|
|
await waitFor(() => expect(onUrlUpdate).toHaveBeenCalled())
|
|
const update = onUrlUpdate.mock.calls.at(-1)![0]
|
|
expect(result.current.query.tagIDs).toEqual([])
|
|
expect(update.searchParams.has('tagIDs')).toBe(false)
|
|
})
|
|
|
|
it('should update creator filter URL state', async () => {
|
|
const { result, onUrlUpdate } = renderWithAdapter()
|
|
|
|
act(() => {
|
|
result.current.setCreatorIDs(['user-1', 'user-2'])
|
|
})
|
|
|
|
await waitFor(() => expect(onUrlUpdate).toHaveBeenCalled())
|
|
const update = onUrlUpdate.mock.calls.at(-1)![0]
|
|
expect(result.current.query.creatorIDs).toEqual(['user-1', 'user-2'])
|
|
expect(update.searchParams.get('creatorIDs')).toBe('user-1;user-2')
|
|
expect(update.options.history).toBe('push')
|
|
})
|
|
|
|
it('should remove creatorIDs from URL when empty', async () => {
|
|
const { result, onUrlUpdate } = renderWithAdapter('?creatorIDs=user-1;user-2')
|
|
|
|
act(() => {
|
|
result.current.setCreatorIDs([])
|
|
})
|
|
|
|
await waitFor(() => expect(onUrlUpdate).toHaveBeenCalled())
|
|
const update = onUrlUpdate.mock.calls.at(-1)![0]
|
|
expect(result.current.query.creatorIDs).toEqual([])
|
|
expect(update.searchParams.has('creatorIDs')).toBe(false)
|
|
})
|
|
|
|
it('should update created-by-me URL state', async () => {
|
|
const { result, onUrlUpdate } = renderWithAdapter()
|
|
|
|
act(() => {
|
|
result.current.setIsCreatedByMe(true)
|
|
})
|
|
|
|
await waitFor(() => expect(onUrlUpdate).toHaveBeenCalled())
|
|
const update = onUrlUpdate.mock.calls.at(-1)![0]
|
|
expect(result.current.query.isCreatedByMe).toBe(true)
|
|
expect(update.searchParams.get('isCreatedByMe')).toBe('true')
|
|
expect(update.options.history).toBe('push')
|
|
})
|
|
|
|
it('should remove isCreatedByMe from URL when disabled', async () => {
|
|
const { result, onUrlUpdate } = renderWithAdapter('?isCreatedByMe=true')
|
|
|
|
act(() => {
|
|
result.current.setIsCreatedByMe(false)
|
|
})
|
|
|
|
await waitFor(() => expect(onUrlUpdate).toHaveBeenCalled())
|
|
const update = onUrlUpdate.mock.calls.at(-1)![0]
|
|
expect(result.current.query.isCreatedByMe).toBe(false)
|
|
expect(update.searchParams.has('isCreatedByMe')).toBe(false)
|
|
})
|
|
})
|