diff --git a/.gitignore b/.gitignore
index 1915649..02d2e30 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,4 +46,8 @@ build/
.vscode/
### Mac OS ###
-.DS_Store
\ No newline at end of file
+.DS_Store
+
+# MCP AI Test logs and reports
+mcp_testlog/
+mcp_testreport/
\ No newline at end of file
diff --git a/config/mcp-config.properties b/config/mcp-config.properties
index 3a4c9de..12d3ee9 100644
--- a/config/mcp-config.properties
+++ b/config/mcp-config.properties
@@ -1,10 +1,29 @@
-# Output directory for generated tests
-output.dir=src/test/ai_generated_tests/k11softwaresolutions
+# Directory for AI prompt templates
+prompt.dir=mcp-prompts/k11softwaresolutions
# Web URL for AI-generated tests
weburl=https://k11softwaresolutions-platform.vercel.app/
username=testuser
password=testpass
+# === MCPTestWorkflow properties (no prefix) ===
+scenario=Login to the dashboard and verify the dashboard is visible
+classNameBase=GeneratedPlaywrightLogin
+ai.packageName=org.k11techlab.framework_unittests.ai_generated.k11softwaresolutions
+# Java package for ConfigurationManager class
+configmanager.package=org.k11techlab.framework.selenium.webuitestengine.configManager
+# Directory for MCP test logs
+log.dir=mcp_testlog
+
+maven.test.dir=src/test/java/org/k11techlab/framework_unittests/ai_generated/k11softwaresolutions
+
+review.prompt=Review the following Java TestNG test class for correctness, best practices, and possible improvements. Provide a concise summary and suggestions.\n\n
+report.src=test-output/emailable-report.html
+# Path to Maven executable for test automation
+maven.cmd.path=C:/Program Files/maven-1.0.2/mvn/bin/mvn.cmd
+# Output directory for generated tests
+output.dir=src/test/java/org/k11techlab/framework_unittests/ai_generated/k11softwaresolutions
+
+
# Default engine for MCP test generation (selenium or playwright)
engine=selenium
# Default package name for generated tests
@@ -18,3 +37,15 @@ mongo.db=mcpdb
mongo.collection=context
+
+# === k11softwaresolutions app-specific properties ===
+k11softwaresolutions.weburl=https://k11softwaresolutions-platform.vercel.app/
+# Page object prompt config
+k11softwaresolutions.prompt.pagedir=mcp-prompts/k11softwaresolutions/pages
+k11softwaresolutions.prompt.pages=pageobject_creation_prompt_multi.txt
+# Test generation prompt config
+k11softwaresolutions.prompt.testdir=mcp-prompts/k11softwaresolutions/tests
+k11softwaresolutions.prompt.logintest=logintest_creation_prompt.txt
+
+# Framework standards prompt for test generation
+k11softwaresolutions.prompt.framework=mcp-prompts/framework_standards_prompt.txt
diff --git a/mcp_prompts/framework_standards_prompt.txt b/mcp_prompts/framework_standards_prompt.txt
new file mode 100644
index 0000000..6d0110f
--- /dev/null
+++ b/mcp_prompts/framework_standards_prompt.txt
@@ -0,0 +1,17 @@
+# Playwright Framework Standards Prompt
+
+- All Playwright test classes must extend `BasePlaywrightTest`.
+- Use `PlaywrightManager.getInstance()` to obtain the browser, context, and page.
+- Do not use `Playwright.create()` or direct browser/page instantiation in test classes.
+- Use `@BeforeClass` and `@AfterClass` for setup and teardown, delegating to `BasePlaywrightTest` where possible.
+- Example test method:
+
+ @Test
+ public void testExample() {
+ Page page = PlaywrightManager.getInstance().getPage();
+ // test steps...
+ }
+
+- Use the Page Object Model for all page interactions.
+- Follow Java and TestNG best practices for naming and structure.
+- All test code should be readable, maintainable, and DRY.
diff --git a/mcp_prompts/k11softwaresolutions/logintest_prompt.txt b/mcp_prompts/k11softwaresolutions/logintest_prompt.txt
new file mode 100644
index 0000000..dbd99c9
--- /dev/null
+++ b/mcp_prompts/k11softwaresolutions/logintest_prompt.txt
@@ -0,0 +1,17 @@
+Generate a complete, compilable Java TestNG test class using Playwright for Java.
+Package: {packageName}
+Class: {className}
+MUST include:
+- All required imports (Playwright, TestNG, ConfigurationManager, etc).
+- A @BeforeClass setUp() method that launches Playwright, a Chromium browser in headless mode, and creates a Page. Store Playwright, Browser, and Page as fields.
+- A @Test method that:
+ - Reads weburl, username, and password using ConfigurationManager.getBundle().getPropertyValue('weburl'), etc.
+ - Navigates to the weburl.
+ - Fills the username and password fields and clicks the login button (use generic selectors if not specified).
+ - Asserts that the dashboard is visible after login (e.g., page.isVisible('text=Dashboard')).
+- A @AfterClass tearDown() method that closes the browser and Playwright.
+- Output ONLY Java code, no markdown.
+- The code must be complete and not truncated.
+
+Scenario:
+{scenario}
diff --git a/mcp_prompts/k11softwaresolutions/pageobject_creation_prompt.txt b/mcp_prompts/k11softwaresolutions/pageobject_creation_prompt.txt
new file mode 100644
index 0000000..e06341e
--- /dev/null
+++ b/mcp_prompts/k11softwaresolutions/pageobject_creation_prompt.txt
@@ -0,0 +1,18 @@
+# Page Object Creation Prompt Example
+
+You are an AI assistant that generates Playwright Page Object Model (POM) Java classes. Use the following JSON structure as input:
+
+{
+ "className": "HomePage",
+ "fields": {
+ "isDashboardVisible": {"id": "Dashboard", "method": "isVisible"},
+ "clickServiceLink": {"id": "service", "text": "Service", "method": "click"},
+ "clickLoginMenu": {"id": "loginMenu", "text": "Login", "method": "click"},
+ "clickRegisterMenu": {"id": "registerMenu", "text": "Register", "method": "click"}
+ }
+}
+
+- Use id as the first preference, then name, then text for selectors.
+- Each field should generate a method in the Java class.
+- Use Playwright's Page API for actions (fill, click, isVisible, etc).
+- Output only valid Java code for the page object class.
diff --git a/mcp_prompts/k11softwaresolutions/pages/pageobject_creation_prompt_multi.txt b/mcp_prompts/k11softwaresolutions/pages/pageobject_creation_prompt_multi.txt
new file mode 100644
index 0000000..f36b6d3
--- /dev/null
+++ b/mcp_prompts/k11softwaresolutions/pages/pageobject_creation_prompt_multi.txt
@@ -0,0 +1,28 @@
+# Page Object Creation Prompt for HomePage and LoginPage
+
+{
+ "pageObjects": [
+ {
+ "className": "HomePage",
+ "fields": {
+ "isDashboardVisible": {"id": "Dashboard", "method": "isVisible"},
+ "clickServiceLink": {"id": "service", "text": "Service", "method": "click"},
+ "clickLoginMenu": {"id": "loginMenu", "text": "Login", "method": "click"},
+ "clickRegisterMenu": {"id": "registerMenu", "text": "Register", "method": "click"}
+ }
+ },
+ {
+ "className": "LoginPage",
+ "fields": {
+ "enterUsername": {"id": "username", "name": "username", "text": "Username", "method": "fill"},
+ "enterPassword": {"id": "password", "name": "password", "text": "Password", "method": "fill"},
+ "clickLogin": {"id": "login", "name": "login", "text": "Login", "method": "click"}
+ }
+ }
+ ]
+}
+
+- Use id as the first preference, then name, then text for selectors.
+- Each field should generate a method in the Java class.
+- Use Playwright's Page API for actions (fill, click, isVisible, etc).
+- Output only valid Java code for the page object classes.
diff --git a/mcp_prompts/k11softwaresolutions/tests/logintest_creation_prompt.txt b/mcp_prompts/k11softwaresolutions/tests/logintest_creation_prompt.txt
new file mode 100644
index 0000000..363b59a
--- /dev/null
+++ b/mcp_prompts/k11softwaresolutions/tests/logintest_creation_prompt.txt
@@ -0,0 +1,18 @@
+# Login Test Generation Prompt
+
+{
+ "testScenario": "Login to the dashboard and verify the dashboard is visible",
+ "testClassName": "GeneratedPlaywrightLoginTest",
+ "pageObjects": ["HomePage", "LoginPage"],
+ "steps": [
+ "Navigate to the login page",
+ "Enter username and password",
+ "Click the login button",
+ "Verify the dashboard is visible"
+ ]
+}
+
+- Use the provided page objects and methods.
+- Use TestNG for the test class structure.
+- Use Playwright's Page API for browser actions.
+- Output only valid Java code for the test class.
diff --git a/pom.xml b/pom.xml
index 2212f00..2ef3d90 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,6 +28,9 @@
2.20
true
+
+ org/k11techlab/framework_unittests/webUITests/wikipedia/**
+
@@ -64,7 +67,6 @@
com.microsoft.playwright
playwright
1.44.0
- test
com.github.javaparser
diff --git a/src/main/java/org/k11techlab/framework/ai/mcp/MCPServer.java b/src/main/java/org/k11techlab/framework/ai/mcp/MCPServer.java
index 51a789e..d66c711 100644
--- a/src/main/java/org/k11techlab/framework/ai/mcp/MCPServer.java
+++ b/src/main/java/org/k11techlab/framework/ai/mcp/MCPServer.java
@@ -29,6 +29,7 @@ public void start(int port) throws IOException {
server.createContext("/mcp/correct-code", new CorrectCodeHandler(new OpenAIClient()));
server.createContext("/mcp/generate-and-run-selenium-test", new GenerateAndRunTestHandler());
server.createContext("/mcp/generate-and-run-playwright-test", new GenerateAndRunTestHandler());
+ server.createContext("/mcp/generate-page-object", new GeneratePageObjectHandler());
server.setExecutor(null);
server.start();
diff --git a/src/main/java/org/k11techlab/framework/ai/mcp/handlers/GenerateAndRunTestHandler.java b/src/main/java/org/k11techlab/framework/ai/mcp/handlers/GenerateAndRunTestHandler.java
index 7afe33c..32618e5 100644
--- a/src/main/java/org/k11techlab/framework/ai/mcp/handlers/GenerateAndRunTestHandler.java
+++ b/src/main/java/org/k11techlab/framework/ai/mcp/handlers/GenerateAndRunTestHandler.java
@@ -33,7 +33,7 @@ public GenerateAndRunTestHandler() {
// Playwright wiring
this.playwrightGenerator = new PlaywrightTestGenerator(openAI);
- this.playwrightWorkflow = new PlaywrightWorkflow(playwrightGenerator, openAI, 2);
+ this.playwrightWorkflow = new PlaywrightWorkflow();
}
@@ -55,7 +55,7 @@ public void handle(HttpExchange exchange) throws IOException {
String packageName = (configPackage != null && !configPackage.isBlank())
? configPackage.trim()
- : "org.k11techlab.framework_unittests.ai_generated";
+ : "org.k11techlab.framework_unittests.ai_generated.k11softwaresolutions";
String classBase = "GeneratedTest_" + System.currentTimeMillis();
diff --git a/src/main/java/org/k11techlab/framework/ai/mcp/handlers/GeneratePageObjectHandler.java b/src/main/java/org/k11techlab/framework/ai/mcp/handlers/GeneratePageObjectHandler.java
new file mode 100644
index 0000000..09138d1
--- /dev/null
+++ b/src/main/java/org/k11techlab/framework/ai/mcp/handlers/GeneratePageObjectHandler.java
@@ -0,0 +1,87 @@
+package org.k11techlab.framework.ai.mcp.handlers;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import org.json.JSONObject;
+
+public class GeneratePageObjectHandler implements HttpHandler {
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ if (!exchange.getRequestMethod().equalsIgnoreCase("POST")) {
+ exchange.sendResponseHeaders(405, -1);
+ return;
+ }
+ String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
+ JSONObject req = new JSONObject(body);
+ // If promptFile is provided, load JSON from file
+ if (req.has("promptFile")) {
+ String promptFile = req.getString("promptFile");
+ try {
+ java.nio.file.Path promptPath = java.nio.file.Paths.get("mcp-prompts", promptFile);
+ String promptContent = new String(java.nio.file.Files.readAllBytes(promptPath), StandardCharsets.UTF_8);
+ int start = promptContent.indexOf('{');
+ int end = promptContent.indexOf('}', start);
+ while (end != -1 && end + 1 < promptContent.length() && promptContent.charAt(end + 1) != '\n') {
+ end = promptContent.indexOf('}', end + 1);
+ }
+ if (start != -1 && end != -1) {
+ req = new JSONObject(promptContent.substring(start, end + 1));
+ }
+ } catch (Exception e) {
+ exchange.sendResponseHeaders(500, -1);
+ return;
+ }
+ }
+ StringBuilder code = new StringBuilder();
+ if (req.has("pageObjects")) {
+ // Multiple page objects
+ org.json.JSONArray arr = req.getJSONArray("pageObjects");
+ for (int i = 0; i < arr.length(); i++) {
+ JSONObject po = arr.getJSONObject(i);
+ code.append(generatePageObjectCode(po));
+ code.append("\n\n");
+ }
+ } else if (req.has("className") && req.has("fields")) {
+ code.append(generatePageObjectCode(req));
+ } else {
+ // Invalid input
+ exchange.sendResponseHeaders(400, -1);
+ return;
+ }
+ byte[] resp = code.toString().getBytes(StandardCharsets.UTF_8);
+ exchange.getResponseHeaders().add("Content-Type", "text/plain; charset=utf-8");
+ exchange.sendResponseHeaders(200, resp.length);
+ try (OutputStream os = exchange.getResponseBody()) {
+ os.write(resp);
+ }
+ }
+
+ private String generatePageObjectCode(JSONObject req) {
+ String className = req.optString("className", "LoginPage");
+ JSONObject fields = req.optJSONObject("fields");
+ StringBuilder code = new StringBuilder();
+ code.append("public class ").append(className).append(" {\n");
+ code.append(" private final com.microsoft.playwright.Page page;\n\n");
+ code.append(" public ").append(className).append("(com.microsoft.playwright.Page page) { this.page = page; }\n\n");
+ for (String key : fields.keySet()) {
+ JSONObject field = fields.getJSONObject(key);
+ String method = field.optString("method", "fill");
+ String id = field.optString("id", "");
+ String name = field.optString("name", "");
+ String text = field.optString("text", "");
+ code.append(" public void ").append(key).append("(String value) {\n");
+ code.append(" String selector = null;\n");
+ if (!id.isEmpty()) code.append(" if (page.querySelector(\"#" + id + "\") != null) selector = \"#" + id + "\";\n");
+ if (!name.isEmpty()) code.append(" else if (page.querySelector(\"input[name='" + name + "']\") != null) selector = \"input[name='" + name + "']\";\n");
+ if (!text.isEmpty()) code.append(" else if (page.querySelector(\"text=" + text + "\") != null) selector = \"text=" + text + "\";\n");
+ code.append(" if (selector != null) page.").append(method).append("(selector, value);\n");
+ code.append(" }\n\n");
+ }
+ code.append("}\n");
+ return code.toString();
+ }
+ }
+
diff --git a/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/GeneratedTestReviewerAndExecutor.java b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/GeneratedTestReviewerAndExecutor.java
new file mode 100644
index 0000000..5794690
--- /dev/null
+++ b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/GeneratedTestReviewerAndExecutor.java
@@ -0,0 +1,67 @@
+package org.k11techlab.framework.ai.mcp.workflow.playwright;
+
+import org.k11techlab.framework.ai.openai.OpenAIClient;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.io.IOException;
+
+public class GeneratedTestReviewerAndExecutor {
+ public static void main(String[] args) {
+ // Path to the generated test file
+ String testFilePath = "src/test/ai_generated_tests/k11softwaresolutions/LoginFunctionalityTest.java";
+ String testClassName = "org.k11techlab.framework_unittests.ai_generated.LoginFunctionalityTest";
+
+ // 1. Review the generated test using OpenAI
+ String code = null;
+ try {
+ code = new String(Files.readAllBytes(Paths.get(testFilePath)));
+ } catch (IOException e) {
+ System.err.println("Failed to read test file: " + e.getMessage());
+ return;
+ }
+ OpenAIClient openAI = new OpenAIClient();
+ String reviewPrompt = "Review the following Java TestNG test class for correctness, best practices, and possible improvements. Provide a concise summary and suggestions.\n\n" + code;
+ String review = openAI.generateResponse(reviewPrompt);
+ System.out.println("\n--- AI Review of Generated Test ---\n");
+ System.out.println(review);
+
+ // 2. Copy the generated test to src/test/java for Maven discovery
+ System.out.println("\n--- Copying Generated Test to src/test/java for Maven discovery ---\n");
+ String destDir = "src/test/java/org/k11techlab/framework_unittests/ai_generated";
+ java.io.File destDirFile = new java.io.File(destDir);
+ if (!destDirFile.exists()) destDirFile.mkdirs();
+ java.io.File destFile = new java.io.File(destDirFile, "LoginFunctionalityTest.java");
+ try {
+ Files.copy(Paths.get(testFilePath), destFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+ System.out.println("Copied to: " + destFile.getAbsolutePath());
+ } catch (IOException e) {
+ System.err.println("Failed to copy test file: " + e.getMessage());
+ return;
+ }
+
+ // 3. Execute the test using Maven (TestNG)
+ System.out.println("\n--- Executing Generated Test with Maven ---\n");
+ try {
+ // Read Maven path from mcp-config.properties
+ java.util.Properties props = new java.util.Properties();
+ try (java.io.FileInputStream fis = new java.io.FileInputStream("config/mcp-config.properties")) {
+ props.load(fis);
+ }
+ String mavenCmd = props.getProperty("maven.cmd.path", "mvn");
+ ProcessBuilder pb = new ProcessBuilder(
+ mavenCmd, "-Dtest=org.k11techlab.framework_unittests.ai_generated.LoginFunctionalityTest", "test"
+ );
+ pb.redirectErrorStream(true);
+ Process process = pb.start();
+ java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getInputStream()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ System.out.println(line);
+ }
+ int exitCode = process.waitFor();
+ System.out.println("\nTest execution finished with exit code: " + exitCode);
+ } catch (Exception e) {
+ System.err.println("Failed to execute test: " + e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/MCPTestWorkflow.java b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/MCPTestWorkflow.java
new file mode 100644
index 0000000..862d25c
--- /dev/null
+++ b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/MCPTestWorkflow.java
@@ -0,0 +1,121 @@
+package org.k11techlab.framework.ai.mcp.workflow.playwright;
+
+import org.k11techlab.framework.ai.openai.OpenAIClient;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.io.IOException;
+import java.io.FileWriter;
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class MCPTestWorkflow {
+ public static void main(String[] args) {
+ // Load config with k11softwaresolutions prefix
+ java.util.Properties props = new java.util.Properties();
+ try (java.io.FileInputStream fis = new java.io.FileInputStream("config/mcp-config.properties")) {
+ props.load(fis);
+ } catch (Exception e) {
+ System.err.println("Failed to load config: " + e.getMessage());
+ return;
+ }
+ String scenario = props.getProperty("scenario", "Login to the dashboard and verify the dashboard is visible");
+ String classNameBase = props.getProperty("classNameBase", "GeneratedPlaywrightLogin");
+ String packageName = props.getProperty("ai.packageName", "org.k11techlab.framework_unittests.ai_generated");
+ String outputDir = props.getProperty("output.dir", "src/test/ai_generated_tests/k11softwaresolutions");
+ String mcpLogDir = props.getProperty("log.dir", "mcp_testlog");
+ String mavenCmd = props.getProperty("maven.cmd.path", "mvn");
+ String reportSrc = props.getProperty("report.src", "test-output/emailable-report.html");
+ new File(mcpLogDir).mkdirs();
+ String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+ String logPrefix = mcpLogDir + "/" + classNameBase + "_" + timestamp;
+ String testFileName = classNameBase + "Test.java";
+ String testFilePath = outputDir + "/" + testFileName;
+
+ // 1. Generate test
+ StringBuilder log = new StringBuilder();
+ log.append("=== Test Generation ===\n");
+ OpenAIClient openAI = new OpenAIClient();
+ PlaywrightTestGenerator generator = new PlaywrightTestGenerator(openAI);
+ String code = generator.generateTest(scenario, classNameBase, packageName);
+ log.append("Generated test code:\n").append(code).append("\n\n");
+ try {
+ File dir = new File(outputDir);
+ dir.mkdirs();
+ FileWriter writer = new FileWriter(testFilePath);
+ writer.write(code);
+ writer.close();
+ log.append("Test saved to: ").append(testFilePath).append("\n");
+ } catch (Exception e) {
+ log.append("Failed to save generated test: ").append(e.getMessage()).append("\n");
+ }
+
+ // 2. Review test
+ log.append("\n=== AI Review ===\n");
+ String reviewPrompt = props.getProperty("review.prompt", "Review the following Java TestNG test class for correctness, best practices, and possible improvements. Provide a concise summary and suggestions.\n\n") + code;
+ String review = openAI.generateResponse(reviewPrompt);
+ log.append(review).append("\n\n");
+ try (FileWriter reviewWriter = new FileWriter(logPrefix + "_review.txt")) {
+ reviewWriter.write(review);
+ } catch (Exception e) {
+ log.append("Failed to save review: ").append(e.getMessage()).append("\n");
+ }
+
+ // 3. Copy test to src/test/java for Maven
+ log.append("\n=== Copy to src/test/java ===\n");
+ String destDir = props.getProperty("maven.test.dir", "src/test/java/org/k11techlab/framework_unittests/ai_generated");
+ File destDirFile = new File(destDir);
+ destDirFile.mkdirs();
+ File destFile = new File(destDirFile, testFileName);
+ try {
+ Files.copy(Paths.get(testFilePath), destFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+ log.append("Copied to: ").append(destFile.getAbsolutePath()).append("\n");
+ } catch (IOException e) {
+ log.append("Failed to copy test file: ").append(e.getMessage()).append("\n");
+ }
+
+ // 4. Execute test with Maven
+ log.append("\n=== Test Execution ===\n");
+ StringBuilder testOutput = new StringBuilder();
+ int exitCode = -1;
+ try {
+ ProcessBuilder pb = new ProcessBuilder(
+ mavenCmd, "-Dtest=" + packageName + "." + classNameBase + "Test", "test"
+ );
+ pb.redirectErrorStream(true);
+ Process process = pb.start();
+ java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getInputStream()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ testOutput.append(line).append("\n");
+ }
+ exitCode = process.waitFor();
+ log.append("Test execution finished with exit code: ").append(exitCode).append("\n");
+ } catch (Exception e) {
+ log.append("Failed to execute test: ").append(e.getMessage()).append("\n");
+ }
+ try (FileWriter execWriter = new FileWriter(logPrefix + "_execution.txt")) {
+ execWriter.write(testOutput.toString());
+ } catch (Exception e) {
+ log.append("Failed to save execution log: ").append(e.getMessage()).append("\n");
+ }
+
+ // 5. Download/copy test report
+ log.append("\n=== Report Download ===\n");
+ String reportDest = logPrefix + "_report.html";
+ try {
+ Files.copy(Paths.get(reportSrc), Paths.get(reportDest), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+ log.append("Report copied to: ").append(reportDest).append("\n");
+ } catch (IOException e) {
+ log.append("Failed to copy report: ").append(e.getMessage()).append("\n");
+ }
+
+ // 6. Save master log
+ try (FileWriter logWriter = new FileWriter(logPrefix + "_workflow.log")) {
+ logWriter.write(log.toString());
+ } catch (Exception e) {
+ System.err.println("Failed to save workflow log: " + e.getMessage());
+ }
+ System.out.println("\nWorkflow complete. Logs and reports saved in: " + mcpLogDir);
+ }
+}
diff --git a/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PageObjectCreator.java b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PageObjectCreator.java
new file mode 100644
index 0000000..be6af7a
--- /dev/null
+++ b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PageObjectCreator.java
@@ -0,0 +1,38 @@
+package org.k11techlab.framework.ai.mcp.workflow.playwright;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class PageObjectCreator {
+ public static void ensurePageObject(String outputDir, String className, String json, StringBuilder log) {
+ String pageObjectFile = outputDir + "/" + className + ".java";
+ File poFile = new File(pageObjectFile);
+ if (!poFile.exists()) {
+ log.append(className).append(" object not found, generating via MCP endpoint...\n");
+ try {
+ URL url = new URL("http://localhost:8090/mcp/generate-page-object");
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("Content-Type", "application/json");
+ conn.setDoOutput(true);
+ try (java.io.OutputStream os = conn.getOutputStream()) {
+ os.write(json.getBytes(java.nio.charset.StandardCharsets.UTF_8));
+ }
+ String poCode;
+ try (java.io.InputStream is = conn.getInputStream()) {
+ poCode = new String(is.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8);
+ }
+ try (FileWriter writer = new FileWriter(pageObjectFile)) {
+ writer.write(poCode);
+ }
+ log.append(className).append(" object generated and saved to: ").append(pageObjectFile).append("\n");
+ } catch (Exception e) {
+ log.append("Failed to generate ").append(className).append(" object: ").append(e.getMessage()).append("\n");
+ }
+ } else {
+ log.append(className).append(" object already exists: ").append(pageObjectFile).append("\n");
+ }
+ }
+}
diff --git a/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightTestGenerator.java b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightTestGenerator.java
index f3a94c1..1e36daf 100644
--- a/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightTestGenerator.java
+++ b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightTestGenerator.java
@@ -1,6 +1,7 @@
package org.k11techlab.framework.ai.mcp.workflow.playwright;
import org.k11techlab.framework.ai.openai.OpenAIClient;
+import org.k11techlab.framework.selenium.webuitestengine.configManager.ConfigurationManager;
public class PlaywrightTestGenerator {
private final OpenAIClient openAI;
@@ -12,18 +13,86 @@ public PlaywrightTestGenerator(OpenAIClient openAI) {
public String generateTest(String scenario, String classNameBase, String packageName) {
String className = classNameBase.endsWith("Test") ? classNameBase : classNameBase + "Test";
- String prompt =
- "Generate a complete Java TestNG test class using Playwright for Java.\n" +
- "Package: " + packageName + "\n" +
- "Class: " + className + "\n" +
- "MUST include:\n" +
- "try (Playwright playwright = Playwright.create()) { ... }\n" +
- "Use Chromium headless with BrowserType.LaunchOptions.\n" +
- "Use env vars WEBURL, USERNAME, PASSWORD.\n" +
- "Output ONLY Java code.\n\nScenario:\n" + scenario;
+ String prompt;
+ String promptDir = "mcp-prompts/k11softwaresolutions";
+ try {
+ String configPromptDir = ConfigurationManager.getBundle().getPropertyValue("prompt.dir");
+ if (configPromptDir != null && !configPromptDir.isEmpty()) {
+ promptDir = configPromptDir;
+ }
+ } catch (Exception e) {
+ // fallback to default if config not found
+ }
+ java.nio.file.Path promptPath = java.nio.file.Paths.get(promptDir, "logintest_prompt.txt");
+ if (java.nio.file.Files.exists(promptPath)) {
+ try {
+ prompt = new String(java.nio.file.Files.readAllBytes(promptPath));
+ prompt = prompt.replace("{packageName}", packageName)
+ .replace("{className}", className)
+ .replace("{scenario}", scenario);
+ } catch (Exception e) {
+ // fallback to default prompt if error reading file
+ prompt = getDefaultPrompt(packageName, className, scenario);
+ }
+ } else {
+ prompt = getDefaultPrompt(packageName, className, scenario);
+ }
String code = openAI.generateResponse(prompt);
+ // Remove markdown code block markers if present
+ code = code.replaceAll("(?s)```[a-zA-Z]*\\s*", "").replaceAll("```", "");
+ // Remove any package statement from the generated code
code = code.replaceFirst("(?m)^package\\s+[^;]+;\\s*", "");
+ // Fix ConfigurationManager import/package dynamically from config
+ String configManagerPackage = "org.k11techlab.framework.selenium.webuitestengine.configManager";
+ try {
+ String configPkg = ConfigurationManager.getBundle().getPropertyValue("configmanager.package");
+ if (configPkg != null && !configPkg.isEmpty()) {
+ configManagerPackage = configPkg;
+ }
+ } catch (Exception e) {
+ // fallback to default if config not found
+ }
+ code = code.replaceAll("import\\s+org\\.k11techlab\\.framework\\.ConfigurationManager;", "import " + configManagerPackage + ".ConfigurationManager;");
+ code = code.replace("org.k11techlab.framework.ConfigurationManager", configManagerPackage + ".ConfigurationManager");
+ // Always add ConfigurationManager import if missing
+ String configManagerImport = "import " + configManagerPackage + ".ConfigurationManager;";
+ if (!code.contains(configManagerImport)) {
+ // Insert after the last import statement
+ int lastImport = code.lastIndexOf("import ");
+ if (lastImport != -1) {
+ int importEnd = code.indexOf(";", lastImport) + 1;
+ code = code.substring(0, importEnd) + "\n" + configManagerImport + code.substring(importEnd);
+ } else {
+ // If no import, insert after package
+ int pkgEnd = code.indexOf(";") + 1;
+ code = code.substring(0, pkgEnd) + "\n" + configManagerImport + code.substring(pkgEnd);
+ }
+ }
+ // Ensure BrowserType import is present if used
+ if (code.contains("BrowserType.")) {
+ if (!code.contains("import com.microsoft.playwright.BrowserType;")) {
+ code = code.replace("import com.microsoft.playwright.Browser;", "import com.microsoft.playwright.Browser;\nimport com.microsoft.playwright.BrowserType;");
+ }
+ }
return "package " + packageName + ";\n\n" + code.trim();
}
+
+ private String getDefaultPrompt(String packageName, String className, String scenario) {
+ return "Generate a complete, compilable Java TestNG test class using Playwright for Java.\n"
+ + "Package: " + packageName + "\n"
+ + "Class: " + className + "\n"
+ + "MUST include:\n"
+ + "- All required imports (Playwright, TestNG, ConfigurationManager, etc).\n"
+ + "- A @BeforeClass setUp() method that launches Playwright, a Chromium browser in headless mode, and creates a Page. Store Playwright, Browser, and Page as fields.\n"
+ + "- A @Test method that:\n"
+ + " - Reads weburl, username, and password using ConfigurationManager.getBundle().getPropertyValue('weburl'), etc.\n"
+ + " - Navigates to the weburl.\n"
+ + " - Clicks the dashboard link if present (e.g., page.isVisible and page.click for 'a:has-text('Dashboard')').\n"
+ + " - Fills the username and password fields and clicks the login button (use generic selectors if not specified).\n"
+ + " - Asserts that the dashboard is visible after login (e.g., page.isVisible('text=Dashboard')).\n"
+ + "- A @AfterClass tearDown() method that closes the browser and Playwright.\n"
+ + "- Output ONLY Java code, no markdown.\n"
+ + "- The code must be complete and not truncated.\n\nScenario:\n" + scenario;
+}
}
diff --git a/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightTestGeneratorLocalDemo.java b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightTestGeneratorLocalDemo.java
new file mode 100644
index 0000000..19a272f
--- /dev/null
+++ b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightTestGeneratorLocalDemo.java
@@ -0,0 +1,45 @@
+package org.k11techlab.framework.ai.mcp.workflow.playwright;
+
+import org.k11techlab.framework.ai.openai.OpenAIClient;
+
+/**
+ * Local demo runner that injects a canned response from a subclassed OpenAIClient
+ * so we can run the PlaywrightTestGenerator without network/API keys.
+ */
+public class PlaywrightTestGeneratorLocalDemo {
+ // Local stub that returns a minimal Playwright Java TestNG skeleton
+ static class LocalOpenAI extends OpenAIClient {
+ @Override
+ public String generateResponse(String prompt, float temperature, int maxTokens) {
+ return "package demo;\n\n" +
+ "import com.microsoft.playwright.*;\n" +
+ "import org.testng.annotations.Test;\n\n" +
+ "public class SamplePlaywrightTest {\n" +
+ " @Test\n" +
+ " public void testLogin() {\n" +
+ " try (Playwright playwright = Playwright.create()) {\n" +
+ " Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(true));\n" +
+ " Page page = browser.newPage();\n" +
+ " String weburl = System.getenv(\"WEBURL\");\n" +
+ " page.navigate(weburl != null ? weburl : \"https://example.com\");\n" +
+ " // login steps using USERNAME/PASSWORD env vars\n" +
+ " }\n" +
+ " }\n" +
+ "}\n";
+ }
+
+ @Override
+ public String generateResponse(String prompt) {
+ return generateResponse(prompt, 0.7f, 200);
+ }
+ }
+
+ public static void main(String[] args) {
+ LocalOpenAI local = new LocalOpenAI();
+ PlaywrightTestGenerator gen = new PlaywrightTestGenerator(local);
+ String scenario = (args.length > 0) ? args[0] : "Login to the dashboard and verify the dashboard is visible";
+ String code = gen.generateTest(scenario, "GeneratedPlaywrightLogin", "org.k11techlab.framework_unittests.ai_generated");
+ System.out.println("\n--- Generated Playwright Test ---\n");
+ System.out.println(code);
+ }
+}
diff --git a/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightWorkflow.java b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightWorkflow.java
index 80fb48a..761c670 100644
--- a/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightWorkflow.java
+++ b/src/main/java/org/k11techlab/framework/ai/mcp/workflow/playwright/PlaywrightWorkflow.java
@@ -1,3 +1,4 @@
+
package org.k11techlab.framework.ai.mcp.workflow.playwright;
import org.k11techlab.framework.ai.openai.OpenAIClient;
@@ -5,129 +6,206 @@
import org.k11techlab.framework.selenium.webuitestengine.configManager.ConfigurationManager;
import java.io.File;
-import java.io.InputStream;
+import org.k11techlab.framework.selenium.webuitestengine.commonUtil.fileHandler.FileUtil;
+import java.io.FileInputStream;
+import java.io.FileWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.Map;
+import java.util.Properties;
public class PlaywrightWorkflow {
+ public static void main(String[] args) throws Exception {
+ String scenario = ConfigurationManager.getString("scenario", "Login to the dashboard and verify the dashboard is visible");
+ String classNameBase = ConfigurationManager.getString("classNameBase", "GeneratedPlaywrightLogin");
+ String packageName = ConfigurationManager.getString("ai.packageName", "org.k11techlab.framework_unittests.ai_generated.k11softwaresolutions");
+ String outputDir = ConfigurationManager.getString("output.dir", "src/test/ai_generated_tests/k11softwaresolutions");
+ String relPath = outputDir.replace("src/test/java/", "");
+ if (relPath.contains("/")) {
+ String[] parts = relPath.split("/");
+ StringBuilder subPkg = new StringBuilder();
+ boolean found = false;
+ for (int i = 0; i < parts.length; i++) {
+ if (parts[i].equals("ai_generated")) {
+ found = true;
+ }
+ if (found && i > 0) {
+ if (!parts[i].isEmpty()) {
+ subPkg.append(".").append(parts[i]);
+ }
+ }
+ }
+ String subPkgStr = subPkg.toString();
+ if (!packageName.endsWith(subPkgStr)) {
+ packageName = packageName + subPkgStr;
+ }
+ }
+ String mcpLogDir = ConfigurationManager.getString("log.dir", "mcp_testlog");
+ String mavenCmd = ConfigurationManager.getString("maven.cmd.path", "mvn");
+ String reportSrc = ConfigurationManager.getString("report.src", "test-output/emailable-report.html");
+ String destDir = ConfigurationManager.getString("maven.test.dir", "src/test/ai_generated");
+ int maxFixAttempts = Integer.parseInt(ConfigurationManager.getString("maxFixAttempts", "2"));
+ // Empty the mcp_testlog directory before test run
+ FileUtil.emptyDirectory(mcpLogDir);
+ new File(mcpLogDir).mkdirs();
+ String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+ String logFile = mcpLogDir + "/" + classNameBase + "_" + timestamp + "_workflow.log";
+ String testFileName = classNameBase + "Test.java";
+ String testFilePath = outputDir + "/" + testFileName;
+ StringBuilder log = new StringBuilder();
+
+ // 1. Ensure Page Object exists
+ log.append("=== Page Object Check ===\n");
+ String pageObjectName = "LoginPage";
+ String pageObjectFile = outputDir + "/" + pageObjectName + ".java";
+ File poFile = new File(pageObjectFile);
+ if (!poFile.exists()) {
+ log.append("Page object not found, generating via MCP endpoint...\n");
+ try {
+ // Example: hardcoded fields for demo; in real use, make this dynamic or configurable
+ String json = "{" +
+ "\"className\":\"" + pageObjectName + "\"," +
+ "\"fields\": {" +
+ "\"enterUsername\": {\"id\":\"username\", \"name\":\"username\", \"text\":\"Username\", \"method\":\"fill\"}," +
+ "\"enterPassword\": {\"id\":\"password\", \"name\":\"password\", \"text\":\"Password\", \"method\":\"fill\"}," +
+ "\"clickLogin\": {\"id\":\"login\", \"name\":\"login\", \"text\":\"Login\", \"method\":\"click\"}" +
+ "}}";
+ java.net.URL url = new java.net.URL("http://localhost:8090/mcp/generate-page-object");
+ java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("Content-Type", "application/json");
+ conn.setDoOutput(true);
+ try (java.io.OutputStream os = conn.getOutputStream()) {
+ os.write(json.getBytes(java.nio.charset.StandardCharsets.UTF_8));
+ }
+ String poCode;
+ try (java.io.InputStream is = conn.getInputStream()) {
+ poCode = new String(is.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8);
+ }
+ try (FileWriter writer = new FileWriter(pageObjectFile)) {
+ writer.write(poCode);
+ }
+ log.append("Page object generated and saved to: ").append(pageObjectFile).append("\n");
+ } catch (Exception e) {
+ log.append("Failed to generate page object: ").append(e.getMessage()).append("\n");
+ }
+ } else {
+ log.append("Page object already exists: ").append(pageObjectFile).append("\n");
+ }
- private final PlaywrightTestGenerator generator;
- private final AICompileRepairEngine repairEngine;
-
- public PlaywrightWorkflow(
- PlaywrightTestGenerator generator,
- OpenAIClient openAI,
- int maxFixAttempts) {
-
- this.generator = generator;
- this.repairEngine = new AICompileRepairEngine(openAI, maxFixAttempts);
- }
-
- public String generateAndRunTest(
- String scenario,
- String classNameBase,
- String packageName) throws Exception {
-
- String className = classNameBase.endsWith("Test")
- ? classNameBase
- : classNameBase + "Test";
-
- String packageDir = packageName.replace('.', '/');
-
- // 1️⃣ Generate code
- String code = generator.generateTest(scenario, classNameBase, packageName);
- code = normalize(code, packageName, className);
+ // 2. Generate test using page object
+ log.append("=== Test Generation (Page Object) ===\n");
+ OpenAIClient openAI = new OpenAIClient();
+ PlaywrightTestGenerator generator = new PlaywrightTestGenerator(openAI);
+ // Instruct generator to use the page object (could be prompt-based or template-based)
+ String code = "import " + packageName + ".LoginPage;\n" +
+ "// ...existing imports...\n" +
+ "public class " + classNameBase + "Test {\n" +
+ " // ...existing setup...\n" +
+ " @Test\n" +
+ " public void testLogin() {\n" +
+ " LoginPage loginPage = new LoginPage(page);\n" +
+ " loginPage.enterUsername(\"testuser\");\n" +
+ " loginPage.enterPassword(\"testpass\");\n" +
+ " loginPage.clickLogin();\n" +
+ " assert loginPage.isDashboardVisible();\n" +
+ " }\n" +
+ "}";
+ try {
+ File dir = new File(outputDir);
+ dir.mkdirs();
+ FileWriter writer = new FileWriter(testFilePath);
+ writer.write(code);
+ writer.close();
+ log.append("Test saved to: ").append(testFilePath).append("\n");
+ } catch (Exception e) {
+ log.append("Failed to save generated test: ").append(e.getMessage()).append("\n");
+ }
- // 2️⃣ Write Java file
- Path javaFilePath = Paths.get(
- "src/test/java",
- packageDir,
- className + ".java"
- );
- Files.createDirectories(javaFilePath.getParent());
- Files.write(javaFilePath, code.getBytes(StandardCharsets.UTF_8));
+ // 2. Copy test to src/test/java for Maven
+ log.append("\n=== Copy to src/test/java ===\n");
+ File destDirFile = new File(destDir);
+ destDirFile.mkdirs();
+ File destFile = new File(destDirFile, testFileName);
+ try {
+ Files.copy(Paths.get(testFilePath), destFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+ log.append("Copied to: ").append(destFile.getAbsolutePath()).append("\n");
+ } catch (Exception e) {
+ log.append("Failed to copy test file: ").append(e.getMessage()).append("\n");
+ }
+ // 3. Compile/run + AI repair loop
+ log.append("\n=== Test Execution & AI Repair ===\n");
+ AICompileRepairEngine repairEngine = new AICompileRepairEngine(openAI, maxFixAttempts);
+ Path javaFilePath = destFile.toPath();
String lastOutput = "";
-
- // 3️⃣ Compile / run + repair loop
- for (int attempt = 0; attempt <= repairEngine.getMaxAttempts(); attempt++) {
-
- RunResult rr = runMavenTest(className);
+ for (int attempt = 0; attempt <= maxFixAttempts; attempt++) {
+ RunResult rr = runMavenTest(mavenCmd, packageName + "." + classNameBase + "Test");
lastOutput = rr.output;
-
+ log.append("\n--- Attempt ").append(attempt + 1).append(" ---\n");
+ log.append(lastOutput).append("\n");
if (rr.exitCode == 0) {
- return "Maven exit code: 0\n" + lastOutput;
+ log.append("Test PASSED on attempt ").append(attempt + 1).append("\n");
+ break;
}
-
- if (attempt == repairEngine.getMaxAttempts()) {
- return "Maven exit code: " + rr.exitCode +
- "\n" + lastOutput +
- "\n\nAUTO-REPAIR exhausted (" + repairEngine.getMaxAttempts() + " attempts)";
+ if (attempt == maxFixAttempts) {
+ log.append("Test FAILED after ").append(maxFixAttempts + 1).append(" attempts\n");
+ break;
}
-
- // 4️⃣ Read broken code (Java 11 safe)
- String brokenCode = new String(
- Files.readAllBytes(javaFilePath),
- StandardCharsets.UTF_8
- );
-
- // 5️⃣ Ask OpenAI to fix compilation errors
+ String brokenCode = new String(Files.readAllBytes(javaFilePath), StandardCharsets.UTF_8);
String fixedCode = repairEngine.fixJavaCompilationErrors(
- brokenCode,
- rr.output,
- scenario,
- packageName,
- className
- );
-
- fixedCode = normalize(fixedCode, packageName, className);
-
+ brokenCode, rr.output, scenario, packageName, classNameBase + "Test");
+ fixedCode = normalize(fixedCode, packageName, classNameBase + "Test");
repairEngine.writeFixedCode(javaFilePath, fixedCode);
+ log.append("AI attempted to repair code.\n");
}
- return lastOutput; // should never reach
- }
-
- // -------------------------
- // Helpers
- // -------------------------
-
- private static String normalize(String code, String packageName, String className) {
- if (code == null) return "";
+ // 4. Download/copy test report
+ log.append("\n=== Report Download ===\n");
+ String reportDest = mcpLogDir + "/" + classNameBase + "_" + timestamp + "_report.html";
+ String reportDest2 = "mcp_testreport/" + classNameBase + "_" + timestamp + "_report.html";
+ try {
+ Files.copy(Paths.get(reportSrc), Paths.get(reportDest), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+ log.append("Report copied to: ").append(reportDest).append("\n");
+ // Also copy to mcp_testreport
+ new File("mcp_testreport").mkdirs();
+ Files.copy(Paths.get(reportSrc), Paths.get(reportDest2), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+ log.append("Report copied to: ").append(reportDest2).append("\n");
+ } catch (Exception e) {
+ log.append("Failed to copy report: ").append(e.getMessage()).append("\n");
+ }
- String c = code.replaceFirst("(?m)^package\\s+[^;]+;\\s*", "");
- c = "package " + packageName + ";\n\n" + c.trim();
- c = c.replaceAll("(?s)public\\s+class\\s+\\w+", "public class " + className);
- return c;
+ // 5. Save master log
+ try (FileWriter logWriter = new FileWriter(logFile)) {
+ logWriter.write(log.toString());
+ } catch (Exception e) {
+ System.err.println("Failed to save workflow log: " + e.getMessage());
+ }
+ System.out.println("\nWorkflow complete. Log and report saved in: " + mcpLogDir);
}
- private static RunResult runMavenTest(String className) throws Exception {
-
+ private static RunResult runMavenTest(String mavenCmd, String testClass) throws Exception {
ProcessBuilder pb = new ProcessBuilder(
- "mvn",
+ mavenCmd,
"-q",
- "-Dtest=" + className,
+ "-Dtest=" + testClass,
"test"
);
-
pb.directory(new File(System.getProperty("user.dir")));
pb.redirectErrorStream(true);
-
Map env = pb.environment();
env.put("WEBURL", safeProp("weburl"));
env.put("USERNAME", safeProp("username"));
env.put("PASSWORD", safeProp("password"));
-
Process p = pb.start();
-
String out;
- try (InputStream is = p.getInputStream()) {
+ try (var is = p.getInputStream()) {
out = new String(is.readAllBytes(), StandardCharsets.UTF_8);
}
-
int exit = p.waitFor();
return new RunResult(exit, out);
}
@@ -141,11 +219,17 @@ private static String safeProp(String key) {
}
}
- // Java 11-compatible result holder
+ private static String normalize(String code, String packageName, String className) {
+ if (code == null) return "";
+ String c = code.replaceFirst("(?m)^package\\s+[^;]+;\\s*", "");
+ c = "package " + packageName + ";\n\n" + c.trim();
+ c = c.replaceAll("(?s)public\\s+class\\s+\\w+", "public class " + className);
+ return c;
+ }
+
private static class RunResult {
final int exitCode;
final String output;
-
RunResult(int exitCode, String output) {
this.exitCode = exitCode;
this.output = output;
diff --git a/src/main/java/org/k11techlab/framework/ai/openai/OpenAIClient.java b/src/main/java/org/k11techlab/framework/ai/openai/OpenAIClient.java
index 5cbd5d6..7251e5b 100644
--- a/src/main/java/org/k11techlab/framework/ai/openai/OpenAIClient.java
+++ b/src/main/java/org/k11techlab/framework/ai/openai/OpenAIClient.java
@@ -1,6 +1,7 @@
-package org.k11techlab.framework.ai.openai;
+package org.k11techlab.framework.ai.openai;
+import org.k11techlab.framework.selenium.webuitestengine.configManager.ConfigurationManager;
import org.k11techlab.framework.ai.llm.LLMInterface;
import org.k11techlab.framework.selenium.webuitestengine.logger.Log;
import java.io.IOException;
@@ -53,7 +54,16 @@ public OpenAIClient() {
@Override
public String generateResponse(String prompt) {
- return generateResponse(prompt, 0.7f, 200);
+ int maxTokens = 2048;
+ try {
+ String configMaxTokens = ConfigurationManager.getBundle().getPropertyValue("openai.maxTokens");
+ if (configMaxTokens != null && !configMaxTokens.isEmpty()) {
+ maxTokens = Integer.parseInt(configMaxTokens);
+ }
+ } catch (Exception e) {
+ // fallback to default if config not found or parse error
+ }
+ return generateResponse(prompt, 0.7f, maxTokens);
}
@Override
diff --git a/src/main/java/org/k11techlab/framework/playwright/BasePlaywrightTest.java b/src/main/java/org/k11techlab/framework/playwright/BasePlaywrightTest.java
new file mode 100644
index 0000000..86c2ac8
--- /dev/null
+++ b/src/main/java/org/k11techlab/framework/playwright/BasePlaywrightTest.java
@@ -0,0 +1,37 @@
+package org.k11techlab.framework.playwright;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import com.aventstack.extentreports.ExtentReports;
+import com.aventstack.extentreports.reporter.ExtentSparkReporter;
+
+public abstract class BasePlaywrightTest {
+ protected PlaywrightManager manager;
+ protected static ExtentReports extent;
+
+ @BeforeClass
+ public void setUpBase() {
+ manager = PlaywrightManager.getInstance();
+ manager.setBrowserOptions(true, 0); // headless, no slowMo
+ manager.initializeBrowser();
+ if (extent == null) {
+ extent = new ExtentReports();
+ ExtentSparkReporter spark = new ExtentSparkReporter("test-output/PlaywrightManagerUnitTest-ExtentReport.html");
+ try {
+ spark.loadXMLConfig("config/extent-config.xml");
+ } catch (java.io.IOException e) {
+ e.printStackTrace();
+ // Optionally, you can log or rethrow the exception as needed
+ }
+ extent.attachReporter(spark);
+ }
+ }
+
+ @AfterClass
+ public void tearDownBase() {
+ manager.quit();
+ if (extent != null) {
+ extent.flush();
+ }
+ }
+}
diff --git a/src/main/java/org/k11techlab/framework/playwright/PlaywrightManager.java b/src/main/java/org/k11techlab/framework/playwright/PlaywrightManager.java
new file mode 100644
index 0000000..a4df9a0
--- /dev/null
+++ b/src/main/java/org/k11techlab/framework/playwright/PlaywrightManager.java
@@ -0,0 +1,167 @@
+package org.k11techlab.framework.playwright;
+
+import com.microsoft.playwright.*;
+
+/**
+ * Playwright-based Browser Manager
+ * Manages Playwright browser instances and pages
+ */
+public class PlaywrightManager {
+ private static volatile PlaywrightManager instance;
+ private Playwright playwright;
+ private Browser browser;
+ private BrowserContext context;
+ private Page page;
+
+ private boolean headless = false;
+ private int slowMo = 50;
+
+ private PlaywrightManager() {
+ // Private constructor for singleton
+ }
+
+ public static PlaywrightManager getInstance() {
+ if (instance == null) {
+ synchronized (PlaywrightManager.class) {
+ if (instance == null) {
+ instance = new PlaywrightManager();
+ }
+ }
+ }
+ return instance;
+ }
+
+ /**
+ * Initialize Playwright with specified browser
+ * @param browserType Browser type (chromium, firefox, webkit)
+ */
+ public void initializeBrowser(String browserType) {
+ quit(); // Ensure previous instances are closed
+ playwright = Playwright.create();
+
+ BrowserType.LaunchOptions launchOptions = new BrowserType.LaunchOptions()
+ .setHeadless(headless)
+ .setSlowMo(slowMo);
+
+ switch (browserType.toLowerCase()) {
+ case "firefox":
+ browser = playwright.firefox().launch(launchOptions);
+ break;
+ case "webkit":
+ case "safari":
+ browser = playwright.webkit().launch(launchOptions);
+ break;
+ case "chromium":
+ case "chrome":
+ default:
+ browser = playwright.chromium().launch(launchOptions);
+ break;
+ }
+
+ context = browser.newContext(new Browser.NewContextOptions()
+ .setViewportSize(1920, 1080));
+ page = context.newPage();
+ }
+
+ /**
+ * Initialize Playwright with default Chromium browser
+ */
+ public void initializeBrowser() {
+ initializeBrowser("chromium");
+ }
+
+ /**
+ * Get the current page instance
+ * @return Playwright Page
+ */
+ public Page getPage() {
+ if (page == null) {
+ initializeBrowser();
+ }
+ return page;
+ }
+
+ /**
+ * Get the current browser instance
+ * @return Playwright Browser
+ */
+ public Browser getBrowser() {
+ return browser;
+ }
+
+ /**
+ * Get the current browser context
+ * @return Playwright BrowserContext
+ */
+ public BrowserContext getContext() {
+ return context;
+ }
+
+ /**
+ * Create a new page in the current context
+ * @return New Playwright Page
+ */
+ public Page newPage() {
+ if (context == null) {
+ initializeBrowser();
+ }
+ return context.newPage();
+ }
+
+ /**
+ * Close the current page
+ */
+ public void closePage() {
+ if (page != null) {
+ page.close();
+ page = null;
+ }
+ }
+
+ /**
+ * Close the browser context
+ */
+ public void closeContext() {
+ if (page != null) {
+ try { page.close(); } catch (Exception ignored) {}
+ page = null;
+ }
+ if (context != null) {
+ try { context.close(); } catch (Exception ignored) {}
+ context = null;
+ }
+ }
+
+ /**
+ * Close the browser
+ */
+ public void closeBrowser() {
+ closeContext();
+ if (browser != null) {
+ try { browser.close(); } catch (Exception ignored) {}
+ browser = null;
+ }
+ }
+
+ /**
+ * Quit Playwright completely
+ */
+ public void quit() {
+ closeBrowser();
+ if (playwright != null) {
+ try { playwright.close(); } catch (Exception ignored) {}
+ playwright = null;
+ }
+ // Do not nullify instance for singleton
+ }
+
+ /**
+ * Set browser options
+ * @param headless Whether to run in headless mode
+ * @param slowMo Slow down operations by specified milliseconds
+ */
+ public void setBrowserOptions(boolean headless, int slowMo) {
+ this.headless = headless;
+ this.slowMo = slowMo;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/k11techlab/framework/playwright/mcp_client/k11softwaresolutions/PageObjectGeneratorClient.java b/src/main/java/org/k11techlab/framework/playwright/mcp_client/k11softwaresolutions/PageObjectGeneratorClient.java
new file mode 100644
index 0000000..aa798e1
--- /dev/null
+++ b/src/main/java/org/k11techlab/framework/playwright/mcp_client/k11softwaresolutions/PageObjectGeneratorClient.java
@@ -0,0 +1,54 @@
+package org.k11techlab.framework.playwright.mcp_client.k11softwaresolutions;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+
+import org.k11techlab.framework.selenium.webuitestengine.configManager.ConfigurationManager;
+
+public class PageObjectGeneratorClient {
+ public static void main(String[] args) throws Exception {
+ // App name prefix
+
+ String appName = "k11softwaresolutions";
+ // Load config values using ConfigurationManager
+ String configMcpPort = ConfigurationManager.getString("mcp.port", "8091");
+ String mcpUrl = "http://localhost:" + configMcpPort + "/mcp/generate-page-object";
+
+ // Fetch app-specific properties
+ String webUrl = ConfigurationManager.getString(appName + ".weburl", ConfigurationManager.getString("weburl", ""));
+ String promptDir = ConfigurationManager.getString(appName + ".prompt.pagedir", "mcp-prompts/" + appName + "/pageobjects");
+ String promptFile = ConfigurationManager.getString(appName + ".prompt.pages", "pageobject_creation_prompt_multi.txt");
+
+ // Compose prompt file path
+ String promptFilePath = promptDir.endsWith("/") ? promptDir + promptFile : promptDir + "/" + promptFile;
+
+ // Build JSON prompt
+ String prompt = String.format("{ \"webUrl\": \"%s\", \"promptFile\": \"%s\" }", webUrl, promptFilePath);
+
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ HttpPost post = new HttpPost(mcpUrl);
+ post.setHeader("Content-Type", "application/json");
+ post.setEntity(new StringEntity(prompt, "UTF-8"));
+
+ try (CloseableHttpResponse response = httpClient.execute(post)) {
+ int code = response.getStatusLine().getStatusCode();
+ System.out.println("Response Code: " + code);
+ StringBuilder responseText = new StringBuilder();
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(response.getEntity().getContent(), "utf-8"))) {
+ String responseLine;
+ while ((responseLine = br.readLine()) != null) {
+ responseText.append(responseLine.trim());
+ }
+ }
+ System.out.println("Response: " + responseText.toString());
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/k11techlab/framework/playwright/mcp_client/k11softwaresolutions/TestGeneratorClient.java b/src/main/java/org/k11techlab/framework/playwright/mcp_client/k11softwaresolutions/TestGeneratorClient.java
new file mode 100644
index 0000000..d17f4b4
--- /dev/null
+++ b/src/main/java/org/k11techlab/framework/playwright/mcp_client/k11softwaresolutions/TestGeneratorClient.java
@@ -0,0 +1,52 @@
+package org.k11techlab.framework.playwright.mcp_client.k11softwaresolutions;
+
+import java.io.*;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+
+import org.k11techlab.framework.selenium.webuitestengine.configManager.ConfigurationManager;
+
+public class TestGeneratorClient {
+ public static void main(String[] args) throws Exception {
+ String appName = "k11softwaresolutions";
+ // Load config values using ConfigurationManager
+ String configMcpPort = ConfigurationManager.getString("mcp.port", "8091");
+ String mcpUrl = "http://localhost:" + configMcpPort + "/mcp/generate-and-run-playwright-test";
+
+ // Fetch app-specific properties
+ String webUrl = ConfigurationManager.getString(appName + ".weburl", ConfigurationManager.getString("weburl", ""));
+ String promptDir = ConfigurationManager.getString(appName + ".prompt.testdir", "mcp-prompts/" + appName + "/tests");
+ String promptFile = ConfigurationManager.getString(appName + ".prompt.logintest", "logintest_creation_prompt.txt");
+ String standardsPrompt = ConfigurationManager.getString(appName + ".prompt.framework", "mcp-prompts/framework_standards_prompt.txt");
+
+ // Compose prompt file path
+ String promptFilePath = promptDir.endsWith("/") ? promptDir + promptFile : promptDir + "/" + promptFile;
+
+ // Build JSON prompt (now includes standardsPrompt)
+ String prompt = String.format("{ \"webUrl\": \"%s\", \"promptFile\": \"%s\", \"standardsPrompt\": \"%s\" }", webUrl, promptFilePath, standardsPrompt);
+
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ HttpPost post = new HttpPost(mcpUrl);
+ post.setHeader("Content-Type", "application/json");
+ post.setEntity(new StringEntity(prompt, "UTF-8"));
+
+ try (CloseableHttpResponse response = httpClient.execute(post)) {
+ int code = response.getStatusLine().getStatusCode();
+ System.out.println("Response Code: " + code);
+ StringBuilder responseText = new StringBuilder();
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(response.getEntity().getContent(), "utf-8"))) {
+ String responseLine;
+ while ((responseLine = br.readLine()) != null) {
+ responseText.append(responseLine.trim());
+ }
+ }
+ System.out.println("Response: " + responseText.toString());
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/k11techlab/framework/selenium/webuitestengine/commonUtil/fileHandler/FileUtil.java b/src/main/java/org/k11techlab/framework/selenium/webuitestengine/commonUtil/fileHandler/FileUtil.java
index b22c140..eff6cd9 100644
--- a/src/main/java/org/k11techlab/framework/selenium/webuitestengine/commonUtil/fileHandler/FileUtil.java
+++ b/src/main/java/org/k11techlab/framework/selenium/webuitestengine/commonUtil/fileHandler/FileUtil.java
@@ -19,6 +19,24 @@
import java.util.Vector;
public class FileUtil extends FileUtils {
+
+ /**
+ * Deletes all files (not subdirectories) in the given directory.
+ * @param dirPath Path to the directory to empty.
+ */
+ public static void emptyDirectory(String dirPath) {
+ File dir = new File(dirPath);
+ if (dir.exists() && dir.isDirectory()) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (File f : files) {
+ if (!f.isDirectory()) {
+ f.delete();
+ }
+ }
+ }
+ }
+ }
private static int counter = -1; /* Protected by tmpFileLock */
private Boolean checkEmptyFile(final File file, long fileLengthLimit) throws IOException {
diff --git a/src/main/resources/k11_logo.png b/src/main/resources/k11_logo.png
deleted file mode 100644
index ebb07ed..0000000
Binary files a/src/main/resources/k11_logo.png and /dev/null differ
diff --git a/src/main/resources/sdetlogo.png b/src/main/resources/sdetlogo.png
deleted file mode 100644
index 4d5a12c..0000000
Binary files a/src/main/resources/sdetlogo.png and /dev/null differ
diff --git a/src/test/ai_generated_tests/GeneratedEcommerceTest.java b/src/test/ai_generated_tests/GeneratedEcommerceTest.java
new file mode 100644
index 0000000..f27aab1
--- /dev/null
+++ b/src/test/ai_generated_tests/GeneratedEcommerceTest.java
@@ -0,0 +1,103 @@
+package org.k11techlab.framework.generated.tests;
+
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+import java.time.Duration;
+
+public class CompleteShoppingFlowTest extends BaseSeleniumTest {
+
+ @BeforeMethod
+ public void setUp() {
+// initializeDriver();
+ getDriver().get("https://demo-store.example.com");
+// }
+
+ @Test
+ public void testShoppingFlow() {
+ try {
+ // Perform search for 'laptop'
+ WebElement searchBox = elementHealer.findElement("search box");
+// searchBox.sendKeys("laptop");
+// searchBox.submit();
+
+// TODO: Implement validation logic below
+ // Validate search results
+// validateSearchResults("laptop");
+
+ // Add item to cart
+ WebElement addToCartButton = elementHealer.findElement("add to cart button");
+// addToCartButton.click();
+
+// TODO: Implement validation logic below
+ // Validate item added to cart
+// validateItemAddedToCart();
+
+// TODO: Implement validation logic below
+ // Proceed to checkout
+ WebElement checkoutButton = elementHealer.findElement("checkout button");
+// checkoutButton.click();
+
+// TODO: Implement validation logic below
+ // Validate checkout process
+// validateCheckoutProcess();
+
+ // Fill shipping details
+// fillShippingDetails();
+
+// TODO: Implement validation logic below
+ // Validate shipping details
+// validateShippingDetails();
+
+// TODO: Implement validation logic below
+ // Verify order summary
+// verifyOrderSummary();
+
+ } catch (Exception e) {
+ captureScreenshot("testShoppingFlow");
+ e.printStackTrace();
+// }
+// }
+
+ @AfterMethod
+ public void tearDown() {
+ driver.quit();
+// }
+
+ private void validateSearchResults(String searchTerm) {
+ // Implement validation logic
+// }
+
+ private void validateItemAddedToCart() {
+ // Implement validation logic
+// }
+
+ private void validateCheckoutProcess() {
+ // Implement validation logic
+// }
+
+ private void fillShippingDetails() {
+ // Implement shipping details filling logic
+// }
+
+ private void validateShippingDetails() {
+ // Implement validation logic
+// }
+
+ private void verifyOrderSummary() {
+ // Implement order summary verification logic
+// }
+
+// }
+
+/* 📚 **Knowledge Sources Used:** */
+// 1. built-in-solutions (Category: ERROR_SOLUTIONS, Relevance: 86.4)
+// 2. built-in-solutions (Category: ERROR_SOLUTIONS, Relevance: 80.1)
+// 3. built-in-solutions (Category: ERROR_SOLUTIONS, Relevance: 57.6)
+
+/* 💡 **Tip:** This response was enhanced with context-aware knowledge retrieval for better accuracy. */
diff --git a/src/test/ai_generated_tests/GeneratedLoginTest.java b/src/test/ai_generated_tests/GeneratedLoginTest.java
new file mode 100644
index 0000000..1587f2b
--- /dev/null
+++ b/src/test/ai_generated_tests/GeneratedLoginTest.java
@@ -0,0 +1,59 @@
+package org.k11techlab.framework.generated.tests;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.AfterMethod;
+
+public class GeneratedTest extends BaseSeleniumTest {
+
+ @BeforeMethod
+ public void setup() {
+ getDriver().get("https://demo.testsite.com");
+// }
+
+ @Test
+ public void loginTest() {
+ try {
+ // Input username
+ WebElement usernameInput = elementHealer.findElement("Username input field");
+// usernameInput.sendKeys("testuser");
+
+ // Input password
+ WebElement passwordInput = elementHealer.findElement("Password input field");
+// passwordInput.sendKeys("password123");
+
+ // Submit login credentials
+ WebElement loginButton = elementHealer.findElement("Login submit button");
+// loginButton.click();
+
+ // Wait for dashboard to load
+ WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+ wait.until(ExpectedConditions.visibilityOfElementLocated("Dashboard"));
+
+ // Validation
+// TODO: Implement validation logic below
+ // Add meaningful assertions here
+
+ } catch (Exception e) {
+ // Handle any exceptions
+ e.printStackTrace();
+ // Capture screenshot
+ captureScreenshot("loginTestFailure");
+// }
+// }
+
+ @AfterMethod
+ public void tearDown() {
+ driver.quit();
+// }
+// }
+
+/* 📚 **Knowledge Sources Used:** */
+// 1. built-in-solutions (Category: ERROR_SOLUTIONS, Relevance: 93.6)
+// 2. built-in-solutions (Category: ERROR_SOLUTIONS, Relevance: 79.2)
+// 3. built-in-solutions (Category: ERROR_SOLUTIONS, Relevance: 65.7)
+
+/* 💡 **Tip:** This response was enhanced with context-aware knowledge retrieval for better accuracy. */
diff --git a/src/test/ai_generated_tests/conversation_history.txt b/src/test/ai_generated_tests/conversation_history.txt
index 20a5bfe..dc63583 100644
--- a/src/test/ai_generated_tests/conversation_history.txt
+++ b/src/test/ai_generated_tests/conversation_history.txt
@@ -1,85 +1,76 @@
-System: ? **Welcome to K11 TechLab AI Test Assistant!**
+System: 🤖 **Welcome to K11 TechLab AI Test Assistant!**
I'm here to help you with test automation using our advanced AI-enhanced framework. I can:
-? **Generate tests** from natural language descriptions
-? **Debug issues** and provide solutions
-? **Review code** and suggest improvements
-?? **Help with framework** setup and configuration
-? **Share best practices** for reliable test automation
+🎯 **Generate tests** from natural language descriptions
+🔍 **Debug issues** and provide solutions
+📋 **Review code** and suggest improvements
+⚙️ **Help with framework** setup and configuration
+🌟 **Share best practices** for reliable test automation
/*
-? **Try saying:**
+💡 **Try saying:**
- "Generate a login test for https://example.com"
- "Help me debug this failing test"
- "Review my test code for improvements"
- "Show me best practices for element finding"
*/
-**Session ID:** `ff8f113f-c4e5-4ed9-af3d-49add41325c3`
+**Session ID:** `45d5e32f-f031-4605-87bd-3c3cb7a57e3c`
**Mode:** General test automation help and guidance
-How can I help you today? ?
+How can I help you today? 😊
User: I'm working on testing an e-commerce website called 'TechStore' at https://techstore.example.com
-Bot: ? Based on the provided knowledge sources, here is some helpful and actionable advice for testing the 'TechStore' e-commerce website at https://techstore.example.com:
+Bot: 💬 Based on the provided knowledge sources, here is some actionable advice for testing the 'TechStore' e-commerce website:
-1. Start by identifying key elements on the TechStore website that are crucial for testing, such as the search bar, product listings, add to cart buttons, checkout process, and user account functionality.
+1. When testing the TechStore website, consider creating test cases for form submissions, dropdown selections, and login functionality similar to the examples provided in Knowledge Source 1, 2, and 3. This will help ensure comprehensive test coverage.
-2. Utilize the AI-enhanced form test example to create tests for submitting forms on the website, such as creating a new account, updating user information, or submitting feedback.
+2. Utilize Selenium WebDriver to interact with elements on the TechStore website, such as finding elements by their IDs, class names, or other attributes. Make sure to handle any potential exceptions, such as ElementNotFoundException, as demonstrated in the test examples.
-3. Implement the AI-enhanced dropdown selection test example to test dropdown menus on the website, such as selecting different product categories or filtering search results.
+3. Implement wait strategies, such as WebDriverWait, to ensure that elements are loaded before interacting with them. This will help prevent test failures due to elements not being immediately available on the page.
-4. Leverage the AI-enhanced login test example to create tests for the login functionality on the TechStore website, ensuring that users can successfully log in with valid credentials.
+4. Capture screenshots in case of test failures to provide visual evidence of issues encountered during test execution. This can help in debugging and identifying the root cause of failures.
-5. Consider incorporating error handling mechanisms in your tests, similar to the form submission test example, to capture and handle any unexpected errors that may occur during test execution.
+5. Consider parameterizing your test data to cover different scenarios, such as submitting forms with different input values, selecting different options from dropdowns, and logging in with different usernames and passwords.
-6. Use WebDriverWait to wait for elements to load dynamically on the website, ensuring that your tests are robust and reliable in different browsing conditions.
-
-7. Regularly monitor and update your test scripts to adapt to any changes in the website's layout or functionality, maintaining the effectiveness of your automated testing suite.
-
-By following these guidelines and leveraging the provided knowledge sources, you can create comprehensive and effective automated tests for the TechStore e-commerce website, helping to ensure its functionality and user experience are of high quality.
+By following these guidelines and leveraging the provided test automation examples, you can effectively test the TechStore e-commerce website and ensure its functionality is robust and user-friendly.
/*
-? **Knowledge Sources Used:**
+📚 **Knowledge Sources Used:**
1. built-in-examples (Category: TEST_EXAMPLES, Relevance: 24.0)
2. built-in-examples (Category: TEST_EXAMPLES, Relevance: 21.0)
3. built-in-examples (Category: TEST_EXAMPLES, Relevance: 21.0)
*/
/*
-? **Tip:** This response was enhanced with context-aware knowledge retrieval for better accuracy.
+💡 **Tip:** This response was enhanced with context-aware knowledge retrieval for better accuracy.
*/
User: The login functionality is on the /login page. Users can login with email and password.
-Bot: ? Based on the provided test examples, here is a suggested approach to automate the login functionality on the /login page using Selenium:
-
-1. Identify the necessary elements on the login page such as the username input field, password input field, and login submit button. You can use elementHealer.findElement method as shown in the testLogin example.
-
-2. Use the WebElement.sendKeys method to enter the email and password into the respective input fields.
-
-3. Use the WebElement.click method to submit the login form by clicking on the login submit button.
-
-4. After successful login, verify the presence of a welcome message or any other indication of successful login using assertions as shown in the testLogin example.
-
-5. Handle any exceptions that may occur during the login process, such as ElementNotFoundException, by implementing error handling mechanisms like capturing a screenshot and throwing the exception as shown in the testFormSubmission example.
+Bot: 💬 Based on the provided test examples, you can create a Selenium test for the login functionality on the /login page by following these steps:
-6. Consider implementing wait strategies, such as WebDriverWait, to ensure that the necessary elements like the login form fields are loaded before interacting with them, as demonstrated in the testDropdownSelection example.
+1. Identify the necessary elements on the login page such as the username input field, password input field, and login submit button.
+2. Use the `elementHealer.findElement()` method to locate and interact with these elements in your test script.
+3. Use the `sendKeys()` method to input the test user's email and password into the respective input fields.
+4. Use the `click()` method to submit the login form.
+5. Use the `elementHealer.findElement()` method to locate the welcome message element that appears after a successful login.
+6. Use an assertion to verify that the welcome message is displayed, indicating a successful login.
-By following these steps and leveraging the provided test examples, you can create a robust and reliable automation test for the login functionality on the /login page using Selenium. Remember to adapt the code snippets and methods to suit the specific elements and behaviors of your application.
+By following these steps and incorporating the provided test examples as a reference, you can create a robust Selenium test for the login functionality on the /login page with AI-enhanced capabilities. Remember to handle any potential exceptions or error scenarios in your test script to ensure comprehensive test coverage.
/*
-? **Knowledge Sources Used:**
+📚 **Knowledge Sources Used:**
1. built-in-examples (Category: TEST_EXAMPLES, Relevance: 44.3)
2. built-in-examples (Category: TEST_EXAMPLES, Relevance: 31.5)
3. built-in-examples (Category: TEST_EXAMPLES, Relevance: 22.5)
*/
/*
-? **Tip:** This response was enhanced with context-aware knowledge retrieval for better accuracy.
+💡 **Tip:** This response was enhanced with context-aware knowledge retrieval for better accuracy.
*/
User: Now generate a comprehensive login test that includes both positive and negative scenarios
-Bot: I'd be happy to generate a test for you! ?
+Bot: I'd be happy to generate a test for you! 🎯
To create the most accurate test, could you please provide:
1. The base URL of the application
diff --git a/src/test/ai_generated_tests/org/k11techlab/framework_unittests/ai_generated/GeneratedPlaywrightLoginTest.java b/src/test/ai_generated_tests/org/k11techlab/framework_unittests/ai_generated/GeneratedPlaywrightLoginTest.java
new file mode 100644
index 0000000..44b359e
--- /dev/null
+++ b/src/test/ai_generated_tests/org/k11techlab/framework_unittests/ai_generated/GeneratedPlaywrightLoginTest.java
@@ -0,0 +1,47 @@
+package org.k11techlab.framework_unittests.ai_generated;
+
+import com.microsoft.playwright.Browser;
+import com.microsoft.playwright.BrowserType;
+import com.microsoft.playwright.Page;
+import com.microsoft.playwright.Playwright;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class GeneratedPlaywrightLoginTest {
+
+ private static Playwright playwright;
+ private static Browser browser;
+ private static Page page;
+
+ @BeforeClass
+ public void setUp() {
+ playwright = Playwright.create();
+ browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(true));
+ page = browser.newPage();
+ }
+
+ @Test
+ public void testLoginAndVerifyDashboard() {
+ String webUrl = ConfigurationManager.getBundle().getPropertyValue("weburl");
+ String username = ConfigurationManager.getBundle().getPropertyValue("username");
+ String password = ConfigurationManager.getBundle().getPropertyValue("password");
+
+ page.navigate(webUrl);
+
+ if (page.isVisible("a:has-text('Dashboard')")) {
+ page.click("a:has-text('Dashboard')");
+ }
+
+ page.fill("input[name='username']", username);
+ page.fill("input[name='password']", password);
+ page.click("button[type='submit']");
+
+ assert page.isVisible("text=Dashboard");
+ }
+
+ @AfterClass
+ public void tearDown() {
+ playwright.close();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/k11techlab/framework_unittests/ai_generated/GeneratedTest_1765827236416Test.java b/src/test/java/org/k11techlab/framework_unittests/ai_generated/GeneratedTest_1765827236416Test.java
deleted file mode 100644
index 3ae0cf7..0000000
--- a/src/test/java/org/k11techlab/framework_unittests/ai_generated/GeneratedTest_1765827236416Test.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.k11techlab.framework_unittests.ai_generated;
-
-import org.testng.annotations.Test;
-import com.microsoft.playwright.Browser;
-import com.microsoft.playwright.BrowserType;
-import com.microsoft.playwright.Page;
-import com.microsoft.playwright.Playwright;
-import org.testng.Assert;
-import com.microsoft.playwright.options.LoadState;
-
-public class GeneratedTest_1765827236416Test {
-
- @Test
- public void testDashboardVisibility() {
- String webURL = System.getenv("WEBURL");
- String username = System.getenv("USERNAME");
- String password = System.getenv("PASSWORD");
- try (Playwright playwright = Playwright.create()) {
- Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(true));
- Page page = browser.newPage();
- page.navigate(webURL);
- page.fill("input[name='username']", username);
- page.fill("input[name='password']", password);
- page.waitForLoadState(LoadState.NETWORKIDLE);
-
-
- Assert.assertTrue(page.isVisible("dashboardElement"));
- browser.close();
- }
- }
- }
diff --git a/src/test/ai_generated_tests/k11softwaresolutions/LoginFunctionalityTest.java b/src/test/java/org/k11techlab/framework_unittests/ai_generated/LoginFunctionalityTest.java
similarity index 91%
rename from src/test/ai_generated_tests/k11softwaresolutions/LoginFunctionalityTest.java
rename to src/test/java/org/k11techlab/framework_unittests/ai_generated/LoginFunctionalityTest.java
index ed8da3b..444d937 100644
--- a/src/test/ai_generated_tests/k11softwaresolutions/LoginFunctionalityTest.java
+++ b/src/test/java/org/k11techlab/framework_unittests/ai_generated/LoginFunctionalityTest.java
@@ -17,6 +17,9 @@ public void testLoginFunctionality() {
getDriver().get(ConfigurationManager.getBundle().getPropertyValue("weburl"));
+ // Click on the dashboard link before login
+ elementHealer.findElement("Dashboard link").click();
+
elementHealer.findElement("Username input field").sendKeys(ConfigurationManager.getBundle().getPropertyValue("username"));
elementHealer.findElement("Password input field").sendKeys(ConfigurationManager.getBundle().getPropertyValue("password"));
elementHealer.findElement("Login button").click();
diff --git a/src/test/java/org/k11techlab/framework_unittests/ai_generated/k11softwaresolutions/GeneratedPlaywrightLoginTest.java b/src/test/java/org/k11techlab/framework_unittests/ai_generated/k11softwaresolutions/GeneratedPlaywrightLoginTest.java
new file mode 100644
index 0000000..f786c89
--- /dev/null
+++ b/src/test/java/org/k11techlab/framework_unittests/ai_generated/k11softwaresolutions/GeneratedPlaywrightLoginTest.java
@@ -0,0 +1,84 @@
+package org.k11techlab.framework_unittests.ai_generated.k11softwaresolutions;
+
+import com.microsoft.playwright.Browser;
+import com.microsoft.playwright.BrowserType;
+import com.microsoft.playwright.Page;
+import com.microsoft.playwright.Playwright;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.k11techlab.framework.selenium.webuitestengine.configManager.ConfigurationManager;
+
+public class GeneratedPlaywrightLoginTest {
+
+ private Playwright playwright;
+ private Browser browser;
+ private Page page;
+
+ @BeforeClass
+ public void setUp() {
+ playwright = Playwright.create();
+ browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(true));
+ page = browser.newPage();
+ }
+
+ @Test
+ public void testLoginAndVerifyDashboard() {
+ String weburl = ConfigurationManager.getBundle().getPropertyValue("weburl");
+ String username = ConfigurationManager.getBundle().getPropertyValue("username");
+ String password = ConfigurationManager.getBundle().getPropertyValue("password");
+
+ page.navigate(weburl);
+
+ // Username field: id > name > text
+ String usernameSelector = null;
+ if (page.querySelector("#username") != null) {
+ usernameSelector = "#username";
+ } else if (page.querySelector("input[name='username']") != null) {
+ usernameSelector = "input[name='username']";
+ } else if (page.querySelector("text=Username") != null) {
+ usernameSelector = "text=Username";
+ }
+ if (usernameSelector != null) {
+ page.fill(usernameSelector, username);
+ }
+
+ // Password field: id > name > text
+ String passwordSelector = null;
+ if (page.querySelector("#password") != null) {
+ passwordSelector = "#password";
+ } else if (page.querySelector("input[name='password']") != null) {
+ passwordSelector = "input[name='password']";
+ } else if (page.querySelector("text=Password") != null) {
+ passwordSelector = "text=Password";
+ }
+ if (passwordSelector != null) {
+ page.fill(passwordSelector, password);
+ }
+
+ // Login button: id > name > text > type=submit
+ String loginBtnSelector = null;
+ if (page.querySelector("#login") != null) {
+ loginBtnSelector = "#login";
+ } else if (page.querySelector("button[name='login']") != null) {
+ loginBtnSelector = "button[name='login']";
+ } else if (page.querySelector("text=Login") != null) {
+ loginBtnSelector = "text=Login";
+ } else if (page.querySelector("button[type='submit']") != null) {
+ loginBtnSelector = "button[type='submit']";
+ }
+ if (loginBtnSelector != null) {
+ page.click(loginBtnSelector);
+ }
+
+ // Wait for dashboard text
+ page.waitForSelector("text=Dashboard", new Page.WaitForSelectorOptions().setTimeout(5000));
+ assert page.isVisible("text=Dashboard");
+ }
+
+ @AfterClass
+ public void tearDown() {
+ browser.close();
+ playwright.close();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/k11techlab/framework_unittests/ai_generated/k11softwaresolutions/LoginPage.java b/src/test/java/org/k11techlab/framework_unittests/ai_generated/k11softwaresolutions/LoginPage.java
new file mode 100644
index 0000000..cfbabe0
--- /dev/null
+++ b/src/test/java/org/k11techlab/framework_unittests/ai_generated/k11softwaresolutions/LoginPage.java
@@ -0,0 +1,59 @@
+package org.k11techlab.framework_unittests.ai_generated.k11softwaresolutions;
+
+import com.microsoft.playwright.Page;
+
+public class LoginPage {
+ private final Page page;
+
+ public LoginPage(Page page) {
+ this.page = page;
+ }
+
+ public void enterUsername(String username) {
+ String selector = null;
+ if (page.querySelector("#username") != null) {
+ selector = "#username";
+ } else if (page.querySelector("input[name='username']") != null) {
+ selector = "input[name='username']";
+ } else if (page.querySelector("text=Username") != null) {
+ selector = "text=Username";
+ }
+ if (selector != null) {
+ page.fill(selector, username);
+ }
+ }
+
+ public void enterPassword(String password) {
+ String selector = null;
+ if (page.querySelector("#password") != null) {
+ selector = "#password";
+ } else if (page.querySelector("input[name='password']") != null) {
+ selector = "input[name='password']";
+ } else if (page.querySelector("text=Password") != null) {
+ selector = "text=Password";
+ }
+ if (selector != null) {
+ page.fill(selector, password);
+ }
+ }
+
+ public void clickLogin() {
+ String selector = null;
+ if (page.querySelector("#login") != null) {
+ selector = "#login";
+ } else if (page.querySelector("button[name='login']") != null) {
+ selector = "button[name='login']";
+ } else if (page.querySelector("text=Login") != null) {
+ selector = "text=Login";
+ } else if (page.querySelector("button[type='submit']") != null) {
+ selector = "button[type='submit']";
+ }
+ if (selector != null) {
+ page.click(selector);
+ }
+ }
+
+ public boolean isDashboardVisible() {
+ return page.isVisible("text=Dashboard");
+ }
+}
diff --git a/src/test/java/org/k11techlab/framework_unittests/ai_mcp/MCPServerIntegrationTest.java b/src/test/java/org/k11techlab/framework_unittests/ai_mcp/MCPServerIntegrationTest.java
new file mode 100644
index 0000000..d27c98b
--- /dev/null
+++ b/src/test/java/org/k11techlab/framework_unittests/ai_mcp/MCPServerIntegrationTest.java
@@ -0,0 +1,190 @@
+package org.k11techlab.framework_unittests.ai_mcp;
+
+import org.k11techlab.framework.ai.mcp.MCPServer;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+import org.k11techlab.framework.selenium.webuitestengine.configManager.ConfigurationManager;
+
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+public class MCPServerIntegrationTest {
+
+ private MCPServer server;
+ private int port = 9000;
+ private boolean startedServer = false;
+
+
+ @BeforeClass
+ public void startServer() throws Exception {
+ // Use ConfigurationManager to get port
+ String portStr = ConfigurationManager.getString("mcp.port", "9000");
+ if (portStr != null && !portStr.isEmpty()) {
+ port = Integer.parseInt(portStr.trim());
+ }
+
+ // Check if server is already running (Apache HttpClient)
+ boolean alreadyRunning = false;
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ HttpGet get = new HttpGet("http://localhost:" + port + "/mcp/health");
+ get.setConfig(org.apache.http.client.config.RequestConfig.custom()
+ .setConnectTimeout(500)
+ .setSocketTimeout(500)
+ .build());
+ try (CloseableHttpResponse response = httpClient.execute(get)) {
+ int responseCode = response.getStatusLine().getStatusCode();
+ if (responseCode == 200) {
+ alreadyRunning = true;
+ }
+ }
+ } catch (Exception e) {
+ // Not running
+ }
+
+ if (!alreadyRunning) {
+ server = new MCPServer();
+ server.start(port);
+ startedServer = true;
+ // Give the server a moment to start
+ Thread.sleep(500);
+ }
+ }
+
+
+ @AfterClass
+ public void stopServer() {
+ if (startedServer && server != null) server.stop();
+ }
+
+ private String httpGet(String path) throws Exception {
+ String url = "http://localhost:" + port + path;
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ HttpGet get = new HttpGet(url);
+ try (CloseableHttpResponse response = httpClient.execute(get)) {
+ int responseCode = response.getStatusLine().getStatusCode();
+ StringBuilder content = new StringBuilder();
+ try (BufferedReader in = new BufferedReader(new InputStreamReader(
+ response.getEntity().getContent(), "utf-8"))) {
+ String inputLine;
+ while ((inputLine = in.readLine()) != null) {
+ content.append(inputLine);
+ }
+ }
+ assertEquals(responseCode, 200, "Expected HTTP 200 for " + path + ", got " + responseCode + ": " + content);
+ return content.toString();
+ }
+ }
+ }
+
+ private String httpPost(String path, String jsonBody) throws Exception {
+ String url = "http://localhost:" + port + path;
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ HttpPost post = new HttpPost(url);
+ post.setHeader("Content-Type", "application/json");
+ if (jsonBody != null) {
+ post.setEntity(new StringEntity(jsonBody, "UTF-8"));
+ }
+ try (CloseableHttpResponse response = httpClient.execute(post)) {
+ int responseCode = response.getStatusLine().getStatusCode();
+ StringBuilder content = new StringBuilder();
+ try (BufferedReader in = new BufferedReader(new InputStreamReader(
+ response.getEntity().getContent(), "utf-8"))) {
+ String inputLine;
+ while ((inputLine = in.readLine()) != null) {
+ content.append(inputLine);
+ }
+ }
+ assertEquals(responseCode, 200, "Expected HTTP 200 for POST " + path + ", got " + responseCode + ": " + content);
+ return content.toString();
+ }
+ }
+ }
+
+ @Test
+ public void testHealthEndpoint() throws Exception {
+ String response = httpGet("/mcp/health");
+ assertTrue(response.toLowerCase().contains("ok") || response.length() > 0, "Health endpoint should return OK or non-empty");
+ }
+
+
+ @Test
+ public void testCompletionEndpoint() throws Exception {
+ // Example payload, adjust as needed for your API
+ String payload = "{\"prompt\":\"Hello, world!\"}";
+ String response = httpPost("/mcp/completion", payload);
+ assertTrue(response.length() > 0, "Completion endpoint should return non-empty response");
+ }
+
+
+ @Test
+ public void testContextEndpoint() throws Exception {
+ // Example payload, adjust as needed for your API
+ String payload = "{\"contextId\":\"test\"}";
+ String response = httpPost("/mcp/context", payload);
+ assertTrue(response.length() > 0, "Context endpoint should return non-empty response");
+ }
+
+ @Test
+ public void testContextListEndpoint() throws Exception {
+ String response = httpGet("/mcp/context/list");
+ assertTrue(response.length() > 0, "Context list endpoint should return non-empty response");
+ }
+
+
+ @Test
+ public void testWorkflowEndpoint() throws Exception {
+ // Example payload, adjust as needed for your API
+ String payload = "{\"workflow\":\"test\"}";
+ String response = httpPost("/mcp/workflow", payload);
+ assertTrue(response.length() > 0, "Workflow endpoint should return non-empty response");
+ }
+
+
+ @Test
+ public void testCorrectCodeEndpoint() throws Exception {
+ // Example payload, adjust as needed for your API
+ String payload = "{\"code\":\"System.out.println(\\\"Hello\\\");\"}";
+ String response = httpPost("/mcp/correct-code", payload);
+ assertTrue(response.length() > 0, "Correct code endpoint should return non-empty response");
+ }
+
+
+ @Test
+ public void testGenerateAndRunSeleniumTestEndpoint() throws Exception {
+ // Example payload for new endpoint structure
+ String payload = "{\"webUrl\":\"https://k11softwaresolutions-platform.vercel.app/\",\"promptFile\":\"mcp-prompts/k11softwaresolutions/tests/logintest_creation_prompt.txt\"}";
+ String response = httpPost("/mcp/generate-and-run-selenium-test", payload);
+ assertTrue(response.length() > 0, "Generate and run selenium test endpoint should return non-empty response");
+ }
+
+ @Test
+ public void testGeneratePageObjectEndpoint() throws Exception {
+ // Use a minimal valid payload for page object generation
+ String payload = "{\"webUrl\":\"https://k11softwaresolutions-platform.vercel.app/\",\"promptFile\":\"mcp-prompts/k11softwaresolutions/pageobjects/pageobject_creation_prompt_multi.txt\"}";
+ String response = httpPost("/mcp/generate-page-object", payload);
+ assertTrue(response.length() > 0, "Generate page object endpoint should return non-empty response");
+ }
+
+ @Test
+ public void testGenerateAndRunPlaywrightTestEndpoint() throws Exception {
+ // Example payload for new endpoint structure
+ String payload = "{\"webUrl\":\"https://k11softwaresolutions-platform.vercel.app/\",\"promptFile\":\"mcp-prompts/k11softwaresolutions/tests/logintest_creation_prompt.txt\"}";
+ String response = httpPost("/mcp/generate-and-run-playwright-test", payload);
+ assertTrue(response.length() > 0, "Generate and run playwright test endpoint should return non-empty response");
+ }
+}
diff --git a/src/test/java/org/k11techlab/framework_unittests/playwright/PlaywrightManagerUnitTest.java b/src/test/java/org/k11techlab/framework_unittests/playwright/PlaywrightManagerUnitTest.java
new file mode 100644
index 0000000..60b4e4c
--- /dev/null
+++ b/src/test/java/org/k11techlab/framework_unittests/playwright/PlaywrightManagerUnitTest.java
@@ -0,0 +1,157 @@
+package org.k11techlab.framework_unittests.playwright;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.k11techlab.framework.playwright.PlaywrightManager;
+import org.k11techlab.framework.playwright.BasePlaywrightTest;
+import com.microsoft.playwright.Page;
+import com.microsoft.playwright.Browser;
+import com.microsoft.playwright.BrowserContext;
+import com.aventstack.extentreports.ExtentTest;
+
+public class PlaywrightManagerUnitTest extends BasePlaywrightTest {
+ private ExtentTest test;
+
+ @Test
+ public void testSingletonInstance() {
+ test = extent.createTest("testSingletonInstance");
+ PlaywrightManager another = PlaywrightManager.getInstance();
+ try {
+ Assert.assertEquals(manager, another, "PlaywrightManager should be singleton");
+ test.pass("Singleton instance verified");
+ } catch (AssertionError e) {
+ test.fail(e);
+ throw e;
+ }
+ }
+
+ @Test
+ public void testBrowserInitialization() {
+ test = extent.createTest("testBrowserInitialization");
+ Browser browser = manager.getBrowser();
+ try {
+ Assert.assertNotNull(browser, "Browser should be initialized");
+ test.pass("Browser initialized");
+ } catch (AssertionError e) {
+ test.fail(e);
+ throw e;
+ }
+ }
+
+ @Test
+ public void testContextInitialization() {
+ test = extent.createTest("testContextInitialization");
+ BrowserContext context = manager.getContext();
+ try {
+ Assert.assertNotNull(context, "BrowserContext should be initialized");
+ test.pass("Context initialized");
+ } catch (AssertionError e) {
+ test.fail(e);
+ throw e;
+ }
+ }
+
+ @Test
+ public void testPageInitialization() {
+ test = extent.createTest("testPageInitialization");
+ Page page = manager.getPage();
+ try {
+ Assert.assertNotNull(page, "Page should be initialized");
+ test.pass("Page initialized");
+ } catch (AssertionError e) {
+ test.fail(e);
+ throw e;
+ }
+ }
+
+ @Test
+ public void testNewPage() {
+ test = extent.createTest("testNewPage");
+ Page newPage = manager.newPage();
+ try {
+ Assert.assertNotNull(newPage, "newPage() should return a new Page");
+ test.pass("New page created");
+ } catch (AssertionError e) {
+ test.fail(e);
+ throw e;
+ }
+ newPage.close();
+ }
+
+ @Test
+ public void testClosePage() {
+ test = extent.createTest("testClosePage");
+ Page page = manager.getPage();
+ manager.closePage();
+ try {
+ java.lang.reflect.Field pageField = manager.getClass().getDeclaredField("page");
+ pageField.setAccessible(true);
+ Object internalPage = pageField.get(manager);
+ Assert.assertNull(internalPage, "Page should be null after closePage()");
+ test.pass("Page closed");
+ } catch (Exception e) {
+ test.fail(e);
+ Assert.fail("Reflection failed: " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCloseContext() {
+ test = extent.createTest("testCloseContext");
+ manager.closeContext();
+ try {
+ Assert.assertNull(manager.getContext(), "Context should be null after closeContext()");
+ test.pass("Context closed");
+ } catch (AssertionError e) {
+ test.fail(e);
+ throw e;
+ }
+ }
+
+ @Test
+ public void testCloseBrowser() {
+ test = extent.createTest("testCloseBrowser");
+ manager.closeBrowser();
+ try {
+ Assert.assertNull(manager.getBrowser(), "Browser should be null after closeBrowser()");
+ test.pass("Browser closed");
+ } catch (AssertionError e) {
+ test.fail(e);
+ throw e;
+ }
+ }
+
+ @Test
+ public void testQuit() {
+ test = extent.createTest("testQuit");
+ manager.quit();
+ try {
+ Assert.assertNull(manager.getBrowser(), "Browser should be null after quit()");
+ Assert.assertNull(manager.getContext(), "Context should be null after quit()");
+ test.pass("PlaywrightManager quit");
+ } catch (AssertionError e) {
+ test.fail(e);
+ throw e;
+ }
+ }
+
+ @Test
+ public void testNavigateToWebUrl() {
+ test = extent.createTest("testNavigateToWebUrl");
+ String webUrl = org.k11techlab.framework.selenium.webuitestengine.configManager.ConfigurationManager.getBundle().getPropertyValue("weburl");
+ try {
+ Assert.assertNotNull(webUrl, "weburl must be set in mcp-config.properties");
+ Page page = manager.getPage();
+ page.navigate(webUrl);
+ String title = page.title();
+ Assert.assertNotNull(title, "Page title should not be null after navigation");
+ Assert.assertFalse(title.isEmpty(), "Page title should not be empty after navigation");
+ test.pass("Navigation to weburl successful, title: " + title);
+ } catch (AssertionError e) {
+ test.fail(e);
+ throw e;
+ }
+ }
+
+ // Teardown is handled by BasePlaywrightTest
+}