AI Unified Process UI layer with Vaadin - Flow and Hilla views, Browserless and Vitest view tests, and Playwright end-to-end tests
94
94%
Does it follow best practices?
Impact
94%
1.08xAverage score across 5 eval scenarios
Low
Low-risk findings worth noting
The source file UC001ManagePersonsIT.java, wrapped in Markdown so that every skill host installs it.
Use the content of the code block below; a copy written to disk takes the name UC001ManagePersonsIT.java.
package com.example.app.views;
import java.util.List;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.assertions.PlaywrightAssertions;
import com.microsoft.playwright.options.AriaRole;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.test.context.TestPropertySource;
import org.vaadin.addons.dramafinder.AbstractBasePlaywrightIT;
import org.vaadin.addons.dramafinder.element.ButtonElement;
import org.vaadin.addons.dramafinder.element.GridElement;
import org.vaadin.addons.dramafinder.element.NotificationElement;
import org.vaadin.addons.dramafinder.element.TextFieldElement;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test for UC-001 "Manage Persons". Every expected value comes from the use case
* specification or the Flyway test data (sorted by name), never from a run of the code.
* AssertJ's assertThat checks values; Playwright's PlaywrightAssertions.assertThat checks
* locators and retries until the browser shows the expected state.
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = "spring.flyway.locations=classpath:db/migration,classpath:db/testdata")
@DisplayName("UC-001: Manage Persons")
class UC001ManagePersonsIT extends AbstractBasePlaywrightIT {
// The one person these tests create; the test data holds no person with this email
private static final String NEW_NAME = "Carol Miller";
private static final String NEW_EMAIL = "carol.miller@example.com";
private static final int EMAIL_COLUMN = 1;
@LocalServerPort
private int port;
@Override
public String getUrl() {
return String.format("http://localhost:%d/", port);
}
@Override
public String getView() {
return "persons";
}
@AfterEach
void removeCreatedPerson() {
// Idempotent: the test may have failed before or after creating the person — and only
// the person a test created, never a row of the shared test data
page.navigate(getUrl() + getView());
GridElement grid = GridElement.get(page);
List<Integer> rows = grid.findRowIndexesWithColumnText(EMAIL_COLUMN, NEW_EMAIL);
if (!rows.isEmpty()) {
grid.select(rows.get(0));
ButtonElement.getByText(page, "Delete").click();
Locator confirm = confirmDialog("Confirm Delete");
ButtonElement.getByText(confirm, "Delete").click();
PlaywrightAssertions.assertThat(confirm).isHidden();
}
}
/**
* The view's ConfirmDialog. Drama Finder has no wrapper for it, and DialogElement matches
* <vaadin-dialog> only: <vaadin-confirm-dialog> carries the role "alertdialog" and its header
* as accessible name (Vaadin 25), so locate it by role and name, narrowed to its tag.
*/
private Locator confirmDialog(String header) {
return page.getByRole(AriaRole.ALERTDIALOG, new Page.GetByRoleOptions().setName(header))
.and(page.locator("vaadin-confirm-dialog"));
}
// One @Nested group per scenario of the specification, named with its heading: the main success
// scenario first, then one per alternative flow ("A1: …"). /use-case-coverage maps the groups by these names.
@Nested
@DisplayName("Main Success Scenario")
class MainSuccessScenario {
@Test
@DisplayName("Step 1: Grid shows the persons on page load")
void grid_displays_data() {
GridElement grid = GridElement.get(page);
// First row of the test data; assert rows, not the total, which other tests change
var firstCell = grid.findCell(0, "Name");
PlaywrightAssertions.assertThat(firstCell.get().getCellContentLocator()).hasText("Eula Lane");
}
@Test
@DisplayName("Step 1: Grid headers match the columns the specification lists")
void grid_has_expected_headers() {
GridElement grid = GridElement.get(page);
assertThat(grid.getHeaderCellContents()).contains("Name", "Email", "Status");
}
@Test
@DisplayName("Step 2: Selecting a row populates the form")
void select_row_populates_form() {
GridElement grid = GridElement.get(page);
grid.select(0);
// First row of the test data — not read back from the grid, which would only
// compare the view with itself
TextFieldElement nameField = TextFieldElement.getByLabel(page, "Name");
nameField.assertValue("Eula Lane");
}
@Test
@DisplayName("Steps 3–5: Saving a new person shows the message and lists the person")
void save_lists_new_person() {
TextFieldElement.getByLabel(page, "Name").setValue(NEW_NAME);
TextFieldElement.getByLabel(page, "Email").setValue(NEW_EMAIL);
ButtonElement.getByText(page, "Save").click();
NotificationElement notification = new NotificationElement(page);
PlaywrightAssertions.assertThat(notification.getContentLocator()).hasText("Person saved");
GridElement grid = GridElement.get(page);
List<Integer> rows = grid.findRowIndexesWithColumnText(EMAIL_COLUMN, NEW_EMAIL);
assertThat(rows).hasSize(1);
var nameCell = grid.findCell(rows.get(0), "Name");
PlaywrightAssertions.assertThat(nameCell.get().getCellContentLocator()).hasText(NEW_NAME);
}
}
@Nested
@DisplayName("A1: Required Field Missing")
class A1RequiredFieldMissing {
@Test
@DisplayName("BR-002: Required field shows the error when empty")
void required_field_shows_error() {
// A new person without a name — no row of the test data is touched
TextFieldElement nameField = TextFieldElement.getByLabel(page, "Name");
TextFieldElement.getByLabel(page, "Email").setValue(NEW_EMAIL);
ButtonElement saveButton = ButtonElement.getByText(page, "Save");
saveButton.click();
// BR-002: the name is required — message as the specification words it
nameField.assertInvalid();
nameField.assertErrorMessage("Field is required");
}
}
@Nested
@DisplayName("A2: Delete Confirmation")
class A2DeleteConfirmation {
@Test
@DisplayName("Cancelling the confirmation keeps the person")
void delete_opens_confirm_dialog() {
GridElement grid = GridElement.get(page);
grid.select(0);
ButtonElement deleteButton = ButtonElement.getByText(page, "Delete");
deleteButton.click();
Locator dialog = confirmDialog("Confirm Delete");
PlaywrightAssertions.assertThat(dialog).isVisible();
ButtonElement cancelButton = ButtonElement.getByText(dialog, "Cancel");
cancelButton.click();
// A2: cancelling keeps the person
PlaywrightAssertions.assertThat(dialog).isHidden();
var firstCell = grid.findCell(0, "Name");
PlaywrightAssertions.assertThat(firstCell.get().getCellContentLocator()).hasText("Eula Lane");
}
}
}