|
1 | 1 | /** @vitest-environment node */ |
2 | | -import { QueryClient } from '@tanstack/react-query' |
| 2 | +import { QueryClient, QueryObserver } from '@tanstack/react-query' |
3 | 3 | import { expect, it, vi } from 'vitest' |
4 | 4 | import type { WorkspaceKnowledgeSearchResult } from '@/lib/api/contracts/knowledge/search' |
5 | 5 | import { resourceScopeKey } from '@/lib/core/resource-scope' |
6 | 6 | import { knowledgeKeys } from '@/hooks/queries/utils/knowledge-keys' |
7 | 7 | import { resetOrganizationSearchAccess } from '@/hooks/queries/utils/reset-organization-search-access' |
| 8 | +import { searchSourceKeys } from '@/hooks/queries/utils/search-source-keys' |
| 9 | + |
| 10 | +it.each([true, false])( |
| 11 | + 'keeps administrative rows visible while revalidating access, refresh success=%s', |
| 12 | + async (success) => { |
| 13 | + const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }) |
| 14 | + const scope = { kind: 'organization', organizationId: 'org-1' } as const |
| 15 | + const adminKey = searchSourceKeys.organizationOverview(scope.organizationId) |
| 16 | + const otherKey = searchSourceKeys.organizationOverview('org-2') |
| 17 | + const viewerKeys = [ |
| 18 | + searchSourceKeys.list(scope), |
| 19 | + searchSourceKeys.overview(scope), |
| 20 | + searchSourceKeys.pages(scope, { search: '', mine: false }), |
| 21 | + ] |
| 22 | + const before = { providers: [{ connectorType: 'gmail', approved: true }] } |
| 23 | + const after = { providers: [{ connectorType: 'gmail', approved: false }] } |
| 24 | + const response = Promise.withResolvers<typeof before>() |
| 25 | + const fetchOverview = vi.fn(() => response.promise) |
| 26 | + client.setQueryData(adminKey, before) |
| 27 | + client.setQueryData(otherKey, before) |
| 28 | + for (const key of viewerKeys) client.setQueryData(key, { privateContent: 'previous access' }) |
| 29 | + const observer = new QueryObserver(client, { |
| 30 | + queryKey: adminKey, |
| 31 | + queryFn: fetchOverview, |
| 32 | + staleTime: Number.POSITIVE_INFINITY, |
| 33 | + }) |
| 34 | + const observed = vi.fn() |
| 35 | + const unsubscribe = observer.subscribe(observed) |
| 36 | + try { |
| 37 | + const refreshing = resetOrganizationSearchAccess(client, scope.organizationId) |
| 38 | + expect(fetchOverview).toHaveBeenCalledOnce() |
| 39 | + expect(observer.getCurrentResult()).toMatchObject({ data: before, isPending: false }) |
| 40 | + for (const key of viewerKeys) expect(client.getQueryData(key)).toBeUndefined() |
| 41 | + expect(client.getQueryState(otherKey)?.isInvalidated).toBe(false) |
| 42 | + |
| 43 | + if (success) response.resolve(after) |
| 44 | + else response.reject(new Error('Could not refresh sources')) |
| 45 | + await refreshing |
| 46 | + |
| 47 | + expect(observer.getCurrentResult()).toMatchObject({ |
| 48 | + data: success ? after : before, |
| 49 | + isError: !success, |
| 50 | + isFetching: false, |
| 51 | + }) |
| 52 | + expect(observed.mock.calls.every(([result]) => result.data && !result.isPending)).toBe(true) |
| 53 | + expect(client.getQueryData(otherKey)).toEqual(before) |
| 54 | + } finally { |
| 55 | + response.resolve(after) |
| 56 | + unsubscribe() |
| 57 | + client.clear() |
| 58 | + } |
| 59 | + } |
| 60 | +) |
8 | 61 |
|
9 | 62 | it.each([ |
10 | 63 | { name: 'document', key: knowledgeKeys.document('kb-direct', 'document-direct') }, |
|
0 commit comments