1212import { act , type ReactNode , useState } from 'react'
1313import { createRoot , type Root } from 'react-dom/client'
1414import { afterEach , describe , expect , it , vi } from 'vitest'
15+ import { InsideModalContext } from '../modal/modal'
1516import { Combobox } from './combobox'
1617
18+ vi . mock ( 'next/navigation' , ( ) => ( {
19+ usePathname : ( ) => '/workspace/workspace-1/home' ,
20+ } ) )
21+
1722let root : Root | null = null
1823let container : HTMLDivElement | null = null
1924
@@ -42,6 +47,12 @@ function click(node: HTMLElement) {
4247 } )
4348}
4449
50+ function mouseDown ( node : HTMLElement ) {
51+ act ( ( ) => {
52+ node . dispatchEvent ( new MouseEvent ( 'mousedown' , { bubbles : true } ) )
53+ } )
54+ }
55+
4556function press ( node : HTMLElement , key : string ) {
4657 act ( ( ) => {
4758 node . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key, bubbles : true } ) )
@@ -60,6 +71,7 @@ afterEach(() => {
6071 container ?. remove ( )
6172 root = null
6273 container = null
74+ document . body . removeAttribute ( 'style' )
6375 vi . restoreAllMocks ( )
6476} )
6577
@@ -72,6 +84,28 @@ describe('Combobox onOpenChange', () => {
7284 expect ( container ?. querySelector ( '[role="listbox"]' ) ) . not . toBeNull ( )
7385 } )
7486
87+ it ( 'keeps portaled options interactive inside modal content' , ( ) => {
88+ const onChange = vi . fn ( )
89+ render (
90+ < InsideModalContext . Provider value >
91+ < Combobox options = { OPTIONS } onChange = { onChange } />
92+ </ InsideModalContext . Provider >
93+ )
94+
95+ click ( trigger ( ) )
96+
97+ const option = [ ...document . querySelectorAll < HTMLElement > ( '[role="option"]' ) ] . find (
98+ ( { textContent } ) => textContent === 'Alpha'
99+ )
100+ if ( ! option ) throw new Error ( 'Alpha option was not rendered' )
101+ expect ( document . body . style . pointerEvents ) . toBe ( 'none' )
102+ expect ( getComputedStyle ( option ) . pointerEvents ) . toBe ( 'auto' )
103+
104+ mouseDown ( option )
105+
106+ expect ( onChange ) . toHaveBeenCalledWith ( 'alpha' )
107+ } )
108+
75109 it ( 'uses the overlay label for the interactive overflow layer' , ( ) => {
76110 render (
77111 < Combobox
@@ -97,6 +131,7 @@ describe('Combobox onOpenChange', () => {
97131 click ( trigger ( ) )
98132
99133 expect ( onOpenChange ) . toHaveBeenCalledWith ( true )
134+ expect ( document . body . style . pointerEvents ) . toBe ( '' )
100135 } )
101136
102137 it ( 'reports the close a second trigger click causes' , ( ) => {
0 commit comments