@sanity/sdk
Version:
162 lines (133 loc) • 5.43 kB
text/typescript
import {createClient, type SanityClient} from '@sanity/client'
import {Subject} from 'rxjs'
import {beforeEach, describe, expect, it, vi} from 'vitest'
import {getAuthMethodState, getTokenState} from '../auth/authStore'
import {createSanityInstance, type SanityInstance} from '../store/createSanityInstance'
import {getClient, getClientState} from './clientStore'
// Mock dependencies
vi.mock('@sanity/client')
vi.mock('../auth/authStore')
let instance: SanityInstance
let authMethod$: Subject<'cookie' | 'localstorage' | undefined>
beforeEach(() => {
vi.resetAllMocks()
// Initialize Subjects ONCE per test run before mocks use them
authMethod$ = new Subject<'cookie' | 'localstorage' | undefined>()
vi.mocked(getTokenState).mockReturnValue({
getCurrent: vi.fn().mockReturnValue('initial-token'),
subscribe: vi.fn(),
observable: new Subject(),
})
vi.mocked(getAuthMethodState).mockReturnValue({
// Mock initial state value if needed by other parts of setup
getCurrent: vi.fn().mockReturnValue(undefined),
subscribe: vi.fn(),
observable: authMethod$, // Consistently return the module-scope Subject
})
vi.mocked(createClient).mockImplementation(
(clientConfig) => ({config: () => clientConfig}) as SanityClient,
)
instance = createSanityInstance({projectId: 'test-project', dataset: 'test-dataset'})
})
afterEach(() => {
instance.dispose()
})
describe('clientStore', () => {
describe('getClient', () => {
it('should create a client with default configuration', () => {
const client = getClient(instance, {apiVersion: '2024-11-12'})
const defaultConfiguration = {
useCdn: false,
ignoreBrowserTokenWarning: true,
allowReconfigure: false,
requestTagPrefix: 'sanity.sdk',
projectId: 'test-project',
dataset: 'test-dataset',
token: 'initial-token',
}
expect(vi.mocked(createClient)).toHaveBeenCalledWith({
...defaultConfiguration,
apiVersion: '2024-11-12',
})
expect(client.config()).toEqual({
...defaultConfiguration,
apiVersion: '2024-11-12',
})
})
it('should throw when using disallowed configuration keys', () => {
expect(() =>
getClient(instance, {
apiVersion: '2024-11-12',
// @ts-expect-error Testing invalid key
illegalKey: 'foo',
}),
).toThrowError(/unsupported properties: illegalKey/)
})
it('should reuse clients with identical configurations', () => {
const options = {apiVersion: '2024-11-12', useCdn: true}
const client1 = getClient(instance, options)
const client2 = getClient(instance, options)
expect(client1).toBe(client2)
expect(vi.mocked(createClient)).toHaveBeenCalledTimes(1)
})
it('should create new clients when configuration changes', () => {
const client1 = getClient(instance, {apiVersion: '2024-11-12'})
const client2 = getClient(instance, {apiVersion: '2023-08-01'})
expect(client1).not.toBe(client2)
expect(vi.mocked(createClient)).toHaveBeenCalledTimes(2)
})
})
describe('token handling', () => {
it('should reset clients when token changes', () => {
// Initial client with first token
const tokenState = getTokenState(instance)
vi.mocked(tokenState.getCurrent).mockReturnValue('first-token')
const client1 = getClient(instance, {apiVersion: '2024-11-12'})
// Simulate token change
vi.mocked(tokenState.getCurrent).mockReturnValue('new-token')
const token$ = tokenState.observable as Subject<string>
token$.next('new-token')
// New client should be created with new token
const client2 = getClient(instance, {apiVersion: '2024-11-12'})
expect(client1).not.toBe(client2)
expect(vi.mocked(createClient)).toHaveBeenCalledWith(
expect.objectContaining({
token: 'new-token',
}),
)
})
})
describe('getClientState', () => {
it('should provide a state source that emits client changes', async () => {
// Get initial client state with a specific configuration
const state = getClientState(instance, {apiVersion: '2024-11-12'})
// Get initial client
const initialClient = state.getCurrent()
expect(initialClient).toBeDefined()
// Setup a spy to track emissions from the observable
const nextSpy = vi.fn()
const subscription = state.observable.subscribe(nextSpy)
// Should have emitted once initially
expect(nextSpy).toHaveBeenCalledTimes(1)
expect(nextSpy).toHaveBeenCalledWith(initialClient)
// Simulate token change
const tokenState = getTokenState(instance)
vi.mocked(tokenState.getCurrent).mockReturnValue('updated-token')
const token$ = tokenState.observable as Subject<string>
token$.next('updated-token')
// Should emit a new client instance
expect(nextSpy).toHaveBeenCalledTimes(2)
// The new client should be different from the initial one
const updatedClient = nextSpy.mock.calls[1][0]
expect(updatedClient).not.toBe(initialClient)
// The updated client should have the new token
expect(updatedClient.config()).toEqual(
expect.objectContaining({
token: 'updated-token',
}),
)
// Clean up subscription
subscription.unsubscribe()
})
})
})