Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.51.0</version>
<version>1.55.0</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@

import io.swaglabs.portal.qa.constants.WebPortalConstants;

import java.util.HashMap;
import java.util.Map;

public class BrowserFactory {

ThreadLocal<Map<String, IBrowser>> BROWWSER_CACHE = ThreadLocal.withInitial(HashMap::new);

public IBrowser createBrowser() {
return switch (BrowserName.fromConfigValue(WebPortalConstants.BROWSER)) {
case CHROME -> new ChromeBrowser();
case MS_EDGE -> new MsEdgeBrowser();
case FIREFOX -> new FirefoxBrowser();
case WEBKIT -> new WebkitBrowser();
};
String browserName = WebPortalConstants.BROWSER;
return BROWWSER_CACHE.get().computeIfAbsent(browserName, name ->
switch (BrowserName.fromConfigValue(browserName)) {
case CHROME -> new ChromeBrowser();
case EDGE -> new EdgeBrowser();
case FIREFOX -> new FirefoxBrowser();
case WEBKIT -> new WebkitBrowser();

});
}
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,58 @@
package io.swaglabs.portal.qa.browsermanager;

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
import io.swaglabs.portal.qa.constants.WebPortalConstants;
import io.swaglabs.portal.qa.exceptions.WebUtilsException;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;

@Slf4j
public class BrowserManager implements IBrowserManager<Page> {

private static final ThreadLocal<BrowserContext> BROWSER_CONTEXT = new ThreadLocal<>();
private static final ThreadLocal<Browser> BROWSER = new ThreadLocal<>();

@Override
public Page getBrowserPage(Playwright playwright) {
Objects.requireNonNull(playwright, "Playwright instance is null in Browser Manager!");
boolean isHeadless = "headless".equals(WebPortalConstants.RUN_MODE);
BrowserContext browserContext = new BrowserFactory().createBrowser().createSession(playwright, isHeadless);
Objects.requireNonNull(browserContext, "Playwright Browser Context is null!");
return browserContext.newPage();
try {
Objects.requireNonNull(playwright, "Playwright instance is null in Browser Manager!");
boolean isHeadless = "headless".equals(WebPortalConstants.RUN_MODE);
BrowserContext browserContext = new BrowserFactory().createBrowser().createSession(playwright, isHeadless);
BROWSER_CONTEXT.set(browserContext);
if (browserContext.browser() != null)
BROWSER.set(browserContext.browser());
return browserContext.newPage();
} catch (Exception e) {
log.error("Browser initialization failed.");
cleanUp();
throw new WebUtilsException("Failed to create browser page: " + e);
}
}

@Override
public void destroyBrowserPage(Page page) {
Objects.requireNonNull(page, "Playwright Browser is null!");
page.close();
try {
if (page != null)
page.close();
} finally {
cleanUp();
}
}

private void cleanUp() {
BrowserContext browserContext = BROWSER_CONTEXT.get();
if (browserContext != null) {
browserContext.close();
BROWSER_CONTEXT.remove();
}
Browser browser = BROWSER.get();
if (browser != null) {
browser.close();
BROWSER.remove();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
public enum BrowserName {

CHROME("chrome"),
MS_EDGE("msedge"),
EDGE("msedge"),
FIREFOX("firefox"),
WEBKIT("webkit");

Expand All @@ -21,7 +21,7 @@ public enum BrowserName {
public static BrowserName fromConfigValue(String browserName) {
Objects.requireNonNull(browserName, "Browser name cannot be null");
return Arrays.stream(BrowserName.values())
.filter(browserType -> browserType.getBrowserType().equalsIgnoreCase(browserName))
.filter(browser -> browser.getBrowserType().equalsIgnoreCase(browserName))
.findFirst().orElseThrow(() -> new WebUtilsException("Unknown browser: " + browserName));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@

import java.util.List;

public class MsEdgeBrowser implements IBrowser {
public class EdgeBrowser implements IBrowser {
@Override
public BrowserContext createSession(Playwright playwright, boolean isHeadless) {
BrowserType.LaunchOptions msedgeLaunchOptions = WebPortalConstants.BROWSER_LAUNCH_OPTIONS
.setHeadless(isHeadless)
.setChannel(BrowserName.MS_EDGE.getBrowserType())
.setChannel(BrowserName.EDGE.getBrowserType())
.setArgs(List.of(WebPortalConstants.WINDOW_POSITION));
return playwright.chromium().launch(msedgeLaunchOptions).newContext(new Browser.NewContextOptions()
.setViewportSize(WebPortalConstants.SCREEN_WIDTH, WebPortalConstants.SCREEN_HEIGHT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import java.util.Objects;

public abstract class WebBasePage {
public class WebBasePage {

protected Page basePage;
protected Locators locators;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ public static ScreenshotsUtils getInstance() {
return instance;
}

public ScreenshotContext takeFullPageScreenshotContext(Page page) {
public void takeFullPageScreenshotContext(Page page, String filePath) {
Objects.requireNonNull(page, "Page cannot be null.");
return new ScreenshotContext(new FullPageScreenshotStrategy(page));
new ScreenshotContext(new FullPageScreenshotStrategy(page)).captureScreenshot(filePath);
}

public ScreenshotContext takeViewportScreenshotContext(Page page) {
public void takeViewportScreenshotContext(Page page, String filePath) {
Objects.requireNonNull(page, "Page cannot be null.");
return new ScreenshotContext(new ViewportScreenshotStrategy(page));
new ScreenshotContext(new ViewportScreenshotStrategy(page)).captureScreenshot(filePath);
}

public void takeElementScreenshot(Locator locator, String fileName) {
Expand Down
20 changes: 10 additions & 10 deletions src/test/java/io/swaglabs/portal/qa/commons/WebBaseTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
import java.util.Objects;

@Slf4j
public abstract class WebBaseTest {
public class WebBaseTest {

protected static ThreadLocal<Page> page = new ThreadLocal<>();
protected static final ThreadLocal<Page> PAGE = new ThreadLocal<>();
private static final ThreadLocal<Playwright> PLAYWRIGHT = new ThreadLocal<>();
private static BrowserManager browserManager;

Expand All @@ -33,9 +33,9 @@ public void setUp() {
@BeforeMethod(alwaysRun = true)
public void init(Method method) {
PLAYWRIGHT.set(Playwright.create());
page.set(browserManager.getBrowserPage(PLAYWRIGHT.get()));
PAGE.set(browserManager.getBrowserPage(PLAYWRIGHT.get()));
log.info("Browser has been set.");
WebTestListeners.setPage(page.get());
WebTestListeners.setPage(PAGE.get());
if (isChromiumBrowser()) {
initializeCdpSession();
}
Expand All @@ -44,7 +44,7 @@ public void init(Method method) {

private void initializeCdpSession() {
if (isChromiumBrowser()) {
CdpUtils.initializeCdpSession(page.get());
CdpUtils.initializeCdpSession(PAGE.get());
CdpUtils.enableCdpSession();
CdpUtils.sendCommand(CdpCommands.NETWORK_ENABLE.getDescription());
CdpUtils.logErrorResponses();
Expand All @@ -60,17 +60,17 @@ private void initializeCdpSession() {
}

private void trackPerformanceMetrics(String methodName) {
PerformanceUtils.evaluatePageLoadTime(page.get(), methodName);
PerformanceUtils.evaluateDomContentLoadTime(page.get(), methodName);
PerformanceUtils.evaluatePageLoadTime(PAGE.get(), methodName);
PerformanceUtils.evaluateDomContentLoadTime(PAGE.get(), methodName);
}

@AfterMethod(alwaysRun = true)
public void destroy() {
if (isChromiumBrowser()) {
CdpUtils.destroyCdpSession();
}
browserManager.destroyBrowserPage(page.get());
page.remove();
browserManager.destroyBrowserPage(PAGE.get());
PAGE.remove();
Objects.requireNonNull(PLAYWRIGHT.get(), "Playwright is null!");
PLAYWRIGHT.get().close();
PLAYWRIGHT.remove();
Expand All @@ -79,6 +79,6 @@ public void destroy() {

private boolean isChromiumBrowser() {
String browserName = WebPortalConstants.BROWSER;
return (browserName.equalsIgnoreCase(BrowserName.CHROME.getBrowserType()) || browserName.equalsIgnoreCase(BrowserName.MS_EDGE.getBrowserType()));
return (browserName.equalsIgnoreCase(BrowserName.CHROME.getBrowserType()) || browserName.equalsIgnoreCase(BrowserName.EDGE.getBrowserType()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ private void takeScreenshot(ITestResult testResult) {
String filePath = Paths.get(dirPath, fileName).toString();
try {
Files.createDirectories(Paths.get(dirPath));
WebPortalConstants.SCREENSHOTS_UTILS.takeFullPageScreenshotContext(currentPage).captureScreenshot(filePath);
WebPortalConstants.SCREENSHOTS_UTILS.takeFullPageScreenshotContext(currentPage, filePath);
} catch (IOException e) {
log.error("Screenshot failed for {}: {}", testName, e.getMessage());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public final class SwagLabsLoginPageTest extends SwagLabsTestBase {
@BeforeMethod(alwaysRun = true)
public void setUpSwagLabsPortal(Method method) {
log.info("Thread id in BeforeMethod for the test method : {} is {}.", method.getName(), Thread.currentThread().getId());
SWAG_LABS_PORTAL.set(new SwagLabsPortal(page.get()));
SWAG_LABS_PORTAL.set(new SwagLabsPortal(PAGE.get()));
SWAG_LABS_PORTAL.get().visit();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,37 @@ public sealed class SwagLabsTestBase extends WebBaseTest permits SwagLabsE2ETest

@BeforeMethod(alwaysRun = true)
public void setUpSwagLabsPortal(Method method) {
log.info("Thread id in BeforeMethod for the test method : {} is {}.", method.getName(), Thread.currentThread().getId());
SWAG_LABS_PORTAL.set(new SwagLabsPortal(page.get()));
SWAG_LABS_PORTAL.get().visit();
boolean isLoggedIn = SWAG_LABS_PORTAL.get().LOGIN_PAGE.isLoginSuccess();
if (!isLoggedIn)
throw new WebPageException("Swags Labs Portal Not Logged In!");
final long threadId = Thread.currentThread().getId();
log.info("Thread {} starting method {}", threadId, method.getName());
try {
// 1. Initialize portal (thread-safe via ThreadLocal)
SWAG_LABS_PORTAL.set(new SwagLabsPortal(PAGE.get()));
// 2. Visit and login
SWAG_LABS_PORTAL.get().visit();
boolean isLoggedIn = SWAG_LABS_PORTAL.get().LOGIN_PAGE.isLoginSuccess();
if (!isLoggedIn)
throw new WebPageException("Swags Labs Portal Not Logged In!");
} catch (Exception e) {
log.error("Initialization failed for thread {}", threadId, e);
cleanUpResources();
throw e;
}
}

@AfterMethod(alwaysRun = true)
public void tearDownSwagLabsPortal(Method method) {
log.info("Thread id in AfterMethod for the test method :{} is {}.", method.getName(), Thread.currentThread().getId());
final long threadId = Thread.currentThread().getId();
log.info("Thread {} finishing method {}", threadId, method.getName());
SWAG_LABS_PORTAL.remove();
}

private void cleanUpResources() {
try {
if (SWAG_LABS_PORTAL.get() != null)
// Simple cleanup - just remove the ThreadLocal
SWAG_LABS_PORTAL.remove();
} catch (Exception e) {
log.error("Thread {} cleanup error", Thread.currentThread().getId(), e);
}
}
}