Skip to content
Merged
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
97 changes: 81 additions & 16 deletions articles/flow/testing/browserless/component-testers.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -57,40 +59,52 @@ 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)`

| [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]`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()`
Expand All @@ -108,10 +122,34 @@ 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

Comment thread
mcollovati marked this conversation as resolved.
| [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()`

| [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()`
|===


Expand Down Expand Up @@ -150,30 +188,57 @@ Button next = test(splitLayout).findInPrimary(Button.class).single();

=== 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.

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");
----

For example, a [classname]`NumberField` with a minimum of `0` rejects negative values through the tester:
[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 that your application handles invalid input correctly, set values directly through the component's Java API instead of the tester:
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 tester constraints to test validation logic
amount.setValue(-5.0);
// Now verify that your application reacts appropriately
// Bypass the tester to exercise the validation logic
code.setValue("123456");
----


[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]
----
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.


[role="since:com.vaadin:vaadin@V25.3"]
=== Upload Constraints

Expand Down
Loading