Skip to main content

AI-powered Selenium to Playwright migration tool

Project description

QAMigrate

AI-powered test framework migration

PyPI version Python 3.11+ License: MIT

A QATonic Innovations product.


QAMigrate converts test suites between frameworks automatically. It parses your code with Tree-sitter, generates equivalent code with Claude or GPT-4, and produces a full migration report with per-file diffs, confidence scores, and estimated time savings.

Supported today (v0.4.x)

Selenium (Java) -> Playwright (Java) only.

  • Source language: Java 11+ with Selenium 3/4, TestNG or JUnit 4/5, Maven or Gradle
  • Target language: Java 17+ with Playwright for Java, JUnit 5, same build tool
  • LLM providers: Anthropic (default) or OpenAI

Roadmap (not yet shipped)

  • v0.5.x: Python Selenium -> Python Playwright (pytest)
  • v0.5.x+: JavaScript/TypeScript Selenium -> Playwright
  • v0.6.x+: Cypress -> Playwright, RestAssured -> Karate

If you have a Selenium project in Python/JS/C#, QAMigrate will NOT migrate it today. Follow the GitHub repo for when support lands.

Why QAMigrate

You don't just get generated code. You get evidence:

  • Per-file diffs -- every pattern we touched, why, and side-by-side before/after
  • Confidence score -- how sure we are about each file, 0 to 100
  • Batch report -- HTML, JSON, and Markdown; share with your team
  • Time-saved estimate -- how many hours of manual work you avoided
  • Dry-run mode -- preview what would change without calling the LLM

What it does

Give it a Selenium file:

// Selenium
@FindBy(id = "username")
private WebElement usernameInput;

public void login(String user, String pass) {
    usernameInput.clear();
    usernameInput.sendKeys(user);
    passwordInput.sendKeys(pass);
    wait.until(ExpectedConditions.elementToBeClickable(loginButton));
    loginButton.click();
}

Get Playwright back:

// Playwright (generated by QAMigrate)
private final Locator usernameInput;

public LoginPage(Page page) {
    this.usernameInput = page.locator("#username");
}

public void login(String user, String pass) {
    usernameInput.fill(user);
    passwordInput.fill(pass);
    loginButton.click(); // Playwright auto-waits
}

Supported patterns (Selenium -> Playwright Java)

  • @FindBy annotations (id, css, xpath, className, name, linkText)
  • PageFactory.initElements removal
  • WebDriverWait / ExpectedConditions removal (Playwright auto-waits)
  • sendKeys -> fill, clear removal, click direct conversion
  • Actions (hover, drag) -> Playwright equivalents
  • Select dropdowns -> selectOption
  • JavascriptExecutor -> page.evaluate()
  • Alert / iframe handling
  • File uploads -> setInputFiles
  • TestNG -> JUnit 5 lifecycle (@BeforeMethod -> @BeforeEach, etc.)
  • @DataProvider -> @MethodSource
  • Assert.assertEquals / assertTrue -> Playwright assertions
  • ChromeDriver setup -> Playwright.create() + browser.newContext()
  • Base class inheritance preservation

Quick start

Prerequisites

Install

pip install qamigrate

That's it. Both the Anthropic and OpenAI SDKs are included; you pick which provider to use at runtime with --provider or in qamigrate.yaml.

Configure

Set one API key (the one for the provider you'll use). If you plan to switch between them, set both.

echo "ANTHROPIC_API_KEY=sk-ant-your-key" > .env
# and/or
echo "OPENAI_API_KEY=sk-your-openai-key" >> .env

Initialize (once per project)

# Auto-injects Playwright + JUnit 5 into your pom.xml so compile-check works.
qamigrate init --project ./my-selenium-project --yes

Migrate

# Dry-run: see what would happen without calling the LLM
qamigrate migrate --all --project ./my-selenium-project --dry-run

# Migrate a single file
qamigrate migrate src/test/java/LoginPage.java --project ./my-selenium-project

# Migrate the whole project with batch compile + report (recommended)
qamigrate migrate --all --project ./my-selenium-project --report ./qamigrate-report

Output goes to playwright/ subdirectories next to each original file. If you use --report <dir>, you get report.html, report.json, and report.md.

Choose your LLM provider

v0.4.0 supports both Anthropic and OpenAI. You can switch providers per-run without editing the config file:

# Use OpenAI for everything
qamigrate migrate --all --project ./p --provider openai --model gpt-4o

# Use Claude for code generation (reasoning-heavy), GPT-4o-mini for
# compile-error cleanup (cheaper and faster):
qamigrate migrate --all --project ./p \
  --coder-provider anthropic --coder-model claude-sonnet-4-20250514 \
  --fixer-provider openai --fixer-model gpt-4o-mini

Or pin it in qamigrate.yaml:

coder:
  provider: anthropic
  model: claude-sonnet-4-20250514
fixer:
  provider: openai
  model: gpt-4o-mini

Example report summary

QAMigrate - Migrating 7 file(s)

-> [1/7] BaseTest.java
   OK src/.../playwright/BaseTest.java (14.1s, 75% confidence)
-> [2/7] LoginPage.java
   OK src/.../playwright/LoginPage.java (17.2s, 75% confidence)
...

Files             7 / 7
Patterns handled  149
Avg confidence    75%
Time              105.3s
Est. hours saved  ~37.2

Report written:
  HTML:     ./qamigrate-report/report.html
  JSON:     ./qamigrate-report/report.json
  Markdown: ./qamigrate-report/report.md

CLI commands

Command Description
qamigrate init Initialize QAMigrate in a project
qamigrate scan Analyze codebase, detect patterns, show complexity
qamigrate analyze NEW in v0.5 -- build a full architecture report (roles, conventions, infra, dependency graph) WITHOUT calling the LLM
qamigrate migrate Convert files to the target framework (now context-aware: sees the whole project's conventions and siblings)

Common flags for migrate:

  • <file> — migrate a single file
  • --all, -a — migrate all Java files under src/test or src/
  • --dry-run — analyze only, no LLM calls, no writes
  • --report <dir> — write HTML + JSON + Markdown report
  • --project, -p <path> — project root (default: current dir)
  • --no-batch-compile — fall back to the v0.2 per-file compile loop

LLM provider flags (v0.4+):

  • --provider <name> — LLM provider for both agents (anthropic | openai)
  • --model <id> — model for both agents (e.g. gpt-4o, claude-sonnet-4-20250514)
  • --coder-provider <name> / --coder-model <id> — override Coder only
  • --fixer-provider <name> / --fixer-model <id> — override Fixer only

Flags on init:

  • --yes, -y — auto-inject Playwright + JUnit 5 deps into pom.xml / build.gradle without prompting

How it works

Scanner (Tree-sitter)     Deterministic AST parsing, pattern detection
       |
Coder (LLM)               Generates Playwright Java via structured output
       |                  (Anthropic or OpenAI, pluggable per agent)
       |
Compiler (javac)          Validates generated code compiles
       |
Fixer (rules + LLM)       Fixes compilation errors, retries up to 3x
       |
Report                    Records every file, pattern, confidence, diff

Plain Python — no LangChain, no graph framework, no agents-of-agents. Each step is a clean module you can read in 5 minutes. Providers live under qamigrate.llm.providers and implement a single generate_structured method; adding Gemini or Ollama is a few hundred lines.

Configuration

Optional qamigrate.yaml in your project root:

pipeline:
  max_retries: 3

coder:
  model: "claude-sonnet-4-20250514"
  max_tokens: 8192

compiler:
  build_tool: "maven"    # or "gradle"
  java_version: "17"
  skip: false            # set true when Playwright JARs aren't on classpath

scanner:
  exclude_patterns:
    - "**/target/**"
    - "**/build/**"
    - "**/playwright/**"

You can also use environment variables with the QAMIGRATE_ prefix:

export QAMIGRATE_COMPILER__SKIP=true       # skip compilation check
export QAMIGRATE_PIPELINE__MAX_RETRIES=5   # more retries

Python API

from qamigrate.agents.pipeline import run_migration
from qamigrate.core.config import QAMigrateConfig
from qamigrate.core.report import MigrationReport

config = QAMigrateConfig()
report = MigrationReport()

result = run_migration(
    file_path=Path("src/test/java/LoginPage.java"),
    project_path=Path("."),
    config=config,
)

if result.record:
    report.add(result.record)

report.finish()
report.write_html(Path("./report.html"))

Development

pip install -e ".[dev]"
pytest tests -v
ruff check src tests

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qamigrate-0.5.1.tar.gz (169.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qamigrate-0.5.1-py3-none-any.whl (117.2 kB view details)

Uploaded Python 3

File details

Details for the file qamigrate-0.5.1.tar.gz.

File metadata

  • Download URL: qamigrate-0.5.1.tar.gz
  • Upload date:
  • Size: 169.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.11

File hashes

Hashes for qamigrate-0.5.1.tar.gz
Algorithm Hash digest
SHA256 0413ad61bb54279dce511643db1f4e25b200209d192b74805989a9935fe0eece
MD5 80be3ead91496543561a9598ec1192b5
BLAKE2b-256 d40961d462baa9386122b7e6185a873b791ceb321f82dbcef051672e9f8052e5

See more details on using hashes here.

File details

Details for the file qamigrate-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: qamigrate-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 117.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.11

File hashes

Hashes for qamigrate-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c6e14a4622c500a319f26b7db1baed140acadf891c40945799cde9f47aac0ae4
MD5 558401e4274ff3fdc062f46c31f02bec
BLAKE2b-256 79adb214128ce8353828f847f80f6ec4ffc71383662f2d78f71ac5b5c63e60a5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page