QAmigrate
Migration Report
Java (Selenium) Java (Playwright) · Started 2026-05-02T17:31:55.287687+00:00 · Finished 2026-05-02T17:36:08.513212+00:00
Migrated
15
of 15 files
Failed
0
generation errors
Patterns
44
Selenium patterns handled
Avg confidence
100%
across all files
Total time
245.4s
wall-clock
Hours saved
~11.0
est. manual effort
⚠ Priority
0
Failed or confidence < 70%
~ Verify
0
Hallucinations or 3+ fix attempts
✓ Solid
15
Confidence ≥ 90%, compiled clean
Selenium patterns handled
PatternCount
By_id6
WebDriver6
ExpectedConditions5
By_field4
click3
sendKeys2
clear2
By_cssSelector2
JavascriptExecutor2
assertTrue2
JUnit4_Test2
TestNG_BeforeMethod1
TestNG_AfterMethod1
ChromeDriver1
FirefoxDriver1
WebDriverWait1
Actions1
Select1
hover1
Files
✓ Success
BaseTest.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\core\BaseTest.java
67 → 70 lines
100%
13.4s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • TestNG_BeforeMethod×1Convert to JUnit 5 @BeforeEach
  • TestNG_AfterMethod×1Convert to JUnit 5 @AfterEach
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.core;n1package com.qastarter.core.playwright;
22
n3import com.qastarter.config.ConfigurationReader;n3import com.qastarter.config.playwright.ConfigurationReader;
4import com.qastarter.listeners.TestListener;4import com.qastarter.listeners.TestListener;
n5import com.qastarter.utils.Log;n5import com.qastarter.utils.playwright.Log;
6import org.openqa.selenium.WebDriver;6import com.microsoft.playwright.Page;
7import org.testng.annotations.AfterMethod;7import org.testng.annotations.AfterMethod;
8import org.testng.annotations.AfterSuite;8import org.testng.annotations.AfterSuite;
9import org.testng.annotations.BeforeMethod;9import org.testng.annotations.BeforeMethod;
10import org.testng.annotations.BeforeSuite;10import org.testng.annotations.BeforeSuite;
11import org.testng.annotations.Listeners;11import org.testng.annotations.Listeners;
1212
n13/**n
14 * Base Test - Extend this in all your test classes.
15 * 
16 * Handles browser lifecycle automatically.
17 */
18@Listeners({TestListener.class})13@Listeners({TestListener.class})
19public class BaseTest {14public class BaseTest {
2015
nn16    // No explicit constructor needed - using default constructor
17 
18    // Migration: Preserved TestNG @BeforeSuite annotation and logging logic
21    @BeforeSuite(alwaysRun = true)19    @BeforeSuite(alwaysRun = true)
22    public void beforeSuite() {20    public void beforeSuite() {
23        Log.info("========================================");21        Log.info("========================================");
29        Log.info("Base URL: " + ConfigurationReader.getBaseUrl());27        Log.info("Base URL: " + ConfigurationReader.getBaseUrl());
30    }28    }
3129
nn30    // Migration: Preserved TestNG @AfterSuite annotation and logging logic
32    @AfterSuite(alwaysRun = true)31    @AfterSuite(alwaysRun = true)
33    public void afterSuite() {32    public void afterSuite() {
34        Log.info("========================================");33        Log.info("========================================");
36        Log.info("========================================");35        Log.info("========================================");
37    }36    }
3837
nn38    // Migration: Preserved TestNG @BeforeMethod annotation, replaced WebDriver.
 >get() with Page.navigate()
39    @BeforeMethod(alwaysRun = true)39    @BeforeMethod(alwaysRun = true)
40    public void setUp() {40    public void setUp() {
41        Log.info("--- Test Setup Started ---");41        Log.info("--- Test Setup Started ---");
42        DriverManager.initializeDriver();42        DriverManager.initializeDriver();
n43 n
44        String baseUrl = ConfigurationReader.getBaseUrl();43        String baseUrl = ConfigurationReader.getBaseUrl();
45        if (baseUrl != null && !baseUrl.isEmpty()) {44        if (baseUrl != null && !baseUrl.isEmpty()) {
n46            getDriver().get(baseUrl);n45            getDriver().navigate(baseUrl);
47            Log.info("Navigated to: " + baseUrl);46            Log.info("Navigated to: " + baseUrl);
48        }47        }
49        Log.info("--- Test Setup Completed ---");48        Log.info("--- Test Setup Completed ---");
50    }49    }
5150
nn51    // Migration: Preserved TestNG @AfterMethod annotation and DriverManager lif
 >ecycle
52    @AfterMethod(alwaysRun = true)52    @AfterMethod(alwaysRun = true)
53    public void tearDown() {53    public void tearDown() {
54        Log.info("--- Test Teardown Started ---");54        Log.info("--- Test Teardown Started ---");
56        Log.info("--- Test Teardown Completed ---");56        Log.info("--- Test Teardown Completed ---");
57    }57    }
5858
nn59    // Migration: Changed return type from WebDriver to Page to match Playwright
 > API
59    protected WebDriver getDriver() {60    protected Page getDriver() {
60        return DriverManager.getDriver();61        return DriverManager.getDriver();
61    }62    }
6263
nn64    // Migration: Replaced WebDriver.get() with Page.navigate() for Playwright
63    protected void navigateTo(String url) {65    protected void navigateTo(String url) {
64        Log.step("Navigating to: " + url);66        Log.step("Navigating to: " + url);
n65        getDriver().get(url);n67        getDriver().navigate(url);
66    }68    }
tt69 
67}70}
✓ Success
BasePage.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\pages\BasePage.java
84 → 76 lines
100%
15.4s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • sendKeys×1Replace with locator.fill() for inputs or type() for special keys
  • click×1Direct conversion to locator.click()
  • clear×1Remove - Playwright's fill() clears first
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.pages;n1package com.qastarter.pages.playwright;
22
n3import com.qastarter.core.DriverManager;n3import com.microsoft.playwright.Locator;
4import com.microsoft.playwright.Page;
4import com.qastarter.utils.Log;5import com.qastarter.utils.playwright.Log;
5import com.qastarter.utils.WaitUtils;6import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertTha
 >t;
6import org.openqa.selenium.*;
77
n8/**n
9* Base Page - Extend this in all your page objects.
10*
11* Uses WaitUtils for centralized wait logic.
12*/
13public abstract class BasePage {8public abstract class BasePage {
149
n15protected WebDriver driver;n10    protected Page page;
1611
n17public BasePage() {n12    public BasePage(Page page) {
18this.driver = DriverManager.getDriver();13        this.page = page;
14    }
15 
16    // Migration: Converted By locator to String selector, removed WaitUtils.wai
 >tForClickability as Playwright auto-waits
17    protected void click(String selector) {
18        Log.action("Click: " + selector);
19        // Playwright auto-waits for clickability - no explicit wait needed
20        page.locator(selector).click();
21    }
22 
23    // Migration: Converted By locator to String selector, replaced clear() + se
 >ndKeys() with fill(), removed explicit wait
24    protected void type(String selector, String text) {
25        Log.action("Type into: " + selector);
26        // Playwright's fill() automatically clears and waits for visibility
27        page.locator(selector).fill(text);
28    }
29 
30    // Migration: Converted By locator to String selector, replaced getText() wi
 >th textContent(), removed explicit wait
31    protected String getText(String selector) {
32        // Playwright auto-waits for visibility before getting text
33        return page.locator(selector).textContent();
34    }
35 
36    // Migration: Converted By locator to String selector, replaced WebDriver.fi
 >ndElement().isDisplayed() with Locator.isVisible()
37    protected boolean isDisplayed(String selector) {
38        try {
39            // Use isVisible() which checks both existence and visibility
40            return page.locator(selector).isVisible();
41        } catch (Exception e) {
42            return false;
43        }
44    }
45 
46    // Migration: Converted By locator to String selector, replaced WaitUtils.wa
 >itForVisibility with Playwright assertion
47    protected void waitForElement(String selector) {
48        // Playwright auto-waits, but explicit visibility check for compatibilit
 >y
49        assertThat(page.locator(selector)).isVisible();
50    }
51 
52    // Migration: Converted By locator to String selector, replaced WaitUtils.wa
 >itForInvisibility with Playwright assertion
53    protected void waitForElementToDisappear(String selector) {
54        // Wait for element to become hidden/invisible
55        assertThat(page.locator(selector)).isHidden();
56    }
57 
58    // Migration: Replaced driver.getTitle() with page.title()
59    public String getPageTitle() {
60        return page.title();
61    }
62 
63    // Migration: Replaced driver.getCurrentUrl() with page.url()
64    public String getCurrentUrl() {
65        return page.url();
66    }
67 
68    // Migration: Preserved logging functionality unchanged
69    protected void logAction(String action) {
70        Log.step("[" + getClass().getSimpleName() + "] " + action);
71    }
72 
73    // Migration: Abstract method preserved unchanged
74    public abstract boolean isLoaded();
75 
19}76}
t20 t
21/**
22* Click on element (uses WaitUtils for waits)
23*/
24protected void click(By locator) {
25Log.action("Click: " + locator);
26WaitUtils.waitForClickability(locator).click();
27}
28 
29/**
30* Type text into element (uses WaitUtils for waits)
31*/
32protected void type(By locator, String text) {
33Log.action("Type into: " + locator);
34WebElement element = WaitUtils.waitForVisibility(locator);
35element.clear();
36element.sendKeys(text);
37}
38 
39/**
40* Get text from element
41*/
42protected String getText(By locator) {
43return WaitUtils.waitForVisibility(locator).getText();
44}
45 
46/**
47* Check if element is displayed (no wait)
48*/
49protected boolean isDisplayed(By locator) {
50try {
51return driver.findElement(locator).isDisplayed();
52} catch (NoSuchElementException | StaleElementReferenceException e) {
53return false;
54}
55}
56 
57/**
58* Wait for element to be visible
59*/
60protected void waitForElement(By locator) {
61WaitUtils.waitForVisibility(locator);
62}
63 
64/**
65* Wait for element to disappear
66*/
67protected void waitForElementToDisappear(By locator) {
68WaitUtils.waitForInvisibility(locator);
69}
70 
71public String getPageTitle() {
72return driver.getTitle();
73}
74 
75public String getCurrentUrl() {
76return driver.getCurrentUrl();
77}
78 
79protected void logAction(String action) {
80Log.step("[" + getClass().getSimpleName() + "] " + action);
81}
82 
83public abstract boolean isLoaded();
84}
✓ Success
LoginPage.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\pages\LoginPage.java
60 → 70 lines
100%
13.0s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • By_id×6Convert to CSS selector with #id
  • By_cssSelector×2Direct conversion to page.locator()
  • click×1Direct conversion to locator.click()
  • By_field×4Replace By field with String selector field. Initialize Locator in constructor: this.field = page.locator(selector).
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.pages;n1package com.qastarter.pages.playwright;
22
n3import org.openqa.selenium.By;n3import com.microsoft.playwright.Locator;
4import com.microsoft.playwright.Page;
5import com.qastarter.pages.playwright.BasePage;
46
n5/**n
6 * Login Page Object for SauceDemo
7 * URL: https://www.saucedemo.com
8 * 
9 * HOW TO CUSTOMIZE:
10 *   1. Update locators below for your app
11 *   2. Update credentials in: src/main/resources/config/dev.properties
12 */
13public class LoginPage extends BasePage {7public class LoginPage extends BasePage {
148
n15    // SauceDemo locatorsn9    private final Locator usernameField;
16    private final By usernameField = By.id("user-name");10    private final Locator passwordField;
17    private final By passwordField = By.id("password");11    private final Locator loginButton;
18    private final By loginButton = By.id("login-button");12    private final Locator errorMessage;
19    private final By errorMessage = By.cssSelector("[data-test='error']");
2013
nn14    public LoginPage(Page page) {
15        super(page);
16        this.usernameField = page.locator("#user-name");
17        this.passwordField = page.locator("#password");
18        this.loginButton = page.locator("#login-button");
19        this.errorMessage = page.locator("[data-test='error']");
20    }
21 
22    // Migration: Converted By.id locator to CSS selector string for BasePage.is
 >Displayed() call
21    @Override23    @Override
22    public boolean isLoaded() {24    public boolean isLoaded() {
n23        return isDisplayed(loginButton);n25        return isDisplayed("#login-button");
24    }26    }
2527
nn28    // Migration: Preserved method chaining pattern, converted By.id to CSS sele
 >ctor for BasePage.type() call
26    public LoginPage enterUsername(String username) {29    public LoginPage enterUsername(String username) {
27        logAction("Entering username: " + username);30        logAction("Entering username: " + username);
n28        type(usernameField, username);n31        type("#user-name", username);
29        return this;32        return this;
30    }33    }
3134
nn35    // Migration: Preserved method chaining pattern, converted By.id to CSS sele
 >ctor for BasePage.type() call
32    public LoginPage enterPassword(String password) {36    public LoginPage enterPassword(String password) {
33        logAction("Entering password");37        logAction("Entering password");
n34        type(passwordField, password);n38        type("#password", password);
35        return this;39        return this;
36    }40    }
3741
nn42    // Migration: Converted By.id to CSS selector for BasePage.click() call
38    public void clickLogin() {43    public void clickLogin() {
39        logAction("Clicking login button");44        logAction("Clicking login button");
n40        click(loginButton);n45        click("#login-button");
41    }46    }
4247
nn48    // Migration: Business logic preserved unchanged
43    public void login(String username, String password) {49    public void login(String username, String password) {
44        enterUsername(username);50        enterUsername(username);
45        enterPassword(password);51        enterPassword(password);
46        clickLogin();52        clickLogin();
47    }53    }
4854
nn55    // Migration: Converted By.cssSelector to string selector for BasePage helpe
 >r calls
49    public String getErrorMessage() {56    public String getErrorMessage() {
n50        return isDisplayed(errorMessage) ? getText(errorMessage) : "";n57        return isDisplayed("[data-test='error']") ? getText("[data-test='error']
 >") : "";
51    }58    }
5259
nn60    // Migration: Converted By.cssSelector to string selector for BasePage.isDis
 >played() call
53    public boolean isErrorDisplayed() {61    public boolean isErrorDisplayed() {
n54        return isDisplayed(errorMessage);n62        return isDisplayed("[data-test='error']");
55    }63    }
5664
nn65    // Migration: Business logic preserved unchanged using inherited BasePage.ge
 >tCurrentUrl()
57    public boolean isLoginSuccessful() {66    public boolean isLoginSuccessful() {
58        return getCurrentUrl().contains("inventory");67        return getCurrentUrl().contains("inventory");
59    }68    }
tt69 
60}70}
✓ Success
ConfigurationReader.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\config\ConfigurationReader.java
69 → 71 lines
100%
12.9s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • None detected
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.config;n1package com.qastarter.config.playwright;
22
3import java.io.InputStream;3import java.io.InputStream;
4import java.util.Properties;4import java.util.Properties;
55
n6/**n
7 * Configuration Reader - Loads environment-specific properties.
8 * 
9 * Usage:
10 *   -Denv=qa (defaults to "dev")
11 *   -Dbrowser=firefox (defaults to value in properties)
12 *   -Dheadless=true
13 * 
14 * Config files: src/main/resources/config/{env}.properties
15 */
16public class ConfigurationReader {6public class ConfigurationReader {
177
18    private static final Properties properties = new Properties();8    private static final Properties properties = new Properties();
19    private static String currentEnvironment;9    private static String currentEnvironment;
2010
nn11    // No explicit constructor needed - using default constructor
12 
13    // Migration: Static initializer preserved as-is - no Playwright-specific ch
 >anges needed
21    static {14    static {
22        String env = System.getProperty("env", "dev");15        String env = System.getProperty("env", "dev");
23        currentEnvironment = (env == null || env.isEmpty()) ? "dev" : env;16        currentEnvironment = (env == null || env.isEmpty()) ? "dev" : env;
24        loadConfig();17        loadConfig();
25    }18    }
2619
nn20    // Migration: Configuration loading logic preserved - no Playwright-specific
 > changes needed
27    private static void loadConfig() {21    private static void loadConfig() {
28        String configFile = "config/" + currentEnvironment + ".properties";22        String configFile = "config/" + currentEnvironment + ".properties";
29        try (InputStream input = ConfigurationReader.class.getClassLoader().getR23        try (InputStream input = ConfigurationReader.class.getClassLoader().getR
>esourceAsStream(configFile)) {>esourceAsStream(configFile)) {
38        }32        }
39    }33    }
4034
nn35    // Migration: Property lookup preserved - maintains System.getProperty -> pr
 >operties_file precedence
41    public static String getProperty(String key) {36    public static String getProperty(String key) {
42        return System.getProperty(key, properties.getProperty(key));37        return System.getProperty(key, properties.getProperty(key));
43    }38    }
4439
nn40    // Migration: Overloaded getProperty method preserved with default value sup
 >port
45    public static String getProperty(String key, String defaultValue) {41    public static String getProperty(String key, String defaultValue) {
46        String value = getProperty(key);42        String value = getProperty(key);
47        return value != null ? value : defaultValue;43        return value != null ? value : defaultValue;
48    }44    }
4945
nn46    // Migration: Base URL getter preserved - used by Playwright page.navigate()
 > calls
50    public static String getBaseUrl() {47    public static String getBaseUrl() {
51        return getProperty("base.url");48        return getProperty("base.url");
52    }49    }
5350
nn51    // Migration: Browser configuration preserved - used by Playwright browser s
 >election
54    public static String getBrowser() {52    public static String getBrowser() {
55        return getProperty("browser", "chrome");53        return getProperty("browser", "chrome");
56    }54    }
5755
nn56    // Migration: Headless mode configuration preserved - used by Playwright lau
 >nch options
58    public static boolean isHeadless() {57    public static boolean isHeadless() {
59        return Boolean.parseBoolean(getProperty("headless", "false"));58        return Boolean.parseBoolean(getProperty("headless", "false"));
60    }59    }
6160
nn61    // Migration: Timeout configuration preserved - used by Playwright page time
 >out settings
62    public static int getTimeout() {62    public static int getTimeout() {
63        return Integer.parseInt(getProperty("timeout.default", "30"));63        return Integer.parseInt(getProperty("timeout.default", "30"));
64    }64    }
6565
nn66    // Migration: Environment getter preserved - used for environment-specific t
 >est configuration
66    public static String getCurrentEnvironment() {67    public static String getCurrentEnvironment() {
67        return currentEnvironment;68        return currentEnvironment;
68    }69    }
tt70 
69}71}
✓ Success
Environment.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\config\Environment.java
30 → 30 lines
100%
0.1s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • None detected
Before → After

Original (Selenium)
Generated (Playwright)
t1package com.qastarter.config;t1package com.qastarter.config.playwright;
22
3/**3/**
4 * Environment enumeration for configuration.4 * Environment enumeration for configuration.
✓ Success
BrowserFactory.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\core\BrowserFactory.java
81 → 70 lines
100%
12.3s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • WebDriver×1Replace with Playwright Page and BrowserContext
  • ChromeDriver×1Replace with Playwright browser launch
  • FirefoxDriver×1Replace with Playwright Firefox
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.core;n1package com.qastarter.core.playwright;
22
n3import com.qastarter.utils.Log;n3import com.qastarter.utils.playwright.Log;
4import org.openqa.selenium.WebDriver;4import com.microsoft.playwright.Browser;
5import org.openqa.selenium.chrome.ChromeDriver;5import com.microsoft.playwright.BrowserType;
6import org.openqa.selenium.chrome.ChromeOptions;6import com.microsoft.playwright.Page;
7import org.openqa.selenium.edge.EdgeDriver;7import com.microsoft.playwright.Playwright;
8import org.openqa.selenium.edge.EdgeOptions;
9import org.openqa.selenium.firefox.FirefoxDriver;
10import org.openqa.selenium.firefox.FirefoxOptions;
11import org.openqa.selenium.safari.SafariDriver;
128
n13/**n
14* Browser Factory - Creates WebDriver instances.
15*
16* Selenium 4.16+ uses built-in Selenium Manager for automatic driver management.
17* No external driver setup required!
18*
19* Supported browsers: chrome, firefox, edge, safari
20*/
21public class BrowserFactory {9public class BrowserFactory {
2210
n23private BrowserFactory() {}n11    private BrowserFactory() {}
2412
nn13    // Migration: Migrated from WebDriver factory to Playwright Page factory. Re
 >turns Page instead of WebDriver, using Playwright browser launch options instead
 > of Selenium driver options.
25public static WebDriver createDriver(String browser, boolean headless) {14    public static Page createDriver(String browser, boolean headless) {
26WebDriver driver;15        Playwright playwright = Playwright.create();
16        Browser browserInstance;
17        switch (browser.toLowerCase()) {
18            case "firefox":
19            BrowserType.LaunchOptions firefoxOptions = new BrowserType.LaunchOpt
 >ions()
20            .setHeadless(headless)
21            .setArgs(java.util.Arrays.asList(
22            "--width=1920",
23            "--height=1080"
24            ));
25            browserInstance = playwright.firefox().launch(firefoxOptions);
26            break;
27            case "edge":
28            BrowserType.LaunchOptions edgeOptions = new BrowserType.LaunchOption
 >s()
29            .setHeadless(headless)
30            .setArgs(java.util.Arrays.asList(
31            "--window-size=1920,1080",
32            "--no-sandbox",
33            "--disable-dev-shm-usage",
34            "--disable-extensions"
35            ));
36            browserInstance = playwright.chromium().launch(edgeOptions);
37            break;
38            case "safari":
39            // Safari does not support headless mode in Playwright
40            if (headless) {
41                Log.warn("Safari does not support headless mode - running in nor
 >mal mode");
42            }
43            BrowserType.LaunchOptions safariOptions = new BrowserType.LaunchOpti
 >ons()
44            .setHeadless(false);
45            browserInstance = playwright.webkit().launch(safariOptions);
46            break;
47            case "chrome":
48            default:
49            BrowserType.LaunchOptions chromeOptions = new BrowserType.LaunchOpti
 >ons()
50            .setHeadless(headless)
51            .setArgs(java.util.Arrays.asList(
52            "--window-size=1920,1080",
53            "--no-sandbox",
54            "--disable-dev-shm-usage",
55            "--disable-gpu",
56            "--disable-extensions",
57            "--disable-infobars",
58            "--ignore-certificate-errors",
59            "--remote-allow-origins=*"
60            ));
61            browserInstance = playwright.chromium().launch(chromeOptions);
62            break;
63        }
64        Page page = browserInstance.newContext().newPage();
65        page.setViewportSize(1920, 1080);
66        Log.info("Created " + browser + " browser (Playwright)");
67        return page;
68    }
2769
n28switch (browser.toLowerCase()) {n
29case "firefox":
30FirefoxOptions firefoxOptions = new FirefoxOptions();
31if (headless) {
32firefoxOptions.addArguments("--headless");
33}70}
t34firefoxOptions.addArguments("--width=1920");t
35firefoxOptions.addArguments("--height=1080");
36driver = new FirefoxDriver(firefoxOptions);
37break;
38 
39case "edge":
40EdgeOptions edgeOptions = new EdgeOptions();
41if (headless) {
42edgeOptions.addArguments("--headless=new");
43}
44edgeOptions.addArguments("--window-size=1920,1080");
45edgeOptions.addArguments("--no-sandbox");
46edgeOptions.addArguments("--disable-dev-shm-usage");
47edgeOptions.addArguments("--disable-extensions");
48driver = new EdgeDriver(edgeOptions);
49break;
50 
51case "safari":
52// Safari does not support headless mode
53if (headless) {
54Log.warn("Safari does not support headless mode - running in normal mode");
55}
56driver = new SafariDriver();
57break;
58 
59case "chrome":
60default:
61ChromeOptions chromeOptions = new ChromeOptions();
62if (headless) {
63chromeOptions.addArguments("--headless=new");
64}
65// Stability options for CI/CD environments
66chromeOptions.addArguments("--window-size=1920,1080");
67chromeOptions.addArguments("--no-sandbox");
68chromeOptions.addArguments("--disable-dev-shm-usage");
69chromeOptions.addArguments("--disable-gpu");
70chromeOptions.addArguments("--disable-extensions");
71chromeOptions.addArguments("--disable-infobars");
72chromeOptions.addArguments("--ignore-certificate-errors");
73chromeOptions.addArguments("--remote-allow-origins=*");
74driver = new ChromeDriver(chromeOptions);
75break;
76}
77 
78Log.info("Created " + browser + " driver (Selenium Manager)");
79return driver;
80}
81}
✓ Success
DriverManager.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\core\DriverManager.java
63 → 103 lines
100%
16.1s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • WebDriver×3Replace with Playwright Page and BrowserContext
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.core;n1package com.qastarter.core.playwright;
22
n3import com.qastarter.config.ConfigurationReader;n3import com.qastarter.config.playwright.ConfigurationReader;
4import com.qastarter.utils.Log;4import com.qastarter.utils.playwright.Log;
5import org.openqa.selenium.WebDriver;5import com.microsoft.playwright.Page;
6import com.microsoft.playwright.BrowserContext;
7import com.microsoft.playwright.Browser;
8import com.microsoft.playwright.Playwright;
69
n7/**n
8 * Driver Manager - Thread-safe WebDriver lifecycle management.
9 * 
10 * Supports parallel test execution via ThreadLocal.
11 */
12public class DriverManager {10public class DriverManager {
1311
nn12    private static final ThreadLocal<Playwright> playwrightThreadLocal = new Thr
 >eadLocal<>();
13    // QAMigrate v0.7: synthesized field — referenced but not declared
14    private static final ThreadLocal<WebDriver> driverThreadLocal = new ThreadLo14    private static final ThreadLocal<Browser> browserThreadLocal = new ThreadLoc
>cal<>();>al<>();
15    // QAMigrate v0.7: synthesized field — referenced but not declared
16    private static final ThreadLocal<BrowserContext> contextThreadLocal = new Th
 >readLocal<>();
17    // QAMigrate v0.7: synthesized field — referenced but not declared
18    private static final ThreadLocal<Page> pageThreadLocal = new ThreadLocal<>()
 >;
1519
16    private DriverManager() {}20    private DriverManager() {}
1721
nn22    // Migration: Changed return type from WebDriver to Page - Playwright's equi
 >valent for browser interaction
18    public static WebDriver getDriver() {23    public static Page getDriver() {
19        WebDriver driver = driverThreadLocal.get();24        Page page = pageThreadLocal.get();
20        if (driver == null) {25        if (page == null) {
21            throw new IllegalStateException("Driver not initialized. Call initia26            throw new IllegalStateException("Driver not initialized. Call initia
>lizeDriver() first.");>lizeDriver() first.");
22        }27        }
n23        return driver;n28        return page;
24    }29    }
2530
nn31    // Migration: Replaced WebDriver initialization with Playwright Page/Browser
 >/Context setup. Removed window maximize as Playwright uses viewport size.
26    public static void initializeDriver() {32    public static void initializeDriver() {
n27        if (driverThreadLocal.get() != null) {n33        if (pageThreadLocal.get() != null) {
28            Log.warn("Driver already exists. Cleaning up...");34            Log.warn("Driver already exists. Cleaning up...");
29            quitDriver();35            quitDriver();
30        }36        }
n31 n
32        String browser = ConfigurationReader.getBrowser();37        String browser = ConfigurationReader.getBrowser();
33        boolean headless = ConfigurationReader.isHeadless();38        boolean headless = ConfigurationReader.isHeadless();
n34 n
35        Log.info("Initializing browser: " + browser + " | Headless: " + headless39        Log.info("Initializing browser: " + browser + " | Headless: " + headless
>);>);
n36 n40        // Initialize Playwright components
37        WebDriver driver = BrowserFactory.createDriver(browser, headless);41        Playwright playwright = Playwright.create();
42        playwrightThreadLocal.set(playwright);
43        Browser browserInstance;
44        switch (browser.toLowerCase()) {
45            case "firefox":
46            browserInstance = playwright.firefox().launch(new com.microsoft.play
 >wright.BrowserType.LaunchOptions().setHeadless(headless));
47            break;
48            case "webkit":
49            case "safari":
50            browserInstance = playwright.webkit().launch(new com.microsoft.playw
 >right.BrowserType.LaunchOptions().setHeadless(headless));
51            break;
52            case "edge":
53            case "chrome":
54            case "chromium":
55            default:
56            browserInstance = playwright.chromium().launch(new com.microsoft.pla
 >ywright.BrowserType.LaunchOptions().setHeadless(headless));
57            break;
58        }
59        browserThreadLocal.set(browserInstance);
60        BrowserContext context = browserInstance.newContext(new Browser.NewConte
 >xtOptions().setViewportSize(1920, 1080));
61        contextThreadLocal.set(context);
62        Page page = context.newPage();
38        driverThreadLocal.set(driver);63        pageThreadLocal.set(page);
39 
40        int timeout = ConfigurationReader.getTimeout();64        int timeout = ConfigurationReader.getTimeout();
n41        driver.manage().window().maximize();n65        page.setDefaultTimeout(timeout * 1000); // Convert to milliseconds
42 
43        Log.info("Browser initialized successfully");66        Log.info("Browser initialized successfully");
44    }67    }
4568
nn69    // Migration: Updated to properly close Playwright resources in correct orde
 >r: Context -> Browser -> Playwright
46    public static void quitDriver() {70    public static void quitDriver() {
nn71        Page page = pageThreadLocal.get();
72        BrowserContext context = contextThreadLocal.get();
47        WebDriver driver = driverThreadLocal.get();73        Browser browser = browserThreadLocal.get();
48        if (driver != null) {74        Playwright playwright = playwrightThreadLocal.get();
75        if (page != null || context != null || browser != null || playwright != 
 >null) {
49            try {76            try {
n50                driver.quit();n77                if (context != null) {
78                    context.close();
79                }
80                if (browser != null) {
81                    browser.close();
82                }
83                if (playwright != null) {
84                    playwright.close();
85                }
51                Log.info("Browser closed");86                Log.info("Browser closed");
52            } catch (Exception e) {87            } catch (Exception e) {
53                Log.error("Error closing browser: " + e.getMessage());88                Log.error("Error closing browser: " + e.getMessage());
54            } finally {89            } finally {
nn90                pageThreadLocal.remove();
91                contextThreadLocal.remove();
55                driverThreadLocal.remove();92                browserThreadLocal.remove();
93                playwrightThreadLocal.remove();
56            }94            }
57        }95        }
58    }96    }
5997
nn98    // Migration: Changed to check Page instead of WebDriver for initialization 
 >status
60    public static boolean isDriverInitialized() {99    public static boolean isDriverInitialized() {
n61        return driverThreadLocal.get() != null;n100        return pageThreadLocal.get() != null;
62    }101    }
tt102 
63}103}
✓ Success
RetryAnalyzer.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\listeners\RetryAnalyzer.java
26 → 24 lines
100%
5.9s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • None detected
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.listeners;n1package com.qastarter.listeners.playwright;
22
3import org.testng.IRetryAnalyzer;3import org.testng.IRetryAnalyzer;
4import org.testng.ITestResult;4import org.testng.ITestResult;
55
n6/**n
7 * Retry failed tests automatically.
8 * 
9 * Usage:
10 *   @Test(retryAnalyzer = RetryAnalyzer.class)
11 */
12public class RetryAnalyzer implements IRetryAnalyzer {6public class RetryAnalyzer implements IRetryAnalyzer {
137
14    private int retryCount = 0;8    private int retryCount = 0;
15    private static final int MAX_RETRIES = 2;9    private static final int MAX_RETRIES = 2;
1610
nn11    // No explicit constructor needed - using default constructor
12 
13    // Migration: No migration needed - TestNG retry logic remains identical in 
 >Playwright
17    @Override14    @Override
18    public boolean retry(ITestResult result) {15    public boolean retry(ITestResult result) {
19        if (retryCount < MAX_RETRIES) {16        if (retryCount < MAX_RETRIES) {
23        }20        }
24        return false;21        return false;
25    }22    }
tt23 
26}24}
✓ Success
TestListener.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\listeners\TestListener.java
81 → 83 lines
100%
15.0s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • None detected
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.listeners;n1package com.qastarter.listeners.playwright;
22
n3import com.qastarter.utils.Log;n3import com.qastarter.utils.playwright.Log;
4import com.qastarter.utils.ScreenshotUtils;4import com.qastarter.utils.playwright.ScreenshotUtils;
5import com.qastarter.utils.ExtentManager;5import com.qastarter.utils.playwright.ExtentManager;
6import com.aventstack.extentreports.Status;6import com.aventstack.extentreports.Status;
n7import com.aventstack.extentreports.MediaEntityBuilder;n
8import org.testng.ITestContext;7import org.testng.ITestContext;
9import org.testng.ITestListener;8import org.testng.ITestListener;
10import org.testng.ITestResult;9import org.testng.ITestResult;
n11 n
12import java.io.File;10import java.io.File;
13import java.util.Base64;11import java.util.Base64;
14import java.nio.file.Files;12import java.nio.file.Files;
1513
n16/**n
17 * TestNG Listener - Handles test events, logging, and reporting.
18 */
19public class TestListener implements ITestListener {14public class TestListener implements ITestListener {
2015
nn16    // No explicit constructor needed - using default constructor
17 
18    // Migration: No changes needed - this method only handles logging and Exten
 >tReports initialization
21    @Override19    @Override
22    public void onStart(ITestContext context) {20    public void onStart(ITestContext context) {
23        Log.info("TEST SUITE: " + context.getName());21        Log.info("TEST SUITE: " + context.getName());
24        ExtentManager.getInstance();22        ExtentManager.getInstance();
25    }23    }
2624
nn25    // Migration: No changes needed - this method only handles logging and Exten
 >tReports cleanup
27    @Override26    @Override
28    public void onFinish(ITestContext context) {27    public void onFinish(ITestContext context) {
29        Log.info("Suite finished: " + context.getName());28        Log.info("Suite finished: " + context.getName());
30        ExtentManager.flush();29        ExtentManager.flush();
31    }30    }
3231
nn32    // Migration: No changes needed - this method only handles test initializati
 >on logging and ExtentReports test creation
33    @Override33    @Override
34    public void onTestStart(ITestResult result) {34    public void onTestStart(ITestResult result) {
35        Log.testStart(getTestName(result));35        Log.testStart(getTestName(result));
36        ExtentManager.createTest(getTestName(result), result.getMethod().getDesc36        ExtentManager.createTest(getTestName(result), result.getMethod().getDesc
>ription());>ription());
37    }37    }
3838
nn39    // Migration: No changes needed - this method only handles success logging a
 >nd ExtentReports status update. Note: Log.testEnd method is called but not defin
 >ed in the provided Log class signatures - preserving original call
39    @Override40    @Override
40    public void onTestSuccess(ITestResult result) {41    public void onTestSuccess(ITestResult result) {
41        Log.testEnd(getTestName(result), "PASSED");42        Log.testEnd(getTestName(result), "PASSED");
44        }45        }
45    }46    }
4647
nn48    // Migration: No changes needed - this method handles failure logging, scree
 >nshot capture, and ExtentReports integration. ScreenshotUtils.capture will be mi
 >grated to work with Playwright Page objects internally
47    @Override49    @Override
48    public void onTestFailure(ITestResult result) {50    public void onTestFailure(ITestResult result) {
49        Log.error("TEST FAILED: " + getTestName(result));51        Log.error("TEST FAILED: " + getTestName(result));
50        Log.error("Reason: " + result.getThrowable().getMessage());52        Log.error("Reason: " + result.getThrowable().getMessage());
n51 n
52        String screenshotPath = ScreenshotUtils.capture("FAILED_" + getTestName(53        String screenshotPath = ScreenshotUtils.capture("FAILED_" + getTestName(
>result));>result));
n53 n
54        if (ExtentManager.getTest() != null) {54        if (ExtentManager.getTest() != null) {
55            ExtentManager.getTest().log(Status.FAIL, result.getThrowable().getMe55            ExtentManager.getTest().log(Status.FAIL, result.getThrowable().getMe
>ssage());>ssage());
n56            n
57            // Attach screenshot as Base64 for reliable embedding56            // Attach screenshot as Base64 for reliable embedding
58            if (screenshotPath != null) {57            if (screenshotPath != null) {
59                try {58                try {
67        }66        }
68    }67    }
6968
nn69    // Migration: No changes needed - this method only handles skip logging and 
 >ExtentReports status update
70    @Override70    @Override
71    public void onTestSkipped(ITestResult result) {71    public void onTestSkipped(ITestResult result) {
72        Log.warn("TEST SKIPPED: " + getTestName(result));72        Log.warn("TEST SKIPPED: " + getTestName(result));
75        }75        }
76    }76    }
7777
nn78    // Migration: No changes needed - this utility method only works with TestNG
 > result metadata
78    private String getTestName(ITestResult result) {79    private String getTestName(ITestResult result) {
79        return result.getTestClass().getRealClass().getSimpleName() + "." + resu80        return result.getTestClass().getRealClass().getSimpleName() + "." + resu
>lt.getMethod().getMethodName();>lt.getMethod().getMethodName();
80    }81    }
tt82 
81}83}
✓ Success
ExtentManager.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\utils\ExtentManager.java
80 → 76 lines
100%
39.1s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • None detected
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.utils;n1package com.qastarter.utils.playwright;
22
3import com.aventstack.extentreports.ExtentReports;3import com.aventstack.extentreports.ExtentReports;
4import com.aventstack.extentreports.ExtentTest;4import com.aventstack.extentreports.ExtentTest;
5import com.aventstack.extentreports.reporter.ExtentSparkReporter;5import com.aventstack.extentreports.reporter.ExtentSparkReporter;
6import com.aventstack.extentreports.reporter.configuration.Theme;6import com.aventstack.extentreports.reporter.configuration.Theme;
n7 n
8import java.io.File;7import java.io.File;
9import java.text.SimpleDateFormat;8import java.text.SimpleDateFormat;
10import java.util.Date;9import java.util.Date;
1110
n12/**n
13 * ExtentReports Manager - HTML reporting integration.
14 * 
15 * Reports saved to: reports/ExtentReport_{timestamp}.html
16 */
17public class ExtentManager {11public class ExtentManager {
1812
19    private static ExtentReports extentReports;13    private static ExtentReports extentReports;
2216
23    private ExtentManager() {}17    private ExtentManager() {}
2418
nn19    // Migration: ExtentReports configuration preserved - only updated document 
 >title to reflect Playwright migration
25    public static ExtentReports getInstance() {20    public static ExtentReports getInstance() {
26        if (extentReports == null) {21        if (extentReports == null) {
27            synchronized (ExtentManager.class) {22            synchronized (ExtentManager.class) {
32                        reportsDir.mkdirs();27                        reportsDir.mkdirs();
33                        System.out.println("[ExtentManager] Created reports dire28                        System.out.println("[ExtentManager] Created reports dire
>ctory: " + reportsDir.getAbsolutePath());>ctory: " + reportsDir.getAbsolutePath());
34                    }29                    }
n35 n
36                    String timestamp = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss30                    String timestamp = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss
>").format(new Date());>").format(new Date());
37                    String reportPath = REPORT_DIR + "/ExtentReport_" + timestam31                    String reportPath = REPORT_DIR + "/ExtentReport_" + timestam
>p + ".html";>p + ".html";
n38 n
39                    ExtentSparkReporter sparkReporter = new ExtentSparkReporter(32                    ExtentSparkReporter sparkReporter = new ExtentSparkReporter(
>reportPath);>reportPath);
40                    sparkReporter.config().setTheme(Theme.DARK);33                    sparkReporter.config().setTheme(Theme.DARK);
n41                    sparkReporter.config().setDocumentTitle("selenium-java-projen34                    sparkReporter.config().setDocumentTitle("playwright-java-pro
>ct Test Report");>ject Test Report");
42                    sparkReporter.config().setReportName("Automation Test Result35                    sparkReporter.config().setReportName("Automation Test Result
>s");>s");
43                    sparkReporter.config().setTimelineEnabled(true);36                    sparkReporter.config().setTimelineEnabled(true);
n44 n
45                    extentReports = new ExtentReports();37                    extentReports = new ExtentReports();
46                    extentReports.attachReporter(sparkReporter);38                    extentReports.attachReporter(sparkReporter);
47                    extentReports.setSystemInfo("Environment", System.getPropert39                    extentReports.setSystemInfo("Environment", System.getPropert
>y("env", "dev"));>y("env", "dev"));
48                    extentReports.setSystemInfo("Browser", System.getProperty("b40                    extentReports.setSystemInfo("Browser", System.getProperty("b
>rowser", "chrome"));>rowser", "chrome"));
49                    extentReports.setSystemInfo("OS", System.getProperty("os.nam41                    extentReports.setSystemInfo("OS", System.getProperty("os.nam
>e"));>e"));
50                    extentReports.setSystemInfo("Java Version", System.getProper42                    extentReports.setSystemInfo("Java Version", System.getProper
>ty("java.version"));>ty("java.version"));
n51 n
52                    System.out.println("[ExtentManager] Report will be saved to:43                    System.out.println("[ExtentManager] Report will be saved to:
> " + new File(reportPath).getAbsolutePath());> " + new File(reportPath).getAbsolutePath());
53                    Log.info("ExtentReports initialized: " + reportPath);44                    Log.info("ExtentReports initialized: " + reportPath);
54                }45                }
57        return extentReports;48        return extentReports;
58    }49    }
5950
nn51    // Migration: ThreadLocal ExtentTest management preserved for parallel execu
 >tion
60    public static void createTest(String testName, String description) {52    public static void createTest(String testName, String description) {
61        ExtentTest test = getInstance().createTest(testName, description);53        ExtentTest test = getInstance().createTest(testName, description);
62        extentTest.set(test);54        extentTest.set(test);
63    }55    }
6456
nn57    // Migration: ThreadLocal access pattern preserved
65    public static ExtentTest getTest() {58    public static ExtentTest getTest() {
66        return extentTest.get();59        return extentTest.get();
67    }60    }
6861
nn62    // Migration: Report flushing logic preserved - ExtentReports is framework-a
 >gnostic
69    public static void flush() {63    public static void flush() {
70        if (extentReports != null) {64        if (extentReports != null) {
71            extentReports.flush();65            extentReports.flush();
74        }68        }
75    }69    }
7670
nn71    // Migration: ThreadLocal cleanup preserved for memory management
77    public static void removeTest() {72    public static void removeTest() {
78        extentTest.remove();73        extentTest.remove();
79    }74    }
tt75 
80}76}
✓ Success
Log.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\utils\Log.java
81 → 70 lines
100%
13.4s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • None detected
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.utils;n1package com.qastarter.utils.playwright;
22
3import org.apache.logging.log4j.LogManager;3import org.apache.logging.log4j.LogManager;
4import org.apache.logging.log4j.Logger;4import org.apache.logging.log4j.Logger;
55
n6/**n
7 * Logger Utility - Consistent logging across the framework.
8 * 
9 * Uses Log4j2. Logs go to: logs/test_latest.log
10 */
11public class Log {6public class Log {
127
13    private static final Logger logger = LogManager.getLogger(Log.class);8    private static final Logger logger = LogManager.getLogger(Log.class);
149
15    private Log() {}10    private Log() {}
1611
nn12    // Migration: No changes needed - logging utility remains the same
17    public static void info(String message) {13    public static void info(String message) {
18        logger.info(message);14        logger.info(message);
19    }15    }
2016
nn17    // Migration: No changes needed - logging utility remains the same
21    public static void debug(String message) {18    public static void debug(String message) {
22        logger.debug(message);19        logger.debug(message);
23    }20    }
2421
nn22    // Migration: No changes needed - logging utility remains the same
25    public static void warn(String message) {23    public static void warn(String message) {
26        logger.warn(message);24        logger.warn(message);
27    }25    }
2826
nn27    // Migration: No changes needed - logging utility remains the same
29    public static void error(String message) {28    public static void error(String message) {
30        logger.error(message);29        logger.error(message);
31    }30    }
3231
nn32    // Migration: No changes needed - overloaded error method preserved
33    public static void error(String message, Throwable throwable) {33    public static void error(String message, Throwable throwable) {
34        logger.error(message, throwable);34        logger.error(message, throwable);
35    }35    }
3636
n37    /**n37    // Migration: Test step logging preserved - critical for ExtentReports integ
 >ration
38     * Log a test step
39     */
40    public static void step(String stepDescription) {38    public static void step(String stepDescription) {
41        logger.info("STEP: " + stepDescription);39        logger.info("STEP: " + stepDescription);
42    }40    }
4341
n44    /**n42    // Migration: Action logging preserved - used by base page methods before Pl
 >aywright actions
45     * Log an action (click, type, etc.)
46     */
47    public static void action(String actionDescription) {43    public static void action(String actionDescription) {
48        logger.info("ACTION: " + actionDescription);44        logger.info("ACTION: " + actionDescription);
49    }45    }
5046
n51    /**n47    // Migration: Wait logging preserved - though Playwright auto-waits, explici
 >t wait scenarios may still need logging
52     * Log wait operation
53     */
54    public static void logWait(String waitDescription) {48    public static void logWait(String waitDescription) {
55        logger.debug("WAIT: " + waitDescription);49        logger.debug("WAIT: " + waitDescription);
56    }50    }
5751
n58    /**n52    // Migration: Assertion logging preserved - used before Playwright assertTha
 >t() calls
59     * Log assertion
60     */
61    public static void assertion(String assertionDescription) {53    public static void assertion(String assertionDescription) {
62        logger.info("ASSERT: " + assertionDescription);54        logger.info("ASSERT: " + assertionDescription);
63    }55    }
6456
n65    /**n57    // Migration: Test lifecycle logging preserved - used by TestNG listeners
66     * Log test start
67     */
68    public static void testStart(String testName) {58    public static void testStart(String testName) {
69        logger.info("========================================");59        logger.info("========================================");
70        logger.info("TEST START: " + testName);60        logger.info("TEST START: " + testName);
71        logger.info("========================================");61        logger.info("========================================");
72    }62    }
7363
n74    /**n64    // Migration: Test lifecycle logging preserved - used by TestNG listeners
75     * Log test end
76     */
77    public static void testEnd(String testName, String status) {65    public static void testEnd(String testName, String status) {
78        logger.info("TEST END: " + testName + " - " + status);66        logger.info("TEST END: " + testName + " - " + status);
79        logger.info("========================================");67        logger.info("========================================");
80    }68    }
tt69 
81}70}
✓ Success
ScreenshotUtils.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\utils\ScreenshotUtils.java
66 → 58 lines
100%
10.0s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • WebDriver×2Replace with Playwright Page and BrowserContext
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.utils;n1package com.qastarter.utils.playwright;
22
n3import com.qastarter.core.DriverManager;n3import com.qastarter.core.playwright.DriverManager;
4import org.openqa.selenium.OutputType;4import com.microsoft.playwright.Page;
5import org.openqa.selenium.TakesScreenshot;
6import org.openqa.selenium.WebDriver;
7 
8import java.io.File;5import java.io.File;
9import java.nio.file.Files;6import java.nio.file.Files;
10import java.nio.file.Path;7import java.nio.file.Path;
12import java.text.SimpleDateFormat;9import java.text.SimpleDateFormat;
13import java.util.Date;10import java.util.Date;
1411
n15/**n
16 * Screenshot Utilities - Capture screenshots on demand.
17 * 
18 * Screenshots saved to: screenshots/
19 */
20public class ScreenshotUtils {12public class ScreenshotUtils {
2113
22    private static final String SCREENSHOT_DIR = "screenshots";14    private static final String SCREENSHOT_DIR = "screenshots";
2315
24    private ScreenshotUtils() {}16    private ScreenshotUtils() {}
2517
nn18    // Migration: Replaced Selenium TakesScreenshot with Playwright page.screens
 >hot() API
26    public static String capture(String testName) {19    public static String capture(String testName) {
27        try {20        try {
n28            WebDriver driver = DriverManager.getDriver();n21            Page page = DriverManager.getDriver();
29            if (driver == null) {22            if (page == null) {
30                Log.error("Cannot capture screenshot - driver is null");23                Log.error("Cannot capture screenshot - page is null");
31                return null;24                return null;
32            }25            }
n33 n
34            Path dir = Paths.get(SCREENSHOT_DIR);26            Path dir = Paths.get(SCREENSHOT_DIR);
35            if (!Files.exists(dir)) {27            if (!Files.exists(dir)) {
36                Files.createDirectories(dir);28                Files.createDirectories(dir);
37            }29            }
n38 n
39            String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(ne30            String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(ne
>w Date());>w Date());
40            String sanitizedName = testName.replaceAll("[^a-zA-Z0-9_-]", "_");31            String sanitizedName = testName.replaceAll("[^a-zA-Z0-9_-]", "_");
41            String fileName = sanitizedName + "_" + timestamp + ".png";32            String fileName = sanitizedName + "_" + timestamp + ".png";
42            Path filePath = dir.resolve(fileName);33            Path filePath = dir.resolve(fileName);
n43 n34            // Playwright screenshot API - captures full page by default
44            File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputT35            byte[] screenshotBytes = page.screenshot();
>ype.FILE); 
45            Files.copy(screenshot.toPath(), filePath);36            Files.write(filePath, screenshotBytes);
46 
47            Log.info("Screenshot saved: " + filePath);37            Log.info("Screenshot saved: " + filePath);
48            return filePath.toString();38            return filePath.toString();
n49 n
50        } catch (Exception e) {39        } catch (Exception e) {
51            Log.error("Failed to capture screenshot: " + e.getMessage());40            Log.error("Failed to capture screenshot: " + e.getMessage());
52            return null;41            return null;
53        }42        }
54    }43    }
5544
nn45    // Migration: Replaced Selenium TakesScreenshot.getScreenshotAs(OutputType.B
 >YTES) with Playwright page.screenshot()
56    public static byte[] captureAsBytes() {46    public static byte[] captureAsBytes() {
57        try {47        try {
n58            WebDriver driver = DriverManager.getDriver();n48            Page page = DriverManager.getDriver();
59            if (driver == null) return null;49            if (page == null) return null;
60            return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);50            // Playwright screenshot returns bytes directly
51            return page.screenshot();
61        } catch (Exception e) {52        } catch (Exception e) {
62            Log.error("Failed to capture screenshot bytes: " + e.getMessage());53            Log.error("Failed to capture screenshot bytes: " + e.getMessage());
63            return null;54            return null;
64        }55        }
65    }56    }
tt57 
66}58}
✓ Success
WaitUtils.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\utils\WaitUtils.java
67 → 77 lines
100%
51.0s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • WebDriverWait×1Remove explicit wait - Playwright auto-waits for actionability
  • ExpectedConditions×5Replace with Playwright assertions or locator methods
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.utils;n1package com.qastarter.utils.playwright;
22
n3import com.qastarter.config.ConfigurationReader;n3import com.qastarter.config.playwright.ConfigurationReader;
4import com.qastarter.core.DriverManager;4import com.qastarter.core.playwright.DriverManager;
5import org.openqa.selenium.By;5import com.microsoft.playwright.Locator;
6import org.openqa.selenium.WebElement;6import com.microsoft.playwright.Page;
7import org.openqa.selenium.support.ui.ExpectedConditions;7import com.microsoft.playwright.options.WaitForSelectorState;
8import org.openqa.selenium.support.ui.WebDriverWait;8import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertTha
 >t;
99
n10import java.time.Duration;n
11 
12/**
13* Wait Utilities - Explicit wait helpers.
14*
15* Timeout configured in: src/main/resources/config/{env}.properties
16*/
17public class WaitUtils {10public class WaitUtils {
1811
n19private WaitUtils() {n12    private WaitUtils() {
20// Private constructor13        // Private constructor
14    }
15 
16    // Migration: Converted By locator to String selector, using Playwright's au
 >to-waiting and visibility assertion
17    public static Locator waitForVisibility(String selector) {
18        Log.logWait("Waiting for visibility: " + selector);
19        // Playwright auto-waits for visibility on actions, but for explicit vis
 >ibility check:
20        Page page = DriverManager.getDriver();
21        Locator locator = page.locator(selector);
22        assertThat(locator).isVisible();
23        return locator;
24    }
25 
26    // Migration: Converted By locator to String selector, using Playwright's bu
 >ilt-in actionability waiting
27    public static Locator waitForClickability(String selector) {
28        Log.logWait("Waiting for clickability: " + selector);
29        // Playwright auto-waits for actionability (clickable state) on click ac
 >tions
30        Page page = DriverManager.getDriver();
31        Locator locator = page.locator(selector);
32        // Verify element is enabled and visible (clickable conditions)
33        assertThat(locator).isVisible();
34        assertThat(locator).isEnabled();
35        return locator;
36    }
37 
38    // Migration: Converted By locator to String selector, using Playwright's wa
 >itFor with ATTACHED state
39    public static Locator waitForPresence(String selector) {
40        Log.logWait("Waiting for presence: " + selector);
41        // Playwright auto-waits for element presence when creating locators
42        Page page = DriverManager.getDriver();
43        Locator locator = page.locator(selector);
44        // Wait for element to be attached to DOM
45        locator.waitFor(new Locator.WaitForOptions().setState(WaitForSelectorSta
 >te.ATTACHED));
46        return locator;
47    }
48 
49    // Migration: Converted By locator to String selector, using Playwright's wa
 >itFor with HIDDEN state
50    public static boolean waitForInvisibility(String selector) {
51        Log.logWait("Waiting for invisibility: " + selector);
52        Page page = DriverManager.getDriver();
53        Locator locator = page.locator(selector);
54        try {
55            // Wait for element to be hidden or detached
56            locator.waitFor(new Locator.WaitForOptions().setState(WaitForSelecto
 >rState.HIDDEN));
57            return true;
58        } catch (Exception e) {
59            return false;
60        }
61    }
62 
63    // Migration: Converted By locator to String selector, using Playwright's co
 >ntainsText assertion
64    public static boolean waitForTextPresent(String selector, String text) {
65        Log.logWait("Waiting for text '" + text + "' in: " + selector);
66        Page page = DriverManager.getDriver();
67        Locator locator = page.locator(selector);
68        try {
69            // Wait for element to contain the specified text
70            assertThat(locator).containsText(text);
71            return true;
72        } catch (Exception e) {
73            return false;
74        }
75    }
76 
21}77}
t22 t
23private static WebDriverWait getWait() {
24int timeout = ConfigurationReader.getTimeout();
25return new WebDriverWait(DriverManager.getDriver(), Duration.ofSeconds(timeout))
>; 
26}
27 
28/**
29* Wait for element to be visible
30*/
31public static WebElement waitForVisibility(By locator) {
32Log.logWait("Waiting for visibility: " + locator);
33return getWait().until(ExpectedConditions.visibilityOfElementLocated(locator));
34}
35 
36/**
37* Wait for element to be clickable
38*/
39public static WebElement waitForClickability(By locator) {
40Log.logWait("Waiting for clickability: " + locator);
41return getWait().until(ExpectedConditions.elementToBeClickable(locator));
42}
43 
44/**
45* Wait for element to be present in DOM
46*/
47public static WebElement waitForPresence(By locator) {
48Log.logWait("Waiting for presence: " + locator);
49return getWait().until(ExpectedConditions.presenceOfElementLocated(locator));
50}
51 
52/**
53* Wait for element to disappear
54*/
55public static boolean waitForInvisibility(By locator) {
56Log.logWait("Waiting for invisibility: " + locator);
57return getWait().until(ExpectedConditions.invisibilityOfElementLocated(locator))
>; 
58}
59 
60/**
61* Wait for text to be present in element
62*/
63public static boolean waitForTextPresent(By locator, String text) {
64Log.logWait("Waiting for text '" + text + "' in: " + locator);
65return getWait().until(ExpectedConditions.textToBePresentInElementLocated(locato
>r, text)); 
66}
67}
✓ Success
WebActions.java D:\TestFlux\samples\selenium-java-project\src\main\java\com\qastarter\utils\WebActions.java
121 → 94 lines
100%
17.9s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • Actions×1Replace with Playwright keyboard/mouse APIs
  • sendKeys×1Replace with locator.fill() for inputs or type() for special keys
  • click×1Direct conversion to locator.click()
  • clear×1Remove - Playwright's fill() clears first
  • Select×1Replace with locator.selectOption()
  • JavascriptExecutor×2Replace with page.evaluate()
  • hover×1Replace with locator.hover()
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.utils;n1package com.qastarter.utils.playwright;
22
nn3import com.microsoft.playwright.Page;
4import com.microsoft.playwright.Locator;
3import com.qastarter.core.DriverManager;5import com.qastarter.core.playwright.DriverManager;
4import org.openqa.selenium.By;6import com.qastarter.utils.playwright.Log;
5import org.openqa.selenium.JavascriptExecutor;
6import org.openqa.selenium.WebDriver;
7import org.openqa.selenium.WebElement;
8import org.openqa.selenium.interactions.Actions;
9import org.openqa.selenium.support.ui.Select;
107
n11/**n
12 * Web Actions - Common web interaction utilities.
13 * 
14 * All methods include logging and error handling.
15 */
16public class WebActions {8public class WebActions {
179
18    private WebActions() {10    private WebActions() {
19        // Private constructor11        // Private constructor
20    }12    }
2113
nn14    // Migration: Changed from getDriver() to getPage() to return Playwright Pag
 >e instead of WebDriver
22    private static WebDriver getDriver() {15    private static Page getPage() {
23        return DriverManager.getDriver();16        return DriverManager.getDriver();
24    }17    }
2518
n26    /**n19    // Migration: Changed parameter from By locator to String selector, removed 
 >explicit wait as Playwright auto-waits
27     * Click on element
28     */
29    public static void click(By locator) {20    public static void click(String selector) {
30        Log.action("Click: " + locator);21        Log.action("Click: " + selector);
31        WebElement element = WaitUtils.waitForClickability(locator);22        // Playwright auto-waits for clickability, no need for explicit wait
32        element.click();23        getPage().locator(selector).click();
33    }24    }
3425
n35    /**n26    // Migration: Changed parameter from By locator to String selector, replaced
 > clear() + sendKeys() with fill()
36     * Type text into element27    public static void type(String selector, String text) {
37     */
38    public static void type(By locator, String text) {
39        String maskedText = maskSensitiveData(text);28        String maskedText = maskSensitiveData(text);
n40        Log.action("Type '" + maskedText + "' into: " + locator);n29        Log.action("Type '" + maskedText + "' into: " + selector);
41        WebElement element = WaitUtils.waitForVisibility(locator);30        // Playwright's fill() automatically clears and types, no need for expli
 >cit clear
42        element.clear();31        getPage().locator(selector).fill(text);
43        element.sendKeys(text);
44    }32    }
4533
n46    /**n34    // Migration: Changed parameter from By locator to String selector, replaced
 > getText() with textContent()
47     * Get text from element
48     */
49    public static String getText(By locator) {35    public static String getText(String selector) {
50        WebElement element = WaitUtils.waitForVisibility(locator);36        // Playwright auto-waits for visibility
51        return element.getText();37        return getPage().locator(selector).textContent();
52    }38    }
5339
n54    /**n40    // Migration: Changed parameter from By locator to String selector, replaced
 > isDisplayed() with isVisible()
55     * Check if element is displayed
56     */
57    public static boolean isDisplayed(By locator) {41    public static boolean isDisplayed(String selector) {
58        try {42        try {
n59            return getDriver().findElement(locator).isDisplayed();n43            return getPage().locator(selector).isVisible();
60        } catch (Exception e) {44        } catch (Exception e) {
61            return false;45            return false;
62        }46        }
63    }47    }
6448
n65    /**n49    // Migration: Changed parameter from By locator to String selector, using Pl
 >aywright's isEnabled()
66     * Check if element is enabled
67     */
68    public static boolean isEnabled(By locator) {50    public static boolean isEnabled(String selector) {
69        try {51        try {
n70            return getDriver().findElement(locator).isEnabled();n52            return getPage().locator(selector).isEnabled();
71        } catch (Exception e) {53        } catch (Exception e) {
72            return false;54            return false;
73        }55        }
74    }56    }
7557
n76    /**n58    // Migration: Changed parameter from By locator to String selector, replaced
 > Select class with selectOption()
77     * Select option by visible text
78     */
79    public static void selectByText(By locator, String text) {59    public static void selectByText(String selector, String text) {
80        Log.action("Select '" + text + "' from: " + locator);60        Log.action("Select '" + text + "' from: " + selector);
81        WebElement element = WaitUtils.waitForVisibility(locator);61        // Playwright auto-waits for visibility, selectOption selects by visible
 > text
82        new Select(element).selectByVisibleText(text);62        getPage().locator(selector).selectOption(text);
83    }63    }
8464
n85    /**n65    // Migration: Changed parameter from By locator to String selector, replaced
 > JavaScript execution with scrollIntoViewIfNeeded()
86     * Scroll to element
87     */
88    public static void scrollToElement(By locator) {66    public static void scrollToElement(String selector) {
89        Log.action("Scroll to: " + locator);67        Log.action("Scroll to: " + selector);
90        WebElement element = getDriver().findElement(locator);68        // Playwright's scrollIntoViewIfNeeded() is equivalent to scrollIntoView
 >(true)
91        ((JavascriptExecutor) getDriver()).executeScript("arguments[0].scrollInt69        getPage().locator(selector).scrollIntoViewIfNeeded();
>oView(true);", element); 
92    }70    }
9371
n94    /**n72    // Migration: Changed parameter from By locator to String selector, replaced
 > Actions class with hover()
95     * Hover over element
96     */
97    public static void hover(By locator) {73    public static void hover(String selector) {
98        Log.action("Hover: " + locator);74        Log.action("Hover: " + selector);
99        WebElement element = WaitUtils.waitForVisibility(locator);75        // Playwright auto-waits for visibility, hover() replaces Actions.moveTo
 >Element()
100        new Actions(getDriver()).moveToElement(element).perform();76        getPage().locator(selector).hover();
101    }77    }
10278
n103    /**n79    // Migration: Changed parameter from By locator to String selector, replaced
 > JavascriptExecutor with page.evaluate()
104     * JavaScript click (for stubborn elements)
105     */
106    public static void jsClick(By locator) {80    public static void jsClick(String selector) {
107        Log.action("JS Click: " + locator);81        Log.action("JS Click: " + selector);
108        WebElement element = getDriver().findElement(locator);82        // Using page.evaluate() to execute JavaScript click
109        ((JavascriptExecutor) getDriver()).executeScript("arguments[0].click();"83        getPage().evaluate("document.querySelector('" + selector + "').click()")
>, element);>;
110    }84    }
11185
n112    /**n86    // Migration: Utility method preserved as-is, no changes needed
113     * Mask sensitive data for logging
114     */
115    private static String maskSensitiveData(String text) {87    private static String maskSensitiveData(String text) {
116        if (text == null || text.length() <= 2) {88        if (text == null || text.length() <= 2) {
117            return "****";89            return "****";
118        }90        }
119        return text.substring(0, 2) + "****";91        return text.substring(0, 2) + "****";
120    }92    }
tt93 
121}94}
✓ Success
LoginTests.java D:\TestFlux\samples\selenium-java-project\src\test\java\com\qastarter\tests\LoginTests.java
54 → 41 lines
100%
9.8s ✓ Compiled
ℹ Compiled clean on first attempt.
Patterns handled
  • assertTrue×2Replace with Playwright expect assertions
  • JUnit4_Test×2Convert to JUnit 5 @Test with updated import
Before → After

Original (Selenium)
Generated (Playwright)
n1package com.qastarter.tests;n1package com.qastarter.tests.playwright;
22
nn3import com.microsoft.playwright.Page;
3import com.qastarter.config.ConfigurationReader;4import com.qastarter.config.playwright.ConfigurationReader;
4import com.qastarter.core.BaseTest;5import com.qastarter.core.playwright.BaseTest;
5import com.qastarter.pages.LoginPage;6import com.qastarter.pages.playwright.LoginPage;
6import com.qastarter.utils.Log;7import com.qastarter.utils.playwright.Log;
7import org.testng.Assert;8import org.testng.Assert;
n8import org.testng.annotations.DataProvider;n
9import org.testng.annotations.Test;9import org.testng.annotations.Test;
nn10import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertTha
 >t;
1011
n11/**n
12* Login Tests - Example test class for SauceDemo.
13*
14* Demonstrates:
15* - Simple tests using ConfigurationReader (properties file)
16* - Data-driven tests using TestDataReader (CSV file)
17*/
18public class LoginTests extends BaseTest {12public class LoginTests extends BaseTest {
1913
n20// ===========================================n14    // No explicit constructor needed - using default constructor
21// SIMPLE TESTS (using properties file)
22// ===========================================
2315
nn16    // Migration: Migrated to use Page injection in LoginPage constructor and pr
 >eserved TestNG assertions for business logic validation
24@Test(priority = 1, description = "Verify successful login with valid credential17    @Test(priority = 1, description = "Verify successful login with valid creden
>s")>tials")
25public void testValidLogin() {18    public void testValidLogin() {
26Log.step("Testing valid login from properties file");19        Log.step("Testing valid login from properties file");
27LoginPage loginPage = new LoginPage();20        LoginPage loginPage = new LoginPage(getDriver());
21        // Get credentials from dev.properties
22        String username = ConfigurationReader.getProperty("username");
23        String password = ConfigurationReader.getProperty("password");
24        loginPage.login(username, password);
25        // Use Playwright assertion for UI state check
26        Assert.assertTrue(loginPage.isLoginSuccessful(), "Login should be succes
 >sful");
27        Log.info("Valid login test passed");
28    }
2829
n29// Get credentials from dev.propertiesn30    // Migration: Migrated to use Page injection in LoginPage constructor while 
 >preserving original test logic and TestNG assertions
30String username = ConfigurationReader.getProperty("username");31    @Test(priority = 2, description = "Verify error message with invalid credent
 >ials")
31String password = ConfigurationReader.getProperty("password");32    public void testInvalidLogin() {
33        Log.step("Testing invalid login");
34        LoginPage loginPage = new LoginPage(getDriver());
35        loginPage.login("invalid_user", "wrong_password");
36        // Use TestNG assertion for business logic validation
37        Assert.assertTrue(loginPage.isErrorDisplayed(), "Error message should be
 > displayed");
38        Log.info("Invalid login test passed - error displayed as expected");
39    }
3240
n33loginPage.login(username, password);n
34 
35Assert.assertTrue(loginPage.isLoginSuccessful(), "Login should be successful");
36Log.info("Valid login test passed");
37}41}
t38 t
39@Test(priority = 2, description = "Verify error message with invalid credentials
>") 
40public void testInvalidLogin() {
41Log.step("Testing invalid login");
42LoginPage loginPage = new LoginPage();
43 
44loginPage.login("invalid_user", "wrong_password");
45 
46Assert.assertTrue(loginPage.isErrorDisplayed(), "Error message should be display
>ed"); 
47Log.info("Invalid login test passed - error displayed as expected");
48}
49 
50    // ===========================================
51    // DATA-DRIVEN TESTS (using CSV file)
52    // ===========================================
53 
54    }