From 803b41ef2b11b189d982697fead680dad0983d51 Mon Sep 17 00:00:00 2001 From: yyh Date: Mon, 11 May 2026 18:59:38 +0800 Subject: [PATCH] test(tag-management): cover tag name filter paths --- .../console/datasets/test_datasets.py | 6 ++ .../services/test_dataset_service_dataset.py | 55 +++++++++++++++ .../__tests__/tag-selector.spec.tsx | 14 ++++ web/service/knowledge/use-dataset.spec.tsx | 69 +++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 web/service/knowledge/use-dataset.spec.tsx diff --git a/api/tests/unit_tests/controllers/console/datasets/test_datasets.py b/api/tests/unit_tests/controllers/console/datasets/test_datasets.py index e5e4f907947..1952e8f94e5 100644 --- a/api/tests/unit_tests/controllers/console/datasets/test_datasets.py +++ b/api/tests/unit_tests/controllers/console/datasets/test_datasets.py @@ -9,6 +9,7 @@ import services from controllers.console import console_ns from controllers.console.app.error import ProviderNotInitializeError from controllers.console.datasets.datasets import ( + ConsoleDatasetListQuery, DatasetApi, DatasetApiBaseUrlApi, DatasetApiDeleteApi, @@ -164,6 +165,11 @@ class TestDatasetList: assert get_datasets_mock.call_args.kwargs["tag_names"] == ["Finance", "Support"] assert status == 200 + def test_query_model_trims_empty_tag_names(self): + query = ConsoleDatasetListQuery.model_validate({"tag_names": ["", " Finance ", "Support", " "]}) + + assert query.tag_names == ["Finance", "Support"] + def test_embedding_available_false(self, app: Flask): api = DatasetListApi() method = unwrap(api.get) diff --git a/api/tests/unit_tests/services/test_dataset_service_dataset.py b/api/tests/unit_tests/services/test_dataset_service_dataset.py index 3d08b6fd096..2d70b4152c9 100644 --- a/api/tests/unit_tests/services/test_dataset_service_dataset.py +++ b/api/tests/unit_tests/services/test_dataset_service_dataset.py @@ -15,6 +15,7 @@ from .dataset_service_test_helpers import ( ProviderTokenNotInitError, RagPipelineDatasetCreateEntity, SimpleNamespace, + TenantAccountRole, _make_knowledge_configuration, _make_retrieval_model, _make_session_context, @@ -24,6 +25,60 @@ from .dataset_service_test_helpers import ( ) +class TestDatasetServiceList: + """Unit tests for dataset list filtering.""" + + def test_get_datasets_filters_by_tag_names(self): + dataset = DatasetServiceUnitDataFactory.create_dataset_mock(dataset_id="dataset-1") + user = SimpleNamespace(id="user-1", current_role=TenantAccountRole.OWNER) + + with ( + patch("services.dataset_service.db") as mock_db, + patch( + "services.dataset_service.TagService.get_target_ids_by_tag_names", + return_value=["dataset-1"], + ) as tag_mock, + ): + mock_db.session.scalars.return_value.all.return_value = [] + mock_db.paginate.return_value = SimpleNamespace(items=[dataset], total=1) + + datasets, total = DatasetService.get_datasets( + page=1, + per_page=20, + tenant_id="tenant-1", + user=user, + include_all=True, + tag_names=["Finance", "Support"], + ) + + assert datasets == [dataset] + assert total == 1 + tag_mock.assert_called_once_with("knowledge", "tenant-1", ["Finance", "Support"]) + mock_db.paginate.assert_called_once() + + def test_get_datasets_returns_empty_when_tag_names_match_no_targets(self): + user = SimpleNamespace(id="user-1", current_role=TenantAccountRole.OWNER) + + with ( + patch("services.dataset_service.db") as mock_db, + patch("services.dataset_service.TagService.get_target_ids_by_tag_names", return_value=[]), + ): + mock_db.session.scalars.return_value.all.return_value = [] + + datasets, total = DatasetService.get_datasets( + page=1, + per_page=20, + tenant_id="tenant-1", + user=user, + include_all=True, + tag_names=["Unknown"], + ) + + assert datasets == [] + assert total == 0 + mock_db.paginate.assert_not_called() + + class TestDatasetServiceValidation: """Unit tests for DatasetService validation helpers.""" diff --git a/web/features/tag-management/__tests__/tag-selector.spec.tsx b/web/features/tag-management/__tests__/tag-selector.spec.tsx index f33470825bc..ec360172c3c 100644 --- a/web/features/tag-management/__tests__/tag-selector.spec.tsx +++ b/web/features/tag-management/__tests__/tag-selector.spec.tsx @@ -128,6 +128,20 @@ describe('TagSelector', () => { expect(screen.getByRole('option', { name: /Backend/i })).toBeInTheDocument() }) + it('reports active state when the popup opens and closes', async () => { + const user = userEvent.setup() + const onActiveChange = vi.fn() + render() + + const trigger = screen.getByRole('combobox', { name: /Frontend/i }) + await user.click(trigger) + await screen.findByRole('combobox', { name: i18n.selectorPlaceholder }) + await user.click(trigger) + + expect(onActiveChange).toHaveBeenNthCalledWith(1, true) + expect(onActiveChange).toHaveBeenNthCalledWith(2, false) + }) + it('applies added tags only when the popup closes', async () => { const user = userEvent.setup() render() diff --git a/web/service/knowledge/use-dataset.spec.tsx b/web/service/knowledge/use-dataset.spec.tsx new file mode 100644 index 00000000000..76f431b87fa --- /dev/null +++ b/web/service/knowledge/use-dataset.spec.tsx @@ -0,0 +1,69 @@ +import type { ReactNode } from 'react' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { renderHook, waitFor } from '@testing-library/react' +import { get } from '../base' +import { useDatasetList, useInfiniteDatasets } from './use-dataset' + +vi.mock('../base', () => ({ + get: vi.fn(), + post: vi.fn(), +})) + +const createWrapper = () => { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { retry: false }, + }, + }) + + return ({ children }: { children: ReactNode }) => ( + + {children} + + ) +} + +const datasetListResponse = { + data: [], + has_more: false, + limit: 20, + page: 1, + total: 0, +} + +describe('dataset list hooks', () => { + beforeEach(() => { + vi.clearAllMocks() + vi.mocked(get).mockResolvedValue(datasetListResponse) + }) + + it('serializes dataset list filters with tag names', async () => { + renderHook( + () => useDatasetList({ + initialPage: 1, + limit: 20, + tag_names: ['Finance', 'Support'], + }), + { wrapper: createWrapper() }, + ) + + await waitFor(() => { + expect(get).toHaveBeenCalledWith('/datasets?tag_names=Finance&tag_names=Support&limit=20&page=1') + }) + }) + + it('normalizes infinite dataset list filters with tag names', async () => { + renderHook( + () => useInfiniteDatasets({ + page: 2, + limit: 10, + tag_names: ['Finance'], + }), + { wrapper: createWrapper() }, + ) + + await waitFor(() => { + expect(get).toHaveBeenCalledWith('/datasets?page=2&limit=10&tag_names=Finance') + }) + }) +})