From 9b6b12179f6670bc4147d06d065870cdb1258503 Mon Sep 17 00:00:00 2001 From: mikhail Date: Mon, 21 Sep 2026 11:42:11 +0300 Subject: [PATCH 1/3] docs: cover the browserless testers and methods added in 1.2 Browserless Test 1.2 adds testers and tester methods that the Component Testers page does not mention, and it changes what a value tester does with a value that breaks a constraint. - Common Testers: rows for TreeGrid, SplitLayout, Card, AvatarGroup, Accordion, Dashboard, Text, and Markdown; new methods on TextField, Checkbox, NumberField, Grid, Dialog, Upload, Breadcrumbs, and Switch. - Constraint Enforcement: a constraint the browser enforces before the value is entered still makes the tester throw, while min, max, step, and required values are committed and leave the field invalid, which isValid() asserts. - Clearing a Value: clear() models the keyboard, clickClearButton() needs a visible clear button, and selection testers have their own wording. - Tester interactions reach the application as client-originated events. Co-Authored-By: Claude Opus 5 (1M context) --- .../browserless/component-testers.adoc | 85 +++++++++++++++---- 1 file changed, 69 insertions(+), 16 deletions(-) diff --git a/articles/flow/testing/browserless/component-testers.adoc b/articles/flow/testing/browserless/component-testers.adoc index ddcc4e5ffc..802ef3cceb 100644 --- a/articles/flow/testing/browserless/component-testers.adoc +++ b/articles/flow/testing/browserless/component-testers.adoc @@ -27,6 +27,8 @@ test(button).click(); String value = textField.getValue(); ---- +A tester drives the component through the same path the browser uses, so a listener that branches on [methodname]`isFromClient()` behaves in a test as it does in a running application. + The `test()` method returns a tester matched to the component's type. You can also request a specific tester type explicitly: [source,java] @@ -57,16 +59,16 @@ The following table shows frequently used testers and their key methods: | Component | Key Tester Methods | [classname]`TextField` -| [methodname]`setValue(String)`, [methodname]`clear()` +| [methodname]`setValue(String)`, [methodname]`clear()`, [since:com.vaadin:vaadin@V25.3]#[methodname]`clickClearButton()`# | [classname]`Button` | [methodname]`click()` | [classname]`Checkbox` -| [methodname]`click()` (toggles checked state) +| [methodname]`click()` (toggles checked state), [since:com.vaadin:vaadin@V25.3]#[methodname]`check()`, [methodname]`uncheck()`# | [classname]`NumberField` -| [methodname]`setValue(double)` +| [methodname]`setValue(double)`, [methodname]`clear()`, [since:com.vaadin:vaadin@V25.3]#[methodname]`stepUp()`, [methodname]`stepDown()`, [methodname]`isValid()`# | [classname]`Select` | [methodname]`selectItem(String)`, [methodname]`selectItem(int)` @@ -75,22 +77,28 @@ The following table shows frequently used testers and their key methods: | [methodname]`selectItem(String)`, [methodname]`getSuggestionItems()` | [classname]`Grid` -| [methodname]`getRow(index)`, [methodname]`size()`, [methodname]`getCellText(row, column)` +| [methodname]`getRow(index)`, [methodname]`size()`, [methodname]`getCellText(row, column)`, [methodname]`select(int)`, [since:com.vaadin:vaadin@V25.3]#[methodname]`deselect(int)`, [methodname]`deselectAll()`# + +| [since:com.vaadin:vaadin@V25.3]#[classname]`TreeGrid`# +| [classname]`TreeGridTester`: [methodname]`expand(int)`, [methodname]`collapse(int)`, [methodname]`isExpanded(int)`, [methodname]`hasChildren(int)`, plus everything [classname]`GridTester` offers | [classname]`Notification` | [methodname]`getText()` | [classname]`Dialog` -| [methodname]`open()`, [methodname]`close()` +| [methodname]`open()`, [methodname]`close()`, [since:com.vaadin:vaadin@V25.3]#[methodname]`pressEscape()`, [methodname]`clickOutside()`# | [classname]`ConfirmDialog` | [methodname]`open()`, [methodname]`confirm()`, [methodname]`cancel()`, [methodname]`reject()` | [classname]`Upload` -| [methodname]`upload(File)`, [methodname]`uploadAll(File...)` +| [methodname]`upload(File)`, [methodname]`uploadAll(File...)`, [since:com.vaadin:vaadin@V25.3]#[methodname]`getLastUploadStatus()`, [methodname]`ensureUploaded()`# + +| [classname]`Accordion` +| [classname]`AccordionTester`: [methodname]`openDetails(String)`, [methodname]`isOpen(String)`, [since:com.vaadin:vaadin@V25.3]#[methodname]`closeDetails()`, [methodname]`closeDetails(String)`, [methodname]`toggleDetails(String)`# | [since:com.vaadin:vaadin@V25.2]#[classname]`Breadcrumbs`# -| [classname]`BreadcrumbsTester`: [methodname]`getItemTexts()`, [methodname]`clickItem(String)`, [methodname]`clickItem(int)` +| [classname]`BreadcrumbsTester`: [methodname]`getItemTexts()`, [methodname]`getItemPaths()`, [methodname]`clickItem(String)`, [methodname]`clickItem(int)` | [since:com.vaadin:vaadin@V25.2]#[classname]`MasterDetailLayout`# | [classname]`MasterDetailLayoutTester`: [methodname]`getMaster()`, [methodname]`getDetail()`, [methodname]`getDetailPlaceholder()`, [methodname]`isDetailPlaceholderVisible()` @@ -108,10 +116,28 @@ The following table shows frequently used testers and their key methods: | [classname]`DecimalRangeSliderTester`: [methodname]`setValue(DecimalRangeSliderValue)`, [methodname]`setStart(Double)`, [methodname]`setEnd(Double)`, [methodname]`incrementStart()`, [methodname]`decrementEnd()`, ... | [since:com.vaadin:vaadin@V25.3]#[classname]`Switch`# -| [classname]`SwitchTester`: [methodname]`isOn()`, [methodname]`click()` +| [classname]`SwitchTester`: [methodname]`isOn()`, [methodname]`click()`, [methodname]`switchOn()`, [methodname]`switchOff()` | [since:com.vaadin:vaadin@V25.3]#[classname]`GridPro`# | [classname]`GridProTester`: [methodname]`setValue(row, column, value)`, plus everything [classname]`GridTester` offers + +| [since:com.vaadin:vaadin@V25.3]#[classname]`SplitLayout`# +| [classname]`SplitLayoutTester`: [methodname]`dragSplitterTo(double)`, [methodname]`getSplitterPosition()`, [methodname]`getPrimaryComponent()`, [methodname]`getSecondaryComponent()` + +| [since:com.vaadin:vaadin@V25.3]#[classname]`Card`# +| [classname]`CardTester`: [methodname]`getTitleAsText()`, [methodname]`getSubtitleAsText()`, [methodname]`getHeader()`, [methodname]`getMedia()`, [methodname]`getFooterComponents()` + +| [since:com.vaadin:vaadin@V25.3]#[classname]`AvatarGroup`# +| [classname]`AvatarGroupTester`: [methodname]`getVisibleItems()`, [methodname]`getOverflowItems()`, [methodname]`getOverflowAbbreviation()` + +| [since:com.vaadin:vaadin@V25.2]#[classname]`Dashboard`# +| [classname]`DashboardTester`: [methodname]`moveWidget(widget, toIndex)`, [methodname]`resizeWidget(widget, colspan, rowspan)`, [methodname]`removeWidget(widget)` + +| [since:com.vaadin:vaadin@V25.2]#[classname]`Text`# +| [classname]`TextTester`: [methodname]`getText()` + +| [since:com.vaadin:vaadin@V25.2]#[classname]`Markdown`# +| [classname]`MarkdownTester`: [methodname]`getContent()` |=== @@ -135,29 +161,56 @@ test(categorySelect).selectItem("Meals & Entertainment"); === Constraint Enforcement -Testers enforce the same constraints that apply to user input in a browser. If a component has constraints like minimum or maximum values, required fields, or step intervals, the tester rejects values that violate them. This ensures your tests reflect actual user behavior. +Testers enforce the constraints that a browser enforces, and they stop where a browser stops. -For example, a [classname]`NumberField` with a minimum of `0` rejects negative values through the tester: +A constraint that keeps the value out of the field makes the tester throw. The maximum length of a text field and an allowed character pattern work this way, because a browser drops the keystrokes that break them: + +[source,java] +---- +TextField code = new TextField("Code"); +code.setMaxLength(5); + +// Throws: a browser stops the typing at five characters +test(code).setValue("123456"); +---- + +[since:com.vaadin:vaadin@V25.3]#A constraint that only marks the field invalid works differently: a browser commits such a value, and so does the tester.# This covers `min`, `max`, `step`, and a required value on [classname]`NumberField`, [classname]`DatePicker`, [classname]`TimePicker`, and [classname]`DateTimePicker`. Assert the outcome with [methodname]`isValid()`, which runs the component's own default validator and honors an invalid state set from outside, such as the state a [classname]`Binder` sets: [source,java] ---- NumberField amount = new NumberField("Amount"); amount.setMin(0); -amount.setStep(0.01); -// This throws an exception — the value violates the minimum constraint +// Committed, as in a browser, and the field is left invalid test(amount).setValue(-5.0); + +Assertions.assertFalse(test(amount).isValid()); +---- + +To test how the application reacts to a value that no user can produce, set that value through the component's Java API instead of the tester: + +[source,java] +---- +// Bypass the tester to exercise the validation logic +code.setValue("123456"); ---- -To test that your application handles invalid input correctly, set values directly through the component's Java API instead of the tester: + +[role="since:com.vaadin:vaadin@V25.3"] +=== Clearing a Value + +Emptying a field works the same way in every text, number, date, and time tester. [methodname]`clear()` models deleting the contents from the keyboard, which a user can do whether or not the component shows a clear button. [methodname]`clickClearButton()` models clicking that button, and fails when the button is hidden: [source,java] ---- -// Bypass tester constraints to test validation logic -amount.setValue(-5.0); -// Now verify that your application reacts appropriately +test(name).clear(); // Always available +test(name).clickClearButton(); // Requires a visible clear button ---- +A field can legitimately end up invalid once emptied, a required field for instance, so [methodname]`clear()` never refuses. + +Selection components use their own wording for the same action: [methodname]`deselectItem()` on [classname]`RadioButtonGroupTester`, [methodname]`clearSelection()` on [classname]`MultiSelectListBoxTester`, and [methodname]`deselectAll()` on [classname]`GridTester`. On [classname]`ComboBoxTester`, [methodname]`selectItem(null)` clears the selection without a clear button. + === Base Methods From f9faa7a9904e4a32c53caffaff88eb9d2b544b7a Mon Sep 17 00:00:00 2001 From: "totally-not-ai[bot]" <290682512+totally-not-ai[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 07:45:46 +0000 Subject: [PATCH 2/3] docs: add the date and time picker rows to the tester table The clearing and validity methods this page documents apply to them too, but the pickers had no row of their own. --- articles/flow/testing/browserless/component-testers.adoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/articles/flow/testing/browserless/component-testers.adoc b/articles/flow/testing/browserless/component-testers.adoc index 802ef3cceb..836a0b37ae 100644 --- a/articles/flow/testing/browserless/component-testers.adoc +++ b/articles/flow/testing/browserless/component-testers.adoc @@ -76,6 +76,12 @@ The following table shows frequently used testers and their key methods: | [classname]`ComboBox` | [methodname]`selectItem(String)`, [methodname]`getSuggestionItems()` +| [classname]`DatePicker`, [classname]`TimePicker` +| [methodname]`setValue(value)`, [since:com.vaadin:vaadin@V25.3]#[methodname]`clear()`, [methodname]`clickClearButton()`, [methodname]`isValid()`# + +| [classname]`DateTimePicker` +| [methodname]`setValue(value)`, [since:com.vaadin:vaadin@V25.3]#[methodname]`clear()`, [methodname]`isValid()`# + | [classname]`Grid` | [methodname]`getRow(index)`, [methodname]`size()`, [methodname]`getCellText(row, column)`, [methodname]`select(int)`, [since:com.vaadin:vaadin@V25.3]#[methodname]`deselect(int)`, [methodname]`deselectAll()`# From bb62b1b4d6f30c6ec9f354f8c701b45960af1416 Mon Sep 17 00:00:00 2001 From: "totally-not-ai[bot]" <290682512+totally-not-ai[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 08:42:10 +0000 Subject: [PATCH 3/3] docs: add the grid context menu and login overlay tester rows GridContextMenuTester is new and is reached through the grid's tester, and the login overlay tester gained the slot-scoped finders. --- articles/flow/testing/browserless/component-testers.adoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/articles/flow/testing/browserless/component-testers.adoc b/articles/flow/testing/browserless/component-testers.adoc index 836a0b37ae..eeb454c87f 100644 --- a/articles/flow/testing/browserless/component-testers.adoc +++ b/articles/flow/testing/browserless/component-testers.adoc @@ -127,6 +127,12 @@ The following table shows frequently used testers and their key methods: | [since:com.vaadin:vaadin@V25.3]#[classname]`GridPro`# | [classname]`GridProTester`: [methodname]`setValue(row, column, value)`, plus everything [classname]`GridTester` offers +| [since:com.vaadin:vaadin@V25.3]#[classname]`GridContextMenu`# +| [classname]`GridContextMenuTester`, obtained with [methodname]`test(grid).contextMenu(row)`: [methodname]`open()`, [methodname]`open(row)`, [methodname]`clickItem(String, String...)`, [methodname]`getItemTexts()` + +| [classname]`LoginOverlay` +| [methodname]`openOverlay()`, [methodname]`isOpen()`, [since:com.vaadin:vaadin@V25.3]#[methodname]`findInFooter(Class)`, [methodname]`findInCustomFormArea(Class)`# + | [since:com.vaadin:vaadin@V25.3]#[classname]`SplitLayout`# | [classname]`SplitLayoutTester`: [methodname]`dragSplitterTo(double)`, [methodname]`getSplitterPosition()`, [methodname]`getPrimaryComponent()`, [methodname]`getSecondaryComponent()`