| |

Selenium to Playwright Migration Part 5: Waits, Retries, and Infrastructure

This is part of the Selenium to Playwright Migration Series. Follow the complete 7-part tutorial to migrate your test suite from Selenium Java to Playwright TypeScript.


The infrastructure layer changes dramatically: WebDriverWait becomes auto-wait, RetryAnalyzer becomes a config line, ScreenshotListener becomes a flag, and ThreadLocal driver becomes browser contexts.

Contents

Wait Strategy Conversion

Before: WaitHelpers.java (60+ lines)

public class WaitHelpers {
    private WebDriverWait wait;
    public WaitHelpers(WebDriver driver) {
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }
    public void waitForVisibility(WebElement element) {
        wait.until(ExpectedConditions.visibilityOf(element));
    }
    public void waitForClickable(WebElement element) {
        wait.until(ExpectedConditions.elementToBeClickable(element));
    }
    public void waitForText(WebElement element, String text) {
        wait.until(ExpectedConditions.textToBePresentInElement(element, text));
    }
}

After: Delete the file entirely

// No WaitHelper needed in Playwright!

// Every action auto-waits for element to be:
// - Attached to DOM
// - Visible
// - Stable (no animation)
// - Enabled
// - Not obscured by other elements

await page.getByRole('button', { name: 'Submit' }).click();
// ^ Automatically waits for all 5 conditions before clicking

// For assertions, expect() auto-retries:
await expect(page.getByText('Success')).toBeVisible();
// ^ Retries every 100ms until visible or timeout (default 5s)

// Custom timeout when needed:
await expect(page.getByText('Report ready')).toBeVisible({ timeout: 30_000 });

Retry Logic: RetryAnalyzer to Config

Before: 40+ lines of Java

public class RetryAnalyzer implements IRetryAnalyzer {
    private int retryCount = 0;
    private static final int MAX_RETRY = 2;
    public boolean retry(ITestResult result) {
        if (retryCount < MAX_RETRY) { retryCount++; return true; }
        return false;
    }
}
public class RetryListener implements IAnnotationTransformer {
    public void transform(ITestAnnotation annotation, ...) {
        annotation.setRetryAnalyzer(RetryAnalyzer.class);
    }
}

After: 1 line in config

// playwright.config.ts
export default defineConfig({
  retries: process.env.CI ? 2 : 0,  // That's it. Done.
});

Screenshot and Video: Listeners to Config

// playwright.config.ts
use: {
  screenshot: 'only-on-failure',  // Replaces ScreenshotListener.java
  video: 'retain-on-failure',     // No Selenium equivalent
  trace: 'on-first-retry',        // Step-by-step replay of every action
}

Test Isolation: ThreadLocal to BrowserContext

In Selenium, you used ThreadLocal<WebDriver> for parallel test isolation. In Playwright, each test automatically gets its own BrowserContext — isolated cookies, localStorage, and session state. Zero configuration needed.

Next: Part 6: AI-Powered Migration — using Claude Code and LLMs to automate the conversion process.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.