mirror of
https://github.com/iflytek/skillhub.git
synced 2026-10-07 02:57:51 +00:00
fix(search): show default discovery list on empty query (#312)
This commit is contained in:
parent
2cfd4a730b
commit
4619e546bf
3 changed files with 67 additions and 15 deletions
|
|
@ -39,12 +39,11 @@ test.describe('Search Input (Real API)', () => {
|
|||
await expect(getSearchCards(page).first()).toBeVisible({ timeout: 10_000 })
|
||||
})
|
||||
|
||||
// TC_SEARCH_INPUT_003 P0 - empty search guidance
|
||||
test('TC_SEARCH_INPUT_003: empty search shows keyword guidance instead of a default list', async ({ page }) => {
|
||||
// TC_SEARCH_INPUT_003 P0 - empty search shows the default discovery list
|
||||
test('TC_SEARCH_INPUT_003: empty search shows the default discovery list', async ({ page }) => {
|
||||
await page.goto(searchUrl(''))
|
||||
await expect(page).toHaveURL(/\/search/)
|
||||
await expect(page.getByRole('heading', { name: 'No results found' })).toBeVisible()
|
||||
await expect(page.getByText('Please enter a search keyword')).toBeVisible()
|
||||
await expect(getSearchCards(page).first()).toBeVisible({ timeout: 10_000 })
|
||||
})
|
||||
|
||||
// TC_SEARCH_INPUT_004 P0 - Enter key triggers search
|
||||
|
|
|
|||
|
|
@ -46,7 +46,13 @@ vi.mock('@/shared/components/skeleton-loader', () => ({
|
|||
}))
|
||||
|
||||
vi.mock('@/shared/components/empty-state', () => ({
|
||||
EmptyState: () => <div>empty-state</div>,
|
||||
EmptyState: ({ title, description }: { title: string; description?: string }) => (
|
||||
<div>
|
||||
empty-state
|
||||
<span>{title}</span>
|
||||
{description ? <span>{description}</span> : null}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/shared/components/pagination', () => ({
|
||||
|
|
@ -202,4 +208,55 @@ describe('SearchPage', () => {
|
|||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('renders the default skill list when the empty query still returns items', () => {
|
||||
useSearchMock.mockReturnValue({
|
||||
q: '',
|
||||
label: '',
|
||||
sort: 'newest',
|
||||
page: 0,
|
||||
starredOnly: false,
|
||||
})
|
||||
useSearchSkillsMock.mockReturnValue({
|
||||
data: {
|
||||
items: [{ id: 1, displayName: 'Demo Skill', summary: 'summary', namespace: 'global', slug: 'demo', downloadCount: 1, starCount: 1, ratingCount: 0, updatedAt: '2026-03-20T00:00:00Z', canSubmitPromotion: false }],
|
||||
total: 1,
|
||||
page: 0,
|
||||
size: 12,
|
||||
},
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
})
|
||||
|
||||
const html = renderToStaticMarkup(<SearchPage />)
|
||||
|
||||
expect(html).toContain('skill-card')
|
||||
expect(html).not.toContain('empty-state')
|
||||
})
|
||||
|
||||
it('shows a generic empty state when the default discovery list is empty', () => {
|
||||
useSearchMock.mockReturnValue({
|
||||
q: '',
|
||||
label: '',
|
||||
sort: 'newest',
|
||||
page: 0,
|
||||
starredOnly: false,
|
||||
})
|
||||
useSearchSkillsMock.mockReturnValue({
|
||||
data: {
|
||||
items: [],
|
||||
total: 0,
|
||||
page: 0,
|
||||
size: 12,
|
||||
},
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
})
|
||||
|
||||
const html = renderToStaticMarkup(<SearchPage />)
|
||||
|
||||
expect(html).toContain('empty-state')
|
||||
expect(html).toContain('search.noResults')
|
||||
expect(html).not.toContain('search.enterKeyword')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -125,8 +125,6 @@ export function SearchPage() {
|
|||
isLoading: isLoadingStarred,
|
||||
isFetching: isFetchingStarred,
|
||||
} = useMyStars(starredOnly && isAuthenticated)
|
||||
const shouldShowGuidance = !starredOnly && !q && !selectedLabel
|
||||
|
||||
useEffect(() => {
|
||||
// Debounce URL updates while the user is typing so query state stays shareable without
|
||||
// triggering a navigation on every keystroke.
|
||||
|
|
@ -202,10 +200,10 @@ export function SearchPage() {
|
|||
: data
|
||||
? Math.ceil(data.total / data.size)
|
||||
: 0
|
||||
const displayItems = shouldShowGuidance ? [] : (starredOnly ? starredPageItems : (data?.items ?? []))
|
||||
const isPageLoading = shouldShowGuidance ? false : (starredOnly ? isLoadingStarred : isLoading)
|
||||
const isUpdatingResults = shouldShowGuidance ? false : (starredOnly ? isFetchingStarred && !isLoadingStarred : isFetching && !isLoading)
|
||||
const resultCount = shouldShowGuidance ? 0 : (starredOnly ? filteredStarredSkills.length : (data?.total ?? 0))
|
||||
const displayItems = starredOnly ? starredPageItems : (data?.items ?? [])
|
||||
const isPageLoading = starredOnly ? isLoadingStarred : isLoading
|
||||
const isUpdatingResults = starredOnly ? isFetchingStarred && !isLoadingStarred : isFetching && !isLoading
|
||||
const resultCount = starredOnly ? filteredStarredSkills.length : (data?.total ?? 0)
|
||||
|
||||
return (
|
||||
<div className={APP_SHELL_PAGE_CLASS_NAME}>
|
||||
|
|
@ -313,11 +311,9 @@ export function SearchPage() {
|
|||
<EmptyState
|
||||
title={starredOnly ? t('search.noStarredResults') : t('search.noResults')}
|
||||
description={
|
||||
shouldShowGuidance
|
||||
? t('search.enterKeyword')
|
||||
: starredOnly
|
||||
starredOnly
|
||||
? (q ? t('search.noStarredResultsFor', { q }) : t('search.noStarredSkills'))
|
||||
: (q ? t('search.noResultsFor', { q }) : t('search.enterKeyword'))
|
||||
: (q ? t('search.noResultsFor', { q }) : undefined)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue