mirror of
https://github.com/langgenius/dify.git
synced 2026-06-26 06:41:10 +08:00
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: fatelei <fatelei@gmail.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: 盐粒 Yanli <yanli@dify.ai> Co-authored-by: Charles Yao <chongbinyao33@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: yunlu.wen <yunlu.wen@dify.ai> Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com> Co-authored-by: Jingyi <jingyi.qi@dify.ai> Co-authored-by: yyh <yuanyouhuilyz@gmail.com> Co-authored-by: Joel <iamjoel007@gmail.com> Co-authored-by: hjlarry <hjlarry@163.com> Co-authored-by: Asuka Minato <i@asukaminato.eu.org> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Xiyuan Chen <52963600+GareArc@users.noreply.github.com> Co-authored-by: gigglewang <gigglewang@dify.ai> Co-authored-by: chariri <w@chariri.moe> Co-authored-by: Evan <2869018789@qq.com> Co-authored-by: zyssyz123 <916125788@qq.com>
152 lines
5.3 KiB
TypeScript
152 lines
5.3 KiB
TypeScript
import { screen, waitFor } from '@testing-library/react'
|
|
import * as React from 'react'
|
|
import { renderToString } from 'react-dom/server'
|
|
import { createSystemFeaturesWrapper, renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
|
|
import WebAppStoreProvider, { useWebAppStore } from '@/context/web-app-context'
|
|
|
|
import { AccessMode } from '@/models/access-control'
|
|
|
|
const navigationMocks = vi.hoisted(() => ({
|
|
usePathname: vi.fn(() => '/chatbot/sample-app'),
|
|
useSearchParams: vi.fn(() => new URLSearchParams()),
|
|
}))
|
|
|
|
const useGetWebAppAccessModeByCodeMock = vi.hoisted(() => vi.fn())
|
|
|
|
vi.mock('@/next/navigation', () => ({
|
|
usePathname: navigationMocks.usePathname,
|
|
useSearchParams: navigationMocks.useSearchParams,
|
|
}))
|
|
|
|
vi.mock('@/service/use-share', () => ({
|
|
useGetWebAppAccessModeByCode: (...args: unknown[]) => useGetWebAppAccessModeByCodeMock(...args),
|
|
}))
|
|
|
|
const mockGetProcessedSystemVariablesFromUrlParams = vi.fn()
|
|
|
|
vi.mock('@/app/components/base/chat/utils', () => ({
|
|
getProcessedSystemVariablesFromUrlParams: (...args: any[]) => mockGetProcessedSystemVariablesFromUrlParams(...args),
|
|
}))
|
|
|
|
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(() => {
|
|
mockGetProcessedSystemVariablesFromUrlParams.mockReset()
|
|
navigationMocks.usePathname.mockReset()
|
|
navigationMocks.usePathname.mockReturnValue('/chatbot/sample-app')
|
|
navigationMocks.useSearchParams.mockReset()
|
|
navigationMocks.useSearchParams.mockReturnValue(new URLSearchParams())
|
|
useGetWebAppAccessModeByCodeMock.mockReset()
|
|
useGetWebAppAccessModeByCodeMock.mockReturnValue({
|
|
isLoading: false,
|
|
data: { accessMode: AccessMode.PUBLIC },
|
|
})
|
|
useWebAppStore.setState(initialWebAppStore, true)
|
|
})
|
|
|
|
describe('WebAppStoreProvider embedded user id handling', () => {
|
|
it('parses share code from redirect_url during server render without window', () => {
|
|
const params = new URLSearchParams()
|
|
params.set('redirect_url', encodeURIComponent('/chatbot/redirected-app'))
|
|
navigationMocks.usePathname.mockReturnValue('/webapp-signin')
|
|
navigationMocks.useSearchParams.mockReturnValue(params)
|
|
const originalWindow = globalThis.window
|
|
Object.defineProperty(globalThis, 'window', {
|
|
configurable: true,
|
|
value: undefined,
|
|
})
|
|
const { wrapper: Wrapper } = createSystemFeaturesWrapper()
|
|
|
|
try {
|
|
expect(() => renderToString(
|
|
<Wrapper>
|
|
<WebAppStoreProvider>
|
|
<div />
|
|
</WebAppStoreProvider>
|
|
</Wrapper>,
|
|
)).not.toThrow()
|
|
}
|
|
finally {
|
|
Object.defineProperty(globalThis, 'window', {
|
|
configurable: true,
|
|
value: originalWindow,
|
|
})
|
|
}
|
|
|
|
expect(useGetWebAppAccessModeByCodeMock).toHaveBeenCalledWith('redirected-app')
|
|
})
|
|
|
|
it('hydrates embedded user and conversation ids from system variables', async () => {
|
|
mockGetProcessedSystemVariablesFromUrlParams.mockResolvedValue({
|
|
user_id: 'iframe-user-123',
|
|
conversation_id: 'conversation-456',
|
|
})
|
|
|
|
renderWithSystemFeatures(
|
|
<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({})
|
|
|
|
renderWithSystemFeatures(
|
|
<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()
|
|
})
|
|
})
|