Skip to content

Commit cf0431c

Browse files
committed
fix(metadata): Stabilize taxonomy stories: await loading, expand by label, scope queries
1 parent cda78ec commit cf0431c

File tree

1 file changed

+43
-31
lines changed

1 file changed

+43
-31
lines changed

src/elements/content-sidebar/stories/tests/MetadataSidebarRedesign-visual.stories.tsx

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -683,44 +683,56 @@ export const EditMultilevelTaxonomy: StoryObj<typeof MetadataSidebarRedesign> =
683683

684684
await waitForLoadingToComplete(canvas);
685685

686-
const editButton = await waitFor(() => canvas.getByRole('button', { name: 'Edit My Taxonomy' }));
687-
686+
const editButton = await canvas.findByRole('button', { name: 'Edit My Taxonomy' });
688687
await userEvent.click(editButton);
689688

690-
const multilevelInput = canvas.getByRole('combobox');
691-
const optionChip = canvas.getByRole('button', { name: 'London' });
692-
689+
const multilevelInput = await canvas.findByRole('combobox');
690+
const optionChip = await canvas.findByRole('button', { name: 'London' });
693691
expect(multilevelInput).toBeInTheDocument();
694692
expect(optionChip).toBeInTheDocument();
695693

696694
await userEvent.click(multilevelInput);
697695

698-
const listbox = await waitFor(() => canvas.getByRole('listbox'));
699-
expect(listbox).toBeInTheDocument();
700-
701-
let expandButtons = await waitFor(() => canvas.getAllByRole('button', { name: 'Expand branch' }));
702-
703-
await userEvent.click(expandButtons[1]);
704-
705-
const hokkaidoOption = await waitFor(() => canvas.getByText('Hokkaido'));
706-
expect(hokkaidoOption).toBeInTheDocument();
707-
708-
expandButtons = await waitFor(() => screen.getAllByRole('button', { name: 'Expand branch' }));
709-
710-
await userEvent.click(expandButtons[2]);
711-
712-
const sapporoOption = await waitFor(() => canvas.getByRole('treeitem', { name: 'Sapporo' }));
713-
714-
expect(sapporoOption).toBeInTheDocument();
715-
expect(sapporoOption).toHaveAttribute('aria-selected', 'false');
716-
717-
await userEvent.click(sapporoOption);
718-
719-
const sapporoSelection = await waitFor(() => canvas.getByRole('gridcell', { name: 'Sapporo' }));
720-
721-
expect(sapporoOption).toBeInTheDocument();
722-
expect(sapporoOption).toHaveAttribute('aria-selected', 'true');
723-
expect(sapporoSelection).toBeInTheDocument();
696+
// Scope subsequent queries to the listbox to avoid race conditions with other UI
697+
const listbox = await canvas.findByRole('listbox');
698+
const listboxCanvas = within(listbox);
699+
700+
// Deterministically expand branches by label to avoid index-based flakiness.
701+
// Tree nodes can lazy-load and reorder expander buttons across renders, so
702+
// clicking expanders by index is unstable. We locate the branch by its label,
703+
// click that branch's own expander, and then await a specific child label to
704+
// appear rather than relying solely on aria-expanded (which can lag or be
705+
// set on a different wrapper depending on render timing).
706+
const expandBranch = async (label: string, expectedChildLabel: string) => {
707+
const labelEl = await listboxCanvas.findByText(label);
708+
const treeitem = labelEl.closest('[role="treeitem"]') as HTMLElement | null;
709+
expect(treeitem).not.toBeNull();
710+
const isExpanded = treeitem?.getAttribute('aria-expanded') === 'true';
711+
if (!isExpanded) {
712+
const expander = within(treeitem as HTMLElement).getByRole('button', { name: 'Expand branch' });
713+
await userEvent.click(expander);
714+
}
715+
// Wait for a known child to render to confirm expansion completed
716+
await listboxCanvas.findByText(expectedChildLabel);
717+
};
718+
719+
await expandBranch('Japan', 'Hokkaido');
720+
await expandBranch('Hokkaido', 'Sapporo');
721+
722+
// Re-scope to the active listbox before selecting the leaf.
723+
// Expanding branches can trigger a tree re-render that unmounts the previous
724+
// popup content. Re-querying the listbox here ensures we don't act on a stale
725+
// element reference and avoids intermittent "element not in the document" errors.
726+
const activeListbox = await canvas.findByRole('listbox');
727+
const activeListboxCanvas = within(activeListbox);
728+
await userEvent.click(await activeListboxCanvas.findByRole('treeitem', { name: 'Sapporo' }));
729+
730+
// Wait for the combobox to collapse after selection
731+
await waitFor(() => expect(multilevelInput).toHaveAttribute('aria-expanded', 'false'));
732+
733+
const chipsGrid = await canvas.findByRole('grid');
734+
const sapporoChip = within(chipsGrid).getByRole('button', { name: 'Sapporo' });
735+
expect(sapporoChip).toBeInTheDocument();
724736
},
725737
};
726738

0 commit comments

Comments
 (0)