@@ -169,4 +169,41 @@ describe("Querystring", function () {
169169 global . fetch . mockClear ( ) ;
170170 delete global . fetch ;
171171 } ) ;
172+
173+ it ( "handles a native change event on the index select" , async function ( ) {
174+ // Regression test: pat-select2 re-dispatches a native `change` event in
175+ // addition to the Select2 v3 jQuery `change` event. jQuery's `change`
176+ // handler catches both, so the index handler fires twice — once with
177+ // `e.val` set (Select2) and once with `e.val` undefined (native event).
178+ // The handler must read the value from the element, not from `e.val`,
179+ // otherwise the native invocation passes `undefined` to createOperator
180+ // and throws.
181+ const criterias = await import ( "./test-querystringcriteria.json" ) ;
182+ global . fetch = jest . fn ( ) . mockImplementation ( mockFetch ( criterias ) ) ;
183+
184+ registry . scan ( document . body ) ;
185+ await utils . timeout ( 1 ) ;
186+
187+ // The last criteria row is the empty one a user fills in.
188+ const indexSelects = document . querySelectorAll (
189+ ".querystring-criteria-index select"
190+ ) ;
191+ const $index = $ ( indexSelects [ indexSelects . length - 1 ] ) ;
192+ const wrapper = $index . parents ( ".querystring-criteria-wrapper" ) [ 0 ] ;
193+
194+ // Pick a value and fire ONLY a native change event (no Select2 `val`).
195+ $index . val ( "Title" ) ;
196+ $index [ 0 ] . dispatchEvent ( new Event ( "change" , { bubbles : true } ) ) ;
197+ await utils . timeout ( 1 ) ;
198+
199+ // The operator select must have been built for the selected index.
200+ const operator = wrapper . querySelector (
201+ ".querystring-criteria-operator select"
202+ ) ;
203+ expect ( operator ) . not . toBeNull ( ) ;
204+ expect ( operator . options . length ) . toBeGreaterThan ( 0 ) ;
205+
206+ global . fetch . mockClear ( ) ;
207+ delete global . fetch ;
208+ } ) ;
172209} ) ;
0 commit comments