@sanity/sdk-react 3.0.0-rc.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/_exports/dashboard.d.ts +209 -0
  2. package/dist/_exports/dashboard.d.ts.map +1 -0
  3. package/dist/_exports/dashboard.js +278 -0
  4. package/dist/_exports/dashboard.js.map +1 -0
  5. package/dist/index.d.ts +86 -261
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +134 -532
  8. package/dist/index.js.map +1 -1
  9. package/dist/useStudioWorkspacesByProjectIdDataset-I4S3CuR5.js +177 -0
  10. package/dist/useStudioWorkspacesByProjectIdDataset-I4S3CuR5.js.map +1 -0
  11. package/package.json +9 -8
  12. package/src/_exports/dashboard.ts +11 -0
  13. package/src/_exports/sdk-react.ts +2 -12
  14. package/src/components/SDKProvider.test.tsx +5 -5
  15. package/src/components/auth/AuthBoundary.tsx +5 -5
  16. package/src/context/{WorkbenchTokenRefresh.test.tsx → DashboardTokenRefresh.test.tsx} +26 -26
  17. package/src/context/{WorkbenchTokenRefresh.tsx → DashboardTokenRefresh.tsx} +14 -14
  18. package/src/context/OrganizationResourcesProvider.test.tsx +9 -9
  19. package/src/context/OrganizationResourcesProvider.tsx +2 -2
  20. package/src/context/{workbenchToken.ts → dashboardToken.ts} +13 -13
  21. package/src/hooks/comlink/useWindowConnection.ts +1 -1
  22. package/src/hooks/{agent → dashboard}/useAgentResourceContext.ts +1 -1
  23. package/src/hooks/dashboard/useFavorite.test.tsx +101 -0
  24. package/src/hooks/dashboard/useFavorite.ts +34 -0
  25. package/src/hooks/dashboard/useFavoriteContext.ts +61 -0
  26. package/src/hooks/dashboard/{useDashboardNavigate.test.ts → useNavigate.test.ts} +3 -3
  27. package/src/hooks/dashboard/{useDashboardNavigate.ts → useNavigate.ts} +5 -5
  28. package/src/hooks/dashboard/useNavigateToStudioDocument.ts +2 -1
  29. package/src/hooks/{auth/useDashboardOrganizationId.test.tsx → dashboard/useOrganizationId.test.tsx} +4 -4
  30. package/src/hooks/{auth/useDashboardOrganizationId.tsx → dashboard/useOrganizationId.tsx} +2 -2
  31. package/src/hooks/dashboard/useUpdateFavorite.test.tsx +146 -0
  32. package/src/hooks/dashboard/useUpdateFavorite.ts +74 -0
  33. package/src/hooks/dashboard/useWindowTitle.ts +1 -1
  34. package/src/hooks/datasets/useDatasets.test.tsx +29 -22
  35. package/src/hooks/datasets/useDatasets.ts +31 -53
  36. package/src/hooks/dashboard/useManageFavorite.test.tsx +0 -379
  37. package/src/hooks/dashboard/useManageFavorite.ts +0 -173
  38. /package/src/hooks/{agent → dashboard}/useAgentResourceContext.test.tsx +0 -0
@@ -1,10 +1,6 @@
1
1
  import {type DatasetsResponse} from '@sanity/client'
2
- import {
3
- createSanityInstance,
4
- getDatasetsState,
5
- resolveDatasets,
6
- type StateSource,
7
- } from '@sanity/sdk'
2
+ import {createSanityInstance, datasets, type StateSource} from '@sanity/sdk'
3
+ import {type FetcherSnapshot} from '@sanity/sdk/_internal'
8
4
  import {type ReactNode} from 'react'
9
5
  import {type Observable} from 'rxjs'
10
6
  import {beforeEach, describe, expect, it, vi} from 'vitest'
@@ -16,32 +12,43 @@ import {useDatasets} from './useDatasets'
16
12
 
17
13
  vi.mock('@sanity/sdk', async (importOriginal) => {
18
14
  const original = await importOriginal<typeof import('@sanity/sdk')>()
19
- return {...original, getDatasetsState: vi.fn(), resolveDatasets: vi.fn()}
15
+ return {...original, datasets: {getState: vi.fn(), resolveState: vi.fn()}}
20
16
  })
21
17
 
22
18
  const stateSource = (
23
19
  current: DatasetsResponse | undefined,
24
- ): StateSource<DatasetsResponse | undefined> =>
25
- ({
26
- getCurrent: vi.fn(() => current),
27
- subscribe: vi.fn(),
20
+ ): StateSource<FetcherSnapshot<DatasetsResponse>> => {
21
+ // Cache the snapshot: useSyncExternalStore requires a referentially stable current value.
22
+ const snapshot = current
23
+ ? {status: 'success', data: current, error: undefined, isFetching: false, dataUpdatedAt: 1}
24
+ : {
25
+ status: 'pending',
26
+ data: undefined,
27
+ error: undefined,
28
+ isFetching: true,
29
+ dataUpdatedAt: undefined,
30
+ }
31
+ return {
32
+ getCurrent: vi.fn(() => snapshot),
33
+ subscribe: vi.fn(() => () => {}),
28
34
  get observable(): Observable<unknown> {
29
35
  throw new Error('Not implemented')
30
36
  },
31
- }) as unknown as StateSource<DatasetsResponse | undefined>
37
+ } as unknown as StateSource<FetcherSnapshot<DatasetsResponse>>
38
+ }
32
39
 
33
40
  const sanityInstance = expect.objectContaining({config: expect.any(Object)})
34
41
 
35
42
  describe('useDatasets', () => {
36
43
  beforeEach(() => {
37
44
  vi.clearAllMocks()
38
- vi.mocked(getDatasetsState).mockReturnValue(stateSource([] as unknown as DatasetsResponse))
45
+ vi.mocked(datasets.getState).mockReturnValue(stateSource([] as unknown as DatasetsResponse))
39
46
  })
40
47
 
41
48
  it('resolves the projectId from the instance config resource', () => {
42
49
  // test-utils wraps with ResourceProvider projectId="test" dataset="test".
43
50
  renderHook(() => useDatasets())
44
- expect(getDatasetsState).toHaveBeenCalledWith(
51
+ expect(datasets.getState).toHaveBeenCalledWith(
45
52
  sanityInstance,
46
53
  expect.objectContaining({projectId: 'test'}),
47
54
  )
@@ -49,7 +56,7 @@ describe('useDatasets', () => {
49
56
 
50
57
  it('lets an explicit projectId override the ambient resource', () => {
51
58
  renderHook(() => useDatasets({projectId: 'explicit-project'}))
52
- expect(getDatasetsState).toHaveBeenCalledWith(
59
+ expect(datasets.getState).toHaveBeenCalledWith(
53
60
  sanityInstance,
54
61
  expect.objectContaining({projectId: 'explicit-project'}),
55
62
  )
@@ -66,7 +73,7 @@ describe('useDatasets', () => {
66
73
  </ResourceProvider>
67
74
  ),
68
75
  })
69
- expect(getDatasetsState).toHaveBeenCalledWith(
76
+ expect(datasets.getState).toHaveBeenCalledWith(
70
77
  sanityInstance,
71
78
  expect.objectContaining({projectId: 'resource-project'}),
72
79
  )
@@ -82,7 +89,7 @@ describe('useDatasets', () => {
82
89
  })
83
90
  // A dataset-less config can't form a DatasetResource; the projectId is carried
84
91
  // via ProjectContext and injected so project-scoped reads still resolve it.
85
- expect(getDatasetsState).toHaveBeenCalledWith(
92
+ expect(datasets.getState).toHaveBeenCalledWith(
86
93
  sanityInstance,
87
94
  expect.objectContaining({projectId: 'config-project'}),
88
95
  )
@@ -101,16 +108,16 @@ describe('useDatasets', () => {
101
108
  </SanityInstanceContext.Provider>
102
109
  ),
103
110
  })
104
- expect(getDatasetsState).toHaveBeenCalledWith(
111
+ expect(datasets.getState).toHaveBeenCalledWith(
105
112
  emptyInstance,
106
113
  expect.objectContaining({projectId: 'bare-project'}),
107
114
  )
108
115
  })
109
116
 
110
- it('suspends via resolveDatasets until dataset data is available', () => {
111
- vi.mocked(getDatasetsState).mockReturnValue(stateSource(undefined))
112
- vi.mocked(resolveDatasets).mockReturnValue(new Promise(() => {}))
117
+ it('suspends via the datasets fetcher until dataset data is available', () => {
118
+ vi.mocked(datasets.getState).mockReturnValue(stateSource(undefined))
119
+ vi.mocked(datasets.resolveState).mockReturnValue(new Promise(() => {}))
113
120
  renderHook(() => useDatasets())
114
- expect(resolveDatasets).toHaveBeenCalled()
121
+ expect(datasets.resolveState).toHaveBeenCalled()
115
122
  })
116
123
  })
@@ -1,64 +1,42 @@
1
1
  import {type DatasetsResponse} from '@sanity/client'
2
- import {
3
- getDatasetsState,
4
- type ProjectHandle,
5
- resolveDatasets,
6
- type SanityInstance,
7
- type StateSource,
8
- } from '@sanity/sdk'
2
+ import {datasets, type ProjectHandle} from '@sanity/sdk'
9
3
 
10
- import {createStateSourceHook} from '../helpers/createStateSourceHook'
4
+ import {createFetcherHook, type FetcherHookResult} from '../helpers/createFetcherHook'
11
5
  import {useResolvedProjectId} from '../helpers/useResolvedProjectId'
12
6
 
13
- type UseDatasets = {
14
- /**
15
- *
16
- * Returns metadata for each dataset the current user has access to.
17
- *
18
- * @category Datasets
19
- * @param options - Optional project/resource to read datasets for. Defaults to
20
- * the resource named in `ResourceProvider`/`SDKProvider`.
21
- * @returns The metadata for your the datasets
22
- *
23
- * @example
24
- * ```tsx
25
- * const datasets = useDatasets()
26
- *
27
- * return (
28
- * <select>
29
- * {datasets.map((dataset) => (
30
- * <option key={dataset.name}>{dataset.name}</option>
31
- * ))}
32
- * </select>
33
- * )
34
- * ```
35
- *
36
- * @remarks
37
- * The `projectId` is resolved in order from:
38
- * 1. an explicit `projectId` option
39
- * 2. A legacy ProjectContext (e.g. a `<ResourceProvider projectId="…">` with no dataset), then
40
- * 3. The active resource (`ResourceProvider`/`SDKProvider`)
41
- * 4. `instance.config`.
42
- */
43
- (options?: ProjectHandle): DatasetsResponse
44
- }
45
-
46
- const useDatasetsBase = createStateSourceHook({
47
- getState: getDatasetsState as (
48
- instance: SanityInstance,
49
- projectHandle?: ProjectHandle,
50
- ) => StateSource<DatasetsResponse>,
51
- shouldSuspend: (instance, projectHandle?: ProjectHandle) =>
52
- // remove `undefined` since we're suspending when that is the case
53
- getDatasetsState(instance, projectHandle).getCurrent() === undefined,
54
- suspender: resolveDatasets,
55
- })
7
+ const useDatasetsBase = createFetcherHook(datasets)
56
8
 
57
9
  /**
10
+ * Returns metadata for each dataset the current user has access to.
11
+ *
12
+ * @category Datasets
13
+ * @param options - Optional project/resource to read datasets for. Defaults to
14
+ * the resource named in `ResourceProvider`/`SDKProvider`.
15
+ * @returns A {@link FetcherHookResult} whose `data` is the metadata for the
16
+ * datasets.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * const {data: datasets} = useDatasets()
21
+ *
22
+ * return (
23
+ * <select>
24
+ * {datasets.map((dataset) => (
25
+ * <option key={dataset.name}>{dataset.name}</option>
26
+ * ))}
27
+ * </select>
28
+ * )
29
+ * ```
30
+ *
31
+ * @remarks
32
+ * The `projectId` is resolved in order from:
33
+ * 1. an explicit `projectId` option
34
+ * 2. A legacy ProjectContext (e.g. a `<ResourceProvider projectId="…">` with no dataset), then
35
+ * 3. The active resource (`ResourceProvider`/`SDKProvider`)
36
+ * 4. `instance.config`.
58
37
  * @public
59
- * @function
60
38
  */
61
- export const useDatasets: UseDatasets = (options) => {
39
+ export function useDatasets(options?: ProjectHandle): FetcherHookResult<DatasetsResponse> {
62
40
  const projectId = useResolvedProjectId(options)
63
41
  return useDatasetsBase(projectId ? {...options, projectId} : options)
64
42
  }
@@ -1,379 +0,0 @@
1
- import {type Message} from '@sanity/comlink'
2
- import {type FavoriteStatusResponse, getFavoritesState, resolveFavoritesState} from '@sanity/sdk'
3
- import {act, renderHook} from '@testing-library/react'
4
- import {BehaviorSubject} from 'rxjs'
5
- import {beforeEach, describe, expect, it, type Mock, vi} from 'vitest'
6
-
7
- import {ResourceProvider} from '../../context/ResourceProvider'
8
- import {useWindowConnection, type WindowConnection} from '../comlink/useWindowConnection'
9
- import {useManageFavorite} from './useManageFavorite'
10
-
11
- type MockFetch = (type: string, data?: unknown, options?: unknown) => Promise<{success: boolean}>
12
- type MockSendMessage = (type: string, data?: unknown) => void
13
-
14
- vi.mock(import('@sanity/sdk'), async (importOriginal) => {
15
- const actual = await importOriginal()
16
- return {
17
- ...actual,
18
- getFavoritesState: vi.fn(),
19
- resolveFavoritesState: vi.fn(),
20
- }
21
- })
22
-
23
- vi.mock('../comlink/useWindowConnection', () => ({
24
- useWindowConnection: vi.fn(),
25
- }))
26
-
27
- describe('useManageFavorite', () => {
28
- let favoriteStatusSubject: BehaviorSubject<FavoriteStatusResponse>
29
- let mockFetch: Mock<MockFetch>
30
- let mockSendMessage: Mock<MockSendMessage>
31
-
32
- const mockDocumentHandle = {
33
- documentId: 'mock-id',
34
- documentType: 'mock-type',
35
- resourceType: 'studio' as const,
36
- }
37
-
38
- beforeEach(() => {
39
- favoriteStatusSubject = new BehaviorSubject<FavoriteStatusResponse>({isFavorited: false})
40
-
41
- // Mock getFavoritesState
42
- vi.mocked(getFavoritesState).mockImplementation(() => ({
43
- subscribe: (callback?: () => void) => {
44
- if (!callback) return () => {}
45
-
46
- const subscription = favoriteStatusSubject.subscribe(() => callback())
47
- callback() // Initial call
48
- return () => subscription.unsubscribe()
49
- },
50
- getCurrent: () => favoriteStatusSubject.getValue(),
51
- observable: favoriteStatusSubject.asObservable(),
52
- }))
53
-
54
- // Mock resolveFavoritesState
55
- vi.mocked(resolveFavoritesState).mockImplementation(async () => {
56
- const newValue = {isFavorited: !favoriteStatusSubject.getValue().isFavorited}
57
- favoriteStatusSubject.next(newValue)
58
- return newValue
59
- })
60
-
61
- // Mock useWindowConnection
62
- mockFetch = vi.fn<MockFetch>().mockResolvedValue({success: true})
63
- mockSendMessage = vi.fn<MockSendMessage>()
64
- vi.mocked(useWindowConnection).mockImplementation(
65
- () =>
66
- ({
67
- fetch: (type: string, data?: unknown, options: unknown = {}) =>
68
- mockFetch(type, data, options),
69
- sendMessage: mockSendMessage,
70
- }) as unknown as WindowConnection<Message>,
71
- )
72
- })
73
-
74
- afterEach(() => {
75
- favoriteStatusSubject.complete()
76
- vi.clearAllMocks()
77
- })
78
-
79
- it('should initialize with default states', () => {
80
- const {result} = renderHook(() => useManageFavorite(mockDocumentHandle), {
81
- wrapper: ({children}) => (
82
- <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
83
- {children}
84
- </ResourceProvider>
85
- ),
86
- })
87
-
88
- expect(result.current.isFavorited).toBe(false)
89
- })
90
-
91
- it('should handle favorite action and update state', async () => {
92
- const {result} = renderHook(() => useManageFavorite(mockDocumentHandle), {
93
- wrapper: ({children}) => (
94
- <ResourceProvider projectId="test" dataset="test" fallback={null}>
95
- {children}
96
- </ResourceProvider>
97
- ),
98
- })
99
-
100
- expect(result.current.isFavorited).toBe(false)
101
-
102
- await act(async () => {
103
- await result.current.favorite()
104
- })
105
-
106
- expect(mockFetch).toHaveBeenCalledWith(
107
- 'dashboard/v1/events/favorite/mutate',
108
- {
109
- document: {
110
- id: 'mock-id',
111
- type: 'mock-type',
112
- resource: {
113
- id: 'test.test',
114
- type: 'studio',
115
- },
116
- },
117
- eventType: 'added',
118
- },
119
- // empty options object (from useWindowConnection)
120
- {},
121
- )
122
- expect(resolveFavoritesState).toHaveBeenCalled()
123
- expect(result.current.isFavorited).toBe(true)
124
- })
125
-
126
- it('should handle unfavorite action and update state', async () => {
127
- const {result} = renderHook(() => useManageFavorite(mockDocumentHandle), {
128
- wrapper: ({children}) => (
129
- <ResourceProvider projectId="test" dataset="test" fallback={null}>
130
- {children}
131
- </ResourceProvider>
132
- ),
133
- })
134
-
135
- // Set initial state to favorited
136
- await act(async () => {
137
- favoriteStatusSubject.next({isFavorited: true})
138
- })
139
-
140
- expect(result.current.isFavorited).toBe(true)
141
-
142
- await act(async () => {
143
- await result.current.unfavorite()
144
- })
145
-
146
- expect(mockFetch).toHaveBeenCalledWith(
147
- 'dashboard/v1/events/favorite/mutate',
148
- {
149
- document: {
150
- id: 'mock-id',
151
- type: 'mock-type',
152
- resource: {
153
- id: 'test.test',
154
- type: 'studio',
155
- },
156
- },
157
- eventType: 'removed',
158
- },
159
- {},
160
- )
161
- expect(resolveFavoritesState).toHaveBeenCalled()
162
- expect(result.current.isFavorited).toBe(false)
163
- })
164
-
165
- it('should not update state if favorite action fails', async () => {
166
- mockFetch.mockResolvedValueOnce({success: false})
167
-
168
- const {result} = renderHook(() => useManageFavorite(mockDocumentHandle), {
169
- wrapper: ({children}) => (
170
- <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
171
- {children}
172
- </ResourceProvider>
173
- ),
174
- })
175
-
176
- expect(result.current.isFavorited).toBe(false)
177
-
178
- await act(async () => {
179
- await result.current.favorite()
180
- })
181
-
182
- expect(resolveFavoritesState).not.toHaveBeenCalled()
183
- expect(result.current.isFavorited).toBe(false)
184
- })
185
-
186
- it('should throw error during favorite/unfavorite actions', async () => {
187
- const errorMessage = 'Failed to update favorite status'
188
- const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
189
-
190
- mockFetch.mockImplementation(() => {
191
- throw new Error(errorMessage)
192
- })
193
-
194
- const {result} = renderHook(() => useManageFavorite(mockDocumentHandle), {
195
- wrapper: ({children}) => (
196
- <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
197
- {children}
198
- </ResourceProvider>
199
- ),
200
- })
201
-
202
- await act(async () => {
203
- await expect(result.current.favorite()).rejects.toThrow(errorMessage)
204
- })
205
-
206
- expect(resolveFavoritesState).not.toHaveBeenCalled()
207
- expect(result.current.isFavorited).toBe(false)
208
-
209
- await act(async () => {
210
- await expect(result.current.unfavorite()).rejects.toThrow(errorMessage)
211
- })
212
-
213
- expect(resolveFavoritesState).not.toHaveBeenCalled()
214
- consoleErrorSpy.mockRestore()
215
- })
216
-
217
- it('should throw error when studio resource is missing projectId or dataset', () => {
218
- const mockDocumentHandleWithoutProjectId = {
219
- documentId: 'mock-id',
220
- documentType: 'mock-type',
221
- resourceType: 'studio' as const,
222
- }
223
-
224
- expect(() =>
225
- renderHook(() => useManageFavorite(mockDocumentHandleWithoutProjectId), {
226
- wrapper: ({children}) => (
227
- <ResourceProvider projectId={undefined} dataset={undefined} fallback={null}>
228
- {children}
229
- </ResourceProvider>
230
- ),
231
- }),
232
- ).toThrow('projectId and dataset are required for studio resources')
233
- })
234
-
235
- it('should throw error when resourceId is missing for non-studio resources', () => {
236
- const mockMediaDocumentHandle = {
237
- documentId: 'mock-id',
238
- documentType: 'mock-type',
239
- resourceType: 'media-library' as const,
240
- resourceId: undefined,
241
- }
242
-
243
- expect(() =>
244
- renderHook(() => useManageFavorite(mockMediaDocumentHandle), {
245
- wrapper: ({children}) => (
246
- <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
247
- {children}
248
- </ResourceProvider>
249
- ),
250
- }),
251
- ).toThrow('resourceId is required for media-library and canvas resources')
252
- })
253
-
254
- it('should include schemaName in payload when provided', async () => {
255
- const mockDocumentHandleWithSchema = {
256
- ...mockDocumentHandle,
257
- schemaName: 'testSchema',
258
- }
259
- const {result} = renderHook(() => useManageFavorite(mockDocumentHandleWithSchema), {
260
- wrapper: ({children}) => (
261
- <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
262
- {children}
263
- </ResourceProvider>
264
- ),
265
- })
266
-
267
- await act(async () => {
268
- await result.current.favorite()
269
- })
270
-
271
- expect(mockFetch).toHaveBeenCalledWith(
272
- 'dashboard/v1/events/favorite/mutate',
273
- {
274
- document: {
275
- id: 'mock-id',
276
- type: 'mock-type',
277
- resource: {
278
- id: 'test-project.test-dataset',
279
- type: 'studio',
280
- schemaName: 'testSchema',
281
- },
282
- },
283
- eventType: 'added',
284
- },
285
- {},
286
- )
287
- })
288
-
289
- it('should default isFavorited to false if state is undefined', () => {
290
- // Mock getFavoritesState to return undefined for getCurrent
291
- vi.mocked(getFavoritesState).mockImplementation(() => ({
292
- subscribe: (callback?: () => void) => {
293
- if (!callback) return () => {}
294
- callback()
295
- return () => {}
296
- },
297
- getCurrent: () => undefined,
298
- observable: favoriteStatusSubject.asObservable(),
299
- }))
300
- const {result} = renderHook(() => useManageFavorite(mockDocumentHandle), {
301
- wrapper: ({children}) => (
302
- <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
303
- {children}
304
- </ResourceProvider>
305
- ),
306
- })
307
- expect(result.current.isFavorited).toBe(false)
308
- })
309
-
310
- it('should do nothing if fetch is missing', async () => {
311
- vi.mocked(useWindowConnection).mockReturnValue({
312
- fetch: undefined,
313
- sendMessage: mockSendMessage,
314
- } as unknown as WindowConnection<Message>)
315
- const {result} = renderHook(() => useManageFavorite(mockDocumentHandle), {
316
- wrapper: ({children}) => (
317
- <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
318
- {children}
319
- </ResourceProvider>
320
- ),
321
- })
322
- await act(async () => {
323
- await result.current.favorite()
324
- await result.current.unfavorite()
325
- })
326
- expect(mockFetch).not.toHaveBeenCalled()
327
- })
328
-
329
- it('should do nothing if documentId is missing', async () => {
330
- const handle = {...mockDocumentHandle, documentId: undefined}
331
- // @ts-expect-error -- no access to ManageFavorite props type
332
- const {result} = renderHook(() => useManageFavorite(handle), {
333
- wrapper: ({children}) => (
334
- <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
335
- {children}
336
- </ResourceProvider>
337
- ),
338
- })
339
- await act(async () => {
340
- await result.current.favorite()
341
- await result.current.unfavorite()
342
- })
343
- expect(mockFetch).not.toHaveBeenCalled()
344
- })
345
-
346
- it('should do nothing if documentType is missing', async () => {
347
- const handle = {...mockDocumentHandle, documentType: undefined}
348
- // @ts-expect-error -- no access to ManageFavorite props type
349
- const {result} = renderHook(() => useManageFavorite(handle), {
350
- wrapper: ({children}) => (
351
- <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
352
- {children}
353
- </ResourceProvider>
354
- ),
355
- })
356
- await act(async () => {
357
- await result.current.favorite()
358
- await result.current.unfavorite()
359
- })
360
- expect(mockFetch).not.toHaveBeenCalled()
361
- })
362
-
363
- it('should do nothing if resourceType is missing', async () => {
364
- const handle = {...mockDocumentHandle, resourceType: undefined, resourceId: 'studio'}
365
- // @ts-expect-error -- no access to ManageFavorite props type
366
- const {result} = renderHook(() => useManageFavorite(handle), {
367
- wrapper: ({children}) => (
368
- <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
369
- {children}
370
- </ResourceProvider>
371
- ),
372
- })
373
- await act(async () => {
374
- await result.current.favorite()
375
- await result.current.unfavorite()
376
- })
377
- expect(mockFetch).not.toHaveBeenCalled()
378
- })
379
- })