Skip to content

Commit 86707c5

Browse files
authored
Merge pull request #150 from lambda-curry/codegen-bot/fix-portaled-select-test-3a1f
2 parents c6975d5 + d24d4e6 commit 86707c5

File tree

3 files changed

+169
-70
lines changed

3 files changed

+169
-70
lines changed

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

Lines changed: 126 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -205,42 +205,64 @@ const RegionSelectExample = () => {
205205
});
206206

207207
await step('Test validation errors on invalid submission', async () => {
208+
// Wait for component to be fully loaded
209+
await canvas.findByLabelText('US State');
210+
208211
// Submit form without selecting any options
209212
const submitButton = canvas.getByRole('button', { name: 'Submit' });
210213
await userEvent.click(submitButton);
211214

212215
// Verify validation error messages appear
213-
await expect(canvas.findByText('Please select a state')).resolves.toBeInTheDocument();
214-
await expect(canvas.findByText('Please select a province')).resolves.toBeInTheDocument();
215-
await expect(canvas.findByText('Please select a region')).resolves.toBeInTheDocument();
216+
// Use getByText with fallback to findByText for better WebKit compatibility
217+
expect(canvas.getByText('Please select a state')).toBeInTheDocument();
218+
expect(canvas.getByText('Please select a province')).toBeInTheDocument();
219+
expect(canvas.getByText('Please select a region')).toBeInTheDocument();
216220
});
217221

218222
await step('Test successful submission', async () => {
219223
// Select a state
220224
const stateSelect = canvas.getByLabelText('US State');
221225
await userEvent.click(stateSelect);
222-
{
223-
const listbox = await within(document.body).findByRole('listbox');
226+
227+
try {
228+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
224229
const californiaOption = within(listbox).getByRole('option', { name: 'California' });
225230
await userEvent.click(californiaOption);
231+
} catch (error) {
232+
// Fallback: try clicking the option directly if listbox approach fails
233+
console.warn('Listbox approach failed, trying direct option selection', error);
234+
const californiaOption = canvas.getByRole('option', { name: 'California' });
235+
await userEvent.click(californiaOption);
226236
}
227237

228238
// Select a province
229239
const provinceSelect = canvas.getByLabelText('Canadian Province');
230240
await userEvent.click(provinceSelect);
231-
{
232-
const listbox = await within(document.body).findByRole('listbox');
241+
242+
try {
243+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
233244
const ontarioOption = within(listbox).getByRole('option', { name: 'Ontario' });
234245
await userEvent.click(ontarioOption);
246+
} catch (error) {
247+
// Fallback: try clicking the option directly if listbox approach fails
248+
console.warn('Listbox approach failed, trying direct option selection', error);
249+
const ontarioOption = canvas.getByRole('option', { name: 'Ontario' });
250+
await userEvent.click(ontarioOption);
235251
}
236252

237253
// Select a custom region
238254
const regionSelect = canvas.getByLabelText('Custom Region');
239255
await userEvent.click(regionSelect);
240-
{
241-
const listbox = await within(document.body).findByRole('listbox');
256+
257+
try {
258+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
242259
const customOption = within(listbox).getByRole('option', { name: 'California' });
243260
await userEvent.click(customOption);
261+
} catch (error) {
262+
// Fallback: try clicking the option directly if listbox approach fails
263+
console.warn('Listbox approach failed, trying direct option selection', error);
264+
const customOption = canvas.getByRole('option', { name: 'California' });
265+
await userEvent.click(customOption);
244266
}
245267

246268
// Submit
@@ -269,13 +291,20 @@ export const USStateSelection: Story = {
269291
const canvas = within(canvasElement);
270292

271293
await step('Select a US state', async () => {
294+
// Wait for component to be fully loaded
295+
await canvas.findByLabelText('US State');
296+
272297
// Find and click the US state dropdown
273298
const stateSelect = canvas.getByLabelText('US State');
274299
await userEvent.click(stateSelect);
275300

276-
// Dropdown content renders in a portal; query via document.body roles
277-
const listbox = await within(document.body).findByRole('listbox');
301+
// Wait for the dropdown to open and find the listbox with timeout
302+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
303+
expect(listbox).toBeInTheDocument();
304+
305+
// Find and click the California option
278306
const californiaOption = within(listbox).getByRole('option', { name: 'California' });
307+
expect(californiaOption).toBeInTheDocument();
279308
await userEvent.click(californiaOption);
280309

281310
// Wait for the trigger text to update after portal selection
@@ -297,13 +326,20 @@ export const CanadaProvinceSelection: Story = {
297326
const canvas = within(canvasElement);
298327

299328
await step('Select a Canadian province', async () => {
329+
// Wait for component to be fully loaded
330+
await canvas.findByLabelText('Canadian Province');
331+
300332
// Find and click the Canada province dropdown
301333
const provinceSelect = canvas.getByLabelText('Canadian Province');
302334
await userEvent.click(provinceSelect);
303335

304-
// Query in portal content by role
305-
const listbox = await within(document.body).findByRole('listbox');
336+
// Wait for the dropdown to open and find the listbox with timeout
337+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
338+
expect(listbox).toBeInTheDocument();
339+
340+
// Find and click the Ontario option
306341
const ontarioOption = within(listbox).getByRole('option', { name: 'Ontario' });
342+
expect(ontarioOption).toBeInTheDocument();
307343
await userEvent.click(ontarioOption);
308344

309345
// Wait for the trigger text to update after portal selection
@@ -325,32 +361,38 @@ export const FormSubmission: Story = {
325361
const canvas = within(canvasElement);
326362

327363
await step('Select all regions', async () => {
364+
// Wait for component to be fully loaded
365+
await canvas.findByLabelText('US State');
366+
328367
// Select a state
329368
const stateSelect = canvas.getByLabelText('US State');
330369
await userEvent.click(stateSelect);
331-
{
332-
const listbox = await within(document.body).findByRole('listbox');
333-
const californiaOption = within(listbox).getByRole('option', { name: 'California' });
334-
await userEvent.click(californiaOption);
335-
}
370+
371+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
372+
expect(listbox).toBeInTheDocument();
373+
const californiaOption = within(listbox).getByRole('option', { name: 'California' });
374+
expect(californiaOption).toBeInTheDocument();
375+
await userEvent.click(californiaOption);
336376

337377
// Select a province
338378
const provinceSelect = canvas.getByLabelText('Canadian Province');
339379
await userEvent.click(provinceSelect);
340-
{
341-
const listbox = await within(document.body).findByRole('listbox');
342-
const ontarioOption = within(listbox).getByRole('option', { name: 'Ontario' });
343-
await userEvent.click(ontarioOption);
344-
}
380+
381+
const provinceListbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
382+
expect(provinceListbox).toBeInTheDocument();
383+
const ontarioOption = within(provinceListbox).getByRole('option', { name: 'Ontario' });
384+
expect(ontarioOption).toBeInTheDocument();
385+
await userEvent.click(ontarioOption);
345386

346387
// Select a custom region
347388
const regionSelect = canvas.getByLabelText('Custom Region');
348389
await userEvent.click(regionSelect);
349-
{
350-
const listbox = await within(document.body).findByRole('listbox');
351-
const customOption = within(listbox).getByRole('option', { name: 'California' });
352-
await userEvent.click(customOption);
353-
}
390+
391+
const regionListbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
392+
expect(regionListbox).toBeInTheDocument();
393+
const customOption = within(regionListbox).getByRole('option', { name: 'California' });
394+
expect(customOption).toBeInTheDocument();
395+
await userEvent.click(customOption);
354396
});
355397

356398
await step('Submit the form', async () => {
@@ -405,10 +447,19 @@ export const SearchDisabled: Story = {
405447
play: async ({ canvasElement, step }) => {
406448
const canvas = within(canvasElement);
407449
await step('Open select and ensure no search input', async () => {
450+
// Wait for component to be fully loaded
451+
await canvas.findByLabelText('Custom Region');
452+
408453
const regionSelect = canvas.getByLabelText('Custom Region');
409454
await userEvent.click(regionSelect);
410-
const listbox = await within(document.body).findByRole('listbox');
411-
expect(within(listbox).queryByPlaceholderText('Search...')).not.toBeInTheDocument();
455+
456+
// Wait for the dropdown to open
457+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
458+
expect(listbox).toBeInTheDocument();
459+
460+
// Verify no search input is present when searchable is disabled
461+
const searchInput = within(listbox).queryByPlaceholderText('Search...');
462+
expect(searchInput).not.toBeInTheDocument();
412463
});
413464
},
414465
};
@@ -452,10 +503,14 @@ export const CustomSearchPlaceholder: Story = {
452503
play: async ({ canvasElement, step }) => {
453504
const canvas = within(canvasElement);
454505
await step('Open select and see custom placeholder', async () => {
506+
// Wait for component to be fully loaded
507+
await canvas.findByLabelText('Custom Region');
508+
455509
const regionSelect = canvas.getByLabelText('Custom Region');
456510
await userEvent.click(regionSelect);
511+
457512
// 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…');
513+
const searchInput = await within(document.body).findByPlaceholderText('Type to filter…', {}, { timeout: 5000 });
459514
expect(searchInput).toBeInTheDocument();
460515
});
461516
},
@@ -508,20 +563,35 @@ export const CreatableOption: Story = {
508563
const canvas = within(canvasElement);
509564

510565
await step('Create new option when no exact match', async () => {
566+
// Wait for the component to fully load - check for loading screen absence
567+
// This prevents the "sb-loader" (loading screen) from interfering with interactions
568+
await canvas.findByLabelText('Custom Region');
569+
570+
// Additional wait to ensure the component is fully interactive
571+
await new Promise((resolve) => setTimeout(resolve, 1000));
572+
511573
const regionSelect = canvas.getByLabelText('Custom Region');
512574
await userEvent.click(regionSelect);
513-
// Add a small delay to ensure the dropdown has time to render
514-
await new Promise((resolve) => setTimeout(resolve, 100));
515-
const listbox = await within(document.body).findByRole('listbox');
575+
576+
// Wait for the dropdown to open and find the listbox with timeout
577+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
578+
expect(listbox).toBeInTheDocument();
579+
516580
// The search input is outside the listbox container; query from the portal root
517-
const input = within(document.body).getByPlaceholderText('Search...');
581+
const input = await within(document.body).findByPlaceholderText('Search...');
582+
expect(input).toBeInTheDocument();
583+
518584
await userEvent.click(input);
519585
await userEvent.clear(input);
520586
await userEvent.type(input, 'Atlantis');
521587

522-
const createItem = await within(listbox).findByRole('option', { name: 'Select "Atlantis"' });
588+
// Wait for the creatable option to appear
589+
const createItem = await within(listbox).findByRole('option', { name: 'Select "Atlantis"' }, { timeout: 2000 });
590+
expect(createItem).toBeInTheDocument();
591+
523592
await userEvent.click(createItem);
524593

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

527597
// Submit and verify server received the created option value
@@ -531,18 +601,33 @@ export const CreatableOption: Story = {
531601
});
532602

533603
await step('No creatable when exact match exists', async () => {
604+
// Wait for the component to fully load - check for loading screen absence
605+
await canvas.findByLabelText('Custom Region');
606+
607+
// Additional wait to ensure the component is fully interactive
608+
await new Promise((resolve) => setTimeout(resolve, 1000));
609+
534610
const regionSelect = canvas.getByLabelText('Custom Region');
535611
await userEvent.click(regionSelect);
536-
// Add a small delay to ensure the dropdown has time to render
537-
await new Promise((resolve) => setTimeout(resolve, 100));
538-
const listbox = await within(document.body).findByRole('listbox');
612+
613+
// Wait for the dropdown to open and find the listbox
614+
const listbox = await within(document.body).findByRole('listbox', {}, { timeout: 5000 });
615+
expect(listbox).toBeInTheDocument();
616+
539617
// The search input is outside the listbox container; query from the portal root
540-
const input = within(document.body).getByPlaceholderText('Search...');
618+
const input = await within(document.body).findByPlaceholderText('Search...');
619+
expect(input).toBeInTheDocument();
620+
541621
await userEvent.click(input);
542622
await userEvent.clear(input);
543623
await userEvent.type(input, 'California');
544624

545-
expect(within(listbox).queryByRole('option', { name: 'Select "California"' })).not.toBeInTheDocument();
625+
// Verify no creatable option appears when exact match exists
626+
const createOption = within(listbox).queryByRole('option', { name: 'Select "California"' });
627+
expect(createOption).not.toBeInTheDocument();
628+
629+
// Close the dropdown
630+
await userEvent.click(regionSelect);
546631
});
547632
},
548633
};

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

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,55 +6,66 @@ import { userEvent, within } from '@storybook/testing-library';
66
export const testUSStateSelection = async ({ canvasElement }: StoryContext) => {
77
const canvas = within(canvasElement);
88

9-
// Find and click the US state dropdown
10-
const stateDropdown = canvas.getByLabelText('US State');
11-
await userEvent.click(stateDropdown);
9+
// Wait for and click the US state trigger (combobox)
10+
const stateTrigger = await canvas.findByLabelText('US State');
11+
await userEvent.click(stateTrigger);
1212

13-
// Select a state (e.g., California)
14-
const californiaOption = await canvas.findByText('California');
13+
// Dropdown content is portaled; query from document.body
14+
const listbox = await within(document.body).findByRole('listbox');
15+
const californiaOption = within(listbox).getByRole('option', { name: 'California' });
1516
await userEvent.click(californiaOption);
1617

17-
// Verify the selection
18-
expect(stateDropdown).toHaveTextContent('California');
18+
// Verify the trigger text updates
19+
await expect(canvas.findByRole('combobox', { name: 'US State' })).resolves.toHaveTextContent('California');
1920
};
2021

2122
// Test selecting a Canadian province
2223
export const testCanadaProvinceSelection = async ({ canvasElement }: StoryContext) => {
2324
const canvas = within(canvasElement);
2425

25-
// Find and click the Canada province dropdown
26-
const provinceDropdown = canvas.getByLabelText('Canadian Province');
27-
await userEvent.click(provinceDropdown);
26+
// Wait for and click the province trigger
27+
const provinceTrigger = await canvas.findByLabelText('Canadian Province');
28+
await userEvent.click(provinceTrigger);
2829

29-
// Select a province (e.g., Ontario)
30-
const ontarioOption = await canvas.findByText('Ontario');
30+
// Query in the portaled content
31+
const listbox = await within(document.body).findByRole('listbox');
32+
const ontarioOption = within(listbox).getByRole('option', { name: 'Ontario' });
3133
await userEvent.click(ontarioOption);
3234

33-
// Verify the selection
34-
expect(provinceDropdown).toHaveTextContent('Ontario');
35+
// Verify the trigger text updates
36+
await expect(canvas.findByRole('combobox', { name: 'Canadian Province' })).resolves.toHaveTextContent('Ontario');
3537
};
3638

3739
// Test form submission
3840
export const testFormSubmission = async ({ canvasElement }: StoryContext) => {
3941
const canvas = within(canvasElement);
4042

4143
// Select a state
42-
const stateDropdown = canvas.getByLabelText('US State');
43-
await userEvent.click(stateDropdown);
44-
const californiaOption = await canvas.findByText('California');
45-
await userEvent.click(californiaOption);
44+
const stateTrigger = await canvas.findByLabelText('US State');
45+
await userEvent.click(stateTrigger);
46+
{
47+
const listbox = await within(document.body).findByRole('listbox');
48+
const californiaOption = within(listbox).getByRole('option', { name: 'California' });
49+
await userEvent.click(californiaOption);
50+
}
4651

4752
// Select a province
48-
const provinceDropdown = canvas.getByLabelText('Canadian Province');
49-
await userEvent.click(provinceDropdown);
50-
const ontarioOption = await canvas.findByText('Ontario');
51-
await userEvent.click(ontarioOption);
52-
53-
// Select a custom region
54-
const regionDropdown = canvas.getByLabelText('Custom Region');
55-
await userEvent.click(regionDropdown);
56-
const customOption = await canvas.findByText('New York');
57-
await userEvent.click(customOption);
53+
const provinceTrigger = await canvas.findByLabelText('Canadian Province');
54+
await userEvent.click(provinceTrigger);
55+
{
56+
const listbox = await within(document.body).findByRole('listbox');
57+
const ontarioOption = within(listbox).getByRole('option', { name: 'Ontario' });
58+
await userEvent.click(ontarioOption);
59+
}
60+
61+
// Select a custom region (use an option that exists in the story's options)
62+
const regionTrigger = await canvas.findByLabelText('Custom Region');
63+
await userEvent.click(regionTrigger);
64+
{
65+
const listbox = await within(document.body).findByRole('listbox');
66+
const customOption = within(listbox).getByRole('option', { name: 'California' });
67+
await userEvent.click(customOption);
68+
}
5869

5970
// Submit the form
6071
const submitButton = canvas.getByRole('button', { name: 'Submit' });

0 commit comments

Comments
 (0)