@sanity/sdk-react 2.2.0 → 2.3.1

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 (33) hide show
  1. package/dist/index.d.ts +2 -3
  2. package/dist/index.js +101 -26
  3. package/dist/index.js.map +1 -1
  4. package/package.json +7 -6
  5. package/src/components/auth/AuthBoundary.test.tsx +33 -20
  6. package/src/components/auth/AuthBoundary.tsx +20 -5
  7. package/src/components/auth/LoginError.tsx +9 -12
  8. package/src/components/errors/CorsErrorComponent.test.tsx +48 -0
  9. package/src/components/errors/CorsErrorComponent.tsx +37 -0
  10. package/src/components/errors/Error.styles.ts +35 -0
  11. package/src/components/errors/Error.tsx +40 -0
  12. package/src/context/ComlinkTokenRefresh.test.tsx +87 -38
  13. package/src/context/ComlinkTokenRefresh.tsx +2 -1
  14. package/src/hooks/auth/useDashboardOrganizationId.test.tsx +16 -7
  15. package/src/hooks/auth/useVerifyOrgProjects.test.tsx +56 -14
  16. package/src/hooks/dashboard/{useManageFavorite.test.ts → useManageFavorite.test.tsx} +99 -44
  17. package/src/hooks/document/{useDocument.test.ts → useDocument.test.tsx} +25 -22
  18. package/src/hooks/document/{useDocumentEvent.test.ts → useDocumentEvent.test.tsx} +17 -16
  19. package/src/hooks/document/{useDocumentPermissions.test.ts → useDocumentPermissions.test.tsx} +101 -40
  20. package/src/hooks/document/{useEditDocument.test.ts → useEditDocument.test.tsx} +52 -22
  21. package/src/hooks/documents/useDocuments.test.tsx +63 -25
  22. package/src/hooks/helpers/createCallbackHook.test.tsx +41 -37
  23. package/src/hooks/paginatedDocuments/usePaginatedDocuments.test.tsx +2 -2
  24. package/src/hooks/presence/usePresence.test.tsx +9 -6
  25. package/src/hooks/preview/useDocumentPreview.test.tsx +15 -16
  26. package/src/hooks/projection/useDocumentProjection.test.tsx +23 -38
  27. package/src/hooks/projection/useDocumentProjection.ts +3 -8
  28. package/src/hooks/query/useQuery.test.tsx +18 -10
  29. package/src/hooks/releases/useActiveReleases.test.tsx +25 -21
  30. package/src/hooks/releases/usePerspective.test.tsx +16 -22
  31. package/src/hooks/users/useUser.test.tsx +32 -15
  32. package/src/hooks/users/useUsers.test.tsx +19 -11
  33. package/src/hooks/_synchronous-groq-js.mjs +0 -4
@@ -1,8 +1,9 @@
1
1
  import {getPresence, type SanityUser, type UserPresence} from '@sanity/sdk'
2
+ import {act, renderHook} from '@testing-library/react'
2
3
  import {NEVER} from 'rxjs'
3
4
  import {describe, expect, it, vi} from 'vitest'
4
5
 
5
- import {act, renderHook} from '../../../test/test-utils'
6
+ import {ResourceProvider} from '../../context/ResourceProvider'
6
7
  import {usePresence} from './usePresence'
7
8
 
8
9
  vi.mock('@sanity/sdk', () => ({
@@ -14,10 +15,6 @@ vi.mock('@sanity/sdk', () => ({
14
15
  })),
15
16
  }))
16
17
 
17
- vi.mock('../context/useSanityInstance', () => ({
18
- useSanityInstance: vi.fn(() => ({config: {projectId: 'test', dataset: 'test'}})),
19
- }))
20
-
21
18
  describe('usePresence', () => {
22
19
  it('should return presence locations and update when the store changes', () => {
23
20
  const initialLocations: UserPresence[] = [
@@ -60,7 +57,13 @@ describe('usePresence', () => {
60
57
  }
61
58
  vi.mocked(getPresence).mockReturnValue(mockPresenceSource)
62
59
 
63
- const {result, unmount} = renderHook(() => usePresence())
60
+ const {result, unmount} = renderHook(() => usePresence(), {
61
+ wrapper: ({children}) => (
62
+ <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
63
+ {children}
64
+ </ResourceProvider>
65
+ ),
66
+ })
64
67
 
65
68
  // Initial state should be correct
66
69
  expect(result.current.locations).toEqual(initialLocations)
@@ -1,8 +1,9 @@
1
1
  import {type DocumentHandle, getPreviewState, type PreviewValue, resolvePreview} from '@sanity/sdk'
2
2
  import {act, render, screen} from '@testing-library/react'
3
- import {Suspense, useRef} from 'react'
3
+ import {useRef} from 'react'
4
4
  import {type Mock} from 'vitest'
5
5
 
6
+ import {ResourceProvider} from '../../context/ResourceProvider'
6
7
  import {useDocumentPreview} from './useDocumentPreview'
7
8
 
8
9
  // Mock IntersectionObserver
@@ -24,20 +25,18 @@ beforeAll(() => {
24
25
  })
25
26
 
26
27
  // Mock the preview store
27
- vi.mock('@sanity/sdk', () => {
28
+ vi.mock('@sanity/sdk', async (importOriginal) => {
29
+ const actual = await importOriginal<typeof import('@sanity/sdk')>()
28
30
  const getCurrent = vi.fn()
29
31
  const subscribe = vi.fn()
30
32
 
31
33
  return {
34
+ ...actual,
32
35
  resolvePreview: vi.fn(),
33
36
  getPreviewState: vi.fn().mockReturnValue({getCurrent, subscribe}),
34
37
  }
35
38
  })
36
39
 
37
- vi.mock('../context/useSanityInstance', () => ({
38
- useSanityInstance: () => ({}),
39
- }))
40
-
41
40
  const mockDocument: DocumentHandle = {
42
41
  documentId: 'doc1',
43
42
  documentType: 'exampleType',
@@ -82,9 +81,9 @@ describe('useDocumentPreview', () => {
82
81
  subscribe.mockImplementation(() => eventsUnsubscribe)
83
82
 
84
83
  render(
85
- <Suspense fallback={<div>Loading...</div>}>
84
+ <ResourceProvider fallback={<div>Loading...</div>}>
86
85
  <TestComponent {...mockDocument} />
87
- </Suspense>,
86
+ </ResourceProvider>,
88
87
  )
89
88
 
90
89
  // Initially, element is not intersecting
@@ -127,9 +126,9 @@ describe('useDocumentPreview', () => {
127
126
  })
128
127
 
129
128
  render(
130
- <Suspense fallback={<div>Loading...</div>}>
129
+ <ResourceProvider fallback={<div>Loading...</div>}>
131
130
  <TestComponent {...mockDocument} />
132
- </Suspense>,
131
+ </ResourceProvider>,
133
132
  )
134
133
 
135
134
  expect(screen.getByText('Loading...')).toBeInTheDocument()
@@ -162,9 +161,9 @@ describe('useDocumentPreview', () => {
162
161
  subscribe.mockImplementation(() => vi.fn())
163
162
 
164
163
  render(
165
- <Suspense fallback={<div>Loading...</div>}>
164
+ <ResourceProvider fallback={<div>Loading...</div>}>
166
165
  <TestComponent {...mockDocument} />
167
- </Suspense>,
166
+ </ResourceProvider>,
168
167
  )
169
168
 
170
169
  expect(screen.getByText('Fallback Title')).toBeInTheDocument()
@@ -192,9 +191,9 @@ describe('useDocumentPreview', () => {
192
191
  }
193
192
 
194
193
  render(
195
- <Suspense fallback={<div>Loading...</div>}>
194
+ <ResourceProvider fallback={<div>Loading...</div>}>
196
195
  <NoRefComponent {...mockDocument} />
197
- </Suspense>,
196
+ </ResourceProvider>,
198
197
  )
199
198
 
200
199
  // Should subscribe immediately without waiting for intersection
@@ -222,9 +221,9 @@ describe('useDocumentPreview', () => {
222
221
  }
223
222
 
224
223
  render(
225
- <Suspense fallback={<div>Loading...</div>}>
224
+ <ResourceProvider fallback={<div>Loading...</div>}>
226
225
  <NonHtmlRefComponent {...mockDocument} />
227
- </Suspense>,
226
+ </ResourceProvider>,
228
227
  )
229
228
 
230
229
  // Should subscribe immediately without waiting for intersection
@@ -1,13 +1,9 @@
1
- import {
2
- type DocumentHandle,
3
- getProjectionState,
4
- resolveProjection,
5
- type ValidProjection,
6
- } from '@sanity/sdk'
1
+ import {type DocumentHandle, getProjectionState, resolveProjection} from '@sanity/sdk'
7
2
  import {act, render, screen} from '@testing-library/react'
8
- import {Suspense, useRef} from 'react'
3
+ import {useRef} from 'react'
9
4
  import {type Mock} from 'vitest'
10
5
 
6
+ import {ResourceProvider} from '../../context/ResourceProvider'
11
7
  import {useDocumentProjection} from './useDocumentProjection'
12
8
 
13
9
  // Mock IntersectionObserver
@@ -29,20 +25,18 @@ beforeAll(() => {
29
25
  })
30
26
 
31
27
  // Mock the projection store
32
- vi.mock('@sanity/sdk', () => {
28
+ vi.mock('@sanity/sdk', async (importOriginal) => {
29
+ const actual = await importOriginal<typeof import('@sanity/sdk')>()
33
30
  const getCurrent = vi.fn()
34
31
  const subscribe = vi.fn()
35
32
 
36
33
  return {
34
+ ...actual,
37
35
  resolveProjection: vi.fn(),
38
36
  getProjectionState: vi.fn().mockReturnValue({getCurrent, subscribe}),
39
37
  }
40
38
  })
41
39
 
42
- vi.mock('../context/useSanityInstance', () => ({
43
- useSanityInstance: () => ({}),
44
- }))
45
-
46
40
  const mockDocument: DocumentHandle = {
47
41
  documentId: 'doc1',
48
42
  documentType: 'exampleType',
@@ -53,13 +47,7 @@ interface ProjectionResult {
53
47
  description: string
54
48
  }
55
49
 
56
- function TestComponent({
57
- document,
58
- projection,
59
- }: {
60
- document: DocumentHandle
61
- projection: ValidProjection
62
- }) {
50
+ function TestComponent({document, projection}: {document: DocumentHandle; projection: string}) {
63
51
  const ref = useRef(null)
64
52
  const {data, isPending} = useDocumentProjection<ProjectionResult>({...document, projection, ref})
65
53
 
@@ -98,9 +86,9 @@ describe('useDocumentProjection', () => {
98
86
  subscribe.mockImplementation(() => eventsUnsubscribe)
99
87
 
100
88
  render(
101
- <Suspense fallback={<div>Loading...</div>}>
89
+ <ResourceProvider fallback={<div>Loading...</div>}>
102
90
  <TestComponent document={mockDocument} projection="{name, description}" />
103
- </Suspense>,
91
+ </ResourceProvider>,
104
92
  )
105
93
 
106
94
  // Initially, element is not intersecting
@@ -148,9 +136,9 @@ describe('useDocumentProjection', () => {
148
136
  subscribe.mockReturnValue(() => {})
149
137
 
150
138
  render(
151
- <Suspense fallback={<div>Loading...</div>}>
139
+ <ResourceProvider fallback={<div>Loading...</div>}>
152
140
  <TestComponent document={mockDocument} projection="{title, description}" />
153
- </Suspense>,
141
+ </ResourceProvider>,
154
142
  )
155
143
 
156
144
  await act(async () => {
@@ -175,9 +163,9 @@ describe('useDocumentProjection', () => {
175
163
  subscribe.mockImplementation(() => vi.fn())
176
164
 
177
165
  render(
178
- <Suspense fallback={<div>Loading...</div>}>
166
+ <ResourceProvider fallback={<div>Loading...</div>}>
179
167
  <TestComponent document={mockDocument} projection="{title, description}" />
180
- </Suspense>,
168
+ </ResourceProvider>,
181
169
  )
182
170
 
183
171
  expect(screen.getByText('Fallback Title')).toBeInTheDocument()
@@ -195,9 +183,9 @@ describe('useDocumentProjection', () => {
195
183
  subscribe.mockImplementation(() => eventsUnsubscribe)
196
184
 
197
185
  const {rerender} = render(
198
- <Suspense fallback={<div>Loading...</div>}>
186
+ <ResourceProvider fallback={<div>Loading...</div>}>
199
187
  <TestComponent document={mockDocument} projection="{title}" />
200
- </Suspense>,
188
+ </ResourceProvider>,
201
189
  )
202
190
 
203
191
  // Change projection
@@ -207,9 +195,9 @@ describe('useDocumentProjection', () => {
207
195
  })
208
196
 
209
197
  rerender(
210
- <Suspense fallback={<div>Loading...</div>}>
198
+ <ResourceProvider fallback={<div>Loading...</div>}>
211
199
  <TestComponent document={mockDocument} projection="{title, description}" />
212
- </Suspense>,
200
+ </ResourceProvider>,
213
201
  )
214
202
 
215
203
  expect(screen.getByText('Updated Title')).toBeInTheDocument()
@@ -224,10 +212,7 @@ describe('useDocumentProjection', () => {
224
212
  const eventsUnsubscribe = vi.fn()
225
213
  subscribe.mockImplementation(() => eventsUnsubscribe)
226
214
 
227
- function NoRefComponent({
228
- projection,
229
- ...docHandle
230
- }: DocumentHandle & {projection: ValidProjection}) {
215
+ function NoRefComponent({projection, ...docHandle}: DocumentHandle & {projection: string}) {
231
216
  const {data} = useDocumentProjection<ProjectionResult>({...docHandle, projection}) // No ref provided
232
217
  return (
233
218
  <div>
@@ -238,9 +223,9 @@ describe('useDocumentProjection', () => {
238
223
  }
239
224
 
240
225
  render(
241
- <Suspense fallback={<div>Loading...</div>}>
226
+ <ResourceProvider fallback={<div>Loading...</div>}>
242
227
  <NoRefComponent {...mockDocument} projection="{title, description}" />
243
- </Suspense>,
228
+ </ResourceProvider>,
244
229
  )
245
230
 
246
231
  // Should subscribe immediately without waiting for intersection
@@ -259,7 +244,7 @@ describe('useDocumentProjection', () => {
259
244
  function NonHtmlRefComponent({
260
245
  projection,
261
246
  ...docHandle
262
- }: DocumentHandle & {projection: ValidProjection}) {
247
+ }: DocumentHandle & {projection: string}) {
263
248
  const ref = useRef({}) // ref.current is not an HTML element
264
249
  const {data} = useDocumentProjection<ProjectionResult>({...docHandle, projection, ref})
265
250
  return (
@@ -271,9 +256,9 @@ describe('useDocumentProjection', () => {
271
256
  }
272
257
 
273
258
  render(
274
- <Suspense fallback={<div>Loading...</div>}>
259
+ <ResourceProvider fallback={<div>Loading...</div>}>
275
260
  <NonHtmlRefComponent {...mockDocument} projection="{title, description}" />
276
- </Suspense>,
261
+ </ResourceProvider>,
277
262
  )
278
263
 
279
264
  // Should subscribe immediately without waiting for intersection
@@ -1,9 +1,4 @@
1
- import {
2
- type DocumentHandle,
3
- getProjectionState,
4
- resolveProjection,
5
- type ValidProjection,
6
- } from '@sanity/sdk'
1
+ import {type DocumentHandle, getProjectionState, resolveProjection} from '@sanity/sdk'
7
2
  import {type SanityProjectionResult} from 'groq'
8
3
  import {useCallback, useSyncExternalStore} from 'react'
9
4
  import {distinctUntilChanged, EMPTY, Observable, startWith, switchMap} from 'rxjs'
@@ -15,7 +10,7 @@ import {useSanityInstance} from '../context/useSanityInstance'
15
10
  * @category Types
16
11
  */
17
12
  export interface useDocumentProjectionOptions<
18
- TProjection extends ValidProjection = ValidProjection,
13
+ TProjection extends string = string,
19
14
  TDocumentType extends string = string,
20
15
  TDataset extends string = string,
21
16
  TProjectId extends string = string,
@@ -115,7 +110,7 @@ export interface useDocumentProjectionResults<TData> {
115
110
  * ```
116
111
  */
117
112
  export function useDocumentProjection<
118
- TProjection extends ValidProjection = ValidProjection,
113
+ TProjection extends string = string,
119
114
  TDocumentType extends string = string,
120
115
  TDataset extends string = string,
121
116
  TProjectId extends string = string,
@@ -1,9 +1,10 @@
1
1
  import {getQueryState, resolveQuery, type StateSource} from '@sanity/sdk'
2
2
  import {act, render, screen} from '@testing-library/react'
3
- import {Suspense, useState} from 'react'
3
+ import {useState} from 'react'
4
4
  import {type Observable, Subject} from 'rxjs'
5
5
  import {beforeEach, describe, expect, it, vi} from 'vitest'
6
6
 
7
+ import {ResourceProvider} from '../../context/ResourceProvider'
7
8
  import {useQuery} from './useQuery'
8
9
 
9
10
  // Mock the functions from '@sanity/sdk'
@@ -16,11 +17,6 @@ vi.mock('@sanity/sdk', async (importOriginal) => {
16
17
  }
17
18
  })
18
19
 
19
- // Mock the Sanity instance hook to return a dummy instance
20
- vi.mock('../context/useSanityInstance', () => ({
21
- useSanityInstance: vi.fn().mockReturnValue({}),
22
- }))
23
-
24
20
  describe('useQuery', () => {
25
21
  beforeEach(() => {
26
22
  vi.resetAllMocks()
@@ -45,7 +41,11 @@ describe('useQuery', () => {
45
41
  )
46
42
  }
47
43
 
48
- render(<TestComponent />)
44
+ render(
45
+ <ResourceProvider projectId="p" dataset="d" fallback={<p>Loading...</p>}>
46
+ <TestComponent />
47
+ </ResourceProvider>,
48
+ )
49
49
 
50
50
  // Verify that the output contains the data and that isPending is false
51
51
  expect(screen.getByTestId('output').textContent).toContain('test data')
@@ -87,9 +87,13 @@ describe('useQuery', () => {
87
87
  }
88
88
 
89
89
  render(
90
- <Suspense fallback={<div data-testid="fallback">Loading...</div>}>
90
+ <ResourceProvider
91
+ projectId="p"
92
+ dataset="d"
93
+ fallback={<div data-testid="fallback">Loading...</div>}
94
+ >
91
95
  <TestComponent />
92
- </Suspense>,
96
+ </ResourceProvider>,
93
97
  )
94
98
 
95
99
  // Initially, since storeValue is undefined, the component should suspend and fallback is shown
@@ -159,7 +163,11 @@ describe('useQuery', () => {
159
163
  )
160
164
  }
161
165
 
162
- render(<WrapperComponent />)
166
+ render(
167
+ <ResourceProvider projectId="p" dataset="d" fallback={<p>Loading...</p>}>
168
+ <WrapperComponent />
169
+ </ResourceProvider>,
170
+ )
163
171
 
164
172
  // Initially, should show data1 and not pending
165
173
  expect(screen.getByTestId('output').textContent).toContain('data1')
@@ -1,16 +1,11 @@
1
- import {getActiveReleasesState, type ReleaseDocument, type SanityInstance} from '@sanity/sdk'
1
+ import {getActiveReleasesState, type ReleaseDocument} from '@sanity/sdk'
2
2
  import {renderHook} from '@testing-library/react'
3
3
  import {BehaviorSubject} from 'rxjs'
4
4
  import {describe, expect, it, vi} from 'vitest'
5
5
 
6
- import {useSanityInstance} from '../context/useSanityInstance'
6
+ import {ResourceProvider} from '../../context/ResourceProvider'
7
7
  import {useActiveReleases} from './useActiveReleases'
8
8
 
9
- // Mock the useSanityInstance hook
10
- vi.mock('../context/useSanityInstance', () => ({
11
- useSanityInstance: vi.fn(),
12
- }))
13
-
14
9
  // Mock the getActiveReleasesState function
15
10
  vi.mock('@sanity/sdk', async () => {
16
11
  const actual = await vi.importActual('@sanity/sdk')
@@ -26,9 +21,6 @@ describe('useActiveReleases', () => {
26
21
  })
27
22
 
28
23
  it('should suspend when initial state is undefined', () => {
29
- const mockInstance = {} as SanityInstance
30
- vi.mocked(useSanityInstance).mockReturnValue(mockInstance)
31
-
32
24
  const mockSubject = new BehaviorSubject<ReleaseDocument[] | undefined>(undefined)
33
25
  const mockStateSource = {
34
26
  subscribe: vi.fn((callback) => {
@@ -41,13 +33,22 @@ describe('useActiveReleases', () => {
41
33
 
42
34
  vi.mocked(getActiveReleasesState).mockReturnValue(mockStateSource)
43
35
 
44
- const {result} = renderHook(() => {
45
- try {
46
- return useActiveReleases()
47
- } catch (e) {
48
- return e
49
- }
50
- })
36
+ const {result} = renderHook(
37
+ () => {
38
+ try {
39
+ return useActiveReleases()
40
+ } catch (e) {
41
+ return e
42
+ }
43
+ },
44
+ {
45
+ wrapper: ({children}) => (
46
+ <ResourceProvider projectId="p" dataset="d" fallback={<p>Loading...</p>}>
47
+ {children}
48
+ </ResourceProvider>
49
+ ),
50
+ },
51
+ )
51
52
 
52
53
  // Verify that the hook threw a promise (suspended)
53
54
  expect(result.current).toBeInstanceOf(Promise)
@@ -55,9 +56,6 @@ describe('useActiveReleases', () => {
55
56
  })
56
57
 
57
58
  it('should resolve with releases when data is available', () => {
58
- const mockInstance = {} as SanityInstance
59
- vi.mocked(useSanityInstance).mockReturnValue(mockInstance)
60
-
61
59
  const mockReleases: ReleaseDocument[] = [
62
60
  {_id: 'release1', _type: 'release'} as ReleaseDocument,
63
61
  {_id: 'release2', _type: 'release'} as ReleaseDocument,
@@ -75,7 +73,13 @@ describe('useActiveReleases', () => {
75
73
 
76
74
  vi.mocked(getActiveReleasesState).mockReturnValue(mockStateSource)
77
75
 
78
- const {result} = renderHook(() => useActiveReleases())
76
+ const {result} = renderHook(() => useActiveReleases(), {
77
+ wrapper: ({children}) => (
78
+ <ResourceProvider projectId="p" dataset="d" fallback={<p>Loading...</p>}>
79
+ {children}
80
+ </ResourceProvider>
81
+ ),
82
+ })
79
83
 
80
84
  // Verify that the hook returned the releases without suspending
81
85
  expect(result.current).toEqual(mockReleases)
@@ -4,20 +4,14 @@ import {
4
4
  getPerspectiveState,
5
5
  type PerspectiveHandle,
6
6
  type ReleaseDocument,
7
- type SanityInstance,
8
7
  } from '@sanity/sdk'
9
8
  import {renderHook} from '@testing-library/react'
10
9
  import {BehaviorSubject} from 'rxjs'
11
10
  import {describe, expect, it, vi} from 'vitest'
12
11
 
13
- import {useSanityInstance} from '../context/useSanityInstance'
12
+ import {ResourceProvider} from '../../context/ResourceProvider'
14
13
  import {usePerspective} from './usePerspective'
15
14
 
16
- // Mock the useSanityInstance hook
17
- vi.mock('../context/useSanityInstance', () => ({
18
- useSanityInstance: vi.fn(),
19
- }))
20
-
21
15
  // Mock the SDK functions
22
16
  vi.mock('@sanity/sdk', async () => {
23
17
  const actual = await vi.importActual('@sanity/sdk')
@@ -36,9 +30,6 @@ describe('usePerspective', () => {
36
30
  })
37
31
 
38
32
  it('should suspend when initial state is undefined', () => {
39
- const mockInstance = {} as SanityInstance
40
- vi.mocked(useSanityInstance).mockReturnValue(mockInstance)
41
-
42
33
  const perspectiveHandle: PerspectiveHandle = {
43
34
  perspective: 'published',
44
35
  }
@@ -76,13 +67,18 @@ describe('usePerspective', () => {
76
67
  vi.mocked(getPerspectiveState).mockReturnValue(mockStateSource)
77
68
  vi.mocked(getActiveReleasesState).mockReturnValue(mockReleasesStateSource)
78
69
 
79
- const {result} = renderHook(() => {
80
- try {
81
- return usePerspective(perspectiveHandle)
82
- } catch (e) {
83
- return e
84
- }
85
- })
70
+ const {result} = renderHook(
71
+ () => {
72
+ try {
73
+ return usePerspective(perspectiveHandle)
74
+ } catch (e) {
75
+ return e
76
+ }
77
+ },
78
+ {
79
+ wrapper: ({children}) => <ResourceProvider fallback={null}>{children}</ResourceProvider>,
80
+ },
81
+ )
86
82
 
87
83
  // Verify that the hook threw a promise (suspended)
88
84
  expect(result.current).toBeInstanceOf(Promise)
@@ -90,9 +86,6 @@ describe('usePerspective', () => {
90
86
  })
91
87
 
92
88
  it('should resolve with perspective when data is available', () => {
93
- const mockInstance = {} as SanityInstance
94
- vi.mocked(useSanityInstance).mockReturnValue(mockInstance)
95
-
96
89
  const perspectiveHandle: PerspectiveHandle = {
97
90
  perspective: 'published',
98
91
  }
@@ -110,11 +103,12 @@ describe('usePerspective', () => {
110
103
 
111
104
  vi.mocked(getPerspectiveState).mockReturnValue(mockStateSource)
112
105
 
113
- const {result} = renderHook(() => usePerspective(perspectiveHandle))
106
+ const {result} = renderHook(() => usePerspective(perspectiveHandle), {
107
+ wrapper: ({children}) => <ResourceProvider fallback={null}>{children}</ResourceProvider>,
108
+ })
114
109
 
115
110
  // Verify that the hook returned the perspective without suspending
116
111
  expect(result.current).toEqual(mockPerspective)
117
112
  expect(mockStateSource.getCurrent).toHaveBeenCalled()
118
- expect(getPerspectiveState).toHaveBeenCalledWith(mockInstance, perspectiveHandle)
119
113
  })
120
114
  })
@@ -6,10 +6,11 @@ import {
6
6
  type UserProfile,
7
7
  } from '@sanity/sdk'
8
8
  import {act, fireEvent, render, screen} from '@testing-library/react'
9
- import {Suspense, useState} from 'react'
9
+ import {useState} from 'react'
10
10
  import {type Observable, Subject} from 'rxjs'
11
11
  import {describe, expect, it, vi} from 'vitest'
12
12
 
13
+ import {ResourceProvider} from '../../context/ResourceProvider'
13
14
  import {useUser} from './useUser'
14
15
 
15
16
  // Mock the functions from '@sanity/sdk'
@@ -22,11 +23,6 @@ vi.mock('@sanity/sdk', async (importOriginal) => {
22
23
  }
23
24
  })
24
25
 
25
- // Mock the Sanity instance hook to return a dummy instance
26
- vi.mock('../context/useSanityInstance', () => ({
27
- useSanityInstance: vi.fn().mockReturnValue({config: {projectId: 'p'}}),
28
- }))
29
-
30
26
  describe('useUser', () => {
31
27
  // Create mock user profiles with all required fields
32
28
  const mockUserProfile: UserProfile = {
@@ -91,7 +87,11 @@ describe('useUser', () => {
91
87
  )
92
88
  }
93
89
 
94
- render(<TestComponent />)
90
+ render(
91
+ <ResourceProvider projectId="p" fallback={null}>
92
+ <TestComponent />
93
+ </ResourceProvider>,
94
+ )
95
95
 
96
96
  // Verify that the output contains the user data and that isPending is false
97
97
  expect(screen.getByTestId('output').textContent).toContain('John Doe (gabc123)')
@@ -146,9 +146,9 @@ describe('useUser', () => {
146
146
  }
147
147
 
148
148
  render(
149
- <Suspense fallback={<div data-testid="fallback">Loading...</div>}>
149
+ <ResourceProvider fallback={<div data-testid="fallback">Loading...</div>}>
150
150
  <TestComponent />
151
- </Suspense>,
151
+ </ResourceProvider>,
152
152
  )
153
153
 
154
154
  // Initially, since storeValue is undefined, the component should suspend and fallback is shown
@@ -237,7 +237,11 @@ describe('useUser', () => {
237
237
  )
238
238
  }
239
239
 
240
- render(<WrapperComponent />)
240
+ render(
241
+ <ResourceProvider fallback={null}>
242
+ <WrapperComponent />
243
+ </ResourceProvider>,
244
+ )
241
245
 
242
246
  // Initially, should show data for first user and not pending
243
247
  expect(screen.getByTestId('output').textContent).toContain('John Doe')
@@ -290,7 +294,11 @@ describe('useUser', () => {
290
294
  )
291
295
  }
292
296
 
293
- render(<TestComponent />)
297
+ render(
298
+ <ResourceProvider fallback={null}>
299
+ <TestComponent />
300
+ </ResourceProvider>,
301
+ )
294
302
 
295
303
  expect(screen.getByTestId('output').textContent).toContain('User not found')
296
304
  expect(screen.getByTestId('output').textContent).toContain('not pending')
@@ -331,7 +339,11 @@ describe('useUser', () => {
331
339
  )
332
340
  }
333
341
 
334
- render(<TestComponent />)
342
+ render(
343
+ <ResourceProvider projectId="test-project" fallback={null}>
344
+ <TestComponent />
345
+ </ResourceProvider>,
346
+ )
335
347
 
336
348
  expect(screen.getByTestId('output').textContent).toContain('John Doe (p12345)')
337
349
  })
@@ -360,8 +372,9 @@ describe('useUser', () => {
360
372
  const {data} = useUser({
361
373
  userId: 'gabc123',
362
374
  resourceType,
363
- projectId: resourceType === 'project' ? 'test-project' : undefined,
364
- organizationId: resourceType === 'organization' ? 'test-org' : undefined,
375
+ ...(resourceType === 'project'
376
+ ? {projectId: 'test-project'}
377
+ : {organizationId: 'test-org'}),
365
378
  })
366
379
  return (
367
380
  <div>
@@ -373,7 +386,11 @@ describe('useUser', () => {
373
386
  )
374
387
  }
375
388
 
376
- render(<WrapperComponent />)
389
+ render(
390
+ <ResourceProvider projectId="test-project" fallback={null}>
391
+ <WrapperComponent />
392
+ </ResourceProvider>,
393
+ )
377
394
 
378
395
  // Initially should show project user
379
396
  expect(screen.getByTestId('output').textContent).toContain('John Doe')