From 4619e546bf60ceb77e272ef1c290eae6e488c0d4 Mon Sep 17 00:00:00 2001
From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Date: Wed, 15 Apr 2026 16:58:21 +0800
Subject: [PATCH] fix(search): show default discovery list on empty query
(#312)
---
web/e2e/search-page-full.spec.ts | 7 ++--
web/src/pages/search.test.tsx | 59 +++++++++++++++++++++++++++++++-
web/src/pages/search.tsx | 16 ++++-----
3 files changed, 67 insertions(+), 15 deletions(-)
diff --git a/web/e2e/search-page-full.spec.ts b/web/e2e/search-page-full.spec.ts
index f5775bfb..be14db8f 100644
--- a/web/e2e/search-page-full.spec.ts
+++ b/web/e2e/search-page-full.spec.ts
@@ -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
diff --git a/web/src/pages/search.test.tsx b/web/src/pages/search.test.tsx
index 726b5553..a921d5d3 100644
--- a/web/src/pages/search.test.tsx
+++ b/web/src/pages/search.test.tsx
@@ -46,7 +46,13 @@ vi.mock('@/shared/components/skeleton-loader', () => ({
}))
vi.mock('@/shared/components/empty-state', () => ({
- EmptyState: () =>
empty-state
,
+ EmptyState: ({ title, description }: { title: string; description?: string }) => (
+
+ empty-state
+ {title}
+ {description ? {description} : null}
+
+ ),
}))
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()
+
+ 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()
+
+ expect(html).toContain('empty-state')
+ expect(html).toContain('search.noResults')
+ expect(html).not.toContain('search.enterKeyword')
+ })
})
diff --git a/web/src/pages/search.tsx b/web/src/pages/search.tsx
index 6258ca19..58c421db 100644
--- a/web/src/pages/search.tsx
+++ b/web/src/pages/search.tsx
@@ -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 (
@@ -313,11 +311,9 @@ export function SearchPage() {
)}