dify/web/app/components/base/ga/__tests__/index.spec.tsx
Stephen Zhou a84c2d36a3
style: format with vp fmt (#38803)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-12 15:57:46 +00:00

167 lines
4.6 KiB
TypeScript

import type { ReactElement, ReactNode } from 'react'
import { render, screen } from '@testing-library/react'
type ConfigState = {
isCloudEdition: boolean
isProd: boolean
}
type GoogleAnalyticsScriptsRenderFn = () => Promise<ReactNode>
const { mockHeaders, mockHeadersGet, configState } = vi.hoisted(() => ({
mockHeaders: vi.fn(),
mockHeadersGet: vi.fn(),
configState: {
isCloudEdition: true,
isProd: true,
} as ConfigState,
}))
vi.mock('@/config', () => ({
get IS_CLOUD_EDITION() {
return configState.isCloudEdition
},
get IS_PROD() {
return configState.isProd
},
}))
vi.mock('@/next/headers', () => ({
headers: mockHeaders,
}))
vi.mock('@/next/script', () => ({
default: ({
id,
strategy,
src,
nonce,
children,
}: {
id?: string
strategy?: string
src?: string
nonce?: string
children?: ReactNode
}) => (
<script
data-testid="mock-next-script"
data-id={id ?? ''}
data-inline={typeof children === 'string' ? children : ''}
data-nonce={nonce ?? ''}
data-src={src ?? ''}
data-strategy={strategy ?? ''}
/>
),
}))
const loadComponent = async () => {
const mod = await import('../index')
return {
renderer: mod.GoogleAnalyticsScripts as GoogleAnalyticsScriptsRenderFn,
}
}
const renderGoogleAnalyticsScripts = async () => {
const { renderer } = await loadComponent()
const element = await renderer()
if (!element) return { element }
render(element as ReactElement)
return { element }
}
describe('GA', () => {
beforeEach(() => {
vi.clearAllMocks()
vi.resetModules()
configState.isCloudEdition = true
configState.isProd = true
mockHeadersGet.mockImplementation((name: string) => (name === 'x-nonce' ? 'test-nonce' : null))
mockHeaders.mockResolvedValue({
get: mockHeadersGet,
})
})
describe('Rendering', () => {
it('should return null when cloud edition is disabled', async () => {
configState.isCloudEdition = false
const { element } = await renderGoogleAnalyticsScripts()
expect(element).toBeNull()
expect(mockHeaders).not.toHaveBeenCalled()
})
it('should return null when not in production', async () => {
configState.isProd = false
const { element } = await renderGoogleAnalyticsScripts()
expect(element).toBeNull()
expect(mockHeaders).not.toHaveBeenCalled()
})
it('should render consent, CookieYes, and Google Analytics scripts in production', async () => {
await renderGoogleAnalyticsScripts()
const scripts = screen.getAllByTestId('mock-next-script')
expect(scripts).toHaveLength(4)
expect(mockHeaders).toHaveBeenCalledTimes(1)
expect(mockHeadersGet).toHaveBeenCalledWith('x-nonce')
expect(scripts[0]).toHaveAttribute('data-id', 'google-consent-defaults')
expect(scripts[0]).toHaveAttribute('data-strategy', 'afterInteractive')
expect(scripts[0]).toHaveAttribute(
'data-inline',
expect.stringContaining(`window.gtag('consent', 'default'`),
)
expect(scripts[0]).toHaveAttribute(
'data-inline',
expect.stringContaining(`analytics_storage: 'denied'`),
)
expect(scripts[1]).toHaveAttribute('data-id', 'cookieyes')
expect(scripts[1]).toHaveAttribute('data-strategy', 'afterInteractive')
expect(scripts[1]).toHaveAttribute(
'data-src',
'https://cdn-cookieyes.com/client_data/2a645945fcae53f8e025a2b1/script.js',
)
expect(scripts[2]).toHaveAttribute('data-id', 'google-analytics')
expect(scripts[2]).toHaveAttribute('data-strategy', 'afterInteractive')
expect(scripts[2]).toHaveAttribute(
'data-src',
'https://www.googletagmanager.com/gtag/js?id=G-DM9497FN4V',
)
expect(scripts[3]).toHaveAttribute('data-id', 'google-analytics-init')
expect(scripts[3]).toHaveAttribute('data-strategy', 'afterInteractive')
expect(scripts[3]).toHaveAttribute(
'data-inline',
expect.stringContaining(`window.gtag('config', 'G-DM9497FN4V');`),
)
scripts.forEach((script) => {
expect(script).toHaveAttribute('data-nonce', 'test-nonce')
})
})
})
describe('Edge Cases', () => {
it('should omit nonce when x-nonce header is missing', async () => {
mockHeadersGet.mockReturnValue(null)
await renderGoogleAnalyticsScripts()
const scripts = screen.getAllByTestId('mock-next-script')
expect(mockHeaders).toHaveBeenCalledTimes(1)
scripts.forEach((script) => {
expect(script).toHaveAttribute('data-nonce', '')
})
})
})
})