Initial commit: Test Automation Framework for Seller Horizon

main
Abdullah Bin Masood Siddiqui 2025-10-31 20:27:32 +05:00
commit a08867560c
21 changed files with 1093 additions and 0 deletions

38
.gitignore vendored Normal file
View File

@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

169
pom.xml Normal file
View File

@ -0,0 +1,169 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.utopiadeals</groupId>
<artifactId>scat</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.jupiter.version>5.10.2</junit.jupiter.version>
<playwright.version>1.49.0</playwright.version>
<jackson.version>2.17.2</jackson.version>
<surefire.version>3.2.5</surefire.version>
<log4j.version>2.23.1</log4j.version>
<extent.reports.versions>5.1.2</extent.reports.versions>
<slf4j.version>2.0.13</slf4j.version>
<logback.version>1.5.6</logback.version>
</properties>
<dependencies>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
<!-- JUnit 5 Params -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
<!-- Playwright Java -->
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>${playwright.version}</version>
</dependency>
<!-- Jackson Databind (JSON parsing) -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- Optional: JSON annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
<scope>compile</scope>
</dependency>
<!-- Loggers ! -->
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>${extent.reports.versions}</version>
</dependency>
<!-- SLF4J API -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- Logback Implementation -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- SLF4J Simple Binding (for tests) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*</include> <!-- All files in all subdirectories -->
</includes>
</testResource>
</testResources>
<plugins>
<!-- Surefire Plugin for running tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire.version}</version>
<configuration>
<!-- Enable JUnit 5 Platform -->
<useModulePath>false</useModulePath>
<includes>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
<argLine>-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005</argLine>
<!-- 👇 Optional: Run in same JVM for better debugging -->
<forkCount>0</forkCount>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<properties>
<seller.cosmos.url>https://app.sellercosmos.com/</seller.cosmos.url>
<env.browser>${env.browser}</env.browser>
<env.headless>${env.headless}</env.headless>
</properties>
</profile>
<profile>
<id>qa</id>
<properties>
<seller.cosmos.url>https://app.sellercosmos.com/</seller.cosmos.url>
<env.browser>chrome</env.browser>
<env.headless>false</env.headless>
</properties>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,64 @@
package com.utopiadeals.framework;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.BrowserType;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
public abstract class BrowserContextManager {
protected Playwright playwright;
private final boolean isHeadless;
protected static final ThreadLocal<BrowserContext> contextThreadLocal = new ThreadLocal<>();
protected static final ThreadLocal<Page> pageThreadLocal = new ThreadLocal<>();
public BrowserContextManager(boolean isHeadless) {
this.playwright = Playwright.create(); // Initialize Playwright here
this.isHeadless = isHeadless;
}
public void initBrowserContext() {
if (contextThreadLocal.get() == null) {
BrowserContext browserContext = createBrowserContext();
contextThreadLocal.set(browserContext);
pageThreadLocal.set(contextThreadLocal.get().newPage());
}
}
public abstract BrowserContext createBrowserContext();
public BrowserType.LaunchOptions getLaunchOptions() {
BrowserType.LaunchOptions launchOptions = new BrowserType.LaunchOptions();
launchOptions.setHeadless(this.isHeadless);
return launchOptions;
}
public static BrowserContext getBrowserContext() {
return contextThreadLocal.get();
}
public static Page getPage() {
if (contextThreadLocal.get() == null) {
throw new IllegalStateException("Browser context is not created.");
}
return pageThreadLocal.get(); // Creating and returning a new Page
}
public void closeBrowserContext() {
if (contextThreadLocal.get() == null) {
throw new IllegalStateException("Browser context is not created.");
}
contextThreadLocal.get().close();
contextThreadLocal.remove();
}
public void closePlaywright() {
playwright.close();
}
}

View File

@ -0,0 +1,63 @@
package com.utopiadeals.framework;
import java.util.HashSet;
import java.util.Set;
public enum BrowserFactory {
CHROME("chrome") {
@Override
public BrowserContextManager getBrowserContextManager(boolean isHeadless) {
return new ChromeContext(isHeadless);
}
},
FIREFOX("firefox") {
@Override
public BrowserContextManager getBrowserContextManager(boolean isHeadless) {
return new FirefoxContext(isHeadless);
}
};
// EDGE {
// @Override
// public BrowserContextManager getBrowserContextManager() {
// return new EdgeDriverManager();
// }
// },
//
// SAFARI {
// @Override
// public BrowserContextManager getBrowserContextManager() {
// return new SafariDriverManager();
// }
// };
private final String value;
BrowserFactory(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static BrowserFactory fromValue(String strValue) throws RuntimeException {
for (BrowserFactory browserId : BrowserFactory.values()) {
if (browserId.getValue().equals(strValue)) {
return browserId;
}
}
throw new RuntimeException();
}
public static Set<String> getAllValues() {
Set<String> values = new HashSet<>();
for (BrowserFactory id : BrowserFactory.values()) {
values.add(id.getValue());
}
return values;
}
public abstract BrowserContextManager getBrowserContextManager(boolean isHeadless);
}

View File

@ -0,0 +1,18 @@
package com.utopiadeals.framework;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
public class ChromeContext extends BrowserContextManager {
public ChromeContext(boolean isHeadless) {
super(isHeadless);
}
public BrowserContext createBrowserContext() {
Browser browser = playwright.chromium().launch(getLaunchOptions());
BrowserContext browserContext = browser.newContext(); // Create browser context
return browserContext;
}
}

View File

@ -0,0 +1,23 @@
package com.utopiadeals.framework;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
public class FirefoxContext extends BrowserContextManager {
public FirefoxContext(boolean isHeadless) {
super(isHeadless);
}
public static FirefoxContext create(boolean isHeadless) {
return new FirefoxContext(isHeadless);
}
public BrowserContext createBrowserContext() {
Browser browser = playwright.firefox().launch(getLaunchOptions());
BrowserContext browserContext = browser.newContext(); // Create browser context
return browserContext;
}
}

View File

@ -0,0 +1,9 @@
package com.utopiadeals.framework;
public class UnsupportedBrowserException extends RuntimeException {
public UnsupportedBrowserException(String browserId) {
super("Unsupported browser: " + browserId);
}
}

View File

@ -0,0 +1,16 @@
package com.utopiadeals.framework.annotations;
import com.utopiadeals.framework.extensions.JsonTestDataArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@ArgumentsSource(JsonTestDataArgumentsProvider.class)
public @interface JsonTestDataExtension {
String value() default "";
}

View File

@ -0,0 +1,156 @@
package com.utopiadeals.framework.extensions;
import com.aventstack.extentreports.AnalysisStrategy;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.MediaEntityBuilder;
import com.aventstack.extentreports.reporter.ExtentSparkReporter;
import com.aventstack.extentreports.reporter.configuration.ExtentSparkReporterConfig;
import com.aventstack.extentreports.reporter.configuration.Theme;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.options.ScreenshotType;
import com.utopiadeals.framework.BrowserContextManager;
import org.junit.jupiter.api.extension.*;
import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Optional;
public class ExtentReportExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, TestWatcher, TestExecutionExceptionHandler {
private static ExtentReports extent;
private static final ThreadLocal<ExtentTest> test = new ThreadLocal<>();
@Override
public void beforeAll(ExtensionContext context) throws Exception {
if (extent == null) {
createExtentReports();
}
}
@Override
public void afterAll(ExtensionContext context) throws Exception {
if (extent != null) {
extent.flush();
}
}
@Override
public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
// This is called WHEN the exception occurs, before @AfterEach
captureFailureScreenshot(test.get(),throwable.getCause());
throw throwable; // Re-throw to maintain normal failure flow
}
@Override
public void beforeEach(ExtensionContext context) throws Exception {
String testName = context.getDisplayName();
String className = context.getTestClass().map(Class::getSimpleName).orElse("Unknown");
ExtentTest extentTest = extent.createTest(testName)
.assignCategory(className);
test.set(extentTest);
}
private void createExtentReports() {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy_MMM_dd_HH_mm_ss", Locale.US);
String reportName = "TestExecutionReport - " + "SellerHorizon" + " - " +
LocalDateTime.now().format(dateTimeFormatter) + ".html";
File extentReportOutputFile = new File("./target/test-output/extent-reports", reportName);
ExtentSparkReporter extentSparkReporter = new ExtentSparkReporter(extentReportOutputFile);
//-- Programmatically configure Extent Report. This is a better practice as opposed to configuring via a configuration file.
ExtentSparkReporterConfig extentSparkReporterConfig = extentSparkReporter.config();
extentSparkReporterConfig.enableOfflineMode(true);
extentSparkReporterConfig.setDocumentTitle("Test Execution Report");
extentSparkReporterConfig.setEncoding("utf-8");
//TODO-Report: Version may be incorporated in report name either from application.properties
// extentSparkReporterConfig.setReportName("TARGET APPLICATION: " +
// ("SellerHorizon") + " VERSION: " +
// (targetApplicationVersion == null ? "[NOT SPECIFIED]" : targetApplicationVersion));
extentSparkReporterConfig.setTheme(Theme.STANDARD);
extentSparkReporterConfig.setTimelineEnabled(true);
// extentSparkReporterConfig.setTimeStampFormat();
ExtentReports extentReports = new ExtentReports();
extentReports.attachReporter(extentSparkReporter);
extentReports.setAnalysisStrategy(AnalysisStrategy.SUITE);
extent = extentReports;
}
@Override
public void testDisabled(ExtensionContext context, Optional<String> reason) {
test.get().skip(reason.orElse("Test disabled"));
}
@Override
public void testSuccessful(ExtensionContext context) {
test.get().pass("Test executed successfully");
}
@Override
public void testAborted(ExtensionContext context, Throwable cause) {
test.get().skip(cause);
}
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
ExtentTest currentTest = test.get();
currentTest.fail(cause);
}
private void captureFailureScreenshot(ExtentTest extentTest, Throwable cause) {
try {
Page page = BrowserContextManager.getPage();
if (page != null && !page.isClosed()) {
// Take screenshot
byte[] screenshot = page.screenshot(new Page.ScreenshotOptions()
.setFullPage(true)
.setType(ScreenshotType.PNG));
String base64Screenshot = java.util.Base64.getEncoder().encodeToString(screenshot);
// Attach screenshot to the failed test
extentTest.fail(cause,
MediaEntityBuilder.createScreenCaptureFromBase64String(base64Screenshot,"Application Screenshot").build()
);
extentTest.info("Page URL: " + page.url());
} else {
extentTest.fail(cause);
extentTest.warning("Could not capture screenshot - page is closed or not available");
}
} catch (Exception e) {
// If screenshot fails, still log the failure
extentTest.fail(cause);
extentTest.warning("Failed to capture screenshot: " + e.getMessage());
}
}
// Only logging methods - no screenshot methods for manual use
public static void logInfo(String message) {
if (test.get() != null) {
test.get().info(message);
}
}
public static void logPass(String message) {
if (test.get() != null) {
test.get().pass(message);
}
}
public static void logWarning(String message) {
if (test.get() != null) {
test.get().warning(message);
}
}
}

View File

@ -0,0 +1,108 @@
package com.utopiadeals.framework.extensions;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.utopiadeals.framework.annotations.JsonTestDataExtension;
import com.utopiadeals.utils.FileIoHelper;
import com.utopiadeals.utils.TestDataProvider;
import com.utopiadeals.utils.config.Constants;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import java.util.*;
import java.util.stream.Stream;
/**
* Provides test data from JSON files for parameterized tests.
* The test data file is expected to be in the resources/test-data directory.
* Expected JSON structure:
* {
* "testMethods": {
* "loginTest": {
* "dataSets": {
* "dataSet-0": {
* "username": "user1@example.com",
* "password": "pass1"
* },
* "dataSet-1": {
* "username": "user2@example.com",
* "password": "pass2"
* }
* }
* }
* }
* }
*/
public class JsonTestDataArgumentsProvider implements ArgumentsProvider {
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final JsonNode rootNode = FileIoHelper.loadJsonFile(Constants.getTestDataPath());
private static final String TEST_METHODS_NODE = "testMethods";
private static final String DATA_SETS_NODE = "dataSets";
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
String testMethodName = context.getRequiredTestMethod().getName();
String[] datasetNames = getDatasetsValue(context);
// Get the test method node
JsonNode testMethodsNode = rootNode.path(TEST_METHODS_NODE);
if (testMethodsNode.isMissingNode()) {
throw new IllegalStateException("No 'testMethods' node found in test data file");
}
JsonNode testMethodNode = testMethodsNode.path(testMethodName);
if (testMethodNode.isMissingNode()) {
throw new IllegalArgumentException("No test data found for method: " + testMethodName);
}
JsonNode dataSetsNode = testMethodNode.path(DATA_SETS_NODE);
if (dataSetsNode.isMissingNode()) {
throw new IllegalStateException("No 'dataSets' node found for method: " + testMethodName);
}
return Arrays.stream(datasetNames)
.map(String::trim)
.filter(datasetName -> !datasetName.isEmpty())
.map(datasetName -> {
JsonNode dataSet = dataSetsNode.path(datasetName);
if (dataSet.isMissingNode()) {
throw new IllegalArgumentException("Dataset not found: " + datasetName +
" for test method: " + testMethodName);
}
return createTestDataProvider(dataSet);
})
.map(Arguments::of);
}
private String[] getDatasetsValue(ExtensionContext context) {
return context.getRequiredTestMethod()
.getAnnotation(JsonTestDataExtension.class)
.value()
.split(",");
}
private TestDataProvider createTestDataProvider(JsonNode dataSetNode) {
try {
Map<String, Object> testData = new HashMap<>();
dataSetNode.fields().forEachRemaining(entry -> {
JsonNode value = entry.getValue();
// Store the appropriate type based on the JSON node type
if (value.isTextual()) {
testData.put(entry.getKey(), value.asText());
} else if (value.isNumber()) {
testData.put(entry.getKey(), value.numberValue());
} else if (value.isBoolean()) {
testData.put(entry.getKey(), value.booleanValue());
} else {
testData.put(entry.getKey(), value);
}
});
return new TestDataProvider(testData);
} catch (Exception e) {
throw new RuntimeException("Failed to create TestDataProvider from JSON: " + e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,53 @@
package com.utopiadeals.utils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.*;
import java.util.Properties;
import static java.lang.ClassLoader.getSystemResourceAsStream;
public class FileIoHelper {
private static final ObjectMapper mapper = new ObjectMapper();
/**
* Loads properties from a file in the classpath
* @param filePath Path to the properties file in the classpath
* @return Properties object containing the loaded properties
*/
public static Properties loadPropertiesFromClasspath(String filePath) {
Properties properties = new Properties();
try (InputStream in = FileIoHelper.class.getClassLoader().getResourceAsStream(filePath)) {
if (in != null) {
properties.load(in);
}
} catch (IOException e) {
throw new RuntimeException("Failed to load properties from: " + filePath, e);
}
return properties;
}
/**
* Loads a JSON file from the classpath or file system
* @param filePath Path to the JSON file (can be in classpath or filesystem)
* @return JsonNode containing the parsed JSON
*/
public static JsonNode loadJsonFile(String filePath) {
try {
// Try to load from classpath first
try (InputStream inputStream = FileIoHelper.class.getClassLoader().getResourceAsStream(filePath)) {
if (inputStream != null) {
return mapper.readTree(inputStream);
}
}
// Fall back to file system
return mapper.readTree(new File(filePath));
} catch (Exception e) {
throw new RuntimeException("Failed to load JSON file: " + filePath, e);
}
}
}

View File

@ -0,0 +1,31 @@
package com.utopiadeals.utils;
import com.utopiadeals.utils.config.Constants;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Properties;
public class PropertyReader {
private static final Logger LOGGER = LogManager.getLogger();
private final Properties properties;
/**
* Instantiates a new Property reader with the provided properties file
*/
public PropertyReader() {
LOGGER.debug("Loading properties from config/{}", Constants.PROPERTIES_NAME);
this.properties = FileIoHelper.loadPropertiesFromClasspath(Constants.PROPERTIES_NAME);
}
/**
* Gets string property value by name
*
* @param propertyName the property name
* @return the string value or null if not found
*/
public String getString(String propertyName) {
return properties.getProperty(propertyName);
}
}

View File

@ -0,0 +1,31 @@
package com.utopiadeals.utils;
import java.util.Map;
public class TestDataProvider {
private final Map<String, Object> testData;
public TestDataProvider(Map<String, Object> testData) {
this.testData = testData;
}
public String getString(String key) {
Object value = testData.get(key);
return value != null ? value.toString() : null;
}
public Integer getInt(String key) {
Object value = testData.get(key);
return value != null ? ((Number) value).intValue() : null;
}
public Boolean getBoolean(String key) {
Object value = testData.get(key);
return value != null ? Boolean.parseBoolean(value.toString()) : null;
}
public Object get(String key) {
return testData.get(key);
}
}

View File

@ -0,0 +1,26 @@
package com.utopiadeals.utils.config;
import com.utopiadeals.utils.PropertyReader;
public class Constants {
public static final String PROPERTIES_NAME = "config/application.properties";
private static PropertyReader props = new PropertyReader();
public static boolean shouldBrowserRunHeadless() {
String headless = props.getString("env.headless");
return (headless != null) && (headless.equals("true"));
}
public static String getBrowser() {
return props.getString("env.browser");
}
public static String getEnvUrl() {
return props.getString("env.url");
}
public static String getTestDataPath() {
return props.getString("test.data.path");
}
}

View File

@ -0,0 +1,60 @@
package com.utopiadeals.web.pages;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Response;
import static com.utopiadeals.framework.BrowserContextManager.getBrowserContext;
import static com.utopiadeals.framework.BrowserContextManager.getPage;
public class BasePage {
private final BrowserContext browserContext;
private final Page page;
private Response pageResponse;
public BasePage() {
this.browserContext = getBrowserContext();
this.page = getPage();
}
public void navigate(String url) {
this.pageResponse = page.navigate(url);
}
protected Locator locator(String selector) {
return page.locator(selector);
}
protected Locator getByText(String text) {
return page.getByText(text);
}
protected void click(Locator locator) {
locator.click();
// Auto-waiting built-in - no need for explicit waits!
}
protected void clear(Locator locator) {
locator.clear();
}
protected void fill(Locator locator, String text) {
locator.fill(text);
}
protected String getText(Locator locator) {
return locator.textContent().trim();
}
protected boolean isVisible(Locator locator) {
return locator.isVisible();
}
public Response getPageResponse() {
return pageResponse;
}
}

View File

@ -0,0 +1,36 @@
package com.utopiadeals.web.pages;
import com.microsoft.playwright.Locator;
public class LoginPage extends BasePage {
private final String emailFieldLocator = "#email";
private final String passwordFieldLocator = "#password";
private final String loginButtonLocator = "button[type=submit]";
public void login(String email, String password) {
clear(getEmailFieldLocator());
fill(getEmailFieldLocator(), email);
clear(getPasswordFieldLocator());
fill(getPasswordFieldLocator(), password);
click(getLoginButtonLocator());
}
private Locator getEmailFieldLocator() {
return locator(emailFieldLocator);
}
private Locator getPasswordFieldLocator() {
return locator(passwordFieldLocator);
}
private Locator getLoginButtonLocator() {
return locator(loginButtonLocator);
}
}

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- Define the appenders -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/application-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>
<!-- Set the default log level -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
<!-- Custom package logging levels -->
<logger name="com.utopiadeals" level="DEBUG"/>
<logger name="org.springframework" level="WARN"/>
<logger name="org.hibernate" level="WARN"/>
<logger name="com.microsoft.playwright" level="INFO"/>
</configuration>

View File

@ -0,0 +1,27 @@
package testsuites;
import com.utopiadeals.framework.annotations.JsonTestDataExtension;
import com.utopiadeals.utils.TestDataProvider;
import com.utopiadeals.web.pages.LoginPage;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
public class LoginTest extends WebTestSuiteBase{
@DisplayName("Login Test")
@ParameterizedTest()
@JsonTestDataExtension("dataSet-0,dataSet-1")
public void loginTest(TestDataProvider testDataProvider){
LoginPage loginPage = new LoginPage();
//loginPage.navigate("https://app.sellercosmos.com/");
String userName = testDataProvider.getString("username");
String password = testDataProvider.getString("password");
loginPage.login(userName,password);
// loginPage.login("utest@utopiadeals.com222222","utest0001");
Assertions.assertTrue(false,"Expecting true but found false");
}
}

View File

@ -0,0 +1,73 @@
package testsuites;
import com.microsoft.playwright.Page;
import com.utopiadeals.framework.BrowserContextManager;
import com.utopiadeals.framework.BrowserFactory;
import com.utopiadeals.framework.extensions.ExtentReportExtension;
import com.utopiadeals.utils.config.Constants;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ExtendWith(ExtentReportExtension.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class WebTestSuiteBase {
private BrowserContextManager browserContextManager;
private final String browserName = Constants.getBrowser();
private final String url = Constants.getEnvUrl();
private final Logger logger = LoggerFactory.getLogger(WebTestSuiteBase.class);
@BeforeAll
public void initializeBrowser() {
if (browserContextManager == null) {
browserContextManager = BrowserFactory.fromValue(browserName).getBrowserContextManager(
Constants.shouldBrowserRunHeadless());
}
logger.info("Browser initialized");
}
@BeforeEach
public void createBrowserContext() {
if (browserContextManager != null) {
browserContextManager.initBrowserContext();
getPage().navigate(url);
}
logger.info("Browser Context initialized");
}
@AfterEach
public void closeBrowserContext() {
if (browserContextManager != null) {
browserContextManager.closeBrowserContext();
}
logger.info("Browser Context closed");
}
@AfterAll
public void closePlaywrightBrowser() {
browserContextManager.closePlaywright();
logger.info("Shutting down");
}
private Page getPage() {
return BrowserContextManager.getPage();
}
protected void logInfo(String message) {
ExtentReportExtension.logInfo(message);
}
protected void logPass(String message) {
ExtentReportExtension.logPass(message);
}
protected void logWarning(String message) {
ExtentReportExtension.logWarning(message);
}
}

View File

@ -0,0 +1,40 @@
env.browser=${env.browser}
env.headless=${env.headless}
env.url=${seller.cosmos.url}
#https://app.sellercosmos.com/
#${env.browser}
#
base.url=https://sellerboard.com
api.base.url=https://api.sellerboard.com
# Browser Configuration
browser.name=chrome
viewport.width=1920
viewport.height=1080
# Timeouts
default.timeout=30
page.load.timeout=60
element.wait.timeout=10
# Test Data
test.data.path=test-data/test-data.json
admin.username=admin@sellerboard.com
admin.password=admin123
test.user.email=test@sellerboard.com
test.user.password=test123
# Reporting & Output
screenshot.path=test-results/screenshots/
video.path=test-results/videos/
report.path=test-results/reports/
# Environment
environment=dev
log.level=INFO

View File

@ -0,0 +1,16 @@
{
"testMethods": {
"loginTest": {
"dataSets": {
"dataSet-0": {
"username": "utest@utopiadeals.com",
"password": "utest0001"
},
"dataSet-1": {
"username": "abdullah@utopiadeals.com",
"password": "Utopia01"
}
}
}
}
}