@sanity/sdk-react 2.15.0 → 2.16.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.
@@ -1,7 +1,14 @@
1
1
  import {getProjectState, type Project, type ProjectOptions, resolveProject} from '@sanity/sdk'
2
- import {identity} from 'rxjs'
3
2
 
4
3
  import {createStateSourceHook} from '../helpers/createStateSourceHook'
4
+ import {useResolvedProjectId} from '../helpers/useResolvedProjectId'
5
+
6
+ const useProjectBase = createStateSourceHook({
7
+ getState: getProjectState,
8
+ shouldSuspend: (instance, ...params) =>
9
+ getProjectState(instance, ...params).getCurrent() === undefined,
10
+ suspender: resolveProject,
11
+ })
5
12
 
6
13
  /**
7
14
  * Returns metadata for a given project.
@@ -29,15 +36,18 @@ import {createStateSourceHook} from '../helpers/createStateSourceHook'
29
36
  * const projectWithoutMembers = useProject({projectId, includeMembers: false})
30
37
  * const projectWithoutFeatures = useProject({projectId, includeFeatures: false})
31
38
  * ```
39
+ * @remarks
40
+ * The `projectId` is resolved in order from:
41
+ * 1. an explicit `projectId` option
42
+ * 2. A legacy ProjectContext (e.g. a `<ResourceProvider projectId="…">` with no dataset), then
43
+ * 3. The active resource (`ResourceProvider`/`SDKProvider`)
44
+ * 4. `instance.config`.
32
45
  * @public
33
46
  * @function
34
47
  */
35
- export const useProject = createStateSourceHook({
36
- getState: getProjectState,
37
- shouldSuspend: (instance, ...params) =>
38
- getProjectState(instance, ...params).getCurrent() === undefined,
39
- suspender: resolveProject,
40
- getConfig: identity,
48
+ export const useProject = ((options?: ProjectOptions<boolean, boolean>) => {
49
+ const projectId = useResolvedProjectId(options)
50
+ return useProjectBase(projectId ? {...options, projectId} : options)
41
51
  }) as <IncludeMembers extends boolean = true, IncludeFeatures extends boolean = true>(
42
52
  options?: ProjectOptions<IncludeMembers, IncludeFeatures>,
43
53
  ) => Project<IncludeMembers, IncludeFeatures>
@@ -1,4 +1,5 @@
1
1
  import {
2
+ createSanityInstance,
2
3
  getUsersState,
3
4
  loadMoreUsers,
4
5
  resolveUsers,
@@ -6,12 +7,14 @@ import {
6
7
  type StateSource,
7
8
  type UserProfile,
8
9
  } from '@sanity/sdk'
9
- import {act, fireEvent, render, screen} from '@testing-library/react'
10
- import {useState} from 'react'
10
+ import {act, fireEvent, render, renderHook, screen} from '@testing-library/react'
11
+ import {type ReactNode, useState} from 'react'
11
12
  import {type Observable, Subject} from 'rxjs'
12
13
  import {describe, expect, it, vi} from 'vitest'
13
14
 
14
15
  import {ResourceProvider} from '../../context/ResourceProvider'
16
+ import {SanityInstanceContext} from '../../context/SanityInstanceContext'
17
+ import {useSanityInstance} from '../context/useSanityInstance'
15
18
  import {useUsers} from './useUsers'
16
19
 
17
20
  // Mock the functions from '@sanity/sdk'
@@ -335,4 +338,100 @@ describe('useUsers', () => {
335
338
  },
336
339
  )
337
340
  })
341
+
342
+ it('resolves the projectId from the default resource for a project-scoped query', () => {
343
+ vi.mocked(getUsersState).mockReturnValue({
344
+ getCurrent: vi.fn().mockReturnValue({data: mockUsers, hasMore: false, totalCount: 2}),
345
+ subscribe: vi.fn(),
346
+ get observable(): Observable<unknown> {
347
+ throw new Error('Not implemented')
348
+ },
349
+ } as unknown as StateSource<
350
+ {data: SanityUser[]; totalCount: number; hasMore: boolean} | undefined
351
+ >)
352
+
353
+ const {
354
+ result: {current: instance},
355
+ } = renderHook(
356
+ () => {
357
+ useUsers({resourceType: 'project'})
358
+ return useSanityInstance()
359
+ },
360
+ {
361
+ wrapper: ({children}: {children: ReactNode}) => (
362
+ <ResourceProvider
363
+ resource={{projectId: 'resource-project', dataset: 'production'}}
364
+ fallback={null}
365
+ >
366
+ {children}
367
+ </ResourceProvider>
368
+ ),
369
+ },
370
+ )
371
+
372
+ expect(getUsersState).toHaveBeenLastCalledWith(
373
+ instance,
374
+ expect.objectContaining({projectId: 'resource-project', resourceType: 'project'}),
375
+ )
376
+ })
377
+
378
+ it('does not inject a projectId for an organization-scoped query', () => {
379
+ vi.mocked(getUsersState).mockReturnValue({
380
+ getCurrent: vi.fn().mockReturnValue({data: mockUsers, hasMore: false, totalCount: 2}),
381
+ subscribe: vi.fn(),
382
+ get observable(): Observable<unknown> {
383
+ throw new Error('Not implemented')
384
+ },
385
+ } as unknown as StateSource<
386
+ {data: SanityUser[]; totalCount: number; hasMore: boolean} | undefined
387
+ >)
388
+
389
+ function TestComponent() {
390
+ useUsers({resourceType: 'organization', organizationId: 'test-org'})
391
+ return null
392
+ }
393
+
394
+ render(
395
+ <ResourceProvider
396
+ resource={{projectId: 'resource-project', dataset: 'production'}}
397
+ fallback={null}
398
+ >
399
+ <TestComponent />
400
+ </ResourceProvider>,
401
+ )
402
+
403
+ // Organization queries key off organizationId; the ambient project resource
404
+ // must not leak in as a projectId.
405
+ expect(vi.mocked(getUsersState).mock.lastCall?.[1]).not.toHaveProperty('projectId')
406
+ })
407
+
408
+ it('resolves a bare projectId from a ResourceProvider when the parent instance has no config', () => {
409
+ vi.mocked(getUsersState).mockReturnValue({
410
+ getCurrent: vi.fn().mockReturnValue({data: mockUsers, hasMore: false, totalCount: 2}),
411
+ subscribe: vi.fn(),
412
+ get observable(): Observable<unknown> {
413
+ throw new Error('Not implemented')
414
+ },
415
+ } as unknown as StateSource<
416
+ {data: SanityUser[]; totalCount: number; hasMore: boolean} | undefined
417
+ >)
418
+
419
+ // An instance with no project/dataset config, then a
420
+ // projectId-only ResourceProvider.
421
+ const emptyInstance = createSanityInstance({})
422
+ renderHook(() => useUsers(), {
423
+ wrapper: ({children}: {children: ReactNode}) => (
424
+ <SanityInstanceContext.Provider value={emptyInstance}>
425
+ <ResourceProvider projectId="bare-project" fallback={null}>
426
+ {children}
427
+ </ResourceProvider>
428
+ </SanityInstanceContext.Provider>
429
+ ),
430
+ })
431
+
432
+ expect(getUsersState).toHaveBeenLastCalledWith(
433
+ emptyInstance,
434
+ expect.objectContaining({projectId: 'bare-project'}),
435
+ )
436
+ })
338
437
  })
@@ -10,6 +10,7 @@ import {
10
10
  import {useCallback, useEffect, useMemo, useState, useSyncExternalStore, useTransition} from 'react'
11
11
 
12
12
  import {useSanityInstance} from '../context/useSanityInstance'
13
+ import {useResolvedProjectId} from '../helpers/useResolvedProjectId'
13
14
  import {trackHookUsage} from '../helpers/useTrackHookUsage'
14
15
 
15
16
  /**
@@ -36,6 +37,23 @@ export interface UsersResult {
36
37
  loadMore: () => void
37
38
  }
38
39
 
40
+ /**
41
+ * Injects a resolved `projectId` into project-scoped users options. A missing
42
+ * `projectId` is a no-op, and organization-scoped queries (explicit
43
+ * `resourceType`/`organizationId`) or options that already carry a `projectId`
44
+ * are returned unchanged.
45
+ */
46
+ function withResolvedProjectId(
47
+ options: GetUsersOptions | undefined,
48
+ projectId: string | undefined,
49
+ ): GetUsersOptions | undefined {
50
+ if (!projectId) return options
51
+ if (!options) return {projectId}
52
+ const isOrgScoped = options.resourceType === 'organization' || !!options.organizationId
53
+ if (isOrgScoped || options.projectId) return options
54
+ return {...options, projectId}
55
+ }
56
+
39
57
  /**
40
58
  *
41
59
  * @public
@@ -67,6 +85,12 @@ export interface UsersResult {
67
85
  * </div>
68
86
  * )
69
87
  * ```
88
+ * @remarks
89
+ * For project-scoped queries the `projectId` is resolved in order from:
90
+ * 1. an explicit `projectId` option
91
+ * 2. A legacy ProjectContext (e.g. a `<ResourceProvider projectId="…">` with no dataset), then
92
+ * 3. The active resource (`ResourceProvider`/`SDKProvider`)
93
+ * 4. `instance.config`.
70
94
  */
71
95
  export function useUsers(options?: GetUsersOptions): UsersResult {
72
96
  const instance = useSanityInstance()
@@ -74,8 +98,16 @@ export function useUsers(options?: GetUsersOptions): UsersResult {
74
98
  // Use React's useTransition to avoid UI jank when user options change
75
99
  const [isPending, startTransition] = useTransition()
76
100
 
101
+ // Resolve the projectId from the ambient project/resource context so a
102
+ // project-scoped users request can pick it up rather than the top-level config.
103
+ const resolvedProjectId = useResolvedProjectId(options)
104
+ const effectiveOptions = useMemo(
105
+ () => withResolvedProjectId(options, resolvedProjectId),
106
+ [options, resolvedProjectId],
107
+ )
108
+
77
109
  // Get the unique key for this users request and its options
78
- const key = getUsersKey(instance, options)
110
+ const key = getUsersKey(instance, effectiveOptions)
79
111
  // Use a deferred state to avoid immediate re-renders when the users request changes
80
112
  const [deferredKey, setDeferredKey] = useState(key)
81
113
  // Parse the deferred users key back into users options
@@ -115,8 +147,8 @@ export function useUsers(options?: GetUsersOptions): UsersResult {
115
147
  const {data, hasMore} = useSyncExternalStore(subscribe, getCurrent)!
116
148
 
117
149
  const loadMore = useCallback(() => {
118
- loadMoreUsers(instance, options)
119
- }, [instance, options])
150
+ loadMoreUsers(instance, effectiveOptions)
151
+ }, [instance, effectiveOptions])
120
152
 
121
153
  return {data, hasMore, isPending, loadMore}
122
154
  }
@@ -0,0 +1,111 @@
1
+ import {type SanityClient} from '@sanity/client'
2
+ import {getClientState, type SanityInstance, type StateSource} from '@sanity/sdk'
3
+ import {firstValueFrom} from 'rxjs'
4
+ import {beforeEach, describe, expect, it, vi} from 'vitest'
5
+
6
+ import {resolveOrgResources} from './resolveOrgResources'
7
+
8
+ vi.mock('@sanity/sdk', () => ({
9
+ getClientState: vi.fn(),
10
+ }))
11
+
12
+ vi.mock('rxjs', () => ({
13
+ firstValueFrom: vi.fn(),
14
+ }))
15
+
16
+ const mockGetClientState = vi.mocked(getClientState)
17
+ const mockFirstValueFrom = vi.mocked(firstValueFrom)
18
+
19
+ const mockRequest = vi.fn()
20
+ const mockClient = {request: mockRequest}
21
+ const mockInstance = {} as SanityInstance
22
+
23
+ beforeEach(() => {
24
+ vi.clearAllMocks()
25
+ mockGetClientState.mockReturnValue({
26
+ observable: 'mock-observable',
27
+ } as unknown as StateSource<SanityClient>)
28
+ mockFirstValueFrom.mockResolvedValue(mockClient as unknown as SanityClient)
29
+ })
30
+
31
+ const ORG_ID = 'org-1'
32
+
33
+ describe('resolveOrgResources', () => {
34
+ it('returns both mediaLibrary and canvas when both requests succeed', async () => {
35
+ mockRequest
36
+ .mockResolvedValueOnce({data: [{id: 'ml-123'}]})
37
+ .mockResolvedValueOnce({data: [{id: 'canvas-456'}]})
38
+
39
+ const result = await resolveOrgResources(mockInstance, ORG_ID)
40
+
41
+ expect(result).toEqual({
42
+ mediaLibrary: {mediaLibraryId: 'ml-123'},
43
+ canvas: {canvasId: 'canvas-456'},
44
+ })
45
+ })
46
+
47
+ it('scopes both requests to the organization', async () => {
48
+ mockRequest
49
+ .mockResolvedValueOnce({data: [{id: 'ml-123'}]})
50
+ .mockResolvedValueOnce({data: [{id: 'canvas-456'}]})
51
+
52
+ await resolveOrgResources(mockInstance, ORG_ID)
53
+
54
+ expect(mockRequest).toHaveBeenCalledWith(
55
+ expect.objectContaining({uri: '/media-libraries', query: {organizationId: ORG_ID}}),
56
+ )
57
+ expect(mockRequest).toHaveBeenCalledWith(
58
+ expect.objectContaining({uri: '/canvases', query: {organizationId: ORG_ID}}),
59
+ )
60
+ })
61
+
62
+ it('returns only mediaLibrary when canvas request fails', async () => {
63
+ mockRequest
64
+ .mockResolvedValueOnce({data: [{id: 'ml-123'}]})
65
+ .mockRejectedValueOnce(new Error('canvas not found'))
66
+
67
+ const result = await resolveOrgResources(mockInstance, ORG_ID)
68
+
69
+ expect(result).toEqual({
70
+ mediaLibrary: {mediaLibraryId: 'ml-123'},
71
+ canvas: undefined,
72
+ })
73
+ })
74
+
75
+ it('returns only canvas when mediaLibrary request fails', async () => {
76
+ mockRequest
77
+ .mockRejectedValueOnce(new Error('media library not found'))
78
+ .mockResolvedValueOnce({data: [{id: 'canvas-456'}]})
79
+
80
+ const result = await resolveOrgResources(mockInstance, ORG_ID)
81
+
82
+ expect(result).toEqual({
83
+ mediaLibrary: undefined,
84
+ canvas: {canvasId: 'canvas-456'},
85
+ })
86
+ })
87
+
88
+ it('returns undefined for both when both requests fail', async () => {
89
+ mockRequest
90
+ .mockRejectedValueOnce(new Error('error 1'))
91
+ .mockRejectedValueOnce(new Error('error 2'))
92
+
93
+ const result = await resolveOrgResources(mockInstance, ORG_ID)
94
+
95
+ expect(result).toEqual({
96
+ mediaLibrary: undefined,
97
+ canvas: undefined,
98
+ })
99
+ })
100
+
101
+ it('returns undefined for both when data arrays are empty', async () => {
102
+ mockRequest.mockResolvedValueOnce({data: []}).mockResolvedValueOnce({data: []})
103
+
104
+ const result = await resolveOrgResources(mockInstance, ORG_ID)
105
+
106
+ expect(result).toEqual({
107
+ mediaLibrary: undefined,
108
+ canvas: undefined,
109
+ })
110
+ })
111
+ })
@@ -0,0 +1,69 @@
1
+ import {
2
+ type CanvasResource,
3
+ getClientState,
4
+ type MediaLibraryResource,
5
+ type SanityInstance,
6
+ } from '@sanity/sdk'
7
+ import {firstValueFrom} from 'rxjs'
8
+
9
+ const API_VERSION = 'v2026-07-09'
10
+
11
+ interface OrgResourcesApiItem {
12
+ id: string
13
+ }
14
+
15
+ interface OrgResourcesApiResponse {
16
+ data: OrgResourcesApiItem[]
17
+ }
18
+
19
+ interface OrgResources {
20
+ mediaLibrary?: MediaLibraryResource
21
+ canvas?: CanvasResource
22
+ }
23
+
24
+ /**
25
+ * Gets the id of the first resource from a settled request result. The request
26
+ * is already scoped to a single organization, so the first item is the one we want.
27
+ */
28
+ function getFirstResourceId(
29
+ result: PromiseSettledResult<OrgResourcesApiResponse>,
30
+ ): string | undefined {
31
+ if (result.status !== 'fulfilled') return undefined
32
+ return result.value.data?.[0]?.id
33
+ }
34
+
35
+ /**
36
+ * Fetches the media library and canvas resources for the given organization.
37
+ * Both requests are scoped to `organizationId` so each response contains only
38
+ * that org's resources. Each resource is fetched independently — a failure for
39
+ * one does not prevent the other from resolving.
40
+ */
41
+ export async function resolveOrgResources(
42
+ instance: SanityInstance,
43
+ organizationId: string,
44
+ ): Promise<OrgResources> {
45
+ const client = await firstValueFrom(
46
+ getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable,
47
+ )
48
+
49
+ const [mediaLibrariesResult, canvasesResult] = await Promise.allSettled([
50
+ client.request<OrgResourcesApiResponse>({
51
+ uri: `/media-libraries`,
52
+ query: {organizationId},
53
+ tag: 'org-resources.media-libraries',
54
+ }),
55
+ client.request<OrgResourcesApiResponse>({
56
+ uri: `/canvases`,
57
+ query: {organizationId},
58
+ tag: 'org-resources.canvases',
59
+ }),
60
+ ])
61
+
62
+ const mediaLibraryId = getFirstResourceId(mediaLibrariesResult)
63
+ const canvasId = getFirstResourceId(canvasesResult)
64
+
65
+ return {
66
+ mediaLibrary: mediaLibraryId ? {mediaLibraryId} : undefined,
67
+ canvas: canvasId ? {canvasId} : undefined,
68
+ }
69
+ }
@@ -1,80 +0,0 @@
1
- import {getDatasetsState, type ProjectHandle, type SanityInstance} from '@sanity/sdk'
2
- import {beforeEach, describe, expect, it, vi} from 'vitest'
3
-
4
- import {createStateSourceHook} from '../helpers/createStateSourceHook'
5
-
6
- // Mock dependencies
7
- vi.mock('@sanity/sdk', () => ({
8
- getDatasetsState: vi.fn(() => ({
9
- getCurrent: vi.fn(() => undefined), // Mocking getCurrent to satisfy the call within shouldSuspend
10
- })),
11
- resolveDatasets: vi.fn(),
12
- }))
13
- vi.mock('../helpers/createStateSourceHook', () => ({
14
- createStateSourceHook: vi.fn(),
15
- }))
16
-
17
- describe('useDatasets', () => {
18
- // Use beforeEach to reset modules and ensure mocks are fresh for each test
19
- beforeEach(() => {
20
- vi.resetModules()
21
- // Re-mock dependencies for each test after resetModules
22
- vi.mock('@sanity/sdk', () => ({
23
- getDatasetsState: vi.fn(() => ({
24
- getCurrent: vi.fn(() => undefined),
25
- })),
26
- resolveDatasets: vi.fn(),
27
- }))
28
- vi.mock('../helpers/createStateSourceHook', () => ({
29
- createStateSourceHook: vi.fn(),
30
- }))
31
- })
32
-
33
- it('should call createStateSourceHook with correct arguments on import', async () => {
34
- // Dynamically import the hook *after* mocks are set up and modules reset
35
- await import('./useDatasets')
36
-
37
- // Check if createStateSourceHook was called during the module evaluation (import)
38
- expect(createStateSourceHook).toHaveBeenCalled()
39
- expect(createStateSourceHook).toHaveBeenCalledWith(
40
- expect.objectContaining({
41
- getState: expect.any(Function),
42
- shouldSuspend: expect.any(Function),
43
- suspender: expect.any(Function), // Actual function reference doesn't matter here as it's mocked
44
- getConfig: expect.any(Function), // Actual function reference doesn't matter here
45
- }),
46
- )
47
- })
48
-
49
- it('shouldSuspend should call getDatasetsState and getCurrent', async () => {
50
- // Dynamically import the hook *after* mocks are set up and modules reset
51
- await import('./useDatasets')
52
-
53
- // Get the arguments passed to createStateSourceHook
54
- // Need to ensure createStateSourceHook mock is correctly typed for access
55
- const mockCreateStateSourceHook = createStateSourceHook as ReturnType<typeof vi.fn>
56
- expect(mockCreateStateSourceHook.mock.calls.length).toBeGreaterThan(0)
57
- const createStateSourceHookArgs = mockCreateStateSourceHook.mock.calls[0][0]
58
- const shouldSuspend = createStateSourceHookArgs.shouldSuspend
59
-
60
- // Mock instance and projectHandle for the test call
61
- const mockInstance = {} as SanityInstance // Use specific type
62
- const mockProjectHandle = {} as ProjectHandle // Use specific type
63
-
64
- // Call the shouldSuspend function
65
- const result = shouldSuspend(mockInstance, mockProjectHandle)
66
-
67
- // Assert that getDatasetsState was called with the correct arguments
68
- // Need to ensure getDatasetsState mock is correctly typed for access
69
- const mockGetDatasetsState = getDatasetsState as ReturnType<typeof vi.fn>
70
- expect(mockGetDatasetsState).toHaveBeenCalledWith(mockInstance, mockProjectHandle)
71
-
72
- // Assert that getCurrent was called on the result of getDatasetsState
73
- expect(mockGetDatasetsState.mock.results.length).toBeGreaterThan(0)
74
- const getDatasetsStateMockResult = mockGetDatasetsState.mock.results[0].value
75
- expect(getDatasetsStateMockResult.getCurrent).toHaveBeenCalled()
76
-
77
- // Assert the result of shouldSuspend based on the mocked getCurrent value
78
- expect(result).toBe(true) // Since getCurrent is mocked to return undefined
79
- })
80
- })
@@ -1,80 +0,0 @@
1
- import {getProjectState, type ProjectHandle, type SanityInstance} from '@sanity/sdk'
2
- import {beforeEach, describe, expect, it, vi} from 'vitest'
3
-
4
- import {createStateSourceHook} from '../helpers/createStateSourceHook'
5
-
6
- // Mock dependencies
7
- vi.mock('@sanity/sdk', () => ({
8
- getProjectState: vi.fn(() => ({
9
- getCurrent: vi.fn(() => undefined), // Mocking getCurrent to satisfy the call within shouldSuspend
10
- })),
11
- resolveProject: vi.fn(),
12
- }))
13
- vi.mock('../helpers/createStateSourceHook', () => ({
14
- createStateSourceHook: vi.fn(),
15
- }))
16
-
17
- describe('useProject', () => {
18
- // Use beforeEach to reset modules and ensure mocks are fresh for each test
19
- beforeEach(() => {
20
- vi.resetModules()
21
- // Re-mock dependencies for each test after resetModules
22
- vi.mock('@sanity/sdk', () => ({
23
- getProjectState: vi.fn(() => ({
24
- getCurrent: vi.fn(() => undefined),
25
- })),
26
- resolveProject: vi.fn(),
27
- }))
28
- vi.mock('../helpers/createStateSourceHook', () => ({
29
- createStateSourceHook: vi.fn(),
30
- }))
31
- })
32
-
33
- it('should call createStateSourceHook with correct arguments on import', async () => {
34
- // Dynamically import the hook *after* mocks are set up and modules reset
35
- await import('./useProject')
36
-
37
- // Check if createStateSourceHook was called during the module evaluation (import)
38
- expect(createStateSourceHook).toHaveBeenCalled()
39
- expect(createStateSourceHook).toHaveBeenCalledWith(
40
- expect.objectContaining({
41
- getState: expect.any(Function),
42
- shouldSuspend: expect.any(Function),
43
- suspender: expect.any(Function), // Actual function reference doesn't matter here as it's mocked
44
- getConfig: expect.any(Function), // Actual function reference doesn't matter here
45
- }),
46
- )
47
- })
48
-
49
- it('shouldSuspend should call getProjectState and getCurrent', async () => {
50
- // Dynamically import the hook *after* mocks are set up and modules reset
51
- await import('./useProject')
52
-
53
- // Get the arguments passed to createStateSourceHook
54
- // Need to ensure createStateSourceHook mock is correctly typed for access
55
- const mockCreateStateSourceHook = createStateSourceHook as ReturnType<typeof vi.fn>
56
- expect(mockCreateStateSourceHook.mock.calls.length).toBeGreaterThan(0)
57
- const createStateSourceHookArgs = mockCreateStateSourceHook.mock.calls[0][0]
58
- const shouldSuspend = createStateSourceHookArgs.shouldSuspend
59
-
60
- // Mock instance and projectHandle for the test call
61
- const mockInstance = {} as SanityInstance // Use specific type
62
- const mockProjectHandle = {} as ProjectHandle // Use specific type
63
-
64
- // Call the shouldSuspend function
65
- const result = shouldSuspend(mockInstance, mockProjectHandle)
66
-
67
- // Assert that getProjectState was called with the correct arguments
68
- // Need to ensure getProjectState mock is correctly typed for access
69
- const mockGetProjectState = getProjectState as ReturnType<typeof vi.fn>
70
- expect(mockGetProjectState).toHaveBeenCalledWith(mockInstance, mockProjectHandle)
71
-
72
- // Assert that getCurrent was called on the result of getProjectState
73
- expect(mockGetProjectState.mock.results.length).toBeGreaterThan(0)
74
- const getProjectStateMockResult = mockGetProjectState.mock.results[0].value
75
- expect(getProjectStateMockResult.getCurrent).toHaveBeenCalled()
76
-
77
- // Assert the result of shouldSuspend based on the mocked getCurrent value
78
- expect(result).toBe(true) // Since getCurrent is mocked to return undefined
79
- })
80
- })