npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vijaypjavvadi/sel2pw

v1.0.0

Published

Convert Java + Selenium + TestNG test suites to Playwright TypeScript (rule-based, AST-driven). Supports Selenium Java, C# NUnit, Cucumber BDD, SpecFlow with optional LLM fallback (Anthropic / OpenAI / Gemini).

Downloads

1,286

Readme

sel2pw — Selenium Java/TestNG → Playwright TypeScript converter

npm version npm downloads License: MIT CI Release Node codebases validated

Most teams are migrating off selenium-java + TestNG (and their BDD/Cucumber and C#/SpecFlow cousins) onto Playwright. The painful part isn't writing new tests — it's the thousands of existing ones you can't afford to throw away.

sel2pw is a CLI and a platform service that takes a Java/Selenium/TestNG project and emits an equivalent Playwright TypeScript project, plus a markdown review report listing everything a human still needs to look at.

What sel2pw is and isn't

sel2pw produces a skeleton for human cleanup — not a finished, runnable test suite. Validated against 15 real-world OSS Selenium codebases, the converter produces output where:

  • Small clean Page Objects (under ~100 lines, standard naming conventions, no exotic generics): output usually compiles with 0–10 TypeScript errors that take minutes to fix. Validated end-to-end on Playwright — tests launched in 3 browsers (Chromium / Firefox / WebKit) successfully.
  • Medium-complexity Page Objects (100–500 lines, some custom helpers): output typically has 20–80 TypeScript errors that take 15-60 min per file to clean up. Mostly project-specific helper imports + a few unsupported Java idioms.
  • Large complex utility classes (1,000+ lines, deep generics, project-specific reporting layers): output has hundreds to thousands of TS errors. For these files, plan a manual port — the converter saves typing on locators and assertions but the heavy logic still needs human attention.

The README's "what it converts" table below is honest about coverage. The 240-pattern reference at docs/CONVERSION_PATTERNS.md lists every pattern with its current support status. Run npx tsc --noEmit against the output before committing — the error count tells you exactly how much manual cleanup remains.

The pitch is "saves a month, not 100% automated." A typical 100-200 file Selenium project converts in 90 seconds and takes 5-15 hours of human cleanup, vs 200-400 hours of hand-migration. That math holds even when individual files have lots of TS errors.

Where this fits in the platform

sel2pw is the Migrate stage of the modern automation platform, alongside three sibling services:

| Stage | Service | What it does | | --- | --- | --- | | 1. Generate | test-case-generation-service (FastAPI, port 4100) | Author new tests from requirements | | 2. Migrate | sel2pw / Converter (this repo, port 4200) | Lift legacy Selenium suites to Playwright | | 3. Stabilise | self-healing-stage-services (FastAPI, port 8003) | Heal broken locators at runtime | | 4. Govern | ai-governance (Python lib + sidecar) | Sanitise every payload before any LLM call | | Orchestrate | modern-automation-platform (Express gateway, port 3000) | Auth, jobs, UI, artifact storage |

Everything is reachable through the platform gateway at /api/v1/converter/*, with the same auth, governance config, and provenance shape as the other services. See INTEGRATION.md for the API contract, gateway wiring, and cross-service flows.

Status — v0.10.3: Validated end-to-end against 8 real-world OSS Selenium codebases (selenium1–8 in the test matrix), 0 failed conversions, 0 unclassified files. 45/45 unit + snapshot tests green. Ships as both an npm package (@vijaypjavvadi/sel2pw) and a standalone Windows .exe distributed via the platform downloads endpoint. Stack: Selenium Java/TestNG, Selenium Java + Cucumber BDD, Selenium C# + NUnit, Selenium C# + SpecFlow — all auto-detected. Optional LLM fallback for genuinely-unknown shapes (Anthropic / OpenAI / Gemini, with ai-governance sanitisation enforced before any model call). SQLite failure telemetry so recurring patterns become one-line patches. See CHANGELOG.md for the full version history (0.1.0 → 0.10.3) and STATUS.md for the current verified state.

What it converts

| Selenium / TestNG | Playwright TypeScript | | --- | --- | | driver.get(url) | await page.goto(url) | | By.id("x") | page.locator('#x') | | By.cssSelector("…") | page.locator('…') | | By.xpath("…") | page.locator('xpath=…') | | By.linkText("Sign out") | page.getByRole('link', { name: 'Sign out' }) | | By.name("q") | page.locator('[name="q"]') | | @FindBy(id="x") WebElement el | readonly el: Locator; (initialised in ctor) | | el.click() | await el.click() | | el.sendKeys("…") | await el.fill('…') | | el.getText() | await el.innerText() | | el.isDisplayed() | await el.isVisible() | | Assert.assertEquals(a, b) | expect(a).toBe(b) | | Assert.assertTrue(x) | expect(x).toBe(true) | | @Test | test('name', async ({ page }) => { ... }) | | @BeforeMethod | test.beforeEach(...) | | @BeforeClass | test.beforeAll(...) | | WebDriverWait...until(...) | removed — Playwright auto-waits on locators | | Thread.sleep(ms) | await page.waitForTimeout(ms) (flagged: prefer waiting on a real condition) | | Page Object class | TS class with page: Page + Locator fields | | BaseTest (lifecycle in superclass) | Flagged → port to Playwright fixture |

Pipeline

Java source files
       │
       ▼
  ┌─────────┐
  │ scanner │  walk dir, classify each .java as test-class / page-object / base / unknown
  └────┬────┘
       ▼
  ┌─────────┐
  │ parser  │  extract IR: locator fields, methods + bodies, @Test/lifecycle annotations
  └────┬────┘
       ▼
  ┌──────────────┐
  │ transformers │  locatorMapper · apiMap · assertionMap · bodyTransformer
  └────┬─────────┘
       ▼
  ┌─────────┐
  │ emitters│  pageObjectEmitter · testClassEmitter · projectEmitter (templates)
  └────┬────┘
       ▼
output/
  pages/login.page.ts
  tests/login.spec.ts
  playwright.config.ts
  package.json
  CONVERSION_REVIEW.md   ← every warning + manual TODO

Install & run

npm install
npm run build

# convert
node dist/cli.js convert <input-java-project> --out <output-playwright-project>

# or dry-run analysis (no writes)
node dist/cli.js analyze <input-java-project>

# end-to-end demo on the bundled sample
npm run convert:sample

CLI commands:

sel2pw convert <inputDir> --out <outputDir> [--templates <dir>] [--dry-run]
sel2pw analyze <inputDir>

Programmatic API:

import { convert } from "sel2pw";
await convert({
  inputDir: "./my-selenium-project",
  outputDir: "./my-playwright-project",
});

Architecture

src/
├── cli.ts                    # commander CLI entry
├── index.ts                  # public convert() / analyze() API
├── types.ts                  # IR — JavaFile, PageObjectIR, TestClassIR, ReviewItem, etc.
├── scanner/projectScanner.ts # walk + classify .java files
├── parser/javaExtractor.ts   # extract IR from raw Java (regex + balanced braces)
├── transformers/
│   ├── locatorMapper.ts      # By.* → page.locator/getByRole
│   ├── apiMap.ts             # WebDriver/WebElement → Playwright async
│   ├── assertionMap.ts       # TestNG Assert → expect()
│   └── bodyTransformer.ts    # orchestrates per-method-body rewrites + warnings
├── emitters/
│   ├── pageObjectEmitter.ts  # POM IR → TS class
│   ├── testClassEmitter.ts   # TestClass IR → spec file
│   └── projectEmitter.ts     # writes templates + converted files
├── reports/reviewReport.ts   # CONVERSION_REVIEW.md
└── utils/naming.ts           # PascalCase / kebab-case / Java→TS type mapping

templates/                    # scaffolded into the output project
├── package.json.tmpl
├── playwright.config.ts.tmpl
├── tsconfig.json.tmpl
└── gitignore.tmpl

examples/selenium-testng-sample/   # input fixture for the demo
└── src/test/java/com/example/...

The IR boundary in parser/javaExtractor.ts is deliberately clean: today it's a regex+balanced-brace extractor (which works fine for conventional TestNG/POM shapes), but a real AST parser (e.g. java-parser on Chevrotain, or a JVM-side JavaParser sidecar) can be slotted in without changing scanner, transformers, or emitters.

What's not yet handled (flagged in CONVERSION_REVIEW.md)

  • @DataProvider parameterisation — emitted as a warning; convert manually to a for (const row of rows()) { test(...) } loop.
  • BaseTest superclass lifecycle — flagged; port shared setup into a Playwright fixture in tests/fixtures.ts.
  • Actions chainsActions(driver).moveToElement(el).click().perform()await locator.hover() + .click() (semantics differ; review).
  • JavascriptExecutor.executeScript(...) — flagged; convert to await page.evaluate(() => ...).
  • iframe switchTo().frame(...) — flagged; use page.frameLocator(...).
  • Alert handling — flagged; use page.on('dialog', d => d.accept()).
  • Cucumber .feature + step defs — not in MVP. Roadmap below.
  • C# / SpecFlow — not in MVP. Roadmap below.

Roadmap

The full punch list lives in PRODUCTION_TASKS.md. Headline:

| Phase | Status | Headline | | --- | --- | --- | | 0 — Platform integration | ✅ Complete | HTTP service at :4200, gateway routes, governance sidecar, self-healing shim, shared types, Docker | | 1 — Hardening | ✅ Complete | Real AST parser (java-parser) with regex fallback, unit + snapshot tests, error recovery, structured logger | | 2 — Coverage gaps | ✅ Complete | @DataProvider, BaseTest → fixture, testng.xml, Actions, executeScript, iframe, alert, cookies, uploads, Hamcrest, JUnit 4/5, .properties.env | | 3 — Output quality | ✅ Complete | Prettier, tsc validate, TODO markers, auth.setup.ts, MIGRATION_NOTES.md, --diff | | 4 — Distribution | ✅ Complete | LICENSE, CI matrix, release workflow, Dependabot, typedoc, Changesets, CONTRIBUTING | | 5 — Stretch | ✅ Scaffolds | Cucumber BDD, auto-fix loop, hybrid AST+LLM, behaviour-parity verifier, C#/SpecFlow design |

Development

npm install
npm run dev -- convert ./examples/selenium-testng-sample --out ./examples/output-playwright
npm test

License

MIT