Skip to content

Commit c3a00c5

Browse files
committed
Fix: enhance listbox retrieval and validation in select stories
Updated the select stories to include a timeout when retrieving the listbox role, ensuring that the dropdown has fully opened before interaction. Added assertions to verify the presence of specific options, improving test reliability and reducing flakiness across multiple story scenarios.
1 parent 3a4ae4c commit c3a00c5

File tree

1 file changed

+54
-13
lines changed

1 file changed

+54
-13
lines changed

apps/docs/src/remix-hook-form/select.stories.tsx

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,13 @@ export const USStateSelection: Story = {
273273
const stateSelect = canvas.getByLabelText('US State');
274274
await userEvent.click(stateSelect);
275275

276-
// Dropdown content renders in a portal; query via document.body roles
277-
const listbox = await within(document.body).findByRole('listbox');
276+
// Wait for the dropdown to open and find the listbox with timeout
277+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
278+
expect(listbox).toBeInTheDocument();
279+
280+
// Find and click the California option
278281
const californiaOption = within(listbox).getByRole('option', { name: 'California' });
282+
expect(californiaOption).toBeInTheDocument();
279283
await userEvent.click(californiaOption);
280284

281285
// Wait for the trigger text to update after portal selection
@@ -301,9 +305,13 @@ export const CanadaProvinceSelection: Story = {
301305
const provinceSelect = canvas.getByLabelText('Canadian Province');
302306
await userEvent.click(provinceSelect);
303307

304-
// Query in portal content by role
305-
const listbox = await within(document.body).findByRole('listbox');
308+
// Wait for the dropdown to open and find the listbox with timeout
309+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
310+
expect(listbox).toBeInTheDocument();
311+
312+
// Find and click the Ontario option
306313
const ontarioOption = within(listbox).getByRole('option', { name: 'Ontario' });
314+
expect(ontarioOption).toBeInTheDocument();
307315
await userEvent.click(ontarioOption);
308316

309317
// Wait for the trigger text to update after portal selection
@@ -329,26 +337,32 @@ export const FormSubmission: Story = {
329337
const stateSelect = canvas.getByLabelText('US State');
330338
await userEvent.click(stateSelect);
331339
{
332-
const listbox = await within(document.body).findByRole('listbox');
340+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
341+
expect(listbox).toBeInTheDocument();
333342
const californiaOption = within(listbox).getByRole('option', { name: 'California' });
343+
expect(californiaOption).toBeInTheDocument();
334344
await userEvent.click(californiaOption);
335345
}
336346

337347
// Select a province
338348
const provinceSelect = canvas.getByLabelText('Canadian Province');
339349
await userEvent.click(provinceSelect);
340350
{
341-
const listbox = await within(document.body).findByRole('listbox');
351+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
352+
expect(listbox).toBeInTheDocument();
342353
const ontarioOption = within(listbox).getByRole('option', { name: 'Ontario' });
354+
expect(ontarioOption).toBeInTheDocument();
343355
await userEvent.click(ontarioOption);
344356
}
345357

346358
// Select a custom region
347359
const regionSelect = canvas.getByLabelText('Custom Region');
348360
await userEvent.click(regionSelect);
349361
{
350-
const listbox = await within(document.body).findByRole('listbox');
362+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
363+
expect(listbox).toBeInTheDocument();
351364
const customOption = within(listbox).getByRole('option', { name: 'California' });
365+
expect(customOption).toBeInTheDocument();
352366
await userEvent.click(customOption);
353367
}
354368
});
@@ -407,8 +421,14 @@ export const SearchDisabled: Story = {
407421
await step('Open select and ensure no search input', async () => {
408422
const regionSelect = canvas.getByLabelText('Custom Region');
409423
await userEvent.click(regionSelect);
410-
const listbox = await within(document.body).findByRole('listbox');
411-
expect(within(listbox).queryByPlaceholderText('Search...')).not.toBeInTheDocument();
424+
425+
// Wait for the dropdown to open
426+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
427+
expect(listbox).toBeInTheDocument();
428+
429+
// Verify no search input is present when searchable is disabled
430+
const searchInput = within(listbox).queryByPlaceholderText('Search...');
431+
expect(searchInput).not.toBeInTheDocument();
412432
});
413433
},
414434
};
@@ -454,8 +474,9 @@ export const CustomSearchPlaceholder: Story = {
454474
await step('Open select and see custom placeholder', async () => {
455475
const regionSelect = canvas.getByLabelText('Custom Region');
456476
await userEvent.click(regionSelect);
477+
457478
// The search input is rendered alongside the listbox in the portal, not inside the listbox itself.
458-
const searchInput = await within(document.body).findByPlaceholderText('Type to filter…');
479+
const searchInput = await within(document.body).findByPlaceholderText('Type to filter…', {}, { timeout: 5000 });
459480
expect(searchInput).toBeInTheDocument();
460481
});
461482
},
@@ -512,17 +533,28 @@ export const CreatableOption: Story = {
512533
const regionSelect = await canvas.findByLabelText('Custom Region');
513534
await userEvent.click(regionSelect);
514535

515-
// Wait for the dropdown to open and find the listbox
536+
// Wait for the dropdown to open and find the listbox with more specific timeout and error handling
516537
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
538+
539+
// Verify the listbox is properly rendered
540+
expect(listbox).toBeInTheDocument();
541+
expect(listbox).toHaveAttribute('role', 'listbox');
542+
517543
// The search input is outside the listbox container; query from the portal root
518544
const input = await within(document.body).findByPlaceholderText('Search...');
545+
expect(input).toBeInTheDocument();
546+
519547
await userEvent.click(input);
520548
await userEvent.clear(input);
521549
await userEvent.type(input, 'Atlantis');
522550

523-
const createItem = await within(listbox).findByRole('option', { name: 'Select "Atlantis"' });
551+
// Wait for the creatable option to appear
552+
const createItem = await within(listbox).findByRole('option', { name: 'Select "Atlantis"' }, { timeout: 2000 });
553+
expect(createItem).toBeInTheDocument();
554+
524555
await userEvent.click(createItem);
525556

557+
// Verify the selection was applied
526558
await expect(canvas.findByRole('combobox', { name: 'Custom Region' })).resolves.toHaveTextContent('Atlantis');
527559

528560
// Submit and verify server received the created option value
@@ -538,13 +570,22 @@ export const CreatableOption: Story = {
538570

539571
// Wait for the dropdown to open and find the listbox
540572
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
573+
expect(listbox).toBeInTheDocument();
574+
541575
// The search input is outside the listbox container; query from the portal root
542576
const input = await within(document.body).findByPlaceholderText('Search...');
577+
expect(input).toBeInTheDocument();
578+
543579
await userEvent.click(input);
544580
await userEvent.clear(input);
545581
await userEvent.type(input, 'California');
546582

547-
expect(within(listbox).queryByRole('option', { name: 'Select "California"' })).not.toBeInTheDocument();
583+
// Verify no creatable option appears when exact match exists
584+
const createOption = within(listbox).queryByRole('option', { name: 'Select "California"' });
585+
expect(createOption).not.toBeInTheDocument();
586+
587+
// Close the dropdown
588+
await userEvent.click(regionSelect);
548589
});
549590
},
550591
};

0 commit comments

Comments
 (0)