Skip to content

Latest commit

 

History

History
248 lines (205 loc) · 8.46 KB

File metadata and controls

248 lines (205 loc) · 8.46 KB

Repository Guidelines

Project Structure & Module Organization

  • Root pom.xml — Core Playwright helpers for Vaadin (src/main/java/...), resources under src/main/resources.

Build, Test, and Development Commands

  • Build all modules + unit tests: ./mvnw clean install
  • Run demo locally: ./mvnw -pl dramafinder-demo spring-boot:run (serves at http://localhost:8080)
  • Run integration tests (Failsafe, includes **/*IT.java): ./mvnw -B verify --file pom.xml
  • Run a single test:
    • IT: ./mvnw -Dit.test=MyViewIT -Pit verify

Coding Style & Naming Conventions

  • Java 21; 4-space indent; organize imports; no trailing whitespace.
  • Packages: lowercase (org.vaadin.dramafinder); classes: PascalCase; methods/fields: camelCase; constants: UPPER_SNAKE_CASE.
  • Public API in dramafinder should be small, cohesive, and documented with Javadoc.
  • Prefer aria role for internal locators

Javadoc Conventions

  • Add a class-level Javadoc for each element class and shared mixin:
    • Identify the Vaadin tag using inline code (e.g., vaadin-text-field).
    • One–two sentence summary of responsibilities and notable behaviors.
    • For factory helpers (e.g., getByLabel), mention the ARIA role used.
  • For public methods, document parameters, return values, and null semantics (especially for assertion helpers where null implies absence).
  • Use {@inheritDoc} on simple overrides (e.g., locator accessors) to avoid duplication.
  • Keep Javadoc concise and consistent; prefer present tense and active voice.

Testing Guidelines

  • Frameworks: JUnit 5, Playwright (Java), Axe-core checks in demo.
  • Unit tests live with their module; integration tests go in src/test/java/**/*IT.java.
  • Tests should be deterministic; avoid timing sleeps—prefer Playwright waits and assertions.

Commit & Pull Request Guidelines

  • Commits: short, imperative subject; optional scope prefix (e.g., core:, demo:). Example: core: add TestFieldElement to test a Vaadin Textfield.
  • PRs: describe intent and approach, link issues, list test coverage and manual steps; include screenshots/gifs for UI changes.
  • Keep changes module-scoped; update README/AGENTS.md when commands or workflows change.

Security & Configuration Tips

  • Requires Java 21. Vaadin demo uses Node tooling; first runs may download frontend and Playwright browser binaries.
  • Do not commit generated/build output: target/, frontend/generated/, vite.generated.ts.
  • Prefer configuration via application.properties in each module’s src/main/resources.

Pitfalls & Patterns

Common Pitfalls

1. Locator Specificity

  • Pitfall: Using overly broad locators that match multiple elements.
  • Solution: Always use .first() when expecting a single element, or filter with Locator.FilterOptions to narrow results.
// Bad: May match multiple elements
page.locator("vaadin-button");

// Good: Specific by accessible name
ButtonElement.getByText(page, "Save");

2. Shadow DOM Piercing

  • Pitfall: Using XPath or CSS selectors that don't pierce shadow DOM.
  • Solution: Playwright auto-pierces shadow DOM with CSS selectors. Use xpath=./* prefix only for direct children to avoid piercing.
// Pierces shadow DOM (default)
getLocator().locator("[slot='input']");

// Does NOT pierce shadow DOM (explicit xpath)
getLocator().locator("xpath=./*[not(@slot)][1]");

3. Input vs Component Locator

  • Pitfall: Calling methods on the wrong locator (component root vs input).
  • Solution: Use getInputLocator() for value/focus operations, getLocator() for component-level attributes.
// Component-level attribute
getLocator().getAttribute("opened");

// Input-level attribute
getInputLocator().getAttribute("value");

4. Async State Changes

  • Pitfall: Asserting state immediately after an action without waiting.
  • Solution: Use Playwright assertions which auto-retry. Avoid raw getAttribute() checks in assertions.
// Bad: No retry, may flake
assertTrue(getLocator().getAttribute("opened") != null);

// Good: Auto-retries until timeout
assertThat(getLocator()).hasAttribute("opened", "");

5. Attribute vs Property

  • Pitfall: Confusing HTML attributes with DOM properties.
  • Solution: Use getAttribute() for HTML attributes, evaluate() or hasJSProperty() for DOM properties.
// HTML attribute
getInputLocator().getAttribute("maxlength");

// DOM property (set via JavaScript)
getLocator().evaluate("(el, v) => el.maxLength = v", max);
assertThat(getLocator()).hasJSProperty("value", expectedValue);

6. Null Handling in Assertions

  • Pitfall: Not handling null values in assertion helpers.
  • Solution: Always check for null and assert absence of attribute.
public void assertMinLength(Integer min) {
    if (min != null) {
        assertThat(getInputLocator()).hasAttribute("minLength", min + "");
    } else {
        // Assert attribute is absent
        assertThat(getInputLocator()).not().hasAttribute("minLength", Pattern.compile(".*"));
    }
}

7. ARIA Role Mismatch

  • Pitfall: Using wrong ARIA role in getByRole() lookups.
  • Solution: Check the actual role of the internal element:
    • Text inputs: TEXTBOX
    • Number inputs: SPINBUTTON
    • Date/time pickers: COMBOBOX
    • Buttons: BUTTON
    • Checkboxes: CHECKBOX
    • Radio buttons: RADIO

Design Patterns

1. Factory Method Pattern

All element classes provide static factory methods for lookup by accessible name:

public static TextFieldElement getByLabel(Page page, String label) {
    return new TextFieldElement(
        page.locator(FIELD_TAG_NAME)
            .filter(new Locator.FilterOptions()
                .setHas(page.getByRole(AriaRole.TEXTBOX,
                    new Page.GetByRoleOptions().setName(label)))
            ).first());
}

2. Mixin Interfaces (Composition)

Shared behavior is extracted into interfaces with default implementations:

public interface HasClearButtonElement extends HasLocatorElement {
    default void clickClearButton() {
        getLocator().locator("[part~='clear-button']").click();
    }
}

3. Locator Delegation Pattern

Elements delegate to specific internal locators for different operations:

@Override
public Locator getFocusLocator() {
    return getInputLocator();  // Focus goes to input, not wrapper
}

@Override
public Locator getEnabledLocator() {
    return getInputLocator();  // Disabled state is on input
}

4. Composite Element Pattern

Complex components compose simpler elements internally:

public class DateTimePickerElement extends VaadinElement {
    private final DatePickerElement datePickerElement;
    private final TimePickerElement timePickerElement;

    public DateTimePickerElement(Locator locator) {
        super(locator);
        datePickerElement = new DatePickerElement(locator.locator(DatePickerElement.FIELD_TAG_NAME));
        timePickerElement = new TimePickerElement(locator.locator(TimePickerElement.FIELD_TAG_NAME));
    }
}

5. Assertion Symmetry Pattern

For each state getter, provide matching assert methods:

public boolean isOpen() { ... }
public void assertOpen() { ... }
public void assertClosed() { ... }

public boolean isChecked() { ... }
public void assertChecked() { ... }
public void assertNotChecked() { ... }

6. Scoped Lookup Pattern

Factory methods support both page-level and scoped lookups:

// Page-level lookup
public static ButtonElement getByText(Page page, String text) { ... }

// Scoped lookup (within a container)
public static ButtonElement getByText(Locator locator, String text) { ... }

Best Practices

  1. Prefer ARIA roles over tag names for element lookup when possible.
  2. Use part selectors for internal component parts (e.g., [part~='input']).
  3. Chain filters rather than complex XPath for readability.
  4. Document null semantics in assertion method Javadocs.
  5. Dispatch events after programmatic value changes if needed:
    getLocator().dispatchEvent("change");
  6. Use constants for tag names and attribute names to avoid typos.
  7. Inherit behavior by extending base elements (e.g., EmailFieldElement extends TextFieldElement).

Agent-Specific Instructions

  • Follow this file's conventions for any edits. Keep patches minimal and focused.
  • Use *IT.java only for end-to-end tests executed by Failsafe.
  • Refer to docs/specifications/ for detailed element API documentation.