feat: add profile auth identity binding flow

This commit is contained in:
IanShaw027
2026-04-20 18:28:44 +08:00
parent 13d9780df4
commit c6d8592484
31 changed files with 3419 additions and 239 deletions

View File

@@ -45,11 +45,15 @@ vi.mock('@/stores', () => ({
})
}))
vi.mock('@/api/auth', () => ({
exchangePendingOAuthCompletion: (...args: any[]) => exchangePendingOAuthCompletion(...args),
completeOIDCOAuthRegistration: (...args: any[]) => completeOIDCOAuthRegistration(...args),
getPublicSettings: (...args: any[]) => getPublicSettings(...args)
}))
vi.mock('@/api/auth', async () => {
const actual = await vi.importActual<typeof import('@/api/auth')>('@/api/auth')
return {
...actual,
exchangePendingOAuthCompletion: (...args: any[]) => exchangePendingOAuthCompletion(...args),
completeOIDCOAuthRegistration: (...args: any[]) => completeOIDCOAuthRegistration(...args),
getPublicSettings: (...args: any[]) => getPublicSettings(...args)
}
})
describe('OidcCallbackView', () => {
beforeEach(() => {
@@ -143,6 +147,43 @@ describe('OidcCallbackView', () => {
expect(replace).toHaveBeenCalledWith('/dashboard')
})
it('supports bind completion after adoption confirmation', async () => {
exchangePendingOAuthCompletion
.mockResolvedValueOnce({
redirect: '/dashboard',
adoption_required: true,
suggested_display_name: 'OIDC Nick',
suggested_avatar_url: 'https://cdn.example/oidc.png'
})
.mockResolvedValueOnce({
redirect: '/profile'
})
const wrapper = mount(OidcCallbackView, {
global: {
stubs: {
AuthLayout: { template: '<div><slot /></div>' },
Icon: true,
RouterLink: { template: '<a><slot /></a>' },
transition: false
}
}
})
await flushPromises()
await wrapper.findAll('button')[0].trigger('click')
await flushPromises()
expect(exchangePendingOAuthCompletion).toHaveBeenNthCalledWith(2, {
adoptDisplayName: true,
adoptAvatar: true
})
expect(setToken).not.toHaveBeenCalled()
expect(showSuccess).toHaveBeenCalledWith('profile.authBindings.bindSuccess')
expect(replace).toHaveBeenCalledWith('/profile')
})
it('renders adoption choices for invitation flow and submits the selected values', async () => {
exchangePendingOAuthCompletion.mockResolvedValue({
error: 'invitation_required',