ProjectDropdown.test.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import { screen } from '@testing-library/react'
  2. import { beforeEach, describe, expect, it, vi } from 'vitest'
  3. import { ProjectDropdown } from './ProjectDropdown'
  4. import { MANAGED_BY } from '@/lib/constants/infrastructure'
  5. import { createMockOrganization, render } from '@/tests/helpers'
  6. const { mockSelectedOrganization, mockSelectedProject, mockSelectorProject } = vi.hoisted(() => ({
  7. mockSelectedOrganization: vi.fn(),
  8. mockSelectedProject: vi.fn(),
  9. mockSelectorProject: vi.fn(),
  10. }))
  11. const mockPush = vi.hoisted(() => vi.fn())
  12. vi.mock('common', async (importOriginal) => {
  13. const original = (await importOriginal()) as typeof import('common')
  14. return {
  15. ...original,
  16. useParams: () => ({ ref: 'proj_1' }),
  17. }
  18. })
  19. vi.mock('next/router', () => ({
  20. useRouter: () => ({
  21. route: '/project/[ref]/settings',
  22. query: { ref: 'proj_1' },
  23. push: mockPush,
  24. }),
  25. }))
  26. vi.mock('@/lib/constants', async (importOriginal) => {
  27. const original = (await importOriginal()) as typeof import('@/lib/constants')
  28. return { ...original, IS_PLATFORM: true }
  29. })
  30. vi.mock('@/hooks/misc/useSelectedProject', () => ({
  31. useSelectedProjectQuery: () => ({
  32. data: mockSelectedProject(),
  33. isPending: false,
  34. }),
  35. }))
  36. vi.mock('@/data/projects/project-detail-query', () => ({
  37. useProjectDetailQuery: () => ({ data: undefined, isPending: false }),
  38. }))
  39. vi.mock('@/hooks/misc/useSelectedOrganization', () => ({
  40. useSelectedOrganizationQuery: () => ({ data: mockSelectedOrganization() }),
  41. }))
  42. vi.mock('@/hooks/misc/useIsFeatureEnabled', () => ({
  43. useIsFeatureEnabled: () => false,
  44. }))
  45. vi.mock('@/components/ui/OrganizationProjectSelector', () => ({
  46. OrganizationProjectSelector: ({ renderRow, renderTrigger }: any) => (
  47. <div>
  48. <div data-testid="project-selector-trigger">{renderTrigger?.({})}</div>
  49. <div data-testid="project-selector-row">{renderRow?.(mockSelectorProject())}</div>
  50. </div>
  51. ),
  52. }))
  53. vi.mock('@/components/ui/PartnerIcon', () => ({
  54. default: ({ organization }: { organization: { managed_by: string } }) =>
  55. organization.managed_by === MANAGED_BY.BRIVEN ? null : (
  56. <div data-testid="partner-icon" data-managed-by={organization.managed_by} />
  57. ),
  58. }))
  59. describe('ProjectDropdown', () => {
  60. beforeEach(() => {
  61. vi.clearAllMocks()
  62. mockSelectedOrganization.mockReturnValue(
  63. createMockOrganization({
  64. slug: 'briven-org',
  65. managed_by: MANAGED_BY.BRIVEN,
  66. })
  67. )
  68. mockSelectedProject.mockReturnValue({
  69. ref: 'proj_1',
  70. name: 'Hammer',
  71. parentRef: 'proj_1',
  72. parent_project_ref: undefined,
  73. integration_source: 'stripe_projects',
  74. })
  75. mockSelectorProject.mockReturnValue({
  76. ref: 'proj_1',
  77. name: 'Hammer',
  78. status: 'ACTIVE_HEALTHY',
  79. integration_source: 'stripe_projects',
  80. })
  81. })
  82. it('uses project detail integration_source for the selected pill and project row data for selector rows', () => {
  83. mockSelectedOrganization.mockReturnValue(
  84. createMockOrganization({
  85. slug: 'stripe-org',
  86. billing_partner: null,
  87. integration_source: 'stripe_projects',
  88. managed_by: MANAGED_BY.STRIPE_PROJECTS,
  89. })
  90. )
  91. render(<ProjectDropdown />)
  92. expect(screen.getAllByTestId('partner-icon')).toHaveLength(2)
  93. })
  94. it('does not fall back to org-level integration state when matching project data is unavailable', () => {
  95. mockSelectedOrganization.mockReturnValue(
  96. createMockOrganization({
  97. slug: 'stripe-org',
  98. billing_partner: null,
  99. integration_source: 'stripe_projects',
  100. managed_by: MANAGED_BY.STRIPE_PROJECTS,
  101. })
  102. )
  103. mockSelectedProject.mockReturnValue({
  104. ref: 'proj_2',
  105. name: 'Mallet',
  106. parentRef: 'proj_2',
  107. parent_project_ref: undefined,
  108. integration_source: null,
  109. })
  110. mockSelectorProject.mockReturnValue({
  111. ref: 'proj_2',
  112. name: 'Mallet',
  113. status: 'ACTIVE_HEALTHY',
  114. integration_source: null,
  115. })
  116. render(<ProjectDropdown />)
  117. expect(screen.queryAllByTestId('partner-icon')).toHaveLength(0)
  118. })
  119. it('falls back to the organization-level state for partner-billed orgs', () => {
  120. mockSelectedOrganization.mockReturnValue(
  121. createMockOrganization({
  122. slug: 'partner-org',
  123. billing_partner: 'vercel_marketplace',
  124. managed_by: MANAGED_BY.VERCEL_MARKETPLACE,
  125. })
  126. )
  127. mockSelectedProject.mockReturnValue({
  128. ref: 'proj_2',
  129. name: 'Mallet',
  130. parentRef: 'proj_2',
  131. parent_project_ref: undefined,
  132. integration_source: null,
  133. })
  134. mockSelectorProject.mockReturnValue({
  135. ref: 'proj_2',
  136. name: 'Mallet',
  137. status: 'ACTIVE_HEALTHY',
  138. integration_source: null,
  139. })
  140. render(<ProjectDropdown />)
  141. expect(screen.getAllByTestId('partner-icon')).toHaveLength(1)
  142. expect(screen.getByTestId('partner-icon')).toHaveAttribute(
  143. 'data-managed-by',
  144. MANAGED_BY.VERCEL_MARKETPLACE
  145. )
  146. })
  147. })