AuthLayout.utils.test.ts 5.1 KB

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