AdvisorButton.test.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import { screen } from '@testing-library/react'
  2. import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
  3. import { AdvisorButton } from '@/components/layouts/AppLayout/AdvisorButton'
  4. import { render } from '@/tests/helpers'
  5. const {
  6. mockUseProjectLintsQuery,
  7. mockUseNotificationsV2Query,
  8. mockUseAdvisorSignals,
  9. mockToggleSidebar,
  10. } = vi.hoisted(() => ({
  11. mockUseProjectLintsQuery: vi.fn(),
  12. mockUseNotificationsV2Query: vi.fn(),
  13. mockUseAdvisorSignals: vi.fn(),
  14. mockToggleSidebar: vi.fn(),
  15. }))
  16. vi.mock('@/data/lint/lint-query', () => ({
  17. useProjectLintsQuery: mockUseProjectLintsQuery,
  18. }))
  19. vi.mock('@/data/notifications/notifications-v2-query', () => ({
  20. useNotificationsV2Query: mockUseNotificationsV2Query,
  21. }))
  22. vi.mock('@/components/ui/AdvisorPanel/useAdvisorSignals', () => ({
  23. useAdvisorSignals: mockUseAdvisorSignals,
  24. }))
  25. vi.mock('@/lib/constants', async (importOriginal) => ({
  26. ...(await importOriginal<typeof import('@/lib/constants')>()),
  27. IS_PLATFORM: true,
  28. }))
  29. vi.mock('@/state/sidebar-manager-state', () => ({
  30. useSidebarManagerSnapshot: () => ({
  31. toggleSidebar: mockToggleSidebar,
  32. activeSidebar: undefined,
  33. }),
  34. }))
  35. describe('AdvisorButton', () => {
  36. beforeEach(() => {
  37. mockUseProjectLintsQuery.mockReturnValue({ data: [], isPending: false, isError: false })
  38. mockUseNotificationsV2Query.mockReturnValue({
  39. data: { pages: [[]] },
  40. isPending: false,
  41. isError: false,
  42. })
  43. mockUseAdvisorSignals.mockReturnValue({
  44. data: [],
  45. isPending: false,
  46. isError: false,
  47. dismissSignal: vi.fn(),
  48. })
  49. })
  50. afterEach(() => {
  51. vi.clearAllMocks()
  52. })
  53. it('shows a warning dot when advisor signals are present', () => {
  54. mockUseAdvisorSignals.mockReturnValue({
  55. data: [
  56. {
  57. id: 'signal-1',
  58. fingerprint: 'signal:banned-ip:203.0.113.10:v1',
  59. source: 'signal',
  60. signalType: 'banned-ip',
  61. severity: 'warning',
  62. tab: 'security',
  63. title: 'Banned IP address',
  64. description: 'Signal',
  65. actions: [],
  66. sourceData: {
  67. type: 'banned-ip',
  68. ip: '203.0.113.10',
  69. },
  70. },
  71. ],
  72. isPending: false,
  73. isError: false,
  74. dismissSignal: vi.fn(),
  75. })
  76. const { container } = render(<AdvisorButton projectRef="project-ref" />)
  77. expect(container.querySelector('.bg-warning')).toBeInTheDocument()
  78. expect(container.querySelector('.bg-destructive')).not.toBeInTheDocument()
  79. expect(container.querySelector('.bg-brand')).not.toBeInTheDocument()
  80. })
  81. it('keeps the destructive dot when a critical issue is present', () => {
  82. mockUseProjectLintsQuery.mockReturnValue({
  83. data: [
  84. {
  85. cache_key: 'lint-1',
  86. name: 'unknown_lint',
  87. detail: 'Critical lint detail',
  88. description: 'Description',
  89. level: 'ERROR',
  90. categories: ['SECURITY'],
  91. metadata: {},
  92. },
  93. ],
  94. isPending: false,
  95. isError: false,
  96. })
  97. mockUseAdvisorSignals.mockReturnValue({
  98. data: [
  99. {
  100. id: 'signal-1',
  101. fingerprint: 'signal:banned-ip:203.0.113.10:v1',
  102. source: 'signal',
  103. signalType: 'banned-ip',
  104. severity: 'warning',
  105. tab: 'security',
  106. title: 'Banned IP address',
  107. description: 'Signal',
  108. actions: [],
  109. sourceData: {
  110. type: 'banned-ip',
  111. ip: '203.0.113.10',
  112. },
  113. },
  114. ],
  115. isPending: false,
  116. isError: false,
  117. dismissSignal: vi.fn(),
  118. })
  119. const { container } = render(<AdvisorButton projectRef="project-ref" />)
  120. expect(container.querySelector('.bg-destructive')).toBeInTheDocument()
  121. expect(container.querySelector('.bg-warning')).not.toBeInTheDocument()
  122. })
  123. it('falls back to the brand dot for unread notifications when there are no issues', () => {
  124. mockUseNotificationsV2Query.mockReturnValue({
  125. data: {
  126. pages: [
  127. [
  128. {
  129. id: 'notif-1',
  130. status: 'new',
  131. priority: 'Info',
  132. },
  133. ],
  134. ],
  135. },
  136. isPending: false,
  137. isError: false,
  138. })
  139. const { container } = render(<AdvisorButton projectRef="project-ref" />)
  140. expect(container.querySelector('.bg-brand')).toBeInTheDocument()
  141. expect(container.querySelector('.bg-warning')).not.toBeInTheDocument()
  142. expect(container.querySelector('.bg-destructive')).not.toBeInTheDocument()
  143. expect(screen.getByRole('button')).toBeInTheDocument()
  144. })
  145. })