dify/web/__tests__/embedded-user-id-store.test...

141 lines
4.5 KiB
TypeScript

import { render, screen, waitFor } from '@testing-library/react'
import * as React from 'react'
import WebAppStoreProvider, { useWebAppStore } from '@/context/web-app-context'
import { AccessMode } from '@/models/access-control'
vi.mock('next/navigation', () => ({
usePathname: vi.fn(() => '/chatbot/sample-app'),
useSearchParams: vi.fn(() => {
const params = new URLSearchParams()
return params
}),
}))
vi.mock('@/service/use-share', () => ({
useGetWebAppAccessModeByCode: vi.fn(() => ({
isLoading: false,
data: { accessMode: AccessMode.PUBLIC },
})),
}))
// Store the mock implementation in a way that survives hoisting
const mockGetProcessedSystemVariablesFromUrlParams = vi.fn()
vi.mock('@/app/components/base/chat/utils', () => ({
getProcessedSystemVariablesFromUrlParams: (...args: any[]) => mockGetProcessedSystemVariablesFromUrlParams(...args),
}))
// Use vi.hoisted to define mock state before vi.mock hoisting
const { mockGlobalStoreState } = vi.hoisted(() => ({
mockGlobalStoreState: {
isGlobalPending: false,
setIsGlobalPending: vi.fn(),
systemFeatures: {},
setSystemFeatures: vi.fn(),
},
}))
vi.mock('@/context/global-public-context', () => {
const useGlobalPublicStore = Object.assign(
(selector?: (state: typeof mockGlobalStoreState) => any) =>
selector ? selector(mockGlobalStoreState) : mockGlobalStoreState,
{
setState: (updater: any) => {
if (typeof updater === 'function')
Object.assign(mockGlobalStoreState, updater(mockGlobalStoreState) ?? {})
else
Object.assign(mockGlobalStoreState, updater)
},
__mockState: mockGlobalStoreState,
},
)
return {
useGlobalPublicStore,
}
})
const TestConsumer = () => {
const embeddedUserId = useWebAppStore(state => state.embeddedUserId)
const embeddedConversationId = useWebAppStore(state => state.embeddedConversationId)
return (
<>
<div data-testid="embedded-user-id">{embeddedUserId ?? 'null'}</div>
<div data-testid="embedded-conversation-id">{embeddedConversationId ?? 'null'}</div>
</>
)
}
const initialWebAppStore = (() => {
const snapshot = useWebAppStore.getState()
return {
shareCode: null as string | null,
appInfo: null,
appParams: null,
webAppAccessMode: snapshot.webAppAccessMode,
appMeta: null,
userCanAccessApp: false,
embeddedUserId: null,
embeddedConversationId: null,
updateShareCode: snapshot.updateShareCode,
updateAppInfo: snapshot.updateAppInfo,
updateAppParams: snapshot.updateAppParams,
updateWebAppAccessMode: snapshot.updateWebAppAccessMode,
updateWebAppMeta: snapshot.updateWebAppMeta,
updateUserCanAccessApp: snapshot.updateUserCanAccessApp,
updateEmbeddedUserId: snapshot.updateEmbeddedUserId,
updateEmbeddedConversationId: snapshot.updateEmbeddedConversationId,
}
})()
beforeEach(() => {
mockGlobalStoreState.isGlobalPending = false
mockGetProcessedSystemVariablesFromUrlParams.mockReset()
useWebAppStore.setState(initialWebAppStore, true)
})
describe('WebAppStoreProvider embedded user id handling', () => {
it('hydrates embedded user and conversation ids from system variables', async () => {
mockGetProcessedSystemVariablesFromUrlParams.mockResolvedValue({
user_id: 'iframe-user-123',
conversation_id: 'conversation-456',
})
render(
<WebAppStoreProvider>
<TestConsumer />
</WebAppStoreProvider>,
)
await waitFor(() => {
expect(screen.getByTestId('embedded-user-id')).toHaveTextContent('iframe-user-123')
expect(screen.getByTestId('embedded-conversation-id')).toHaveTextContent('conversation-456')
})
expect(useWebAppStore.getState().embeddedUserId).toBe('iframe-user-123')
expect(useWebAppStore.getState().embeddedConversationId).toBe('conversation-456')
})
it('clears embedded user id when system variable is absent', async () => {
useWebAppStore.setState(state => ({
...state,
embeddedUserId: 'previous-user',
embeddedConversationId: 'existing-conversation',
}))
mockGetProcessedSystemVariablesFromUrlParams.mockResolvedValue({})
render(
<WebAppStoreProvider>
<TestConsumer />
</WebAppStoreProvider>,
)
await waitFor(() => {
expect(screen.getByTestId('embedded-user-id')).toHaveTextContent('null')
expect(screen.getByTestId('embedded-conversation-id')).toHaveTextContent('null')
})
expect(useWebAppStore.getState().embeddedUserId).toBeNull()
expect(useWebAppStore.getState().embeddedConversationId).toBeNull()
})
})