@@ -117,19 +117,18 @@ QUnit.module('typesense-minibar', hooks => {
117
117
mockFetchResponse = null ;
118
118
} ) ;
119
119
120
- let renderDone ;
121
- async function expectRender ( cb ) {
120
+ async function expectRender ( targetElement , cb ) {
121
+ let renderDone ;
122
122
const promise = new Promise ( resolve => { renderDone = resolve ; } ) ;
123
+ const observer = new MutationObserver ( ( ) => {
124
+ renderDone ( ) ;
125
+ } ) ;
126
+ observer . observe ( targetElement , { attributes : true , childList : true , subtree : true } ) ;
123
127
cb ( ) ;
128
+ await new Promise ( resolve => setTimeout ( resolve ) ) ;
129
+ observer . disconnect ( ) ;
124
130
return await promise ;
125
131
}
126
- hooks . before ( ( ) => {
127
- const renderSuper = TypesenseMinibar . prototype . render ;
128
- TypesenseMinibar . prototype . render = function ( ) {
129
- renderSuper . call ( this ) ;
130
- renderDone ( ) ;
131
- } ;
132
- } ) ;
133
132
134
133
let bar ;
135
134
hooks . afterEach ( ( ) => {
@@ -141,15 +140,15 @@ QUnit.module('typesense-minibar', hooks => {
141
140
document . head . querySelectorAll ( 'link[rel=preconnect]' ) . forEach ( link => link . remove ( ) ) ;
142
141
} ) ;
143
142
144
- QUnit . test ( 'TypesenseMinibar constructor [fail without input element]' , assert => {
143
+ QUnit . test ( 'init [fail without input element]' , assert => {
145
144
const form = parseHTML ( '<form>' ) ;
146
145
147
146
assert . throws ( ( ) => {
148
- bar = new TypesenseMinibar ( form ) ;
147
+ bar = tsminibar ( form ) ;
149
148
} , TypeError ) ;
150
149
} ) ;
151
150
152
- QUnit . test . each ( 'TypesenseMinibar input' , {
151
+ QUnit . test . each ( 'input' , {
153
152
'no results' : {
154
153
value : 'something' ,
155
154
resp : API_RESP_EMPTY ,
@@ -183,96 +182,101 @@ QUnit.module('typesense-minibar', hooks => {
183
182
} , async ( assert , { value, resp, expect } ) => {
184
183
const form = parseHTML ( '<form><input type="search"></form>' ) ;
185
184
const input = form . firstChild ;
186
- const bar = new TypesenseMinibar ( form ) ;
185
+ bar = tsminibar ( form ) ;
186
+ const listbox = form . querySelector ( '[role=listbox]' ) ;
187
187
188
188
mockFetchResponse = resp ;
189
189
input . value = value ;
190
- await expectRender ( ( ) => {
190
+ await expectRender ( form , ( ) => {
191
191
simulate ( input , 'input' ) ;
192
192
} ) ;
193
193
194
- assert . equal ( normalizeHTML ( bar . listbox . innerHTML ) , normalizeHTML ( expect ) , 'listbox HTML' ) ;
194
+ assert . equal ( normalizeHTML ( listbox . innerHTML ) , normalizeHTML ( expect ) , 'listbox HTML' ) ;
195
195
} ) ;
196
196
197
- QUnit . test ( 'TypesenseMinibar input [memory cache hit]' , async assert => {
197
+ QUnit . test ( 'input [memory cache hit]' , async assert => {
198
198
const form = parseHTML ( '<form><input type="search"></form>' ) ;
199
199
const input = form . firstChild ;
200
- const bar = new TypesenseMinibar ( form ) ;
200
+ bar = tsminibar ( form ) ;
201
+ const listbox = form . querySelector ( '[role=listbox]' ) ;
201
202
202
203
mockFetchResponse = API_RESP_FULL_MATCH_SOME ;
203
204
input . value = 'some' ;
204
- await expectRender ( ( ) => {
205
+ await expectRender ( form , ( ) => {
205
206
simulate ( input , 'input' ) ;
206
207
} ) ;
207
- assert . equal ( bar . listbox . querySelector ( '.tsmb-suggestion_title' ) . textContent , 'Some' , 'result 1' ) ;
208
+ assert . equal ( listbox . querySelector ( '.tsmb-suggestion_title' ) . textContent , 'Some' , 'result 1' ) ;
208
209
209
210
mockFetchResponse = API_RESP_FULL_MATCH_SOMETHING ;
210
211
input . value = 'something' ;
211
- await expectRender ( ( ) => {
212
+ await expectRender ( form , ( ) => {
212
213
simulate ( input , 'input' ) ;
213
214
} ) ;
214
- assert . equal ( bar . listbox . querySelector ( '.tsmb-suggestion_title' ) . textContent , 'Some › Thing' , 'result 2' ) ;
215
+ assert . equal ( listbox . querySelector ( '.tsmb-suggestion_title' ) . textContent , 'Some › Thing' , 'result 2' ) ;
215
216
216
217
// expect cache hit, no fetch
217
218
mockFetchResponse = null ;
218
219
input . value = 'some' ;
219
- await expectRender ( ( ) => {
220
+ await expectRender ( form , ( ) => {
220
221
simulate ( input , 'input' ) ;
221
222
} ) ;
222
- assert . equal ( bar . listbox . querySelector ( '.tsmb-suggestion_title' ) . textContent , 'Some' , 'result 3' ) ;
223
+ assert . equal ( listbox . querySelector ( '.tsmb-suggestion_title' ) . textContent , 'Some' , 'result 3' ) ;
223
224
} ) ;
224
225
225
- QUnit . test ( 'TypesenseMinibar listbox [close on empty string or backspace]' , async assert => {
226
+ QUnit . test ( 'listbox [close on empty string or backspace]' , async assert => {
226
227
const form = parseHTML ( '<form><input type="search"></form>' ) ;
227
228
const input = form . firstChild ;
228
- const bar = new TypesenseMinibar ( form ) ;
229
+ bar = tsminibar ( form ) ;
230
+ const listbox = form . querySelector ( '[role=listbox]' ) ;
229
231
230
232
mockFetchResponse = API_RESP_FULL_MATCH_SOMETHING ;
231
233
input . value = 'something' ;
232
- await expectRender ( ( ) => {
234
+ await expectRender ( form , ( ) => {
233
235
simulate ( input , 'input' ) ;
234
236
} ) ;
235
- assert . false ( bar . listbox . hidden , 'listbox not hidden' ) ;
237
+ assert . false ( listbox . hidden , 'listbox not hidden' ) ;
236
238
237
239
mockFetchResponse = null ; // expect no fetch request for empty query
238
240
input . value = '' ;
239
241
simulate ( input , 'input' ) ;
240
242
241
- assert . true ( bar . listbox . hidden , 'listbox hidden' ) ;
243
+ assert . true ( listbox . hidden , 'listbox hidden' ) ;
242
244
} ) ;
243
245
244
- QUnit . test ( 'TypesenseMinibar listbox [close on Esc]' , async assert => {
246
+ QUnit . test ( 'listbox [close on Esc]' , async assert => {
245
247
const form = parseHTML ( '<form><input type="search"></form>' ) ;
246
248
const input = form . firstChild ;
247
- const bar = new TypesenseMinibar ( form ) ;
249
+ bar = tsminibar ( form ) ;
250
+ const listbox = form . querySelector ( '[role=listbox]' ) ;
248
251
249
252
mockFetchResponse = API_RESP_FULL_MATCH_SOMETHING ;
250
253
input . value = 'something' ;
251
- await expectRender ( ( ) => {
254
+ await expectRender ( form , ( ) => {
252
255
simulate ( input , 'input' ) ;
253
256
} ) ;
254
- assert . false ( bar . listbox . hidden , 'listbox not hidden' ) ;
255
- assert . equal ( bar . listbox . querySelector ( 'mark' ) . outerHTML , '<mark>something</mark>' , 'snippet' ) ;
257
+ assert . false ( listbox . hidden , 'listbox not hidden' ) ;
258
+ assert . equal ( listbox . querySelector ( 'mark' ) . outerHTML , '<mark>something</mark>' , 'snippet' ) ;
256
259
257
260
mockFetchResponse = null ;
258
261
simulate ( input , 'keydown' , { code : 'Escape' } ) ;
259
262
260
- assert . true ( bar . listbox . hidden , 'listbox hidden' ) ;
263
+ assert . true ( listbox . hidden , 'listbox hidden' ) ;
261
264
} ) ;
262
265
263
- QUnit . test ( 'TypesenseMinibar listbox [arrow key cursor]' , async assert => {
266
+ QUnit . test ( 'listbox [arrow key cursor]' , async assert => {
264
267
const form = parseHTML ( '<form><input type="search"></form>' ) ;
265
268
const input = form . firstChild ;
266
- const bar = new TypesenseMinibar ( form ) ;
269
+ bar = tsminibar ( form ) ;
270
+ const listbox = form . querySelector ( '[role=listbox]' ) ;
267
271
268
272
mockFetchResponse = API_RESP_MULTIPLE ;
269
273
input . value = 'tv' ;
270
- await expectRender ( ( ) => {
274
+ await expectRender ( form , ( ) => {
271
275
simulate ( input , 'input' ) ;
272
276
} ) ;
273
- assert . false ( bar . listbox . hidden , 'listbox not hidden' ) ;
277
+ assert . false ( listbox . hidden , 'listbox not hidden' ) ;
274
278
assert . equal (
275
- normalizeHTML ( bar . listbox . outerHTML ) ,
279
+ normalizeHTML ( listbox . outerHTML ) ,
276
280
normalizeHTML ( `<div role="listbox">
277
281
<div role="option"><a href="https://example.test/a" tabindex="-1"><div class="tsmb-suggestion_title">Person</div><div class="tsmb-suggestion_content"></div></a></div>
278
282
<div role="option"><a href="https://example.test/b" tabindex="-1"><div class="tsmb-suggestion_title">Woman</div><div class="tsmb-suggestion_content"></div></a></div>
@@ -281,11 +285,11 @@ QUnit.module('typesense-minibar', hooks => {
281
285
'initial result'
282
286
) ;
283
287
284
- await expectRender ( ( ) => {
288
+ await expectRender ( form , ( ) => {
285
289
simulate ( input , 'keydown' , { code : 'ArrowDown' } ) ; // -1 to 0
286
290
} ) ;
287
291
assert . equal (
288
- normalizeHTML ( bar . listbox . outerHTML ) ,
292
+ normalizeHTML ( listbox . outerHTML ) ,
289
293
normalizeHTML ( `<div role="listbox">
290
294
<div role="option" aria-selected="true"><a href="https://example.test/a" tabindex="-1"><div class="tsmb-suggestion_title">Person</div><div class="tsmb-suggestion_content"></div></a></div>
291
295
<div role="option"><a href="https://example.test/b" tabindex="-1"><div class="tsmb-suggestion_title">Woman</div><div class="tsmb-suggestion_content"></div></a></div>
@@ -296,11 +300,11 @@ QUnit.module('typesense-minibar', hooks => {
296
300
297
301
simulate ( input , 'keydown' , { code : 'ArrowDown' } ) ; // 0 to 1
298
302
simulate ( input , 'keydown' , { code : 'ArrowDown' } ) ; // 1 to 2
299
- await expectRender ( ( ) => {
303
+ await expectRender ( form , ( ) => {
300
304
simulate ( input , 'keydown' , { code : 'ArrowDown' } ) ; // 2 to -1
301
305
} ) ;
302
306
assert . equal (
303
- normalizeHTML ( bar . listbox . outerHTML ) ,
307
+ normalizeHTML ( listbox . outerHTML ) ,
304
308
normalizeHTML ( `<div role="listbox">
305
309
<div role="option"><a href="https://example.test/a" tabindex="-1"><div class="tsmb-suggestion_title">Person</div><div class="tsmb-suggestion_content"></div></a></div>
306
310
<div role="option"><a href="https://example.test/b" tabindex="-1"><div class="tsmb-suggestion_title">Woman</div><div class="tsmb-suggestion_content"></div></a></div>
@@ -310,11 +314,11 @@ QUnit.module('typesense-minibar', hooks => {
310
314
) ;
311
315
312
316
simulate ( input , 'keydown' , { code : 'ArrowUp' } ) ; // -1 to 2 (wrap around)
313
- await expectRender ( ( ) => {
317
+ await expectRender ( form , ( ) => {
314
318
simulate ( input , 'keydown' , { code : 'ArrowUp' } ) ; // 2 to 1
315
319
} ) ;
316
320
assert . equal (
317
- normalizeHTML ( bar . listbox . outerHTML ) ,
321
+ normalizeHTML ( listbox . outerHTML ) ,
318
322
normalizeHTML ( `<div role="listbox">
319
323
<div role="option"><a href="https://example.test/a" tabindex="-1"><div class="tsmb-suggestion_title">Person</div><div class="tsmb-suggestion_content"></div></a></div>
320
324
<div role="option" aria-selected="true"><a href="https://example.test/b" tabindex="-1"><div class="tsmb-suggestion_title">Woman</div><div class="tsmb-suggestion_content"></div></a></div>
@@ -324,24 +328,24 @@ QUnit.module('typesense-minibar', hooks => {
324
328
) ;
325
329
} ) ;
326
330
327
- QUnit . test ( 'TypesenseMinibar focus [slash]' , async assert => {
331
+ QUnit . test ( 'focus [slash]' , async assert => {
328
332
const form = parseHTML ( '<form><input type="search"></form>' ) ;
329
333
const input = form . firstChild ;
330
334
document . body . append ( form ) ;
331
335
assert . true ( ! document . activeElement || ! form . contains ( document . activeElement ) , 'initial focus' ) ;
332
336
333
- bar = new TypesenseMinibar ( form ) ;
337
+ bar = tsminibar ( form ) ;
334
338
assert . true ( ! document . activeElement || ! form . contains ( document . activeElement ) , 'focus after contruct' ) ;
335
339
336
340
simulate ( document , 'keydown' , { key : '/' } ) ;
337
341
assert . strictEqual ( document . activeElement , input , 'focus after slash' ) ;
338
342
} ) ;
339
343
340
- QUnit . test ( 'TypesenseMinibar focus [preconnect]' , async assert => {
344
+ QUnit . test ( 'focus [preconnect]' , async assert => {
341
345
const form = parseHTML ( '<form><input type="search"></form>' ) ;
342
346
const input = form . firstChild ;
343
347
document . body . append ( form ) ;
344
- bar = new TypesenseMinibar ( form ) ;
348
+ bar = tsminibar ( form ) ;
345
349
346
350
assert . strictEqual ( document . head . querySelectorAll ( 'link[rel=preconnect]' ) . length , 0 , 'initial preconnect' ) ;
347
351
0 commit comments