CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

ai-unified-process/aiup-vaadin

AI Unified Process UI layer with Vaadin - Flow and Hilla views, Browserless and Vitest view tests, and Playwright end-to-end tests

Quality

96%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

UC001ManagePersonsTest.java.mdskills/vaadin-flow-ui-test/references/

UC001ManagePersonsTest.java

The source file UC001ManagePersonsTest.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 UC001ManagePersonsTest.java.

package com.example.app.views;

import java.util.stream.IntStream;

import com.example.app.person.Person;
import com.example.app.usecase.UseCase;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.confirmdialog.ConfirmDialog;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.browserless.SpringBrowserlessTest;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.security.test.context.support.WithMockUser;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * Use case test for UC-001 "Manage Persons". The view gets its data from the service layer
 * (PersonService returning Person records); the test drives the view only and seeds data through
 * the Flyway test migrations, never through the service. Labels and messages come from the
 * vaadin-flow-ui Handover and the specification.
 */
@SpringBootTest
@WithMockUser(roles = "ADMIN")   // the actor's role, as @RolesAllowed("ADMIN") on the view
class UC001ManagePersonsTest extends SpringBrowserlessTest {

    // The one person these tests create; the test data holds no person with this email
    private static final String NEW_EMAIL = "carol.miller@example.com";

    @Autowired
    private JdbcClient jdbcClient;

    @AfterEach
    void removeCreatedPerson() {
        // Idempotent and targeted: a test may have failed before or after creating the person
        jdbcClient.sql("delete from person where email = ?").param(NEW_EMAIL).update();
    }

    @Test
    @UseCase(id = "UC-001")
    void grid_lists_the_persons_of_the_test_data() {
        navigate(ManagePersonsView.class);

        // Expected values come from the Flyway test data (sorted by first name), never from a
        // run of the code. Assert rows, not the total: other use cases' test data may share the table.
        Grid<Person> grid = find(Grid.class).id("person-grid");
        assertThat(test(grid).getRow(0).firstName()).isEqualTo("Eula");
        assertThat(test(grid).getCellText(0, 1)).isEqualTo("Lane");
    }

    @Test
    @UseCase(id = "UC-001")
    void selecting_a_row_fills_the_form() {
        navigate(ManagePersonsView.class);

        Grid<Person> grid = find(Grid.class).id("person-grid");
        grid.select(test(grid).getRow(0));

        // First row of the test data — not read back from the grid, which would only compare
        // the view with itself
        assertThat(find(TextField.class).withCaption("First Name").single().getValue()).isEqualTo("Eula");
        assertThat(find(TextField.class).withCaption("Last Name").single().getValue()).isEqualTo("Lane");
    }

    @Test
    @UseCase(id = "UC-001")
    void saving_a_new_person_shows_the_message_and_lists_the_person() {
        navigate(ManagePersonsView.class);

        createPerson("Carol", "Miller", NEW_EMAIL);

        // Main success scenario step 5: the exact message the specification states
        Notification notification = find(Notification.class).single();
        assertThat(test(notification).getText()).isEqualTo("Person saved");
        // Postcondition: the new person is persisted — read back from the database, not only from the
        // grid — and listed
        assertThat(jdbcClient.sql("select first_name from person where email = ?")
                .param(NEW_EMAIL).query(String.class).list()).containsExactly("Carol");
        assertThat(rowOf(find(Grid.class).id("person-grid"), NEW_EMAIL)).isNotNegative();
    }

    @Test
    @UseCase(id = "UC-001")
    void required_first_name_shows_validation_error() {
        navigate(ManagePersonsView.class);

        TextField firstName = find(TextField.class).withCaption("First Name").single();
        test(find(TextField.class).withCaption("Last Name").single()).setValue("Miller");
        test(find(TextField.class).withCaption("Email").single()).setValue(NEW_EMAIL);
        test(find(Button.class).withText("Save").single()).click();

        // Entity model: the first name is required — message as the specification words it
        assertThat(firstName.isInvalid()).isTrue();
        assertThat(firstName.getErrorMessage()).isEqualTo("Field is required");
        assertThat(rowOf(find(Grid.class).id("person-grid"), NEW_EMAIL)).isNegative();
    }

    @Test
    @UseCase(id = "UC-001", scenario = "A1: Email Already Registered", businessRules = {"BR-001"})
    void saving_with_a_registered_email_is_rejected() {
        navigate(ManagePersonsView.class);

        // BR-001: the email is unique — eula.lane@example.com is registered by the test data
        createPerson("Carol", "Miller", "eula.lane@example.com");

        Notification notification = find(Notification.class).single();
        assertThat(test(notification).getText()).isEqualTo("Email already registered");
    }

    @Test
    @UseCase(id = "UC-001", scenario = "A2: Delete Confirmation")
    void delete_removes_the_person_after_confirmation() {
        navigate(ManagePersonsView.class);
        // Delete a person this test created, never a row of the shared test data
        createPerson("Carol", "Miller", NEW_EMAIL);

        Grid<Person> grid = find(Grid.class).id("person-grid");
        grid.select(test(grid).getRow(rowOf(grid, NEW_EMAIL)));
        test(find(Button.class).withText("Delete").single()).click();

        ConfirmDialog dialog = find(ConfirmDialog.class).single();
        test(dialog).confirm();

        // Postcondition of A2: the person is removed from the database and the grid
        assertThat(find(ConfirmDialog.class).exists()).isFalse();
        assertThat(jdbcClient.sql("select count(*) from person where email = ?")
                .param(NEW_EMAIL).query(Long.class).single()).isZero();
        assertThat(rowOf(grid, NEW_EMAIL)).isNegative();
    }

    private void createPerson(String firstName, String lastName, String email) {
        test(find(TextField.class).withCaption("First Name").single()).setValue(firstName);
        test(find(TextField.class).withCaption("Last Name").single()).setValue(lastName);
        test(find(TextField.class).withCaption("Email").single()).setValue(email);
        test(find(Button.class).withText("Save").single()).click();
    }

    /** Index of the row with this email, or -1 — reads every row, so it works with lazy data providers. */
    private int rowOf(Grid<Person> grid, String email) {
        return IntStream.range(0, test(grid).size())
                .filter(i -> email.equals(test(grid).getRow(i).email()))
                .findFirst()
                .orElse(-1);
    }
}

.mcp.json

README.md

tile.json