Best for
- Use when the user asks to "write Browserless tests", "write Vaadin UI unit tests", "unit test a Vaadin view without a browser", "create view tests with the official Vaadin testing framework", or mentions Browserless tes…
AI-Unified-Process/marketplace/aiup-vaadin-jooq/skills/browserless-test/SKILL.md
Creates Vaadin Browserless server-side unit tests for Vaadin views covering navigation, component interactions, form validation, grid operations, and notifications. Use when the user asks to "write Browserless tests", "write Vaadin UI unit tests", "unit test a Vaadin view without a browser", "create view tests with the official Vaadin testing framework", or mentions Browserless testing, SpringBrowserlessTest, browserless-test-junit6, UI Unit Testing, or server-side Vaadin testing.
Decision brief
Creates Vaadin Browserless server-side unit tests for Vaadin views covering navigation, component interactions, form validation, grid operations, and notifications.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/AI-Unified-Process/marketplace --skill "aiup-vaadin-jooq/skills/browserless-test"Inspect the Agent Skill "browserless-test" from https://github.com/AI-Unified-Process/marketplace/blob/4d073197a39f3b79b7aae9ee5407c00a8f6e1975/aiup-vaadin-jooq/skills/browserless-test/SKILL.md at commit 4d073197a39f3b79b7aae9ee5407c00a8f6e1975. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Create Vaadin Browserless unit tests for Vaadin views based on the use case $ARGUMENTS. Browserless Testing executes the UI directly inside the JVM — no browser, no WebDriver, no servlet container.
Annotate each test method with the use case ID and (when applicable) the scenario and business rules it covers. The values must match headings in the corresponding UC-XXX-.md spec:
1. Read the use case specification (docs/use-cases/UC-XXX-.md) to identify the main success scenario, alternative flows (A1, A2, …), and referenced business rules (BR-XXX) 2. Check whether a UseCase annotation type already exists in the project. If not, create UseCase.java with…
A diff of the specification change may follow the file path in the arguments. When it is there, it is the definitive list of what changed — work through it change by change. A removed line means the scenario it described was dropped: delete the tests that exist only for it inste…
Browserless tests are use case tests. Each test class verifies the behavior of exactly one use case from the use case specification (docs/use-cases/UC-XXX-.md).
Permission review
The documentation includes network, browsing, or remote request actions.
Component query API: https://vaadin.com/docs/latest/flow/testing/browserless/component-queryEvidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 97/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 106 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Create Vaadin Browserless unit tests for Vaadin views based on the use case $ARGUMENTS. Browserless Testing executes the UI directly inside the JVM — no browser, no WebDriver, no servlet container.
Browserless Testing is the official, recommended server-side testing framework for Vaadin. It has been free and open source under Apache 2.0 since Vaadin 25.1 (previously the commercial UI Unit Testing add-on). It supersedes the community Karibu Testing library — prefer this skill over /karibu-test for any new test code.
If the Vaadin MCP server (https://mcp.vaadin.com/docs) is configured, use it for documentation lookups; otherwise rely on your own knowledge and the documentation links below. See the MCP setup rule to configure this optional server.
A diff of the specification change may follow the file path in the arguments. When it is there, it is the definitive list of what changed — work through it change by change. A removed line means the scenario it described was dropped: delete the tests that exist only for it instead of keeping them as passing extras.
Before writing new tests, look for an existing test class for this use case — search for
UC<id>*Test and for methods annotated @UseCase(id = "UC-XXX"). If one exists, update it to
match the current specification instead of creating a second test class:
@UseCase AnnotationBrowserless tests are use case tests. Each test class verifies the behavior of exactly one use
case from the use case specification (docs/use-cases/UC-XXX-*.md).
Test classes must be named after the use case using the pattern
UC<id><PascalCaseUseCaseName>Test — for example UC001RegisterPersonTest for use case UC-001
"Register Person". This makes the link between spec and test obvious and is the convention the AIUP
IntelliJ Navigator plugin relies on.
@UseCase annotationEvery test method must be annotated with @UseCase(id = "UC-XXX", ...) so the
AIUP IntelliJ Navigator plugin can wire up
gutter icons and Find Usages between the Markdown spec and the Java tests.
Bootstrap step. Before writing any tests, check whether the project already contains an
annotation type named UseCase (search the project for @interface UseCase). If it does not,
create it. The package does not matter — the plugin resolves the annotation by short name — but a
conventional location is src/main/java/<group>/<artifact>/usecase/UseCase.java. The annotation
must have exactly this shape:
package com.example.app.usecase;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UseCase {
String id();
String scenario() default "Main Success Scenario";
String[] businessRules() default {};
}
Annotate each test method with the use case ID and (when applicable) the scenario and business
rules it covers. The values must match headings in the corresponding UC-XXX-*.md spec:
| Attribute | Maps to spec heading | Default |
|---|---|---|
id | **Use Case ID:** UC-XXX | (required) |
scenario | ## Main Success Scenario or ### A1: … | "Main Success Scenario" |
businessRules | ### BR-XXX headings inside the same UC | {} |
@Test
@UseCase(id = "UC-001")
void register_person_with_valid_data() { ... }
@Test
@UseCase(id = "UC-001", scenario = "A1: Email Already Exists")
void registration_fails_when_email_already_exists() { ... }
@Test
@UseCase(id = "UC-001", scenario = "A2: Invalid Postal Code", businessRules = {"BR-003"})
void registration_fails_when_postal_code_invalid() { ... }
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>browserless-test-junit6</artifactId>
<scope>test</scope>
</dependency>
@Transactional annotation (transaction boundaries must stay intact)LocatorJ, _get, _find, _click, GridKt, NotificationsKt — those are the legacy Karibu API. Use the Browserless $() query and test() wrapper insteadtest(...) — use the component's Java API directly (e.g. textField.getValue(), button.isEnabled())$() for overlay components (Context Menu, Menu Bar) — use the dedicated tester's clickItem() / find() methodsCreate test data using Flyway migrations in src/test/resources/db/migration.
| Approach | Location | Purpose |
|---|---|---|
| Flyway migration | src/test/resources/db/migration/V*.sql | Populate test data |
| Manual cleanup | @AfterEach method | Remove test-created data |
Extend com.vaadin.testbench.unit.SpringBrowserlessTest and annotate the class with @SpringBootTest. The base class creates the Vaadin session, UI, and component tree inside the JUnit JVM.
@SpringBootTest
class PersonViewTest extends SpringBrowserlessTest {
// ...
}
For non-Spring projects, extend com.vaadin.testbench.unit.BrowserlessTest instead.
Use references/UC001ManagePersonsTest.java as the test
class structure. It demonstrates the UC<id><Name>Test class naming, the @UseCase annotation on
every test method, and how to map alternative flows (scenario = "A1: …") and business rules
(businessRules = {"BR-…"}) onto the spec headings.
navigate(PersonView.class); // by class
navigate("person", PersonView.class); // by route
navigate(PersonDetailView.class, "42"); // with URL parameter
navigate(PersonTemplateView.class, Map.of("id", "42")); // with URL template
HasElement currentView = getCurrentView();
$() Query// Single result
TextField name = $(TextField.class).single();
Button save = $(Button.class).withText("Save").single();
TextField nameField = $(TextField.class).withCaption("Name").single();
ComboBox<Country> country = $(ComboBox.class).withId("country").single();
// Scope to current view
TextField name = $view(TextField.class).single();
// Scope to a parent component
TextField name = $(TextField.class, view.formLayout).single();
// All matching
List<Button> buttons = $(Button.class).all();
// Existence check (no exception)
if ($(Notification.class).exists()) { /* ... */ }
| Filter | Purpose |
|---|---|
withText(String) | Exact text match |
withTextContaining(String) | Substring text match |
withCaption(String) | Exact caption (label) match |
withCaptionContaining(String) | Substring caption match |
withId(String) | Component ID |
withClassName(String...) | Has all given CSS class names |
withAttribute(String[, String]) | Has attribute (optionally with value) |
withValue(V) | For HasValue components |
withPropertyValue(getter, value) | Custom getter match |
withCondition(Predicate) | Custom predicate |
| Operator | Purpose |
|---|---|
single() | Expect exactly one match |
last() | Last match |
atIndex(int) | Match at position |
all() | Return List |
id(String) | Match by ID |
exists() | Boolean check, no exception |
withResultsSize(int) / withResultsSize(min, max) | Assert count |
test(...) WrapperUse test(component) for actions (click, setValue, selectItem). Read state from the component's Java API.
// Form interactions
test($(TextField.class).withCaption("Name").single()).setValue("John");
test($(ComboBox.class).withCaption("Country").single()).selectItem("Switzerland");
test($(DatePicker.class).withCaption("Birth Date").single())
.setValue(LocalDate.of(1990, 1, 1));
test($(Checkbox.class).withCaption("Active").single()).click();
// Buttons
test($(Button.class).withText("Save").single()).click();
// Reading state — use the component API, not the tester
String value = $(TextField.class).withCaption("Name").single().getValue();
| Component | Key Tester Methods |
|---|---|
| TextField | setValue(String), clear() |
| NumberField | setValue(double) |
| Checkbox | click() (toggles) |
| Button | click(), rightClick(), middleClick() |
| Select | selectItem(String), selectItem(int) |
| ComboBox | selectItem(String), getSuggestionItems() |
| DatePicker | setValue(LocalDate) |
| Grid | getRow(int), size(), getCellText(row, column) |
| Notification | getText() |
| Dialog | open(), close() |
| ConfirmDialog | open(), confirm(), cancel(), reject() |
| Upload | upload(File), uploadAll(File...) |
| ContextMenu | clickItem(String...), clickItem(int...), isItemChecked() |
| MenuBar | clickItem(String...) |
Grid<PersonRecord> grid = $(Grid.class).single();
// Size
assertThat(test(grid).size()).isEqualTo(100);
// Selected items (via Java API)
Set<PersonRecord> selected = grid.getSelectedItems();
// Cell value as text
String name = test(grid).getCellText(0, 1);
// Underlying row data
PersonRecord row = test(grid).getRow(0);
// Component column action — get the renderer's component and click it
test(grid).getRow(0); // ensure row is materialized
$(Button.class, grid).withCondition(b -> /* ... */).first().click();
// Notification is open?
assertThat($(Notification.class).exists()).isTrue();
// Read its text
String message = test($(Notification.class).single()).getText();
assertThat(message).isEqualTo("Record saved successfully");
// No notification
assertThat($(Notification.class).exists()).isFalse();
ConfirmDialog dialog = $(ConfirmDialog.class).single();
test(dialog).confirm(); // click confirm
test(dialog).cancel(); // click cancel
test(dialog).reject(); // click reject (3-button dialogs)
fireShortcut(Key.ENTER);
fireShortcut(Key.KEY_S, KeyModifier.CONTROL);
For components without a stable label/text, set a test ID on the server side and look up by ID:
// Server-side
submitButton.setTestId("submit-button");
// In the test
Button submit = $(Button.class).id("submit-button");
Use AssertJ for assertions; read state from component APIs, not from test(...).
| Assertion Type | Example |
|---|---|
| Grid size | assertThat(test(grid).size()).isEqualTo(10) |
| Component visible | assertThat(button.isVisible()).isTrue() |
| Component enabled | assertThat(button.isEnabled()).isTrue() |
| Field value | assertThat(textField.getValue()).isEqualTo("x") |
| Field invalid | assertThat(textField.isInvalid()).isTrue() |
| Collection size | assertThat(items).hasSize(5) |
| Notification text | assertThat(test(notif).getText()).isEqualTo("Saved") |
| Component open | assertThat($(Dialog.class).exists()).isTrue() |
docs/use-cases/UC-XXX-*.md) to identify the main success
scenario, alternative flows (A1, A2, …), and referenced business rules (BR-XXX)UseCase annotation type already exists in the project. If not, create
UseCase.java with the canonical shape shown aboveUC<id><PascalCaseUseCaseName>Test, extending
SpringBrowserlessTest and annotated @SpringBootTest (or open the existing one)@UseCase(id = "UC-XXX", scenario = "…", businessRules = {"BR-…"})
mirroring the spec headingsnavigate(...)$() / $view()test(component)$()...exists() to verify the component is in the treegetCurrentView() to confirm navigation succeededContextMenuTester, MenuBarTester) — $() won't see them@UseCase annotation contract): https://github.com/AI-Unified-Process/intellij-pluginhttps://mcp.vaadin.com/docs)Alternatives
mgiovani/cc-arsenal
Multi-agent review team: architecture, security, performance, testing, style, docs/UX, plus an adversary that cross-examines the other 6, for security-sensitive, architectural, or large PRs (15+ files) where a single-agent pass risks missing cross-cutting issues. Use for auth/payments/PII changes, schema/pattern changes, compliance sign-off, or when asked to 'get the review team on this' / 'multi-agent review' / 'thorough review before merge'. For a standard PR or a quick pre-merge check, use /r
event4u-app/agent-config
Use when writing Playwright E2E tests — browser automation, visual regression testing, Page Objects, fixtures, and reliable test patterns.
JasonColapietro/suede-creator-skills
Design AI evals that catch regressions before users do: rubrics, test cases, failure modes, acceptance gates, and AI-SPEC artifacts.
AI-Unified-Process/marketplace
Creates Karibu server-side unit tests for Vaadin views covering navigation, component interactions, form validation, grid operations, and notifications. Use when the user asks to "write Karibu tests", "unit test a Vaadin view", "test the UI server-side", "create view tests", or mentions Karibu testing, Vaadin unit tests, or server-side UI testing.