dify/web/app/device/components/__tests__/authorize-sso.spec.tsx
Yunlu Wen a728e0ac69
feat: adding dify cli (#36348)
Co-authored-by: GareArc <garethcxy@dify.ai>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: L1nSn0w <l1nsn0w@qq.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: gigglewang <gigglewang@dify.ai>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Xiyuan Chen <52963600+GareArc@users.noreply.github.com>
2026-05-26 01:12:36 +00:00

80 lines
3.1 KiB
TypeScript

import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import AuthorizeSSO from '../authorize-sso'
const mockCtx = {
subject_email: 'gareth@company.com',
subject_issuer: 'Okta (okta.company.com)',
user_code: 'ABCD-3456',
csrf_token: 'tok',
expires_at: '2099-01-01T00:00:00Z',
}
const mockFetchApprovalContext = vi.fn()
const mockApproveExternal = vi.fn()
vi.mock('@/service/device-flow', () => ({
fetchApprovalContext: () => mockFetchApprovalContext(),
approveExternal: (...args: unknown[]) => mockApproveExternal(...args),
DeviceFlowError: class extends Error {
code: string
status: number
constructor(code: string, status = 400) {
super(code)
this.code = code
this.status = status
}
},
}))
describe('AuthorizeSSO', () => {
beforeEach(() => {
vi.clearAllMocks()
mockFetchApprovalContext.mockResolvedValue(mockCtx)
mockApproveExternal.mockResolvedValue(undefined)
})
it('renders subject_email and issuer after context loads', async () => {
render(<AuthorizeSSO onApproved={vi.fn()} onError={vi.fn()} />)
await screen.findByText('gareth@company.com')
expect(screen.getByText('Okta (okta.company.com)')).toBeInTheDocument()
})
it('renders single Authorize button with no Cancel', async () => {
render(<AuthorizeSSO onApproved={vi.fn()} onError={vi.fn()} />)
await screen.findByRole('button', { name: /Authorize/i })
expect(screen.queryByRole('button', { name: /Cancel/i })).not.toBeInTheDocument()
})
it('calls approveExternal with ctx and user_code on Authorize click', async () => {
render(<AuthorizeSSO onApproved={vi.fn()} onError={vi.fn()} />)
await screen.findByRole('button', { name: /Authorize/i })
await userEvent.click(screen.getByRole('button', { name: /Authorize/i }))
await waitFor(() => expect(mockApproveExternal).toHaveBeenCalledWith(mockCtx, mockCtx.user_code))
})
it('calls onApproved after successful approve', async () => {
const onApproved = vi.fn()
render(<AuthorizeSSO onApproved={onApproved} onError={vi.fn()} />)
await screen.findByRole('button', { name: /Authorize/i })
await userEvent.click(screen.getByRole('button', { name: /Authorize/i }))
await waitFor(() => expect(onApproved).toHaveBeenCalled())
})
it('shows loadErr fallback when fetchApprovalContext rejects', async () => {
mockFetchApprovalContext.mockRejectedValue(new Error('network'))
render(<AuthorizeSSO onApproved={vi.fn()} onError={vi.fn()} />)
await screen.findByText('This session is no longer valid')
})
it('calls onError when approveExternal throws', async () => {
mockApproveExternal.mockRejectedValue(new Error('unexpected'))
const onError = vi.fn()
render(<AuthorizeSSO onApproved={vi.fn()} onError={onError} />)
await screen.findByRole('button', { name: /Authorize/i })
await userEvent.click(screen.getByRole('button', { name: /Authorize/i }))
await waitFor(() => expect(onError).toHaveBeenCalledWith(expect.any(String)))
})
})