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