Skip to main content

Overview

This guide addresses common issues you may encounter when writing tests with Drama Finder, organized by category with practical solutions.

Locator Issues

Element Not Found

Symptoms:
  • Error: Element not found
  • PlaywrightException: Timeout 15000ms exceeded
  • Locator returns null or empty
Common Causes:
  1. Incorrect Label or Text
    // Wrong: Typo in label
    TextFieldElement field = TextFieldElement.getByLabel(page, "Usernme");
    
    // Correct: Exact label text
    TextFieldElement field = TextFieldElement.getByLabel(page, "Username");
    
  2. Element Not Yet Rendered
    // Wrong: Immediate lookup after navigation
    page.navigate("/dashboard");
    ButtonElement button = ButtonElement.getByText(page, "Save");
    button.click(); // May fail
    
    // Correct: Wait for Vaadin to be ready
    page.navigate("/dashboard");
    page.waitForFunction(WAIT_FOR_VAADIN_SCRIPT);
    ButtonElement button = ButtonElement.getByText(page, "Save");
    button.click();
    
  3. Shadow DOM Not Pierced
    // Wrong: XPath doesn't pierce shadow DOM
    Locator input = getLocator().locator("xpath=//input");
    
    // Correct: CSS selector pierces shadow DOM
    Locator input = getLocator().locator("input");
    
Solution:
  • Verify the exact label/text in your application
  • Ensure Vaadin Flow is ready before interactions
  • Use CSS selectors, not XPath, for shadow DOM elements
  • Check element visibility with assertVisible() first

Multiple Elements Matched

Symptoms:
  • Error: Multiple elements found
  • Wrong element is selected
  • Ambiguous locator warning
Common Causes:
  1. Missing .first() Call
    // Wrong: May match multiple buttons
    ButtonElement button = new ButtonElement(page.locator("vaadin-button"));
    
    // Correct: Explicitly select first match
    ButtonElement button = new ButtonElement(
        page.locator("vaadin-button").first()
    );
    
  2. Not Using Scoped Lookup
    // Wrong: May match buttons in other dialogs
    ButtonElement confirmButton = ButtonElement.getByText(page, "Confirm");
    
    // Correct: Scope to specific dialog
    DialogElement dialog = DialogElement.get(page);
    ButtonElement confirmButton = ButtonElement.getByText(
        dialog.getLocator(), "Confirm"
    );
    
Solution:
  • Always use .first() when creating elements from broad selectors
  • Use scoped lookups within containers
  • Use more specific factory methods (getByLabel, getByText)
  • Add unique labels or aria-labels to distinguish similar elements

Wrong Locator Type

Symptoms:
  • getAttribute() returns unexpected results
  • Actions don’t work (click, fill, etc.)
  • State checks fail
Common Causes:
  1. Component vs. Input Locator Confusion
    TextFieldElement field = TextFieldElement.getByLabel(page, "Email");
    
    // Wrong: Value is on input, not component
    String value = field.getLocator().getAttribute("value"); // null or wrong
    
    // Correct: Use input locator for value
    String value = field.getInputLocator().getAttribute("value");
    
    // Wrong: Disabled is on input, not component
    String disabled = field.getLocator().getAttribute("disabled");
    
    // Correct: Check enabled locator
    String disabled = field.getEnabledLocator().getAttribute("disabled");
    
  2. Focus Locator Mismatch
    // Wrong: Focus might be on input, not wrapper
    field.getLocator().focus();
    
    // Correct: Use focus locator
    field.getFocusLocator().focus();
    
    // Or use the element method
    field.focus();
    
Solution:
  • Use getInputLocator() for: value, maxlength, pattern, placeholder
  • Use getLocator() for: theme, class, opened, component-level attributes
  • Use getEnabledLocator() and getFocusLocator() for state checks
  • Consult element documentation for which locator to use

Timing and Synchronization Issues

Flaky Tests Due to Timing

Symptoms:
  • Tests fail intermittently
  • “Element not visible” errors
  • State assertions fail randomly
Common Causes:
  1. Not Using Auto-Retry Assertions
    // Wrong: No retry, checks immediately
    assertTrue(button.getLocator().getAttribute("disabled") != null);
    
    // Correct: Auto-retries until timeout
    button.assertDisabled();
    // or
    assertThat(button.getLocator()).hasAttribute("disabled", "");
    
  2. Hard Waits Instead of Smart Waits
    // Wrong: Fixed wait, may be too short or too long
    button.click();
    page.waitForTimeout(2000);
    assertThat(page.getByText("Success")).isVisible();
    
    // Correct: Wait for specific condition
    button.click();
    assertThat(page.getByText("Success")).isVisible(); // Auto-waits
    
  3. Not Waiting for Vaadin Flow
    // Wrong: Navigate and immediately interact
    page.navigate("/form");
    TextFieldElement field = TextFieldElement.getByLabel(page, "Name");
    field.setValue("John"); // May fail if not ready
    
    // Correct: Wait for Vaadin (done in setupTest())
    // Ensure your base class waits for Vaadin after navigation
    
Solution:
  • Use Playwright assertions that auto-retry
  • Avoid Thread.sleep() and page.waitForTimeout()
  • Use element-specific assertion methods
  • Ensure WAIT_FOR_VAADIN_SCRIPT runs after navigation
  • Increase default timeouts if necessary

Actions Not Taking Effect

Symptoms:
  • click() does nothing
  • setValue() doesn’t change value
  • Form submission fails
Common Causes:
  1. Element Not Actionable
    // Wrong: Element might be covered, disabled, or invisible
    button.getLocator().click();
    
    // Correct: Check state first
    button.assertVisible();
    button.assertEnabled();
    button.click();
    
  2. Missing Event Dispatch
    // Wrong: Programmatic change without event
    field.getInputLocator().evaluate("el => el.value = 'test'");
    // Vaadin doesn't detect change
    
    // Correct: Use fill and dispatch event
    field.getInputLocator().fill("test");
    field.getLocator().dispatchEvent("change");
    
    // Best: Use element method
    field.setValue("test");
    
  3. Wrong Element Clicked
    // Wrong: Clicking wrapper instead of checkbox
    CheckboxElement checkbox = CheckboxElement.getByLabel(page, "Agree");
    checkbox.getLocator().click(); // Might not work
    
    // Correct: Use element method that targets right element
    checkbox.check();
    
Solution:
  • Verify element is visible, enabled, and stable before actions
  • Use element-specific action methods (setValue, check, selectItem)
  • Dispatch events after programmatic changes
  • Check for overlays or loading indicators covering elements

Assertion Failures

Unexpected Attribute Values

Symptoms:
  • Expected attribute not present
  • Attribute has different value than expected
  • null when expecting a value
Common Causes:
  1. Attribute vs. Property Confusion
    // Wrong: maxLength is a property, not attribute
    String maxLen = field.getInputLocator().getAttribute("maxLength");
    
    // Correct: Use lowercase for attribute
    String maxLen = field.getInputLocator().getAttribute("maxlength");
    
    // Or use property check
    assertThat(field.getInputLocator()).hasJSProperty("maxLength", 10);
    
  2. Boolean Attributes
    // Wrong: Boolean attributes have empty string value, not "true"
    assertThat(button.getLocator()).hasAttribute("disabled", "true");
    
    // Correct: Empty string indicates presence
    assertThat(button.getLocator()).hasAttribute("disabled", "");
    
    // Or check for absence
    assertThat(button.getLocator()).not().hasAttribute("disabled", "");
    
  3. Null Handling
    // Wrong: Doesn't handle null case
    public void assertPrefix(String text) {
        assertThat(getPrefixLocator()).hasText(text); // Fails if no prefix
    }
    
    // Correct: Handle null properly
    public void assertPrefix(String text) {
        if (text != null) {
            assertThat(getPrefixLocator()).hasText(text);
        } else {
            assertThat(getPrefixLocator()).not().isVisible();
        }
    }
    
Solution:
  • Use lowercase attribute names
  • Boolean attributes: check for empty string or absence
  • Handle null values in assertion helpers
  • Use hasJSProperty for DOM properties

State Check Failures

Symptoms:
  • assertEnabled() fails when element appears enabled
  • assertChecked() fails for checked checkbox
  • Focus assertions fail
Common Causes:
  1. Checking Wrong Element
    // Wrong: Focused attribute is on component, not input
    TextFieldElement field = TextFieldElement.getByLabel(page, "Name");
    assertThat(field.getInputLocator()).hasAttribute("focused", "");
    
    // Correct: Check component element
    assertThat(field.getLocator()).hasAttribute("focused", "");
    
    // Or use helper
    field.assertIsFocused();
    
  2. Invalid State Not Triggered
    // Wrong: Validation might not run yet
    TextFieldElement field = TextFieldElement.getByLabel(page, "Email");
    field.setValue("");
    field.assertInvalid(); // Might fail if not validated
    
    // Correct: Trigger validation (e.g., blur or submit)
    field.setValue("");
    ButtonElement submit = ButtonElement.getByText(page, "Submit");
    submit.click(); // Triggers validation
    field.assertInvalid();
    
  3. Async State Change
    // Wrong: State might not have updated yet
    button.click();
    assertTrue(button.getLocator().getAttribute("disabled") != null);
    
    // Correct: Use auto-retry assertion
    button.click();
    button.assertDisabled(); // Waits for state to change
    
Solution:
  • Use correct locator for state checks (component vs. input)
  • Trigger validation before checking invalid state
  • Use assertions that auto-retry
  • Check element documentation for state location

Setup and Configuration Issues

Browser Launch Failures

Symptoms:
  • Error: Executable doesn't exist
  • Browser crashes on startup
  • Headless mode issues
Common Causes:
  1. Playwright Browsers Not Installed
    # Install all browsers
    mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install"
    
    # Or just Chromium
    mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install chromium"
    
  2. Missing Dependencies (Linux)
    # Install system dependencies
    mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install-deps"
    
  3. Permissions Issues
    # Check Playwright cache directory
    ls -la ~/.cache/ms-playwright/
    
    # Fix permissions if needed
    chmod -R 755 ~/.cache/ms-playwright/
    
Solution:
  • Install Playwright browsers before running tests
  • Install system dependencies on Linux
  • Check file permissions
  • Use Docker with pre-installed browsers for CI

Port and Network Issues

Symptoms:
  • Connection refused errors
  • Tests can’t navigate to URL
  • Blank pages
Common Causes:
  1. Port Not Available
    // Use random port to avoid conflicts
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    public class MyViewIT extends SpringPlaywrightIT {
        // SpringPlaywrightIT handles random port
    }
    
  2. Server Not Started
    // Ensure Spring Boot is starting
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    // Check application context loads
    
  3. Wrong URL
    // Wrong: Hardcoded port
    @Override
    public String getUrl() {
        return "http://localhost:8080/";
    }
    
    // Correct: Use injected port
    @LocalServerPort
    private int port;
    
    @Override
    public String getUrl() {
        return String.format("http://localhost:%d/", port);
    }
    
Solution:
  • Use RANDOM_PORT in Spring Boot tests
  • Inject @LocalServerPort for dynamic port
  • Verify application starts successfully
  • Check for port conflicts

Vaadin-Specific Issues

Symptoms:
  • White screen
  • JavaScript errors
  • Components not rendering
  • WAIT_FOR_VAADIN_SCRIPT times out
Common Causes:
  1. Dev Mode Bundle Not Built
    # Build Vaadin frontend
    mvn vaadin:build-frontend
    
  2. Node Modules Missing
    # Clean and rebuild
    mvn clean
    mvn vaadin:prepare-frontend
    mvn vaadin:build-frontend
    
  3. Frontend Resources Not Served
    # application.properties for tests
    vaadin.productionMode=false
    spring.web.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
    
  4. JavaScript Errors
    // Enable console logging to debug
    page.onConsoleMessage(msg -> System.out.println(msg.text()));
    
Solution:
  • Build frontend before running tests
  • Check for JavaScript errors in console
  • Verify Vaadin resources are accessible
  • Use production mode for faster tests (if applicable)
  • Check network tab for failed resource loads

Performance Issues

Slow Test Execution

Symptoms:
  • Individual tests take > 10 seconds
  • Test suite takes very long
  • Frequent timeouts
Common Causes:
  1. Long Default Timeouts
    // Reduce timeouts if appropriate
    @BeforeEach
    public void setupTest() throws Exception {
        page = browser.get().newPage();
        page.navigate(getUrl() + getView());
        page.waitForFunction(WAIT_FOR_VAADIN_SCRIPT);
        page.setDefaultTimeout(5000);  // Reduce from 15000
    }
    
  2. Not Using Production Mode
    # application-test.properties
    vaadin.productionMode=true
    
  3. Redundant Navigation
    // Wrong: Navigating multiple times
    @Test
    public void test1() {
        page.navigate("/form");
        // ... test
    }
    
    @Test
    public void test2() {
        page.navigate("/form");
        // ... test
    }
    
    // Correct: Use getView() for initial navigation
    @Override
    public String getView() {
        return "form"; // setupTest() navigates once
    }
    
  4. Not Running in Parallel
    <!-- Enable parallel execution -->
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-failsafe-plugin</artifactId>
        <configuration>
            <parallel>classes</parallel>
            <threadCount>4</threadCount>
        </configuration>
    </plugin>
    
Solution:
  • Use production mode for tests when possible
  • Enable parallel test execution
  • Reduce timeouts if tests don’t need long waits
  • Avoid redundant navigation
  • Profile tests to find bottlenecks

ARIA Role Issues

Wrong ARIA Role in Lookups

Symptoms:
  • getByLabel can’t find element
  • Factory methods return null
  • Multiple elements matched unexpectedly
Common Causes:
  1. Wrong ARIA Role for Component
    // Wrong: Text inputs have role TEXTBOX
    page.getByRole(AriaRole.INPUT, new Page.GetByRoleOptions().setName("Email"))
    
    // Correct: Use TEXTBOX for text fields
    page.getByRole(AriaRole.TEXTBOX, new Page.GetByRoleOptions().setName("Email"))
    
  2. Component Type Mismatch
    // Wrong: Number fields have role SPINBUTTON, not TEXTBOX
    TextFieldElement numberField = TextFieldElement.getByLabel(page, "Age");
    
    // Correct: Use number field element
    IntegerFieldElement numberField = IntegerFieldElement.getByLabel(page, "Age");
    
Reference: Common ARIA Roles
  • Text inputs: TEXTBOX
  • Number inputs: SPINBUTTON
  • Date/time pickers: COMBOBOX
  • Buttons: BUTTON
  • Checkboxes: CHECKBOX
  • Radio buttons: RADIO
  • ComboBox/Select: COMBOBOX
  • Links: LINK
Solution:
  • Use correct element type for component
  • Check actual ARIA role in browser DevTools
  • Refer to Vaadin documentation for component roles
  • Use Drama Finder factory methods (they use correct roles)

Debugging Tips

Enable Visual Debugging

# Run with visible browser
mvn -Dit.test=MyViewIT -Dheadless=false verify

Console Logging

// Log console messages
page.onConsoleMessage(msg -> {
    System.out.println("[" + msg.type() + "] " + msg.text());
});

// Log page errors
page.onPageError(exception -> {
    System.err.println("Page error: " + exception);
});

Screenshots on Failure

@AfterEach
public void cleanupTest(TestInfo testInfo) {
    if (testInfo.getTestMethod().isPresent()) {
        // Screenshot on failure (check via TestWatcher if needed)
        page.screenshot(new Page.ScreenshotOptions()
            .setPath(Paths.get("screenshots/" + testInfo.getDisplayName() + ".png")));
    }
    page.close();
}

Slow Motion

@BeforeAll
public static void setup() {
    Playwright p = Playwright.create();
    playwright.set(p);
    browser.set(p.chromium().launch(new LaunchOptions()
        .setHeadless(false)
        .setSlowMo(1000))); // 1 second between actions
}

Trace Recording

@BeforeEach
public void setupTest() throws Exception {
    page = browser.get().newPage();
    
    // Start tracing
    browser.get().newContext().tracing().start(new Tracing.StartOptions()
        .setScreenshots(true)
        .setSnapshots(true));
    
    page.navigate(getUrl() + getView());
    page.waitForFunction(WAIT_FOR_VAADIN_SCRIPT);
}

@AfterEach
public void cleanupTest() {
    // Stop tracing and save
    browser.get().contexts().get(0).tracing().stop(
        new Tracing.StopOptions().setPath(Paths.get("trace.zip"))
    );
    page.close();
}

Getting Help

Check Documentation

Element Reference

Detailed API documentation

Best Practices

Writing maintainable tests

Common Patterns

Real-world examples

Setup Guide

Initial configuration

Community Resources

  • Drama Finder GitHub: Report issues and request features
  • Playwright Documentation: Official Playwright Java docs
  • Vaadin Documentation: Component behavior and attributes
  • Stack Overflow: Tag questions with playwright, vaadin, and drama-finder

Creating Bug Reports

When reporting issues, include:
  1. Minimal reproducible example
    @Test
    public void testReproduceIssue() {
        // Minimal code that reproduces the problem
    }
    
  2. Environment details
    • Java version
    • Playwright version
    • Vaadin version
    • Drama Finder version
    • OS and browser
  3. Error messages and stack traces
  4. Screenshots or videos if applicable
  5. Expected vs. actual behavior

Build docs developers (and LLMs) love