Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions docs/specifications/TooltipElement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# TooltipElement

> Full API (methods, signatures, descriptions): see [api-reference.md](../../skills/vaadin-playwright-test/api-reference.md). This note covers only behaviour that isn't obvious from the signatures.

## A tooltip is always reached through the component it describes

Flow's `com.vaadin.flow.component.shared.Tooltip` has no constructor: a tooltip
is created for a component, and the resulting `<vaadin-tooltip slot="tooltip">`
is a light-DOM child of that component. So there is no "id of the tooltip" to
look it up by — scope the lookup to the target instead, or go through the
`HasTooltipElement` mixin:

```java
// through the mixin — the usual way
ButtonElement save = ButtonElement.getByText(page, "Save");
save.getTooltip().assertText("Saves the current draft");

// scoped to the target component
TooltipElement tooltip = TooltipElement.get(page.locator("#save-button"));

// by the tooltip's own text, when the target is not the interesting part
TooltipElement.getByText(page, "Saves the current draft");
```

`HasTooltipElement` is a thin facade over `TooltipElement`:
`assertTooltipHasText(...)` is `getTooltip().assertText(...)`. Use the mixin for
the text, and `getTooltip()` as soon as the test cares about the opened state,
the position, or triggering the tooltip.

## Assert the opened state, not visibility

`<vaadin-tooltip>` is `display: contents` and renders nothing of its own — what
appears on screen is the `<vaadin-tooltip-overlay>` in its shadow DOM. So the
open/closed assertions read the `opened` attribute the component reflects, which
flips exactly when the tooltip opens and closes:

```java
tooltip.assertOpened(); // opened attribute present
tooltip.assertClosed(); // opened attribute absent
tooltip.isOpened();
```

When a test genuinely needs the rendered box — a screenshot, a bounding-box
assertion — reach for the overlay instead of the host:

```java
assertThat(tooltip.getOverlayLocator()).isVisible();
```

## The text is readable while the tooltip is closed

The tooltip content lives in a `role="tooltip"` element that stays in the DOM
whether the tooltip is open or not, so text assertions need no interaction:

```java
// no hover needed
field.assertTooltipHasText("Tooltip for the field");
```

`assertText(null)` asserts that the tooltip shows nothing. A tooltip with empty
text keeps its overlay hidden, so absence is asserted on the content's
visibility rather than on the element being gone.

## Opening a tooltip is delayed

`hoverTarget()` moves the pointer to the centre of the element the tooltip
describes — the live `target` element reference, which no selector can express —
after scrolling it into view. Vaadin then waits out the tooltip's hover delay,
500 ms by default, before opening. Follow it with a retrying assertion, never
with the plain getter:

```java
tooltip.hoverTarget();
tooltip.assertOpened(); // absorbs the hover delay
// tooltip.isOpened() // would read false, too early

tooltip.closeWithEscape();
tooltip.assertClosed();
```

`closeWithEscape()` presses `Escape` on the page, because the component listens
for the key on the document and the tooltip host cannot be focused. A tooltip in
manual mode ignores both hover and `Escape`; drive it from the server side and
assert the result:

```java
// tooltip.setManual(true) on the server
ButtonElement.getByText(page, "Show tooltip").click();
tooltip.assertOpened();
```

## The position is read from the overlay

`Tooltip.setPosition(...)` sets a DOM property on the host and nothing else; it
is the overlay that reflects the *effective* position as an attribute.
`getPosition()` and `assertPosition(...)` read it there, so they answer with the
configured position, or with `bottom` when none was configured:

```java
// no position configured
tooltip.assertPosition("bottom");

// Tooltip.TooltipPosition.TOP_START
tooltip.assertPosition("top-start");
```

There is no "absent" case, so `assertPosition(null)` is not supported.
1 change: 1 addition & 0 deletions llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ behaviour isn't obvious from the signatures:
- [SliderElement](docs/specifications/SliderElement.md) - Keyboard-driven value changes, step snapping
- [TextAreaElement](docs/specifications/TextAreaElement.md) - Input-locator override
- [UploadElement](docs/specifications/UploadElement.md) - Hidden-file-input pattern
- [TooltipElement](docs/specifications/TooltipElement.md) - Opened state without visibility, hover delay, position on the overlay

## Key Patterns

Expand Down
43 changes: 39 additions & 4 deletions skills/vaadin-playwright-test/api-reference.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# DramaFinder API Reference

> **Auto-generated from source — do not edit by hand.** Regenerate with `jbang tools/generate-api-reference.java`.
> DramaFinder 1.1.7-SNAPSHOT — 55 element wrappers.
> DramaFinder 1.1.7-SNAPSHOT — 56 element wrappers.

Complete public API of every DramaFinder element wrapper. Each element lists the shared mixin interfaces it implements; those interfaces' methods are documented once under **Shared mixins** at the end (not repeated per element) — except where an element overrides one to change its behaviour, in which case the element lists it again with the behaviour that applies there. Method one-liners come from Javadoc.

Expand Down Expand Up @@ -125,6 +125,7 @@ Wrapped web-component tag, its wrapper class, and the wrapper's actual static fa
| `<vaadin-text-area>` | [TextAreaElement](#textareaelement) | `getByLabel(Locator, String)`, `getByLabel(Page, String)` |
| `<vaadin-text-field>` | [TextFieldElement](#textfieldelement) | `getByLabel(Locator, String)`, `getByLabel(Page, String)` |
| `<vaadin-time-picker>` | [TimePickerElement](#timepickerelement) | `getByLabel(Locator, String)`, `getByLabel(Page, String)` |
| `<vaadin-tooltip>` | [TooltipElement](#tooltipelement) | `get(Locator)`, `get(Page)`, `getByText(Page, String)` |
| `<vaadin-upload>` | [UploadElement](#uploadelement) | `getByButtonText(Page, String)` |
| `<vaadin-virtual-list>` | [VirtualListElement](#virtuallistelement) | `get(Page)` |
| — | [AbstractLoginElement](#abstractloginelement) | *constructor only* |
Expand All @@ -140,7 +141,7 @@ Wrapped web-component tag, its wrapper class, and the wrapper's actual static fa

## Elements

[AbstractLoginElement](#abstractloginelement) · [AbstractNumberFieldElement](#abstractnumberfieldelement) · [AccordionElement](#accordionelement) · [AccordionPanelElement](#accordionpanelelement) · [AppLayoutElement](#applayoutelement) · [AvatarElement](#avatarelement) · [AvatarGroupElement](#avatargroupelement) · [BadgeElement](#badgeelement) · [BigDecimalFieldElement](#bigdecimalfieldelement) · [BreadcrumbsElement](#breadcrumbselement) · [BreadcrumbsItemElement](#breadcrumbsitemelement) · [ButtonElement](#buttonelement) · [CardElement](#cardelement) · [CheckboxElement](#checkboxelement) · [CheckboxGroupElement](#checkboxgroupelement) · [ComboBoxElement](#comboboxelement) · [ContextMenuElement](#contextmenuelement) · [DatePickerElement](#datepickerelement) · [DateTimePickerElement](#datetimepickerelement) · [DetailsElement](#detailselement) · [DialogElement](#dialogelement) · [EmailFieldElement](#emailfieldelement) · [GridElement](#gridelement) · [IntegerFieldElement](#integerfieldelement) · [ListBoxElement](#listboxelement) · [LoginFormElement](#loginformelement) · [LoginOverlayElement](#loginoverlayelement) · [MarkdownElement](#markdownelement) · [MenuBarElement](#menubarelement) · [MenuElement](#menuelement) · [MenuItemElement](#menuitemelement) · [MessageInputElement](#messageinputelement) · [MessageListElement](#messagelistelement) · [MultiSelectComboBoxElement](#multiselectcomboboxelement) · [NotificationElement](#notificationelement) · [NumberFieldElement](#numberfieldelement) · [PasswordFieldElement](#passwordfieldelement) · [PopoverElement](#popoverelement) · [ProgressBarElement](#progressbarelement) · [RadioButtonGroupElement](#radiobuttongroupelement) · [SelectElement](#selectelement) · [SideNavigationElement](#sidenavigationelement) · [SideNavigationItemElement](#sidenavigationitemelement) · [SliderElement](#sliderelement) · [SplitLayoutElement](#splitlayoutelement) · [SwitchElement](#switchelement) · [TabElement](#tabelement) · [TabSheetElement](#tabsheetelement) · [TabsElement](#tabselement) · [TextAreaElement](#textareaelement) · [TextFieldElement](#textfieldelement) · [TimePickerElement](#timepickerelement) · [TreeGridElement](#treegridelement) · [UploadElement](#uploadelement) · [VirtualListElement](#virtuallistelement)
[AbstractLoginElement](#abstractloginelement) · [AbstractNumberFieldElement](#abstractnumberfieldelement) · [AccordionElement](#accordionelement) · [AccordionPanelElement](#accordionpanelelement) · [AppLayoutElement](#applayoutelement) · [AvatarElement](#avatarelement) · [AvatarGroupElement](#avatargroupelement) · [BadgeElement](#badgeelement) · [BigDecimalFieldElement](#bigdecimalfieldelement) · [BreadcrumbsElement](#breadcrumbselement) · [BreadcrumbsItemElement](#breadcrumbsitemelement) · [ButtonElement](#buttonelement) · [CardElement](#cardelement) · [CheckboxElement](#checkboxelement) · [CheckboxGroupElement](#checkboxgroupelement) · [ComboBoxElement](#comboboxelement) · [ContextMenuElement](#contextmenuelement) · [DatePickerElement](#datepickerelement) · [DateTimePickerElement](#datetimepickerelement) · [DetailsElement](#detailselement) · [DialogElement](#dialogelement) · [EmailFieldElement](#emailfieldelement) · [GridElement](#gridelement) · [IntegerFieldElement](#integerfieldelement) · [ListBoxElement](#listboxelement) · [LoginFormElement](#loginformelement) · [LoginOverlayElement](#loginoverlayelement) · [MarkdownElement](#markdownelement) · [MenuBarElement](#menubarelement) · [MenuElement](#menuelement) · [MenuItemElement](#menuitemelement) · [MessageInputElement](#messageinputelement) · [MessageListElement](#messagelistelement) · [MultiSelectComboBoxElement](#multiselectcomboboxelement) · [NotificationElement](#notificationelement) · [NumberFieldElement](#numberfieldelement) · [PasswordFieldElement](#passwordfieldelement) · [PopoverElement](#popoverelement) · [ProgressBarElement](#progressbarelement) · [RadioButtonGroupElement](#radiobuttongroupelement) · [SelectElement](#selectelement) · [SideNavigationElement](#sidenavigationelement) · [SideNavigationItemElement](#sidenavigationitemelement) · [SliderElement](#sliderelement) · [SplitLayoutElement](#splitlayoutelement) · [SwitchElement](#switchelement) · [TabElement](#tabelement) · [TabSheetElement](#tabsheetelement) · [TabsElement](#tabselement) · [TextAreaElement](#textareaelement) · [TextFieldElement](#textfieldelement) · [TimePickerElement](#timepickerelement) · [TooltipElement](#tooltipelement) · [TreeGridElement](#treegridelement) · [UploadElement](#uploadelement) · [VirtualListElement](#virtuallistelement)

### AbstractLoginElement

Expand Down Expand Up @@ -1752,6 +1753,39 @@ PlaywrightElement for <vaadin-time-picker>.
- `LocalTime getValueAsLocalTime()` — Get the current value as a LocalTime.
- `void assertValue(LocalTime value)` — Assert that the value equals the provided time.

### TooltipElement `<vaadin-tooltip>`

PlaywrightElement for <vaadin-tooltip>.

**Extends:** VaadinElement
**Implements:** HasThemeElement, HasStyleElement

**Constants:** `String FIELD_TAG_NAME = "vaadin-tooltip"`

**Constructors:**

- `TooltipElement(Locator locator)` — Create a new TooltipElement.

**Static factory methods:**

- `TooltipElement get(Page page)` — Get the first TooltipElement on the page.
- `TooltipElement get(Locator locator)` — Get the first TooltipElement within a scope, typically the component the tooltip is attached to.
- `TooltipElement getByText(Page page, String text)` — Get a TooltipElement by its text.

**Methods:**

- `Locator getContentLocator()` — Locator for the element carrying the tooltip content, i.e. the role="tooltip" node.
- `Locator getOverlayLocator()` — Locator for the <vaadin-tooltip-overlay> the tooltip renders in its shadow DOM.
- `String getText()` — Get the tooltip text.
- `void assertText(String text)` — Assert the tooltip text.
- `boolean isOpened()` — Whether the tooltip is open.
- `void assertOpened()` — Assert that the tooltip is open.
- `void assertClosed()` — Assert that the tooltip is closed.
- `String getPosition()` — Get the effective position of the tooltip relative to its target, e.g. top-start or bottom.
- `void assertPosition(String position)` — Assert the effective position of the tooltip relative to its target.
- `void hoverTarget()` — Hover the element the tooltip describes, which opens the tooltip unless it is in manual mode.
- `void closeWithEscape()` — Close the tooltip by pressing Escape.

### TreeGridElement

PlaywrightElement for Vaadin Tree Grid.
Expand Down Expand Up @@ -2083,15 +2117,16 @@ Mixin for components that support the theme attribute.

### HasTooltipElement

Utilities to interact with components implementing Vaadin's HasTooltip the first child with role tooltip
Utilities to interact with components implementing Vaadin's HasTooltip, i.e. components hosting a slotted <vaadin-tooltip>.

**Extends:** HasLocatorElement

**Methods:**

- `TooltipElement getTooltip()` — The component's tooltip.
- `Locator getTooltipLocator()` — Locator for the tooltip content (role=tooltip).
- `String getTooltipText()` — Tooltip text content.
- `void assertTooltipHasText(String text)`
- `void assertTooltipHasText(String text)` — Assert the tooltip text.

### HasValidationPropertiesElement

Expand Down
2 changes: 2 additions & 0 deletions skills/vaadin-playwright-test/element-mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Also scan `src/main/java` for any `*Element.java` files not listed here (custom
| `MessageInput` | `MessageInputElement` | `get(page)`, `typeAndSubmit()`, `submit()`, `assertValue()` |
| `MessageList` | `MessageListElement` | `get(page)`, `assertMessageCount()`, `assertMessageText(index, text)`, `assertMessageUserName(index, name)` |
| `Popover` | `PopoverElement` | `getByLabel(page, label)` or `new PopoverElement(page)`, `assertOpen()`, `assertClosed()` |
| `Tooltip` | `TooltipElement` | `get(page)`, `get(locator)` scoped to the target component, `getByText(page, text)`, or `someElement.getTooltip()`; `getText()`, `assertText()`, `isOpened()`, `assertOpened()`, `assertClosed()`, `getPosition()`, `assertPosition()`, `hoverTarget()`, `closeWithEscape()` |
| `SideNavigation` | `SideNavigationElement` | `getByLabel(page, label)`, `clickItem(label)`, `getItem(label)`, `assertCollapsed()`, `assertExpanded()` |
| `Card` | `CardElement` | `getByTitle(page, title)`, `assertTitle()`, `assertSubtitle()` |
| `Markdown` | `MarkdownElement` | `get(page)`, `getRenderedLocator()`, `getText()`, `assertContainsText()`, `getHeadings()`, `getLinks()`, `getCodeBlocks()`, `assertHeading(index, text)`, `assertLink(text, href)`, `assertCodeBlockLanguage(index, language)` |
Expand Down Expand Up @@ -110,6 +111,7 @@ element.assertTheme("small");
element.assertLabel("Expected label");
element.assertHelperHasText("Helper text");
element.assertTooltipHasText("Tooltip text");
element.getTooltip(); // TooltipElement: opened state, position, hoverTarget()
element.assertAriaLabel("Aria label");
element.assertIsFocused();
element.assertIsNotFocused();
Expand Down
Loading
Loading