AuthLayout.utils.test.ts156 lines · main
| 1 | import { describe, expect, it } from 'vitest' |
| 2 | |
| 3 | import { generateAuthMenu, GenerateAuthMenuOptions } from './AuthLayout.utils' |
| 4 | |
| 5 | const allFeaturesEnabled: GenerateAuthMenuOptions = { |
| 6 | ref: 'test-ref', |
| 7 | isPlatform: true, |
| 8 | showOverview: true, |
| 9 | features: { |
| 10 | signInProviders: true, |
| 11 | rateLimits: true, |
| 12 | emails: true, |
| 13 | multiFactor: true, |
| 14 | attackProtection: true, |
| 15 | performance: true, |
| 16 | passkeys: true, |
| 17 | }, |
| 18 | } |
| 19 | |
| 20 | const allFeaturesDisabled: GenerateAuthMenuOptions = { |
| 21 | ref: 'test-ref', |
| 22 | isPlatform: true, |
| 23 | showOverview: false, |
| 24 | features: { |
| 25 | signInProviders: false, |
| 26 | rateLimits: false, |
| 27 | emails: false, |
| 28 | multiFactor: false, |
| 29 | attackProtection: false, |
| 30 | performance: false, |
| 31 | passkeys: true, |
| 32 | }, |
| 33 | } |
| 34 | |
| 35 | function flatItemNames(menu: ReturnType<typeof generateAuthMenu>): string[] { |
| 36 | return menu.flatMap((group) => group.items.map((item) => item.name)) |
| 37 | } |
| 38 | |
| 39 | function findItem(menu: ReturnType<typeof generateAuthMenu>, name: string) { |
| 40 | for (const group of menu) { |
| 41 | const item = group.items.find((i) => i.name === name) |
| 42 | if (item) return item |
| 43 | } |
| 44 | return undefined |
| 45 | } |
| 46 | |
| 47 | describe('generateAuthMenu', () => { |
| 48 | it('platform with all features enabled includes all menu items', () => { |
| 49 | const menu = generateAuthMenu(allFeaturesEnabled) |
| 50 | const names = flatItemNames(menu) |
| 51 | |
| 52 | expect(names).toContain('Overview') |
| 53 | expect(names).toContain('Users') |
| 54 | expect(names).toContain('OAuth Apps') |
| 55 | expect(names).toContain('Emails') |
| 56 | expect(names).toContain('Sign In / Providers') |
| 57 | expect(names).toContain('OAuth Server') |
| 58 | expect(names).toContain('Passkeys') |
| 59 | expect(names).toContain('Sessions') |
| 60 | expect(names).toContain('Rate Limits') |
| 61 | expect(names).toContain('Multi-Factor') |
| 62 | expect(names).toContain('URL Configuration') |
| 63 | expect(names).toContain('Attack Protection') |
| 64 | expect(names).toContain('Auth Hooks') |
| 65 | expect(names).toContain('Audit Logs') |
| 66 | expect(names).toContain('Performance') |
| 67 | }) |
| 68 | |
| 69 | it('platform with all features disabled shows only core items', () => { |
| 70 | const menu = generateAuthMenu(allFeaturesDisabled) |
| 71 | const names = flatItemNames(menu) |
| 72 | |
| 73 | expect(names).toContain('Users') |
| 74 | expect(names).toContain('OAuth Apps') |
| 75 | expect(names).toContain('Policies') |
| 76 | expect(names).toContain('OAuth Server') |
| 77 | expect(names).toContain('Passkeys') |
| 78 | expect(names).toContain('Sessions') |
| 79 | expect(names).toContain('URL Configuration') |
| 80 | expect(names).toContain('Auth Hooks') |
| 81 | expect(names).toContain('Audit Logs') |
| 82 | |
| 83 | expect(names).not.toContain('Overview') |
| 84 | expect(names).not.toContain('Emails') |
| 85 | expect(names).not.toContain('Sign In / Providers') |
| 86 | expect(names).not.toContain('Rate Limits') |
| 87 | expect(names).not.toContain('Multi-Factor') |
| 88 | expect(names).not.toContain('Attack Protection') |
| 89 | expect(names).not.toContain('Performance') |
| 90 | }) |
| 91 | |
| 92 | it('self-hosted hides OAuth Apps, Notifications, and platform-only Configuration items', () => { |
| 93 | const menu = generateAuthMenu({ |
| 94 | ...allFeaturesEnabled, |
| 95 | isPlatform: false, |
| 96 | }) |
| 97 | const names = flatItemNames(menu) |
| 98 | const groupTitles = menu.map((g) => g.title) |
| 99 | |
| 100 | expect(names).not.toContain('OAuth Apps') |
| 101 | expect(groupTitles).not.toContain('Notifications') |
| 102 | |
| 103 | // Configuration should only have Policies |
| 104 | const configGroup = menu.find((g) => g.title === 'Configuration')! |
| 105 | expect(configGroup.items).toHaveLength(1) |
| 106 | expect(configGroup.items[0].name).toBe('Policies') |
| 107 | }) |
| 108 | |
| 109 | it('shows Overview when showOverview is true', () => { |
| 110 | const menu = generateAuthMenu({ ...allFeaturesDisabled, showOverview: true }) |
| 111 | expect(flatItemNames(menu)).toContain('Overview') |
| 112 | }) |
| 113 | |
| 114 | it('hides Overview when showOverview is false', () => { |
| 115 | const menu = generateAuthMenu({ ...allFeaturesEnabled, showOverview: false }) |
| 116 | expect(flatItemNames(menu)).not.toContain('Overview') |
| 117 | }) |
| 118 | |
| 119 | it.each([ |
| 120 | ['signInProviders', 'Sign In / Providers'], |
| 121 | ['rateLimits', 'Rate Limits'], |
| 122 | ['emails', 'Emails'], |
| 123 | ['multiFactor', 'Multi-Factor'], |
| 124 | ['attackProtection', 'Attack Protection'], |
| 125 | ['performance', 'Performance'], |
| 126 | ] as const)('feature flag %s toggles %s', (flag, itemName) => { |
| 127 | const withEnabled = generateAuthMenu({ |
| 128 | ...allFeaturesDisabled, |
| 129 | features: { ...allFeaturesDisabled.features, [flag]: true }, |
| 130 | }) |
| 131 | const withDisabled = generateAuthMenu({ |
| 132 | ...allFeaturesEnabled, |
| 133 | features: { ...allFeaturesEnabled.features, [flag]: false }, |
| 134 | }) |
| 135 | |
| 136 | expect(flatItemNames(withEnabled)).toContain(itemName) |
| 137 | expect(flatItemNames(withDisabled)).not.toContain(itemName) |
| 138 | }) |
| 139 | |
| 140 | it('generates correct URLs using the ref parameter', () => { |
| 141 | const menu = generateAuthMenu({ ...allFeaturesEnabled, ref: 'my-project' }) |
| 142 | const users = findItem(menu, 'Users') |
| 143 | const oauthApps = findItem(menu, 'OAuth Apps') |
| 144 | |
| 145 | expect(users?.url).toBe('/project/my-project/auth/users') |
| 146 | expect(oauthApps?.url).toBe('/project/my-project/auth/oauth-apps') |
| 147 | }) |
| 148 | |
| 149 | it('hides Passkeys when passkeys feature is false', () => { |
| 150 | const menu = generateAuthMenu({ |
| 151 | ...allFeaturesEnabled, |
| 152 | features: { ...allFeaturesEnabled.features, passkeys: false }, |
| 153 | }) |
| 154 | expect(flatItemNames(menu)).not.toContain('Passkeys') |
| 155 | }) |
| 156 | }) |