Skip to content

feat: clickFor + clickMenu — retry-safe click-to-reveal helper #58

Description

@rickcedwhat-ai

Problem

Multi-step click interactions flake when intermediate states are slow or transient — clicking a button to open a dropdown, then clicking an item inside it. toPass reruns the whole block blindly, which causes toggle-button problems (clicking again closes the thing you just opened).

Design

clickFor (internal primitive)

await clickFor(trigger, reveals, async (revealed) => {
  await revealed.getByRole('menuitem', { name: 'Delete' }).click();
});

Retry logic:

  1. If reveals is not yet visible → click trigger
  2. Wait for reveals to become visible (short timeout)
  3. If still not visible → retry from top
  4. Run callback
  5. If callback fails and reveals is no longer visible → retry from top
  6. If callback fails and reveals is still visible → throw (genuine error, not a flake)

Key insight: check visibility before clicking so retries don't toggle the trigger closed. A slow dropdown that's already open gets acted on directly without re-clicking.

No state revert on retry — clickFor targets single-action interactions. Multi-step rollback belongs in .cleanup().

clickMenu (public shorthand)

// Locator item
await clickMenu(trigger, page.getByRole('menuitem', { name: 'Delete' }));

// String shorthand
await clickMenu(trigger, 'Delete');

Built on clickFor — trigger click + wait for menu + click item, with the retry logic above.

Relationship to hoverMenu

hoverMenu already has per-step retry (re-hover current step if next doesn't appear) plus the L-shaped mouse path for diagonal-move safety. They solve similar flake problems but the mechanics are different enough to keep them separate. Both could share the "check before acting" principle though.

Open questions

  • What should the default retry count and reveal timeout be?
  • Should clickFor be exported or stay internal? Current thinking: internal only.
  • Are there other natural clickFor wrappers beyond clickMenu? (clickToSelect for custom dropdowns/comboboxes was floated)
  • Should hoverMenu be refactored to use the same "check visibility before hovering" pattern on retries?

Related

  • Closes or relates to the broader DX theme of eliminating toPass boilerplate for common interaction patterns

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions