This commit is contained in:
Stephen Zhou 2026-03-19 11:18:28 +08:00
parent 8e52267acb
commit 7fc0014d66
No known key found for this signature in database
2 changed files with 118 additions and 3 deletions

View File

@ -0,0 +1,111 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import InviteSettingsPage from '../page'
const mockReplace = vi.fn()
const mockRefetch = vi.fn()
const mockActivateMember = vi.fn()
const mockSetLocaleOnClient = vi.fn()
const mockResolvePostLoginRedirect = vi.fn()
let mockInviteToken = 'invite-token'
let mockCheckRes: {
is_valid: boolean
data: {
workspace_name: string
email: string
workspace_id: string
}
} | undefined
vi.mock('@/next/navigation', () => ({
useRouter: () => ({
replace: mockReplace,
}),
useSearchParams: () => ({
get: (key: string) => key === 'invite_token' ? mockInviteToken : null,
}),
}))
vi.mock('@/context/global-public-context', () => ({
useGlobalPublicStore: (selector: (state: { systemFeatures: { branding: { enabled: boolean } } }) => unknown) =>
selector({
systemFeatures: {
branding: {
enabled: true,
},
},
}),
}))
vi.mock('@/service/use-common', () => ({
useInvitationCheck: () => ({
data: mockCheckRes,
refetch: mockRefetch,
}),
}))
vi.mock('@/service/common', () => ({
activateMember: (...args: unknown[]) => mockActivateMember(...args),
}))
vi.mock('@/i18n-config', () => ({
setLocaleOnClient: (...args: unknown[]) => mockSetLocaleOnClient(...args),
}))
vi.mock('../../utils/post-login-redirect', () => ({
resolvePostLoginRedirect: () => mockResolvePostLoginRedirect(),
}))
describe('InviteSettingsPage', () => {
beforeEach(() => {
vi.clearAllMocks()
mockInviteToken = 'invite-token'
mockCheckRes = undefined
mockActivateMember.mockResolvedValue({ result: 'success' })
mockSetLocaleOnClient.mockResolvedValue(undefined)
mockResolvePostLoginRedirect.mockReturnValue('/apps')
})
describe('Activation Gating', () => {
it('should not activate when invitation validation is still pending and Enter is pressed', () => {
render(<InviteSettingsPage />)
const nameInput = screen.getByLabelText('login.name')
fireEvent.change(nameInput, { target: { value: 'Alice' } })
fireEvent.keyDown(nameInput, { key: 'Enter', code: 'Enter', charCode: 13 })
expect(mockActivateMember).not.toHaveBeenCalled()
})
it('should activate when invitation validation has succeeded', async () => {
mockCheckRes = {
is_valid: true,
data: {
workspace_name: 'Demo Workspace',
email: 'alice@example.com',
workspace_id: 'workspace-1',
},
}
render(<InviteSettingsPage />)
const nameInput = screen.getByLabelText('login.name')
fireEvent.change(nameInput, { target: { value: 'Alice' } })
fireEvent.keyDown(nameInput, { key: 'Enter', code: 'Enter', charCode: 13 })
await waitFor(() => {
expect(mockActivateMember).toHaveBeenCalledWith({
url: '/activate',
body: {
token: 'invite-token',
name: 'Alice',
interface_language: 'en-US',
timezone: expect.any(String),
},
})
})
expect(mockSetLocaleOnClient).toHaveBeenCalledWith('en-US', false)
expect(mockReplace).toHaveBeenCalledWith('/apps')
})
})
})

View File

@ -36,9 +36,12 @@ export default function InviteSettingsPage() {
},
}
const { data: checkRes, refetch: recheck } = useInvitationCheck(checkParams.params, !!token)
const canActivate = checkRes?.is_valid === true
const handleActivate = useCallback(async () => {
try {
if (!canActivate)
return
if (!name) {
Toast.notify({ type: 'error', message: t('enterYourName', { ns: 'login' }) })
return
@ -62,7 +65,7 @@ export default function InviteSettingsPage() {
catch {
recheck()
}
}, [language, name, recheck, timezone, token, router, t])
}, [canActivate, language, name, recheck, timezone, token, router, t])
if (checkRes?.is_valid === false) {
return (
@ -104,7 +107,8 @@ export default function InviteSettingsPage() {
if (e.key === 'Enter') {
e.preventDefault()
e.stopPropagation()
handleActivate()
if (canActivate)
handleActivate()
}
}}
/>
@ -144,7 +148,7 @@ export default function InviteSettingsPage() {
variant="primary"
className="w-full"
onClick={handleActivate}
disabled={!checkRes?.is_valid}
disabled={!canActivate}
>
{`${t('join', { ns: 'login' })} ${checkRes?.data?.workspace_name ?? ''}`}
</Button>