Generate Playwright integration tests for Vaadin 25 views using the DramaFinder library, including element interaction, form validation, grid assertions, and navigation checks. Use when the user wants to write IT tests for a Vaadin view, mentions DramaFinder, or asks about Playwright testing in a Vaadin project.
How this skill is triggered — by the user, by Claude, or both
Slash command
/vaadin-playwright-test:vaadin-playwright-testThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Always follow [@TESTING.md](TESTING.md) when generating tests. Key rules:
Always follow @TESTING.md when generating tests. Key rules:
aria-label, aria-role, or
data-testid over CSS classes or generated IDsgrid.locator("vaadin-grid-cell-content"),
combo.locator("vaadin-combo-box-item")). These shadow/light-DOM tags are
implementation details — the wrapper already exposes the count, content, and
state you need. Raw locators are a last resort, allowed only for a
component that has no wrapper at all (see Step 2).Thread.sleep() — use Playwright auto-waiting or waitFor methods
insteadRun these checks in parallel before doing anything else:
pom.xml for
<artifactId>dramafinder</artifactId>.pom.xml for spring-boot-starter.*IT.java files under src/test/java.SpringPlaywrightIT already in project? —
find src/test/java -name SpringPlaywrightIT.java.Resolve the latest version (Step 1 of setup.md) and propose the following in a single confirmation:
org.vaadin.addons:dramafinder:<VERSION> and
com.microsoft.playwright:playwright (test scope) to pom.xml with
<dramafinder.version> in <properties>.src/test/java/<basePackage>/it/support/SpringPlaywrightIT.java.On confirmation, execute setup.md end-to-end, then continue with Step 2.
If existing *IT.java files are found, read one or two to understand the
project's conventions (base class, package structure, assertion style, helper
methods) and use them as the template.
If no existing IT tests exist, use the default structure in Step 3.
SpringPlaywrightIT locationRead the target view source provided by the user. Extract:
@Route("value") → URL path (default: class name lowercased, stripped of
View suffix, e.g. PersonView → /person).@PageTitle("...") → expected page titleSee element-mapping.md for the full component → element class table, and api-reference.md for the complete public API (every element, its methods, signatures and one-line descriptions) of the version you have installed.
Never download or unzip the DramaFinder jar/sources to discover its API. The complete, always-current signature reference is bundled beside this skill in api-reference.md (auto-generated from source). If a method isn't there, it doesn't exist in this version — do not guess or dig into the jar. The few components with non-obvious behaviour also have prose docs in the specifications folder.
To look up an element, grep
api-reference.mdfor the element name and read only that section (each is a### <Name>Elementheading) — don't read the whole file. Shared mixin methods are documented once under "Shared mixins".
Before writing any raw locator, confirm there is genuinely no wrapper: check
element-mapping.md and scan src/main/java for
*Element.java files (custom extensions not in the table). Only if neither
covers the component may you use a plain Playwright locator. For recurring
needs, create your own element class extending VaadinElement,
or open an issue in the
DramaFinder repository to request one.
A wrapper exposes the count/content/state you need — use it instead of digging into the component's internal tags.
// ❌ WRONG — reaching into Grid internals with a raw locator
GridElement leaderboardGrid = GridElement.get(page);
// Vaadin Grid renders row cells as vaadin-grid-cell-content inside the grid element
int cellCount = leaderboardGrid.getLocator().locator("vaadin-grid-cell-content").count();
// ✅ RIGHT — use the GridElement API
GridElement leaderboardGrid = GridElement.get(page);
int rows = leaderboardGrid.getRenderedRowCount(); // or getTotalRowCount()
int cols = leaderboardGrid.getColumnCount();
leaderboardGrid.assertCellContent(0, "Score", "100");
leaderboardGrid.assertRowCount(10);
The same rule applies to every wrapped component: ComboBoxElement.selectByText()
not combo.locator("vaadin-combo-box-item"); MenuBarElement.clickItem() not
a raw vaadin-menu-bar-button locator; and so on.
package
<same.package.as.view>; // mirror src/test/java structure
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.vaadin.addons.dramafinder.element.TextFieldElement; // import only used elements
import <basePackage>.it.support.SpringPlaywrightIT; // Spring projects: actual location from Step 1
// import org.vaadin.addons.dramafinder.AbstractBasePlaywrightIT; // non-Spring projects
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
// omit if not Spring Boot
public class <ViewName>IT extends
SpringPlaywrightIT { // or AbstractBasePlaywrightIT
@Override
public String getView () {
return "/<route-path>";
}
@Test
public void testTitle () {
assertThat(page).hasTitle("<PageTitle value>");
}
// ... component tests below
}
Use SpringPlaywrightIT if Spring Boot is detected, AbstractBasePlaywrightIT
otherwise.
Smoke test (one per component):
@Test
public void test<ComponentLabel>(){
TextFieldElement field = TextFieldElement.getByLabel(page, "My Label");
field.
assertVisible();
field.
assertLabel("My Label");
field.
assertValue("");
field.
setValue("test value");
field.
assertValue("test value");
}
Form with validation:
@Test
public void testFormSubmitWithInvalidInput() {
TextFieldElement nameField = TextFieldElement.getByLabel(page, "Name");
ButtonElement submitBtn = ButtonElement.getByText(page, "Save");
nameField.setValue("");
submitBtn.click();
nameField.assertInvalid();
nameField.assertErrorMessage("Field is required");
}
@Test
public void testFormSubmitWithValidInput() {
TextFieldElement nameField = TextFieldElement.getByLabel(page, "Name");
ButtonElement submitBtn = ButtonElement.getByText(page, "Save");
nameField.setValue("Jane Doe");
submitBtn.click();
nameField.assertValid();
}
Grid data loading:
@Test
public void testGridLoadsData() {
GridElement grid = GridElement.get(page);
grid.assertRowCount(10); // adjust to expected count
grid.assertCellContent(0, 0, "Expected cell value");
}
Display the full generated test class in a code block. Then ask:
Shall I write this to
src/test/java/<package>/<ViewName>IT.java?
Only write the file after explicit confirmation. Place it in src/test/java
mirroring the view's package under src/main/java.
After writing, ask:
Do you want me to run this test now with
mvn verify -Dit.test=<ViewName>IT?
Warn the user: the first Vaadin frontend build takes 3–5 minutes. Subsequent runs are ~25 seconds.
Guides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.
npx claudepluginhub parttio/dramafinder --plugin vaadin-playwright-test