@sanity/sdk-react 2.2.0 → 2.3.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 (32) hide show
  1. package/dist/index.d.ts +2 -3
  2. package/dist/index.js +92 -19
  3. package/dist/index.js.map +1 -1
  4. package/package.json +6 -5
  5. package/src/components/auth/AuthBoundary.test.tsx +33 -20
  6. package/src/components/auth/AuthBoundary.tsx +11 -1
  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 +53 -40
  13. package/src/hooks/auth/useDashboardOrganizationId.test.tsx +16 -7
  14. package/src/hooks/auth/useVerifyOrgProjects.test.tsx +56 -14
  15. package/src/hooks/dashboard/{useManageFavorite.test.ts → useManageFavorite.test.tsx} +99 -44
  16. package/src/hooks/document/{useDocument.test.ts → useDocument.test.tsx} +25 -22
  17. package/src/hooks/document/{useDocumentEvent.test.ts → useDocumentEvent.test.tsx} +17 -16
  18. package/src/hooks/document/{useDocumentPermissions.test.ts → useDocumentPermissions.test.tsx} +101 -40
  19. package/src/hooks/document/{useEditDocument.test.ts → useEditDocument.test.tsx} +52 -22
  20. package/src/hooks/documents/useDocuments.test.tsx +63 -25
  21. package/src/hooks/helpers/createCallbackHook.test.tsx +41 -37
  22. package/src/hooks/paginatedDocuments/usePaginatedDocuments.test.tsx +2 -2
  23. package/src/hooks/presence/usePresence.test.tsx +9 -6
  24. package/src/hooks/preview/useDocumentPreview.test.tsx +15 -16
  25. package/src/hooks/projection/useDocumentProjection.test.tsx +23 -38
  26. package/src/hooks/projection/useDocumentProjection.ts +3 -8
  27. package/src/hooks/query/useQuery.test.tsx +18 -10
  28. package/src/hooks/releases/useActiveReleases.test.tsx +25 -21
  29. package/src/hooks/releases/usePerspective.test.tsx +16 -22
  30. package/src/hooks/users/useUser.test.tsx +32 -15
  31. package/src/hooks/users/useUsers.test.tsx +19 -11
  32. package/src/hooks/_synchronous-groq-js.mjs +0 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/sdk-react",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "private": false,
5
5
  "description": "Sanity SDK React toolkit for Content OS",
6
6
  "keywords": [
@@ -42,7 +42,7 @@
42
42
  "browserslist": "extends @sanity/browserslist-config",
43
43
  "prettier": "@sanity/prettier-config",
44
44
  "dependencies": {
45
- "@sanity/client": "^7.10.0",
45
+ "@sanity/client": "^7.12.0",
46
46
  "@sanity/message-protocol": "^0.12.0",
47
47
  "@sanity/types": "^3.83.0",
48
48
  "@types/lodash-es": "^4.17.12",
@@ -51,7 +51,7 @@
51
51
  "react-compiler-runtime": "19.1.0-rc.2",
52
52
  "react-error-boundary": "^5.0.0",
53
53
  "rxjs": "^7.8.2",
54
- "@sanity/sdk": "2.2.0"
54
+ "@sanity/sdk": "2.3.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@sanity/browserslist-config": "^1.0.5",
@@ -66,6 +66,7 @@
66
66
  "@vitest/coverage-v8": "3.1.2",
67
67
  "babel-plugin-react-compiler": "19.1.0-rc.1",
68
68
  "eslint": "^9.22.0",
69
+ "groq-js": "^1.19.0",
69
70
  "jsdom": "^25.0.1",
70
71
  "prettier": "^3.5.3",
71
72
  "react": "^19.1.0",
@@ -77,8 +78,8 @@
77
78
  "@repo/config-eslint": "0.0.0",
78
79
  "@repo/config-test": "0.0.1",
79
80
  "@repo/package.bundle": "3.82.0",
80
- "@repo/tsconfig": "0.0.1",
81
- "@repo/package.config": "0.0.1"
81
+ "@repo/package.config": "0.0.1",
82
+ "@repo/tsconfig": "0.0.1"
82
83
  },
83
84
  "peerDependencies": {
84
85
  "react": "^18.0.0 || ^19.0.0",
@@ -8,7 +8,6 @@ import {ResourceProvider} from '../../context/ResourceProvider'
8
8
  import {useAuthState} from '../../hooks/auth/useAuthState'
9
9
  import {useLoginUrl} from '../../hooks/auth/useLoginUrl'
10
10
  import {useVerifyOrgProjects} from '../../hooks/auth/useVerifyOrgProjects'
11
- import {useSanityInstance} from '../../hooks/context/useSanityInstance'
12
11
  import {AuthBoundary} from './AuthBoundary'
13
12
 
14
13
  // Mock hooks
@@ -23,9 +22,6 @@ vi.mock('../../hooks/auth/useHandleAuthCallback', () => ({
23
22
  vi.mock('../../hooks/auth/useLogOut', () => ({
24
23
  useLogOut: vi.fn(() => async () => {}),
25
24
  }))
26
- vi.mock('../../hooks/context/useSanityInstance', () => ({
27
- useSanityInstance: vi.fn(),
28
- }))
29
25
 
30
26
  // Mock AuthError throwing scenario
31
27
  vi.mock('./AuthError', async (importOriginal) => {
@@ -109,7 +105,6 @@ describe('AuthBoundary', () => {
109
105
  const mockUseAuthState = vi.mocked(useAuthState)
110
106
  const mockUseLoginUrl = vi.mocked(useLoginUrl)
111
107
  const mockUseVerifyOrgProjects = vi.mocked(useVerifyOrgProjects)
112
- const mockUseSanityInstance = vi.mocked(useSanityInstance)
113
108
  const testProjectIds = ['proj-test'] // Example project ID for tests
114
109
 
115
110
  // Mock Sanity instance
@@ -139,8 +134,6 @@ describe('AuthBoundary', () => {
139
134
  mockUseLoginUrl.mockReturnValue('http://example.com/login')
140
135
  // Default mock for useVerifyOrgProjects - returns null (no error)
141
136
  mockUseVerifyOrgProjects.mockImplementation(() => null)
142
- // Mock useSanityInstance to return our mock instance
143
- mockUseSanityInstance.mockReturnValue(mockSanityInstance)
144
137
  })
145
138
 
146
139
  afterEach(() => {
@@ -170,7 +163,9 @@ describe('AuthBoundary', () => {
170
163
  isExchangingToken: false,
171
164
  })
172
165
  const {container} = render(
173
- <AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>,
166
+ <ResourceProvider projectId="p" dataset="d" fallback={null}>
167
+ <AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>
168
+ </ResourceProvider>,
174
169
  )
175
170
 
176
171
  // The callback screen renders null check that it renders nothing
@@ -184,7 +179,11 @@ describe('AuthBoundary', () => {
184
179
  currentUser: null,
185
180
  token: 'exampleToken',
186
181
  })
187
- render(<AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>)
182
+ render(
183
+ <ResourceProvider projectId="p" dataset="d" fallback={null}>
184
+ <AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>
185
+ </ResourceProvider>,
186
+ )
188
187
 
189
188
  expect(screen.getByText('Protected Content')).toBeInTheDocument()
190
189
  })
@@ -194,7 +193,11 @@ describe('AuthBoundary', () => {
194
193
  type: AuthStateType.ERROR,
195
194
  error: new Error('test error'),
196
195
  })
197
- render(<AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>)
196
+ render(
197
+ <ResourceProvider projectId="p" dataset="d" fallback={null}>
198
+ <AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>
199
+ </ResourceProvider>,
200
+ )
198
201
 
199
202
  // The AuthBoundary should throw an AuthError internally
200
203
  // and then display the LoginError component as the fallback.
@@ -207,7 +210,11 @@ describe('AuthBoundary', () => {
207
210
  })
208
211
 
209
212
  it('renders children when logged in and org verification passes', () => {
210
- render(<AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>)
213
+ render(
214
+ <ResourceProvider projectId="p" dataset="d" fallback={null}>
215
+ <AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>
216
+ </ResourceProvider>,
217
+ )
211
218
  expect(screen.getByText('Protected Content')).toBeInTheDocument()
212
219
  })
213
220
 
@@ -226,9 +233,11 @@ describe('AuthBoundary', () => {
226
233
 
227
234
  // Need to catch the error thrown during render. ErrorBoundary mock handles this.
228
235
  render(
229
- <AuthBoundary verifyOrganization={true} projectIds={testProjectIds}>
230
- <div>Protected Content</div>
231
- </AuthBoundary>,
236
+ <ResourceProvider projectId="p" dataset="d" fallback={null}>
237
+ <AuthBoundary verifyOrganization={true} projectIds={testProjectIds}>
238
+ <div>Protected Content</div>
239
+ </AuthBoundary>
240
+ </ResourceProvider>,
232
241
  )
233
242
 
234
243
  // The ErrorBoundary's FallbackComponent should be rendered
@@ -256,9 +265,11 @@ describe('AuthBoundary', () => {
256
265
  })
257
266
 
258
267
  render(
259
- <AuthBoundary verifyOrganization={false} projectIds={testProjectIds}>
260
- <div>Protected Content</div>
261
- </AuthBoundary>,
268
+ <ResourceProvider projectId="p" dataset="d" fallback={null}>
269
+ <AuthBoundary verifyOrganization={false} projectIds={testProjectIds}>
270
+ <div>Protected Content</div>
271
+ </AuthBoundary>
272
+ </ResourceProvider>,
262
273
  )
263
274
 
264
275
  // Should render children because verification is disabled
@@ -279,9 +290,11 @@ describe('AuthBoundary', () => {
279
290
  mockUseVerifyOrgProjects.mockImplementation(() => null)
280
291
 
281
292
  render(
282
- <AuthBoundary projectIds={testProjectIds}>
283
- <div>Protected Content</div>
284
- </AuthBoundary>,
293
+ <ResourceProvider projectId="p" dataset="d" fallback={null}>
294
+ <AuthBoundary projectIds={testProjectIds}>
295
+ <div>Protected Content</div>
296
+ </AuthBoundary>
297
+ </ResourceProvider>,
285
298
  )
286
299
 
287
300
  await waitFor(() => {
@@ -1,4 +1,5 @@
1
- import {AuthStateType} from '@sanity/sdk'
1
+ import {CorsOriginError} from '@sanity/client'
2
+ import {AuthStateType, getCorsErrorProjectId} from '@sanity/sdk'
2
3
  import {useEffect, useMemo} from 'react'
3
4
  import {ErrorBoundary, type FallbackProps} from 'react-error-boundary'
4
5
 
@@ -6,6 +7,7 @@ import {ComlinkTokenRefreshProvider} from '../../context/ComlinkTokenRefresh'
6
7
  import {useAuthState} from '../../hooks/auth/useAuthState'
7
8
  import {useLoginUrl} from '../../hooks/auth/useLoginUrl'
8
9
  import {useVerifyOrgProjects} from '../../hooks/auth/useVerifyOrgProjects'
10
+ import {CorsErrorComponent} from '../errors/CorsErrorComponent'
9
11
  import {isInIframe} from '../utils'
10
12
  import {AuthError} from './AuthError'
11
13
  import {ConfigurationError} from './ConfigurationError'
@@ -107,6 +109,14 @@ export function AuthBoundary({
107
109
  }: AuthBoundaryProps): React.ReactNode {
108
110
  const FallbackComponent = useMemo(() => {
109
111
  return function LoginComponentWithLayoutProps(fallbackProps: FallbackProps) {
112
+ if (fallbackProps.error instanceof CorsOriginError) {
113
+ return (
114
+ <CorsErrorComponent
115
+ {...fallbackProps}
116
+ projectId={getCorsErrorProjectId(fallbackProps.error)}
117
+ />
118
+ )
119
+ }
110
120
  return <LoginErrorComponent {...fallbackProps} />
111
121
  }
112
122
  }, [LoginErrorComponent])
@@ -5,6 +5,7 @@ import {type FallbackProps} from 'react-error-boundary'
5
5
 
6
6
  import {useAuthState} from '../../hooks/auth/useAuthState'
7
7
  import {useLogOut} from '../../hooks/auth/useLogOut'
8
+ import {Error} from '../errors/Error'
8
9
  import {AuthError} from './AuthError'
9
10
  import {ConfigurationError} from './ConfigurationError'
10
11
  /**
@@ -59,17 +60,13 @@ export function LoginError({error, resetErrorBoundary}: LoginErrorProps): React.
59
60
  }, [authState, handleRetry, error])
60
61
 
61
62
  return (
62
- <div className="sc-login-error">
63
- <div className="sc-login-error__content">
64
- <h2 className="sc-login-error__title">
65
- {error instanceof AuthError ? 'Authentication Error' : 'Configuration Error'}
66
- </h2>
67
- <p className="sc-login-error__description">{authErrorMessage}</p>
68
- </div>
69
-
70
- <button className="sc-login-error__button" onClick={handleRetry}>
71
- Retry
72
- </button>
73
- </div>
63
+ <Error
64
+ heading={error instanceof AuthError ? 'Authentication Error' : 'Configuration Error'}
65
+ description={authErrorMessage}
66
+ cta={{
67
+ text: 'Retry',
68
+ onClick: handleRetry,
69
+ }}
70
+ />
74
71
  )
75
72
  }
@@ -0,0 +1,48 @@
1
+ import {describe, expect, it} from 'vitest'
2
+
3
+ import {render, screen} from '../../../test/test-utils'
4
+ import {CorsErrorComponent} from './CorsErrorComponent'
5
+
6
+ describe('CorsErrorComponent', () => {
7
+ it('shows origin and manage link when projectId is provided', () => {
8
+ const origin = 'https://example.com'
9
+ const originalLocation = window.location
10
+ // Redefine window.location to control origin in this test
11
+ Object.defineProperty(window, 'location', {
12
+ value: {origin},
13
+ configurable: true,
14
+ })
15
+
16
+ render(
17
+ <CorsErrorComponent
18
+ projectId="proj123"
19
+ error={new Error('nope')}
20
+ resetErrorBoundary={() => {}}
21
+ />,
22
+ )
23
+
24
+ expect(screen.getByText('Before you continue…')).toBeInTheDocument()
25
+ expect(screen.getByText(origin)).toBeInTheDocument()
26
+
27
+ const link = screen.getByRole('link', {name: 'Manage CORS configuration'}) as HTMLAnchorElement
28
+ expect(link).toBeInTheDocument()
29
+ expect(link.target).toBe('_blank')
30
+ expect(link.rel).toContain('noopener')
31
+ expect(link.href).toContain('https://sanity.io/manage/project/proj123/api')
32
+ expect(link.href).toContain('cors=add')
33
+ expect(link.href).toContain(`origin=${encodeURIComponent(origin)}`)
34
+ expect(link.href).toContain('credentials=include')
35
+
36
+ // restore
37
+ Object.defineProperty(window, 'location', {value: originalLocation})
38
+ })
39
+
40
+ it('shows error message when projectId is null', () => {
41
+ const error = new Error('some error message')
42
+ render(<CorsErrorComponent projectId={null} error={error} resetErrorBoundary={() => {}} />)
43
+
44
+ expect(screen.getByText('Before you continue…')).toBeInTheDocument()
45
+ expect(screen.getByText('some error message')).toBeInTheDocument()
46
+ expect(screen.queryByRole('link', {name: 'Manage CORS configuration'})).toBeNull()
47
+ })
48
+ })
@@ -0,0 +1,37 @@
1
+ import {useMemo} from 'react'
2
+ import {type FallbackProps} from 'react-error-boundary'
3
+
4
+ import {Error} from './Error'
5
+
6
+ type CorsErrorComponentProps = FallbackProps & {
7
+ projectId: string | null
8
+ }
9
+
10
+ export function CorsErrorComponent({projectId, error}: CorsErrorComponentProps): React.ReactNode {
11
+ const origin = window.location.origin
12
+ const corsUrl = useMemo(() => {
13
+ const url = new URL(`https://sanity.io/manage/project/${projectId}/api`)
14
+ url.searchParams.set('cors', 'add')
15
+ url.searchParams.set('origin', origin)
16
+ url.searchParams.set('credentials', 'include')
17
+ return url.toString()
18
+ }, [origin, projectId])
19
+ return (
20
+ <Error
21
+ heading="Before you continue…"
22
+ {...(projectId
23
+ ? {
24
+ description:
25
+ 'To access your content, you need to <strong>add the following URL as a CORS origin</strong> to your Sanity project.',
26
+ code: origin,
27
+ cta: {
28
+ text: 'Manage CORS configuration',
29
+ href: corsUrl,
30
+ },
31
+ }
32
+ : {
33
+ description: error?.message,
34
+ })}
35
+ />
36
+ )
37
+ }
@@ -0,0 +1,35 @@
1
+ const FONT_SANS_SERIF = `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Helvetica, Arial, system-ui, sans-serif`
2
+ const FONT_MONOSPACE = `-apple-system-ui-monospace, 'SF Mono', Menlo, Monaco, Consolas, monospace`
3
+
4
+ const styles: Record<string, React.CSSProperties> = {
5
+ container: {
6
+ padding: '28px',
7
+ fontFamily: FONT_SANS_SERIF,
8
+ display: 'flex',
9
+ flexDirection: 'column',
10
+ gap: '21px',
11
+ fontSize: '14px',
12
+ },
13
+ heading: {
14
+ margin: 0,
15
+ fontSize: '28px',
16
+ fontWeight: 700,
17
+ },
18
+ paragraph: {
19
+ margin: 0,
20
+ },
21
+ link: {
22
+ appearance: 'none',
23
+ background: 'transparent',
24
+ border: 0,
25
+ padding: 0,
26
+ font: 'inherit',
27
+ textDecoration: 'underline',
28
+ cursor: 'pointer',
29
+ },
30
+ code: {
31
+ fontFamily: FONT_MONOSPACE,
32
+ },
33
+ }
34
+
35
+ export default styles
@@ -0,0 +1,40 @@
1
+ import styles from './Error.styles'
2
+
3
+ type ErrorProps = {
4
+ heading: string
5
+ description?: string
6
+ code?: string
7
+ cta?: {
8
+ text: string
9
+ href?: string
10
+ onClick?: () => void
11
+ }
12
+ }
13
+
14
+ export function Error({heading, description, code, cta}: ErrorProps): React.ReactNode {
15
+ return (
16
+ <div style={styles['container']}>
17
+ <h1 style={styles['heading']}>{heading}</h1>
18
+
19
+ {description && (
20
+ <p style={styles['paragraph']} dangerouslySetInnerHTML={{__html: description}} />
21
+ )}
22
+
23
+ {code && <code style={styles['code']}>{code}</code>}
24
+
25
+ {cta && (cta.href || cta.onClick) && (
26
+ <p style={styles['paragraph']}>
27
+ {cta.href ? (
28
+ <a style={styles['link']} href={cta.href} target="_blank" rel="noopener noreferrer">
29
+ {cta.text}
30
+ </a>
31
+ ) : (
32
+ <button style={styles['link']} onClick={cta.onClick}>
33
+ {cta.text}
34
+ </button>
35
+ )}
36
+ </p>
37
+ )}
38
+ </div>
39
+ )
40
+ }
@@ -5,8 +5,8 @@ import {afterEach, beforeEach, describe, expect, it, type Mock, vi} from 'vitest
5
5
 
6
6
  import {useAuthState} from '../hooks/auth/useAuthState'
7
7
  import {useWindowConnection} from '../hooks/comlink/useWindowConnection'
8
- import {useSanityInstance} from '../hooks/context/useSanityInstance'
9
8
  import {ComlinkTokenRefreshProvider} from './ComlinkTokenRefresh'
9
+ import {ResourceProvider} from './ResourceProvider'
10
10
 
11
11
  // Mocks
12
12
  vi.mock('@sanity/sdk', async () => {
@@ -26,20 +26,13 @@ vi.mock('../hooks/comlink/useWindowConnection', () => ({
26
26
  useWindowConnection: vi.fn(),
27
27
  }))
28
28
 
29
- vi.mock('../hooks/context/useSanityInstance', () => ({
30
- useSanityInstance: vi.fn(),
31
- }))
32
-
33
29
  // Use simpler mock typings
34
30
  const mockGetIsInDashboardState = getIsInDashboardState as Mock
35
31
  const mockSetAuthToken = setAuthToken as Mock
36
32
  const mockUseAuthState = useAuthState as Mock
37
33
  const mockUseWindowConnection = useWindowConnection as Mock
38
- const mockUseSanityInstance = useSanityInstance as Mock
39
34
 
40
35
  const mockFetch = vi.fn()
41
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
- const mockSanityInstance: any = {projectId: 'test', dataset: 'test'}
43
36
 
44
37
  describe('ComlinkTokenRefresh', () => {
45
38
  beforeEach(() => {
@@ -47,7 +40,6 @@ describe('ComlinkTokenRefresh', () => {
47
40
  mockGetIsInDashboardState.mockReturnValue({getCurrent: vi.fn(() => false)})
48
41
  mockUseAuthState.mockReturnValue({type: AuthStateType.LOGGED_IN})
49
42
  mockUseWindowConnection.mockReturnValue({fetch: mockFetch})
50
- mockUseSanityInstance.mockReturnValue(mockSanityInstance)
51
43
  })
52
44
 
53
45
  afterEach(() => {
@@ -64,9 +56,11 @@ describe('ComlinkTokenRefresh', () => {
64
56
  it('should not request new token on 401 if not in dashboard', async () => {
65
57
  mockUseAuthState.mockReturnValue({type: AuthStateType.LOGGED_IN})
66
58
  const {rerender} = render(
67
- <ComlinkTokenRefreshProvider>
68
- <div>Test</div>
69
- </ComlinkTokenRefreshProvider>,
59
+ <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
60
+ <ComlinkTokenRefreshProvider>
61
+ <div>Test</div>
62
+ </ComlinkTokenRefreshProvider>
63
+ </ResourceProvider>,
70
64
  )
71
65
 
72
66
  mockUseAuthState.mockReturnValue({
@@ -75,9 +69,11 @@ describe('ComlinkTokenRefresh', () => {
75
69
  })
76
70
  act(() => {
77
71
  rerender(
78
- <ComlinkTokenRefreshProvider>
79
- <div>Test</div>
80
- </ComlinkTokenRefreshProvider>,
72
+ <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
73
+ <ComlinkTokenRefreshProvider>
74
+ <div>Test</div>
75
+ </ComlinkTokenRefreshProvider>
76
+ </ResourceProvider>,
81
77
  )
82
78
  })
83
79
 
@@ -95,9 +91,11 @@ describe('ComlinkTokenRefresh', () => {
95
91
 
96
92
  it('should initialize useWindowConnection with correct parameters', () => {
97
93
  render(
98
- <ComlinkTokenRefreshProvider>
99
- <div>Test</div>
100
- </ComlinkTokenRefreshProvider>,
94
+ <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
95
+ <ComlinkTokenRefreshProvider>
96
+ <div>Test</div>
97
+ </ComlinkTokenRefreshProvider>
98
+ </ResourceProvider>,
101
99
  )
102
100
 
103
101
  expect(mockUseWindowConnection).toHaveBeenCalledWith(
@@ -116,16 +114,18 @@ describe('ComlinkTokenRefresh', () => {
116
114
  mockFetch.mockResolvedValueOnce({token: 'new-token'})
117
115
 
118
116
  render(
119
- <ComlinkTokenRefreshProvider>
120
- <div>Test</div>
121
- </ComlinkTokenRefreshProvider>,
117
+ <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
118
+ <ComlinkTokenRefreshProvider>
119
+ <div>Test</div>
120
+ </ComlinkTokenRefreshProvider>
121
+ </ResourceProvider>,
122
122
  )
123
123
 
124
124
  await act(async () => {
125
125
  await vi.advanceTimersByTimeAsync(100)
126
126
  })
127
127
 
128
- expect(mockSetAuthToken).toHaveBeenCalledWith(mockSanityInstance, 'new-token')
128
+ expect(mockSetAuthToken).toHaveBeenCalledWith(expect.any(Object), 'new-token')
129
129
  expect(mockFetch).toHaveBeenCalledTimes(1)
130
130
  })
131
131
 
@@ -137,9 +137,11 @@ describe('ComlinkTokenRefresh', () => {
137
137
  mockFetch.mockResolvedValueOnce({token: null})
138
138
 
139
139
  render(
140
- <ComlinkTokenRefreshProvider>
141
- <div>Test</div>
142
- </ComlinkTokenRefreshProvider>,
140
+ <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
141
+ <ComlinkTokenRefreshProvider>
142
+ <div>Test</div>
143
+ </ComlinkTokenRefreshProvider>
144
+ </ResourceProvider>,
143
145
  )
144
146
 
145
147
  await act(async () => {
@@ -157,9 +159,11 @@ describe('ComlinkTokenRefresh', () => {
157
159
  mockFetch.mockRejectedValueOnce(new Error('Fetch failed'))
158
160
 
159
161
  render(
160
- <ComlinkTokenRefreshProvider>
161
- <div>Test</div>
162
- </ComlinkTokenRefreshProvider>,
162
+ <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
163
+ <ComlinkTokenRefreshProvider>
164
+ <div>Test</div>
165
+ </ComlinkTokenRefreshProvider>
166
+ </ResourceProvider>,
163
167
  )
164
168
 
165
169
  await act(async () => {
@@ -173,9 +177,12 @@ describe('ComlinkTokenRefresh', () => {
173
177
  it('should not request new token for non-401 errors', async () => {
174
178
  mockUseAuthState.mockReturnValue({type: AuthStateType.LOGGED_IN})
175
179
  const {rerender} = render(
176
- <ComlinkTokenRefreshProvider>
177
- <div>Test</div>
178
- </ComlinkTokenRefreshProvider>,
180
+ <ResourceProvider fallback={null}>
181
+ <ComlinkTokenRefreshProvider>
182
+ <div>Test</div>
183
+ </ComlinkTokenRefreshProvider>
184
+ ,
185
+ </ResourceProvider>,
179
186
  )
180
187
 
181
188
  mockUseAuthState.mockReturnValue({
@@ -184,9 +191,11 @@ describe('ComlinkTokenRefresh', () => {
184
191
  })
185
192
  act(() => {
186
193
  rerender(
187
- <ComlinkTokenRefreshProvider>
188
- <div>Test</div>
189
- </ComlinkTokenRefreshProvider>,
194
+ <ResourceProvider fallback={null}>
195
+ <ComlinkTokenRefreshProvider>
196
+ <div>Test</div>
197
+ </ComlinkTokenRefreshProvider>
198
+ </ResourceProvider>,
190
199
  )
191
200
  })
192
201
 
@@ -199,17 +208,21 @@ describe('ComlinkTokenRefresh', () => {
199
208
  it('should request new token on LOGGED_OUT state', async () => {
200
209
  mockUseAuthState.mockReturnValue({type: AuthStateType.LOGGED_IN})
201
210
  const {rerender} = render(
202
- <ComlinkTokenRefreshProvider>
203
- <div>Test</div>
204
- </ComlinkTokenRefreshProvider>,
211
+ <ResourceProvider fallback={null}>
212
+ <ComlinkTokenRefreshProvider>
213
+ <div>Test</div>
214
+ </ComlinkTokenRefreshProvider>
215
+ </ResourceProvider>,
205
216
  )
206
217
 
207
218
  mockUseAuthState.mockReturnValue({type: AuthStateType.LOGGED_OUT})
208
219
  act(() => {
209
220
  rerender(
210
- <ComlinkTokenRefreshProvider>
211
- <div>Test</div>
212
- </ComlinkTokenRefreshProvider>,
221
+ <ResourceProvider fallback={null}>
222
+ <ComlinkTokenRefreshProvider>
223
+ <div>Test</div>
224
+ </ComlinkTokenRefreshProvider>
225
+ </ResourceProvider>,
213
226
  )
214
227
  })
215
228
 
@@ -1,14 +1,11 @@
1
- import {createSanityInstance, getDashboardOrganizationId} from '@sanity/sdk'
1
+ import {getDashboardOrganizationId} from '@sanity/sdk'
2
2
  import {renderHook} from '@testing-library/react'
3
3
  import {throwError} from 'rxjs'
4
4
  import {describe, expect, it, vi} from 'vitest'
5
5
 
6
+ import {ResourceProvider} from '../../context/ResourceProvider'
6
7
  import {useDashboardOrganizationId} from './useDashboardOrganizationId'
7
8
 
8
- vi.mock('../context/useSanityInstance', () => ({
9
- useSanityInstance: vi.fn().mockReturnValue(createSanityInstance({projectId: 'p', dataset: 'd'})),
10
- }))
11
-
12
9
  vi.mock('@sanity/sdk', async (importOriginal) => {
13
10
  const actual = await importOriginal()
14
11
  return {...(actual || {}), getDashboardOrganizationId: vi.fn()}
@@ -23,7 +20,13 @@ describe('useDashboardOrganizationId', () => {
23
20
  observable: throwError(() => new Error('Unexpected usage of observable')),
24
21
  })
25
22
 
26
- const {result} = renderHook(() => useDashboardOrganizationId())
23
+ const {result} = renderHook(() => useDashboardOrganizationId(), {
24
+ wrapper: ({children}) => (
25
+ <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
26
+ {children}
27
+ </ResourceProvider>
28
+ ),
29
+ })
27
30
  expect(result.current).toBeUndefined()
28
31
  })
29
32
 
@@ -36,7 +39,13 @@ describe('useDashboardOrganizationId', () => {
36
39
  observable: throwError(() => new Error('Unexpected usage of observable')),
37
40
  })
38
41
 
39
- const {result} = renderHook(() => useDashboardOrganizationId())
42
+ const {result} = renderHook(() => useDashboardOrganizationId(), {
43
+ wrapper: ({children}) => (
44
+ <ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
45
+ {children}
46
+ </ResourceProvider>
47
+ ),
48
+ })
40
49
  expect(result.current).toBe(mockOrgId)
41
50
  })
42
51
  })