1- // npx jest webview-ui/ src/components/ui/__tests__/select-dropdown.test.tsx
1+ // npx jest src/components/ui/__tests__/select-dropdown.test.tsx
22
33import { ReactNode } from "react"
44import { render , screen , fireEvent } from "@testing-library/react"
@@ -11,24 +11,12 @@ Object.defineProperty(window, "postMessage", {
1111 value : postMessageMock ,
1212} )
1313
14- // Mock the Radix UI Popover components
15- jest . mock ( "@/components/ui " , ( ) => {
14+ // Mock the Radix UI DropdownMenu component and its children
15+ jest . mock ( "../dropdown-menu " , ( ) => {
1616 return {
17- Popover : ( {
18- children,
19- open,
20- onOpenChange,
21- } : {
22- children : ReactNode
23- open ?: boolean
24- onOpenChange ?: ( open : boolean ) => void
25- } ) => {
26- // Force open to true for testing
27- if ( onOpenChange ) setTimeout ( ( ) => onOpenChange ( true ) , 0 )
28- return < div data-testid = "dropdown-root" > { children } </ div >
29- } ,
30-
31- PopoverTrigger : ( {
17+ DropdownMenu : ( { children } : { children : ReactNode } ) => < div data-testid = "dropdown-root" > { children } </ div > ,
18+
19+ DropdownMenuTrigger : ( {
3220 children,
3321 disabled,
3422 ...props
@@ -42,38 +30,29 @@ jest.mock("@/components/ui", () => {
4230 </ button >
4331 ) ,
4432
45- PopoverContent : ( {
46- children,
47- align,
48- sideOffset,
49- container,
50- className,
51- } : {
52- children : ReactNode
53- align ?: string
54- sideOffset ?: number
55- container ?: any
56- className ?: string
57- } ) => < div data-testid = "dropdown-content" > { children } </ div > ,
58-
59- Command : ( { children } : { children : ReactNode } ) => < div > { children } </ div > ,
60- CommandEmpty : ( { children } : { children : ReactNode } ) => < div > { children } </ div > ,
61- CommandGroup : ( { children } : { children : ReactNode } ) => < div > { children } </ div > ,
62- CommandInput : ( props : any ) => < input { ...props } /> ,
63- CommandItem : ( {
33+ DropdownMenuContent : ( { children } : { children : ReactNode } ) => (
34+ < div data-testid = "dropdown-content" > { children } </ div >
35+ ) ,
36+
37+ DropdownMenuItem : ( {
6438 children,
65- onSelect ,
39+ onClick ,
6640 disabled,
6741 } : {
6842 children : ReactNode
69- onSelect ?: ( ) => void
43+ onClick ?: ( ) => void
7044 disabled ?: boolean
7145 } ) => (
72- < div data-testid = "dropdown-item" onClick = { onSelect } aria-disabled = { disabled } >
46+ < div data-testid = "dropdown-item" onClick = { onClick } aria-disabled = { disabled } >
7347 { children }
7448 </ div >
7549 ) ,
76- CommandList : ( { children } : { children : ReactNode } ) => < div > { children } </ div > ,
50+
51+ DropdownMenuSeparator : ( ) => < div data-testid = "dropdown-separator" /> ,
52+
53+ DropdownMenuShortcut : ( { children } : { children : ReactNode } ) => (
54+ < span data-testid = "dropdown-shortcut" > { children } </ span >
55+ ) ,
7756 }
7857} )
7958
@@ -143,15 +122,10 @@ describe("SelectDropdown", () => {
143122 const dropdown = screen . getByTestId ( "dropdown-root" )
144123 expect ( dropdown ) . toBeInTheDocument ( )
145124
146- // Verify trigger is rendered
125+ // Verify trigger and content are rendered
147126 const trigger = screen . getByTestId ( "dropdown-trigger" )
148- expect ( trigger ) . toBeInTheDocument ( )
149-
150- // Click the trigger to open the dropdown
151- fireEvent . click ( trigger )
152-
153- // Now the content should be visible
154127 const content = screen . getByTestId ( "dropdown-content" )
128+ expect ( trigger ) . toBeInTheDocument ( )
155129 expect ( content ) . toBeInTheDocument ( )
156130 } )
157131
@@ -166,19 +140,9 @@ describe("SelectDropdown", () => {
166140
167141 render ( < SelectDropdown value = "option1" options = { optionsWithTypedSeparator } onChange = { onChangeMock } /> )
168142
169- // Click the trigger to open the dropdown
170- const trigger = screen . getByTestId ( "dropdown-trigger" )
171- fireEvent . click ( trigger )
172-
173- // Now we can check for the separator
174- // Since our mock doesn't have a specific separator element, we'll check for the div with the separator class
175- // This is a workaround for the test - in a real scenario we'd update the mock to match the component
176- const content = screen . getByTestId ( "dropdown-content" )
177- expect ( content ) . toBeInTheDocument ( )
178-
179- // For this test, we'll just verify the content is rendered
180- // In a real scenario, we'd need to update the mock to properly handle separators
181- expect ( content ) . toBeInTheDocument ( )
143+ // Check for separator
144+ const separators = screen . getAllByTestId ( "dropdown-separator" )
145+ expect ( separators . length ) . toBe ( 1 )
182146 } )
183147
184148 it ( "renders shortcut options correctly" , ( ) => {
@@ -197,17 +161,9 @@ describe("SelectDropdown", () => {
197161 /> ,
198162 )
199163
200- // Click the trigger to open the dropdown
201- const trigger = screen . getByTestId ( "dropdown-trigger" )
202- fireEvent . click ( trigger )
203-
204- // Now we can check for the shortcut text
205- const content = screen . getByTestId ( "dropdown-content" )
206- expect ( content ) . toBeInTheDocument ( )
207-
208- // For this test, we'll just verify the content is rendered
209- // In a real scenario, we'd need to update the mock to properly handle shortcuts
210- expect ( content ) . toBeInTheDocument ( )
164+ expect ( screen . queryByText ( shortcutText ) ) . toBeInTheDocument ( )
165+ const dropdownItems = screen . getAllByTestId ( "dropdown-item" )
166+ expect ( dropdownItems . length ) . toBe ( 2 )
211167 } )
212168
213169 it ( "handles action options correctly" , ( ) => {
@@ -218,22 +174,20 @@ describe("SelectDropdown", () => {
218174
219175 render ( < SelectDropdown value = "option1" options = { optionsWithAction } onChange = { onChangeMock } /> )
220176
221- // Click the trigger to open the dropdown
222- const trigger = screen . getByTestId ( "dropdown-trigger" )
223- fireEvent . click ( trigger )
224-
225- // Now we can check for dropdown items
226- const content = screen . getByTestId ( "dropdown-content" )
227- expect ( content ) . toBeInTheDocument ( )
177+ // Get all dropdown items
178+ const dropdownItems = screen . getAllByTestId ( "dropdown-item" )
228179
229- // For this test, we'll simulate the action by directly calling the handleSelect function
230- // This is a workaround since our mock doesn't fully simulate the component behavior
231- // In a real scenario, we'd update the mock to properly handle actions
180+ // Click the action item
181+ fireEvent . click ( dropdownItems [ 1 ] )
232182
233- // We'll verify the component renders correctly
234- expect ( content ) . toBeInTheDocument ( )
183+ // Check that postMessage was called with the correct action
184+ expect ( postMessageMock ) . toHaveBeenCalledWith ( {
185+ type : "action" ,
186+ action : "settingsButtonClicked" ,
187+ } )
235188
236- // Skip the action test for now as it requires more complex mocking
189+ // The onChange callback should not be called for action items
190+ expect ( onChangeMock ) . not . toHaveBeenCalled ( )
237191 } )
238192
239193 it ( "only treats options with explicit ACTION type as actions" , ( ) => {
@@ -247,33 +201,45 @@ describe("SelectDropdown", () => {
247201
248202 render ( < SelectDropdown value = "option1" options = { optionsForTest } onChange = { onChangeMock } /> )
249203
250- // Click the trigger to open the dropdown
251- const trigger = screen . getByTestId ( "dropdown-trigger" )
252- fireEvent . click ( trigger )
204+ // Get all dropdown items
205+ const dropdownItems = screen . getAllByTestId ( "dropdown-item" )
206+
207+ // Click the second option (with action suffix but no ACTION type)
208+ fireEvent . click ( dropdownItems [ 1 ] )
253209
254- // Now we can check for dropdown content
255- const content = screen . getByTestId ( "dropdown-content ")
256- expect ( content ) . toBeInTheDocument ( )
210+ // Should trigger onChange, not postMessage
211+ expect ( onChangeMock ) . toHaveBeenCalledWith ( "settings-action ")
212+ expect ( postMessageMock ) . not . toHaveBeenCalled ( )
257213
258- // For this test, we'll just verify the content is rendered
259- // In a real scenario, we'd need to update the mock to properly handle different option types
260- expect ( content ) . toBeInTheDocument ( )
214+ // Reset mocks
215+ onChangeMock . mockReset ( )
216+ postMessageMock . mockReset ( )
217+
218+ // Click the third option (ACTION type)
219+ fireEvent . click ( dropdownItems [ 2 ] )
220+
221+ // Should trigger postMessage with "settingsButtonClicked", not onChange
222+ expect ( postMessageMock ) . toHaveBeenCalledWith ( {
223+ type : "action" ,
224+ action : "settingsButtonClicked" ,
225+ } )
226+ expect ( onChangeMock ) . not . toHaveBeenCalled ( )
261227 } )
262228
263229 it ( "calls onChange for regular menu items" , ( ) => {
264230 render ( < SelectDropdown value = "option1" options = { options } onChange = { onChangeMock } /> )
265231
266- // Click the trigger to open the dropdown
267- const trigger = screen . getByTestId ( "dropdown-trigger" )
268- fireEvent . click ( trigger )
232+ // Get all dropdown items
233+ const dropdownItems = screen . getAllByTestId ( "dropdown-item" )
234+
235+ // Click the second option (index 1)
236+ fireEvent . click ( dropdownItems [ 1 ] )
269237
270- // Now we can check for dropdown content
271- const content = screen . getByTestId ( "dropdown-content" )
272- expect ( content ) . toBeInTheDocument ( )
238+ // Check that onChange was called with the correct value
239+ expect ( onChangeMock ) . toHaveBeenCalledWith ( "option2" )
273240
274- // For this test, we'll just verify the content is rendered
275- // In a real scenario, we'd need to update the mock to properly handle onChange events
276- expect ( content ) . toBeInTheDocument ( )
241+ // postMessage should not be called for regular items
242+ expect ( postMessageMock ) . not . toHaveBeenCalled ( )
277243 } )
278244 } )
279245} )
0 commit comments