A Java automation framework for browser, desktop, and API testing — powered by Chrome DevTools Protocol (CDP), Windows UI Automation, and SikuliX. Includes MCP servers for AI-driven browser and desktop control.
- Browser Automation — Direct CDP (Chrome DevTools Protocol) integration, no WebDriver required
- Browser Lifecycle — Auto-discover and launch Chrome/Edge in headless or headed mode with isolated browser contexts for parallel testing
- Video Recording — CDP-based screen recording to MJPEG AVI (works in headless mode)
- MCP Servers — JSON-RPC 2.0 stdio servers for AI tools (Claude Desktop, Cursor) to control browsers and desktops
- Desktop Automation — Windows UI Automation via JNA and W3C WebDriver server protocol
- Playwright-Like Trace Viewer — Detailed CDP-based browser test execution tracing (screenshots, network logs, console messages, and source code snippets)
- Image-Based Automation — SikuliX pattern matching for visual element interaction, with Page Object annotation support
- REST API Client — Apache HttpClient wrapper for API testing
- AI-Powered Locators — Natural-language element finding via Ollama LLM integration
- Visual Assertions — Automated image comparison for visual regression testing
- MongoDB Integration — Full CRUD operations (insert, find, update, delete, aggregation) with connection pooling and authentication support
- SQL Database Integration — CRUD operations (insert, batch insert, find, update, delete, table count) and generic parameterized SQL execution for JDBC-compliant databases
- JMeter Load Testing — Programmatic execution of JMeter
.jmxfiles viajmeter-java-dslintegrated into TestNG - Utilities — JSON parsing (Jackson), Excel, PDF, file operations, logging, and ExtentReports integration
- Java 21+
- Maven 3.8+
- Windows (required for desktop automation features)
- Chromium-based browser (for CDP features)
Add the repository and dependency to your pom.xml:
<repositories>
<repository>
<id>github</id>
<url>https://maven.pkg.github.com/aji4032/Wheel3</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.github.aji4032</groupId>
<artifactId>Wheel3</artifactId>
<version>LATEST</version>
</dependency>
</dependencies>git clone https://github.com/aji4032/Wheel3.git
cd Wheel3
mvn clean packagesrc/main/java/
├── cdphandler/ # CDP browser automation engine
│ ├── BrowserLauncher # Discover & launch Chrome/Edge (headless/headed, auto-port)
│ ├── BrowserContext # Isolated browser contexts for parallel test execution
│ ├── CdpHandler # Factory: createDriver(), launchAndConnect()
│ ├── CdpDriver # Browser driver (navigation, windows, tabs, screenshots)
│ ├── CdpElement # Element interactions (click, type, drag, scroll)
│ ├── CdpClient # WebSocket client for CDP communication
│ ├── CdpUtility # Low-level CDP command execution
│ ├── CdpScripts # JavaScript snippets for element operations
│ ├── OllamaUtility # AI-powered action planning via Ollama LLM
│ ├── ApiInterceptor # Network request/response interception
│ ├── ICdpDriver # Driver interface
│ ├── ICdpElement # Element interface
│ ├── CdpBy # Locator record (CSS, XPath, piercing CSS, natural language)
│ ├── CdpKey # Keyboard key constants
│ └── CdpDriverProxy / CdpElementProxy / OllamaProxy # Dynamic proxies
├── mcp/ # MCP servers for AI tool integration
│ ├── BrowserMcpServer # Browser MCP stdio entry point
│ ├── SikuliMcpServer # Sikuli desktop MCP stdio entry point
│ ├── McpToolDispatcher # Routes browser tool calls
│ ├── SikuliToolDispatcher # Routes Sikuli tool calls (PFRML targets)
│ └── McpResponse # Response formatting
├── w3c/ # Windows desktop automation (JNA-based W3C WebDriver server & client)
│ ├── W3CDriver # Singleton desktop driver (window lookup, manages local W3C server)
│ ├── W3CWindow # Window interactions (findElement, focus, close, maximize, minimize)
│ ├── W3CElement # Element interactions (clickButton, setEditBoxValue, getEditBoxValue, getText)
│ ├── W3CBy # Locator record (automationId, className, name)
│ ├── W3CActions # Rich helpers (checkbox, combobox, radio, tab, menu, list, grid)
│ └── W3CLocatorType # Locator type enum
├── sikuli/ # Image-based automation
│ ├── SikuliActions # Click, type, wait, drag via image patterns
│ ├── SikuliFactory # Screen/region factory & page object init
│ └── FindPatternBy # Page Object annotation for Sikuli patterns
├── apachehttpclient/ # REST API testing
│ ├── APIExecutor # GET/POST/PUT/DELETE executor
│ └── ResponseObject # Response wrapper
├── apps/ # Sample application page objects
│ └── calculator/
│ └── CalculatorApp # Windows Calculator page object (W3C-based)
└── tools/ # Shared utilities
├── JSONParser # JSON parsing (Jackson)
├── FileUtilities # File, ZIP, PDF, Base64 operations
├── ExcelUtilities # Excel read/write
├── MongoDBUtilities # MongoDB CRUD, connection pooling, authentication
├── SQLDatabaseUtilities # SQL DB CRUD, generic queries, parameterized updates
├── Log # Log4j + ExtentReports logging
├── ExtentManager # ExtentReports singleton
├── ExtentTestNGListener # TestNG lifecycle listener (auto video attachment)
├── ScreenRecorder # CDP-based video recording (MJPEG AVI, headless-safe)
├── JMeterRunner # Programmatic JMeter JMX test executor
├── DriverContext # Thread-local driver holder for infrastructure classes
├── CommandLineExecutor # OS command execution
├── PropertyFileHandler # Properties file reader
├── HTMLParser # HTML parsing with dom4j
├── Checksum # MD5/SHA checksums
└── Utilities # Wait/retry helpers
src/test/java/
├── cdphandler/
│ ├── CdpTestBase # Abstract base: shared browser, per-test BrowserContext isolation
│ ├── BrowserLauncherTest # BrowserLauncher unit tests
│ ├── BrowserContextTest # BrowserContext unit tests
│ ├── CdpByTest # Locator tests
│ ├── CdpScriptsTest # JS script tests
│ └── SampleTest # End-to-end browser automation sample
├── mcp/
│ └── McpToolDispatcherTest # MCP tool routing tests
├── tools/
│ ├── JSONParserTest # JSON parsing tests
│ ├── JMeterRunnerTest # JMeter runner integration tests
│ ├── JMeterTest # TestNG JMeter wrapper tests
│ └── SQLDatabaseUtilitiesTest # SQL database utility tests
└── apps/calculator/ # Calculator app tests
// Launch Chrome automatically and get a ready-to-use driver
ICdpDriver driver = CdpHandler.launchAndConnect();
driver.get("https://google.com");
// Find and interact with elements
ICdpElement searchBox = driver.findElement(CdpBy.cssSelector("input[name='q']"));
searchBox.sendKeys("Wheel3 automation");
// Screenshots
String base64Screenshot = driver.captureScreenshot();
driver.close();// Launch with explicit control
BrowserLauncher.LaunchedBrowser browser = BrowserLauncher.launch();
String pageWs = BrowserLauncher.getFirstPageWsUrl(browser.port());
ICdpDriver driver = CdpHandler.createDriver(pageWs);
driver.get("https://example.com");
// ... test ...
driver.close();
browser.close(); // kills Chrome process & cleans up temp profilepublic class MyTest extends CdpTestBase {
@Test
public void testIsolated() {
// Each test gets its own BrowserContext — zero shared state
getDriver().get("https://example.com");
ICdpElement heading = getDriver().findElement(CdpBy.cssSelector("h1"));
Assert.assertNotNull(heading.getText());
}
}// Automatically records browser viewport (works in headless mode)
ScreenRecorder.startRecording(driver.getCdpUtility(), "myTest");
// ... test steps ...
File video = ScreenRecorder.stopRecording(); // → target/recordings/myTest_20260502_120000.avi// Start detailed test execution tracing
File traceZip = new File("target/traces/test_trace.zip");
driver.startTracing(traceZip);
// Run browser operations...
driver.get("https://example.com");
ICdpElement btn = driver.findElement(CdpBy.cssSelector("button"));
btn.click();
// Stop tracing (generates ZIP with interactive HTML viewer, screenshots, console, and network logs)
driver.stopTracing();# Execute testng.xml
java -cp desktop-ui-automation-1.1.0-SNAPSHOT-jar-with-dependencies.jar org.testng.TestNG src/test/resources/testng.xml# Start the Browser MCP stdio server
java -jar desktop-ui-automation-1.1.0-SNAPSHOT-jar-with-dependencies.jar ws://localhost:9222/devtools/page/...Configure in Claude Desktop or Cursor's MCP settings to enable AI-driven browser control.
The Sikuli MCP server exposes image-based desktop automation via JSON-RPC 2.0 stdio, allowing AI tools to click, type, scroll, drag-drop, and screenshot the desktop using image pattern matching.
Launch:
# Build the fat JAR
mvn package -DskipTests
# Start the Sikuli MCP server
java -jar target/desktop-ui-automation-1.1.0-SNAPSHOT-sikuli-jar-with-dependencies.jar \
--imagePath "C:/my_images" \
--resultDir "C:/test_results"| CLI Flag | Description |
|---|---|
--imagePath <dir> |
Base directory for image files (so tools can use filenames instead of full paths) |
--resultDir <dir> |
Directory where screenshots and result artifacts are saved |
Available tools: click, double_click, hover, drag_drop, type_text, scroll, exists, wait_vanish, capture_screenshot, set_result_dir
Target types (PFRML): Tools accept a target that can be a simple image filename string or a JSON object with a type field — filename, pattern (with similarity/offset), text (OCR), region (x,y,w,h), or location (x,y).
Sample interaction (newline-delimited JSON-RPC via stdin/stdout):
// Get a desktop window by title (automatically starts local W3C server on a free port)
W3CDriver desktop = W3CDriver.getInstance();
W3CWindow notepad = desktop.getWindow("Untitled - Notepad");
// Find and interact with elements
W3CBy editArea = W3CBy.ByAutomationId("edit area", "15");
W3CElement editor = notepad.findElement(editArea);
editor.setEditBoxValue("Hello from Wheel3!");
// Rich control actions using W3CActions helper
W3CElement checkbox = notepad.findElement(W3CBy.ByAutomationId("My Checkbox", "1002"));
W3CActions.getInstance().toggleCheckbox(checkbox);
// Window management
notepad.maximizeWindow();
notepad.closeWindow();// Connect to MongoDB
MongoDBUtilities mongo = new MongoDBUtilities("mongodb://localhost:27017");
// Insert a document
mongo.insertOne("myDb", "users", Map.of("name", "Alice", "age", 30));
// Query documents with filters
List<Document> results = mongo.find("myDb", "users", Filters.eq("age", 30));
// Update documents
mongo.updateOne("myDb", "users",
Filters.eq("name", "Alice"),
Updates.set("age", 31)
);
// Delete documents
mongo.deleteOne("myDb", "users", Filters.eq("name", "Alice"));
// Aggregation
List<Bson> pipeline = Arrays.asList(
new Document("$match", new Document("status", "active")),
new Document("$group", new Document("_id", "$category").append("count", new Document("$sum", 1)))
);
List<Document> aggregationResults = mongo.aggregate("myDb", "users", pipeline);
// Connection management
boolean isAlive = mongo.ping("myDb");
mongo.close(); // Resource cleanup// Connect with explicit credentials
MongoDBUtilities mongo = new MongoDBUtilities(
"mongodb://host:27017",
"admin", // auth database
"username", // username
"password" // password
);
mongo.insertOne("appDb", "logs", Map.of("level", "INFO", "message", "Test"));
mongo.close();// Connect to a SQL database (e.g. H2 in-memory, MySQL, PostgreSQL, etc.)
SQLDatabaseUtilities db = new SQLDatabaseUtilities("jdbc:h2:mem:testdb", "sa", "");
// Insert a row using key-value maps
db.insertOne("users", Map.of("name", "Alice", "age", 30, "status", "active"));
// Query rows with parameterized where clause
List<Map<String, Object>> results = db.find("users", "age = ?", 30);
// Update records
db.updateOne("users", Map.of("status", "inactive"), "name = ?", "Alice");
// Delete records
db.deleteOne("users", "name = ?", "Alice");
// Run generic queries or updates with prepared statement bindings
List<Map<String, Object>> customResults = db.executeQuery(
"SELECT name FROM users WHERE status = ? AND age > ?",
"active", 25
);
// Connection management
boolean isAlive = db.ping();
db.close(); // Resource cleanup// Compare an actual base64 image against a saved baseline
// (Auto-creates the baseline if it doesn't exist)
VisualAssert.assertMatchesBaseline("login_page", driver.captureScreenshot());ResponseObject response = APIExecutor.get("https://api.example.com/users");
String body = response.getResponseBody();// Run standard .jmx files programmatically and fail the TestNG test if errors exist
TestPlanStats stats = JMeterRunner.run("src/test/resources/my-perf-test.jmx");
// Or run with custom report directories and JTL results
JMeterRunner.run(new File("my-test.jmx"), new File("target/custom-report"), new File("target/results.jtl"));The project uses GitHub Actions (.github/workflows/ci.yml) with:
- Build — Runs on every push and PR to
main - Publish — Deploys to GitHub Packages on push to
mainor manual trigger - Manual dispatch — Trigger a publish anytime from the Actions tab
| Category | Library | Version |
|---|---|---|
| Language | Java | 21 |
| Browser Automation | Chrome DevTools Protocol | Direct WebSocket |
| Desktop Automation | JNA Windows UI Automation | 5.14.0 |
| Image Automation | SikuliX | 2.0.5 |
| Visual Assertions | Image Comparison | 4.4.0 |
| HTTP Client | OkHttp | 5.3.2 |
| REST Client | Apache HttpClient | 4.5.14 |
| JMeter Automation | jmeter-java-dsl | 2.2 |
| Database (NoSQL) | MongoDB Driver (Sync) | 5.8.0 |
| Database (SQL) | H2 Database Engine (test scope) | 2.4.240 |
| JSON | Jackson | 2.22.0 |
| XML/HTML | dom4j | 2.2.0 |
| Logging | Log4j 2 | 2.26.0 |
| Reporting | ExtentReports + ChainTest | 5.1.2 / 1.0.12 |
| Testing | TestNG | 7.12.0 |
See LICENSE for details.