Files
supabase/apps/studio/components/interfaces/Account/Preferences/AccountIdentities.utils.test.ts
fadymak 17dde3d324 feat(account): let OAuth-only users add a password to their account (#49057)
Allows a user to add a password which automatically creates and email
identity to enable email + password authentication for OAuth-only
accounts.

Gated behind a feature flag: `enableAccountPassword`

When a user does not have an email identity, allow them to set a
password:

<img width="762" height="284" alt="Screenshot 2026-08-13 at 14 52 53"
src="https://github.com/user-attachments/assets/70b4883a-ed38-488a-a1b7-908caa112a0b"
/>

Password modal:

<img width="519" height="423" alt="Screenshot 2026-08-13 at 14 56 57"
src="https://github.com/user-attachments/assets/56ac370d-9e6c-4b05-986f-3aa9a51826c2"
/>

Email identity has been created, allow unlinking and/or updating email
address or password:

<img width="764" height="285" alt="Screenshot 2026-08-13 at 14 55 04"
src="https://github.com/user-attachments/assets/5d9d7692-f4e3-4638-958d-15fefad01333"
/>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * OAuth-only accounts can set a password from Sign-in methods.
* Added password visibility controls, validation guidance, and success
or error feedback.
  * Sign-in methods display the account email when available.

* **Updates**
* Renamed “Account identities” to “Sign-in methods” throughout account
preferences.
* Standardized password requirements across password setup and reset
forms.
* Setting a password refreshes the current session and signs out other
sessions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-08-14 14:56:23 +02:00

76 lines
2.4 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { parseRedirectMessage, shouldShowAddPasswordRow } from './AccountIdentities.utils'
describe('parseRedirectMessage', () => {
it('drops the trailing sb marker and decodes + as spaces', () => {
expect(
parseRedirectMessage(
'/account/me#message=Confirmation+link+accepted.+Please+proceed+to+confirm+link+sent+to+the+other+email&sb='
)
).toBe('Confirmation link accepted. Please proceed to confirm link sent to the other email')
})
it('returns undefined when there is no hash', () => {
expect(parseRedirectMessage('/account/me')).toBeUndefined()
})
it('returns undefined when the fragment has no message key', () => {
expect(parseRedirectMessage('/account/me#sb=')).toBeUndefined()
})
it('finds message even when it is not the first fragment param', () => {
expect(parseRedirectMessage('/account/me#sb=&message=Hi+there')).toBe('Hi there')
})
it('preserves a literal + via percent-encoding', () => {
expect(parseRedirectMessage('/account/me#message=a%2Bb&sb=')).toBe('a+b')
})
})
describe('shouldShowAddPasswordRow', () => {
const email = 'user@example.com'
it('shows the row for an OAuth-only user', () => {
expect(shouldShowAddPasswordRow({ identities: [{ provider: 'github' }], email })).toBe(true)
})
it('shows the row when there are no identities at all', () => {
expect(shouldShowAddPasswordRow({ identities: [], email })).toBe(true)
})
it('hides the row when an email identity already exists', () => {
expect(shouldShowAddPasswordRow({ identities: [{ provider: 'email' }], email })).toBe(false)
expect(
shouldShowAddPasswordRow({
identities: [{ provider: 'github' }, { provider: 'email' }],
email,
})
).toBe(false)
})
it('hides the row for SSO users', () => {
expect(
shouldShowAddPasswordRow({
identities: [{ provider: 'sso:4d21b3cf-3a2f-44d3-b7d6-2b0dd393f671' }],
email,
})
).toBe(false)
expect(
shouldShowAddPasswordRow({
identities: [{ provider: 'github' }, { provider: 'sso' }],
email,
})
).toBe(false)
})
it('hides the row when the user has no email', () => {
expect(
shouldShowAddPasswordRow({ identities: [{ provider: 'github' }], email: undefined })
).toBe(false)
expect(shouldShowAddPasswordRow({ identities: [{ provider: 'github' }], email: '' })).toBe(
false
)
})
})